• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Golang names.ParseTag函数代码示例

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

本文整理汇总了Golang中github.com/juju/names.ParseTag函数的典型用法代码示例。如果您正苦于以下问题:Golang ParseTag函数的具体用法?Golang ParseTag怎么用?Golang ParseTag使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。



在下文中一共展示了ParseTag函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。

示例1: networkParamsToStateParams

func networkParamsToStateParams(networks []params.Network, ifaces []params.NetworkInterface) (
	[]state.NetworkInfo, []state.NetworkInterfaceInfo, error,
) {
	stateNetworks := make([]state.NetworkInfo, len(networks))
	for i, network := range networks {
		tag, err := names.ParseTag(network.Tag, names.NetworkTagKind)
		if err != nil {
			return nil, nil, err
		}
		stateNetworks[i] = state.NetworkInfo{
			Name:       tag.Id(),
			ProviderId: network.ProviderId,
			CIDR:       network.CIDR,
			VLANTag:    network.VLANTag,
		}
	}
	stateInterfaces := make([]state.NetworkInterfaceInfo, len(ifaces))
	for i, iface := range ifaces {
		tag, err := names.ParseTag(iface.NetworkTag, names.NetworkTagKind)
		if err != nil {
			return nil, nil, err
		}
		stateInterfaces[i] = state.NetworkInterfaceInfo{
			MACAddress:    iface.MACAddress,
			NetworkName:   tag.Id(),
			InterfaceName: iface.InterfaceName,
			IsVirtual:     iface.IsVirtual,
		}
	}
	return stateNetworks, stateInterfaces, nil
}
开发者ID:rogpeppe,项目名称:juju,代码行数:31,代码来源:provisioner.go


示例2: cacheAPIInfo

// cacheAPIInfo updates the local environment settings (.jenv file)
// with the provided apiInfo, assuming we've just successfully
// connected to the API server.
func cacheAPIInfo(info configstore.EnvironInfo, apiInfo *api.Info) (err error) {
	defer errors.Contextf(&err, "failed to cache API credentials")
	environUUID := ""
	if apiInfo.EnvironTag != "" {
		tag, err := names.ParseTag(apiInfo.Tag, names.EnvironTagKind)
		if err != nil {
			return err
		}
		environUUID = tag.Id()
	}
	info.SetAPIEndpoint(configstore.APIEndpoint{
		Addresses:   apiInfo.Addrs,
		CACert:      string(apiInfo.CACert),
		EnvironUUID: environUUID,
	})
	tag, err := names.ParseTag(apiInfo.Tag, names.UserTagKind)
	if err != nil {
		return err
	}
	info.SetAPICredentials(configstore.APICredentials{
		User:     tag.Id(),
		Password: apiInfo.Password,
	})
	return info.Write()
}
开发者ID:rogpeppe,项目名称:juju,代码行数:28,代码来源:api.go


示例3: Remove

// Remove removes volumes and filesystems from state.
func (s *StorageProvisionerAPI) Remove(args params.Entities) (params.ErrorResults, error) {
	canAccess, err := s.getStorageEntityAuthFunc()
	if err != nil {
		return params.ErrorResults{}, err
	}
	results := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	one := func(arg params.Entity) error {
		tag, err := names.ParseTag(arg.Tag)
		if err != nil {
			return errors.Trace(err)
		}
		if !canAccess(tag) {
			return common.ErrPerm
		}
		switch tag := tag.(type) {
		case names.FilesystemTag:
			return s.st.RemoveFilesystem(tag)
		case names.VolumeTag:
			return s.st.RemoveVolume(tag)
		default:
			// should have been picked up by canAccess
			logger.Debugf("unexpected %v tag", tag.Kind())
			return common.ErrPerm
		}
	}
	for i, arg := range args.Entities {
		err := one(arg)
		results.Results[i].Error = common.ServerError(err)
	}
	return results, nil
}
开发者ID:imoapps,项目名称:juju,代码行数:34,代码来源:storageprovisioner.go


示例4: Name

// Name returns the unit's name.
func (u *Unit) Name() string {
	tag, err := names.ParseTag(u.tag, names.UnitTagKind)
	if err != nil {
		panic(err)
	}
	return tag.Id()
}
开发者ID:rogpeppe,项目名称:juju,代码行数:8,代码来源:unit.go


示例5: TestEntitySetPassword

func (s *machineSuite) TestEntitySetPassword(c *gc.C) {
	entity, err := apiagent.NewState(s.st).Entity(s.machine.Tag())
	c.Assert(err, jc.ErrorIsNil)

	err = entity.SetPassword("foo")
	c.Assert(err, gc.ErrorMatches, "password is only 3 bytes long, and is not a valid Agent password")
	err = entity.SetPassword("foo-12345678901234567890")
	c.Assert(err, jc.ErrorIsNil)
	err = entity.ClearReboot()
	c.Assert(err, jc.ErrorIsNil)

	err = s.machine.Refresh()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(s.machine.PasswordValid("bar"), jc.IsFalse)
	c.Assert(s.machine.PasswordValid("foo-12345678901234567890"), jc.IsTrue)

	// Check that we cannot log in to mongo with the correct password.
	// This is because there's no mongo password set for s.machine,
	// which has JobHostUnits
	info := s.MongoInfo(c)
	// TODO(dfc) this entity.Tag should return a Tag
	tag, err := names.ParseTag(entity.Tag())
	c.Assert(err, jc.ErrorIsNil)
	info.Tag = tag
	info.Password = "foo-12345678901234567890"
	err = tryOpenState(s.State.ModelTag(), info)
	c.Assert(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized)
}
开发者ID:AlexisBruemmer,项目名称:juju,代码行数:28,代码来源:machine_test.go


示例6: Remove

// Remove removes every given entity from state, calling EnsureDead
// first, then Remove. It will fail if the entity is not present.
func (r *Remover) Remove(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canModify, err := r.getCanModify()
	if err != nil {
		return params.ErrorResults{}, errors.Trace(err)
	}
	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		err = ErrPerm
		if canModify(tag) {
			err = r.removeEntity(tag)
		}
		result.Results[i].Error = ServerError(err)
	}
	return result, nil
}
开发者ID:imoapps,项目名称:juju,代码行数:27,代码来源:remove.go


示例7: WatchInterfaces

// WatchInterfaces returns a NotifyWatcher for observing changes
// to each unit's service configuration settings.
func (n *NetworkerAPI) WatchInterfaces(args params.Entities) (params.NotifyWatchResults, error) {
	result := params.NotifyWatchResults{
		Results: make([]params.NotifyWatchResult, len(args.Entities)),
	}
	canAccess, err := n.getAuthFunc()
	if err != nil {
		return result, err
	}
	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		if !canAccess(tag) {
			err = common.ErrPerm
		} else {
			tag, ok := tag.(names.MachineTag)
			if ok {
				id := tag.Id()
				result.Results[i].NotifyWatcherId, err = n.watchOneMachineInterfaces(id)
			}
		}
		result.Results[i].Error = common.ServerError(err)
	}
	return result, nil
}
开发者ID:imoapps,项目名称:juju,代码行数:29,代码来源:networker.go


示例8: WatchRetryStrategy

// WatchRetryStrategy watches for changes to the environment. Currently we only allow
// changes to the boolean that determines whether retries should be attempted or not.
func (h *RetryStrategyAPI) WatchRetryStrategy(args params.Entities) (params.NotifyWatchResults, error) {
	results := params.NotifyWatchResults{
		Results: make([]params.NotifyWatchResult, len(args.Entities)),
	}
	canAccess, err := h.accessUnit()
	if err != nil {
		return params.NotifyWatchResults{}, errors.Trace(err)
	}
	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			results.Results[i].Error = common.ServerError(err)
			continue
		}
		err = common.ErrPerm
		if canAccess(tag) {
			watch := h.st.WatchForModelConfigChanges()
			// Consume the initial event. Technically, API calls to Watch
			// 'transmit' the initial event in the Watch response. But
			// NotifyWatchers have no state to transmit.
			if _, ok := <-watch.Changes(); ok {
				results.Results[i].NotifyWatcherId = h.resources.Register(watch)
				err = nil
			} else {
				err = watcher.EnsureErr(watch)
			}
		}
		results.Results[i].Error = common.ServerError(err)
	}
	return results, nil
}
开发者ID:AlexisBruemmer,项目名称:juju,代码行数:33,代码来源:retrystrategy.go


示例9: checkCreds

// checkCreds validates the entities credentials in the current environment.
// If the entity is a user, and lookForEnvUser is true, an env user must exist
// for the environment.  In the case of a user logging in to the server, but
// not an environment, there is no env user needed.  While we have the env
// user, if we do have it, update the last login time.
func checkCreds(st *state.State, req params.LoginRequest, lookForEnvUser bool) (state.Entity, *time.Time, error) {
	tag, err := names.ParseTag(req.AuthTag)
	if err != nil {
		return nil, nil, err
	}
	entity, err := st.FindEntity(tag)
	if errors.IsNotFound(err) {
		// We return the same error when an entity does not exist as for a bad
		// password, so that we don't allow unauthenticated users to find
		// information about existing entities.
		logger.Debugf("entity %q not found", tag)
		return nil, nil, common.ErrBadCreds
	}
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	authenticator, err := authentication.FindEntityAuthenticator(entity)
	if err != nil {
		return nil, nil, err
	}

	if err = authenticator.Authenticate(entity, req.Credentials, req.Nonce); err != nil {
		logger.Debugf("bad credentials")
		return nil, nil, err
	}

	// For user logins, update the last login time.
	// NOTE: this code path is only for local users. When we support remote
	// user logins with bearer tokens, we will need to make sure that we also
	// update the last connection times for the environment users there.
	var lastLogin *time.Time
	if user, ok := entity.(*state.User); ok {
		userLastLogin, err := user.LastLogin()
		if err != nil && !state.IsNeverLoggedInError(err) {
			return nil, nil, errors.Trace(err)
		}
		if lookForEnvUser {
			envUser, err := st.EnvironmentUser(user.UserTag())
			if err != nil {
				return nil, nil, errors.Wrap(err, common.ErrBadCreds)
			}
			// The last connection for the environment takes precedence over
			// the local user last login time.
			userLastLogin, err = envUser.LastConnection()
			if err != nil && !state.IsNeverConnectedError(err) {
				return nil, nil, errors.Trace(err)
			}
			envUser.UpdateLastConnection()
		}
		// Only update the user's last login time if it is a successful
		// login, meaning that if we are logging into an environment, make
		// sure that there is an environment user in that environment for
		// this user.
		user.UpdateLastLogin()
		lastLogin = &userLastLogin
	}

	return entity, lastLogin, nil
}
开发者ID:kakamessi99,项目名称:juju,代码行数:65,代码来源:admin.go


示例10: WatchLoggingConfig

// WatchLoggingConfig starts a watcher to track changes to the logging config
// for the agents specified..  Unfortunately the current infrastruture makes
// watching parts of the config non-trivial, so currently any change to the
// config will cause the watcher to notify the client.
func (api *LoggerAPI) WatchLoggingConfig(arg params.Entities) params.NotifyWatchResults {
	result := make([]params.NotifyWatchResult, len(arg.Entities))
	for i, entity := range arg.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result[i].Error = common.ServerError(err)
			continue
		}
		err = common.ErrPerm
		if api.authorizer.AuthOwner(tag) {
			watch := api.state.WatchForEnvironConfigChanges()
			// Consume the initial event. Technically, API calls to Watch
			// 'transmit' the initial event in the Watch response. But
			// NotifyWatchers have no state to transmit.
			if _, ok := <-watch.Changes(); ok {
				result[i].NotifyWatcherId = api.resources.Register(watch)
				err = nil
			} else {
				err = watcher.MustErr(watch)
			}
		}
		result[i].Error = common.ServerError(err)
	}
	return params.NotifyWatchResults{Results: result}
}
开发者ID:kapilt,项目名称:juju,代码行数:29,代码来源:logger.go


示例11: LoggingConfig

// LoggingConfig reports the logging configuration for the agents specified.
func (api *LoggerAPI) LoggingConfig(arg params.Entities) params.StringResults {
	if len(arg.Entities) == 0 {
		return params.StringResults{}
	}
	results := make([]params.StringResult, len(arg.Entities))
	config, configErr := api.state.EnvironConfig()
	for i, entity := range arg.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		err = common.ErrPerm
		if api.authorizer.AuthOwner(tag) {
			if configErr == nil {
				results[i].Result = config.LoggingConfig()
				err = nil
			} else {
				err = configErr
			}
		}
		results[i].Error = common.ServerError(err)
	}
	return params.StringResults{Results: results}
}
开发者ID:kapilt,项目名称:juju,代码行数:26,代码来源:logger.go


示例12: SetPasswords

// SetPasswords sets the given password for each supplied entity, if possible.
func (pc *PasswordChanger) SetPasswords(args params.EntityPasswords) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Changes)),
	}
	if len(args.Changes) == 0 {
		return result, nil
	}
	canChange, err := pc.getCanChange()
	if err != nil {
		return params.ErrorResults{}, errors.Trace(err)
	}
	for i, param := range args.Changes {
		tag, err := names.ParseTag(param.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		if !canChange(tag) {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		if err := pc.setPassword(tag, param.Password); err != nil {
			result.Results[i].Error = ServerError(err)
		}
	}
	return result, nil
}
开发者ID:imoapps,项目名称:juju,代码行数:28,代码来源:password.go


示例13: loginRequest

// loginRequest forms a LoginRequest from the information
// in the given HTTP request.
func (ctxt *httpContext) loginRequest(r *http.Request) (params.LoginRequest, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		// No authorization header implies an attempt
		// to login with macaroon authentication.
		return params.LoginRequest{
			Macaroons: httpbakery.RequestMacaroons(r),
		}, nil
	}
	parts := strings.Fields(authHeader)
	if len(parts) != 2 || parts[0] != "Basic" {
		// Invalid header format or no header provided.
		return params.LoginRequest{}, errors.New("invalid request format")
	}
	// Challenge is a base64-encoded "tag:pass" string.
	// See RFC 2617, Section 2.
	challenge, err := base64.StdEncoding.DecodeString(parts[1])
	if err != nil {
		return params.LoginRequest{}, errors.New("invalid request format")
	}
	tagPass := strings.SplitN(string(challenge), ":", 2)
	if len(tagPass) != 2 {
		return params.LoginRequest{}, errors.New("invalid request format")
	}
	// Ensure that a sensible tag was passed.
	_, err = names.ParseTag(tagPass[0])
	if err != nil {
		return params.LoginRequest{}, errors.Trace(common.ErrBadCreds)
	}
	return params.LoginRequest{
		AuthTag:     tagPass[0],
		Credentials: tagPass[1],
		Nonce:       r.Header.Get(params.MachineNonceHeader),
	}, nil
}
开发者ID:pmatulis,项目名称:juju,代码行数:37,代码来源:httpcontext.go


示例14: Name

// Name returns the service name.
func (s *Service) Name() string {
	tag, err := names.ParseTag(s.tag, names.ServiceTagKind)
	if err != nil {
		panic(fmt.Sprintf("%q is not a valid service tag", s.tag))
	}
	return tag.Id()
}
开发者ID:rogpeppe,项目名称:juju,代码行数:8,代码来源:service.go


示例15: Actions

// Actions takes a list of ActionTags, and returns the full Action for
// each ID.
func (a *ActionAPI) Actions(arg params.Entities) (params.ActionResults, error) {
	response := params.ActionResults{Results: make([]params.ActionResult, len(arg.Entities))}
	for i, entity := range arg.Entities {
		currentResult := &response.Results[i]
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			currentResult.Error = common.ServerError(common.ErrBadId)
			continue
		}
		actionTag, ok := tag.(names.ActionTag)
		if !ok {
			currentResult.Error = common.ServerError(common.ErrBadId)
			continue
		}
		action, err := a.state.ActionByTag(actionTag)
		if err != nil {
			currentResult.Error = common.ServerError(common.ErrBadId)
			continue
		}
		receiverTag, err := names.ActionReceiverTag(action.Receiver())
		if err != nil {
			currentResult.Error = common.ServerError(err)
			continue
		}
		response.Results[i] = common.MakeActionResult(receiverTag, action)
	}
	return response, nil
}
开发者ID:AlexisBruemmer,项目名称:juju,代码行数:30,代码来源:action.go


示例16: Tools

// Tools finds the tools necessary for the given agents.
func (t *ToolsGetter) Tools(args params.Entities) (params.ToolsResults, error) {
	result := params.ToolsResults{
		Results: make([]params.ToolsResult, len(args.Entities)),
	}
	canRead, err := t.getCanRead()
	if err != nil {
		return result, err
	}
	agentVersion, err := t.getGlobalAgentVersion()
	if err != nil {
		return result, err
	}
	toolsStorage, err := t.toolsStorageGetter.ToolsStorage()
	if err != nil {
		return result, err
	}
	defer toolsStorage.Close()

	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		agentTools, err := t.oneAgentTools(canRead, tag, agentVersion, toolsStorage)
		if err == nil {
			result.Results[i].Tools = agentTools
			// TODO(axw) Get rid of this in 1.22, when all upgraders
			// are known to ignore the flag.
			result.Results[i].DisableSSLHostnameVerification = true
		}
		result.Results[i].Error = ServerError(err)
	}
	return result, nil
}
开发者ID:pmatulis,项目名称:juju,代码行数:36,代码来源:tools.go


示例17: CharmURL

// CharmURL returns the charm URL for all given units or services.
func (u *UniterAPI) CharmURL(args params.Entities) (params.StringBoolResults, error) {
	result := params.StringBoolResults{
		Results: make([]params.StringBoolResult, len(args.Entities)),
	}
	accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
	canAccess, err := accessUnitOrService()
	if err != nil {
		return params.StringBoolResults{}, err
	}
	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		err = common.ErrPerm
		if canAccess(tag) {
			var unitOrService state.Entity
			unitOrService, err = u.st.FindEntity(tag)
			if err == nil {
				charmURLer := unitOrService.(interface {
					CharmURL() (*charm.URL, bool)
				})
				curl, ok := charmURLer.CharmURL()
				if curl != nil {
					result.Results[i].Result = curl.String()
					result.Results[i].Ok = ok
				}
			}
		}
		result.Results[i].Error = common.ServerError(err)
	}
	return result, nil
}
开发者ID:zhouqt,项目名称:juju,代码行数:35,代码来源:uniter.go


示例18: authenticate

// authenticate parses HTTP basic authentication and authorizes the
// request by looking up the provided tag and password against state.
func (h *httpHandler) authenticate(r *http.Request) error {
	parts := strings.Fields(r.Header.Get("Authorization"))
	if len(parts) != 2 || parts[0] != "Basic" {
		// Invalid header format or no header provided.
		return fmt.Errorf("invalid request format")
	}
	// Challenge is a base64-encoded "tag:pass" string.
	// See RFC 2617, Section 2.
	challenge, err := base64.StdEncoding.DecodeString(parts[1])
	if err != nil {
		return fmt.Errorf("invalid request format")
	}
	tagPass := strings.SplitN(string(challenge), ":", 2)
	if len(tagPass) != 2 {
		return fmt.Errorf("invalid request format")
	}
	// Only allow users, not agents.
	if _, err := names.ParseTag(tagPass[0], names.UserTagKind); err != nil {
		return common.ErrBadCreds
	}
	// Ensure the credentials are correct.
	_, err = checkCreds(h.state, params.Creds{
		AuthTag:  tagPass[0],
		Password: tagPass[1],
	})
	return err
}
开发者ID:rogpeppe,项目名称:juju,代码行数:29,代码来源:httphandler.go


示例19: InstanceId

// InstanceId returns the provider specific instance id for each given
// machine or an CodeNotProvisioned error, if not set.
func (ig *InstanceIdGetter) InstanceId(args params.Entities) (params.StringResults, error) {
	result := params.StringResults{
		Results: make([]params.StringResult, len(args.Entities)),
	}
	canRead, err := ig.getCanRead()
	if err != nil {
		return result, err
	}
	for i, entity := range args.Entities {
		tag, err := names.ParseTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		err = ErrPerm
		if canRead(tag) {
			var instanceId instance.Id
			instanceId, err = ig.getInstanceId(tag)
			if err == nil {
				result.Results[i].Result = string(instanceId)
			}
		}
		result.Results[i].Error = ServerError(err)
	}
	return result, nil
}
开发者ID:kapilt,项目名称:juju,代码行数:28,代码来源:instanceidgetter.go


示例20: Login

// Login authenticates as the entity with the given name and password.
// Subsequent requests on the state will act as that entity.  This
// method is usually called automatically by Open. The machine nonce
// should be empty unless logging in as a machine agent.
func (st *State) Login(tag, password, nonce string) error {
	var result params.LoginResult
	err := st.APICall("Admin", 0, "", "Login", &params.Creds{
		AuthTag:  tag,
		Password: password,
		Nonce:    nonce,
	}, &result)
	if err == nil {
		authtag, err := names.ParseTag(tag)
		if err != nil {
			return err
		}
		st.authTag = authtag
		hostPorts, err := addAddress(result.Servers, st.addr)
		if err != nil {
			st.Close()
			return err
		}
		st.hostPorts = hostPorts
		st.environTag = result.EnvironTag
		st.facadeVersions = make(map[string][]int, len(result.Facades))
		for _, facade := range result.Facades {
			st.facadeVersions[facade.Name] = facade.Versions
		}
	}
	return err
}
开发者ID:kapilt,项目名称:juju,代码行数:31,代码来源:state.go



注:本文中的github.com/juju/names.ParseTag函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Golang names.ParseUnitTag函数代码示例发布时间:2022-05-23
下一篇:
Golang names.ParseStorageTag函数代码示例发布时间:2022-05-23
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap