Пример #1
0
// SendMetrics will send any unsent metrics onto the metric collection service.
func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseEnvironTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		err = metricsender.SendMetrics(api.state, sender, maxBatchesPerSend)
		if err != nil {
			err = errors.Annotate(err, "failed to send metrics")
			logger.Warningf("%v", err)
			result.Results[i].Error = common.ServerError(err)
			continue
		}
	}
	return result, nil
}
Пример #2
0
// CleanupOldMetrics removes old metrics from the collection.
// The single arg params is expected to contain and environment uuid.
// Even though the call will delete all metrics across environments
// it serves to validate that the connection has access to at least one environment.
func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseEnvironTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		err = api.state.CleanupOldMetrics()
		if err != nil {
			err = errors.Annotate(err, "failed to cleanup old metrics")
			result.Results[i].Error = common.ServerError(err)
		}
	}
	return result, nil
}
Пример #3
0
// EnvironmentStatus returns a status summary for each environment tag passed in.
func (c *Client) EnvironmentStatus(tags ...names.EnvironTag) ([]base.EnvironmentStatus, error) {
	result := params.EnvironmentStatusResults{}
	envs := make([]params.Entity, len(tags))
	for i, tag := range tags {
		envs[i] = params.Entity{Tag: tag.String()}
	}
	req := params.Entities{
		Entities: envs,
	}
	if err := c.facade.FacadeCall("EnvironmentStatus", req, &result); err != nil {
		return nil, err
	}

	results := make([]base.EnvironmentStatus, len(result.Results))
	for i, r := range result.Results {
		env, err := names.ParseEnvironTag(r.EnvironTag)
		if err != nil {
			return nil, errors.Annotatef(err, "EnvironTag %q at position %d", r.EnvironTag, i)
		}
		owner, err := names.ParseUserTag(r.OwnerTag)
		if err != nil {
			return nil, errors.Annotatef(err, "OwnerTag %q at position %d", r.OwnerTag, i)
		}

		results[i] = base.EnvironmentStatus{
			UUID:               env.Id(),
			Life:               r.Life,
			Owner:              owner.Canonical(),
			HostedMachineCount: r.HostedMachineCount,
			ServiceCount:       r.ServiceCount,
		}

	}
	return results, nil
}
Пример #4
0
// 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.ParseEnvironTag(apiInfo.Tag)
		if err != nil {
			return err
		}
		environUUID = tag.Id()
	}
	info.SetAPIEndpoint(configstore.APIEndpoint{
		Addresses:   apiInfo.Addrs,
		CACert:      string(apiInfo.CACert),
		EnvironUUID: environUUID,
	})
	tag, err := names.ParseUserTag(apiInfo.Tag)
	if err != nil {
		return err
	}
	info.SetAPICredentials(configstore.APICredentials{
		User:     tag.Id(),
		Password: apiInfo.Password,
	})
	return info.Write()
}
Пример #5
0
func (s *environSuite) TestParseEnvironTag(c *gc.C) {
	for i, t := range parseEnvironTagTests {
		c.Logf("test %d: %s", i, t.tag)
		got, err := names.ParseEnvironTag(t.tag)
		if err != nil || t.err != nil {
			c.Check(err, gc.DeepEquals, t.err)
			continue
		}
		c.Check(got, gc.FitsTypeOf, t.expected)
		c.Check(got, gc.Equals, t.expected)
	}
}
Пример #6
0
// EnvironmentUUID returns the environment UUID from the client connection.
func (c *Client) EnvironmentUUID() string {
	value := c.st.EnvironTag()
	if value != "" {
		tag, err := names.ParseEnvironTag(value)
		if err != nil {
			logger.Warningf("environ tag not an environ: %v", err)
			return ""
		}
		return tag.Id()
	}
	return ""
}
Пример #7
0
// EnsureAvailabilitySingle applies a single StateServersSpec specification to the current environment.
// Exported so it can be called by the legacy client API in the client package.
func EnsureAvailabilitySingle(st *state.State, spec params.StateServersSpec) (params.StateServersChanges, error) {
	if !st.IsStateServer() {
		return params.StateServersChanges{}, errors.New("unsupported with hosted environments")
	}
	// Check if changes are allowed and the command may proceed.
	blockChecker := common.NewBlockChecker(st)
	if err := blockChecker.ChangeAllowed(); err != nil {
		return params.StateServersChanges{}, errors.Trace(err)
	}
	// Validate the environment tag if present.
	if spec.EnvironTag != "" {
		tag, err := names.ParseEnvironTag(spec.EnvironTag)
		if err != nil {
			return params.StateServersChanges{}, errors.Errorf("invalid environment tag: %v", err)
		}
		if _, err := st.FindEntity(tag); err != nil {
			return params.StateServersChanges{}, err
		}
	}

	series := spec.Series
	if series == "" {
		ssi, err := st.StateServerInfo()
		if err != nil {
			return params.StateServersChanges{}, err
		}

		// We should always have at least one voting machine
		// If we *really* wanted we could just pick whatever series is
		// in the majority, but really, if we always copy the value of
		// the first one, then they'll stay in sync.
		if len(ssi.VotingMachineIds) == 0 {
			// Better than a panic()?
			return params.StateServersChanges{}, fmt.Errorf("internal error, failed to find any voting machines")
		}
		templateMachine, err := st.Machine(ssi.VotingMachineIds[0])
		if err != nil {
			return params.StateServersChanges{}, err
		}
		series = templateMachine.Series()
	}
	changes, err := st.EnsureAvailability(spec.NumStateServers, spec.Constraints, series, spec.Placement)
	if err != nil {
		return params.StateServersChanges{}, err
	}
	return stateServersChanges(changes), nil
}
Пример #8
0
func (c *ControllerAPI) environStatus(tag string) (params.EnvironmentStatus, error) {
	var status params.EnvironmentStatus
	envTag, err := names.ParseEnvironTag(tag)
	if err != nil {
		return status, errors.Trace(err)
	}
	st, err := c.state.ForEnviron(envTag)
	if err != nil {
		return status, errors.Trace(err)
	}
	defer st.Close()

	machines, err := st.AllMachines()
	if err != nil {
		return status, errors.Trace(err)
	}

	var hostedMachines []*state.Machine
	for _, m := range machines {
		if !m.IsManager() {
			hostedMachines = append(hostedMachines, m)
		}
	}

	services, err := st.AllServices()
	if err != nil {
		return status, errors.Trace(err)
	}

	env, err := st.Environment()
	if err != nil {
		return status, errors.Trace(err)
	}
	if err != nil {
		return status, errors.Trace(err)
	}

	return params.EnvironmentStatus{
		EnvironTag:         tag,
		OwnerTag:           env.Owner().String(),
		Life:               params.Life(env.Life().String()),
		HostedMachineCount: len(hostedMachines),
		ServiceCount:       len(services),
	}, nil
}
Пример #9
0
Файл: api.go Проект: kapilt/juju
// cacheChangedAPIInfo updates the local environment settings (.jenv file)
// with the provided API server addresses if they have changed. It will also
// save the environment tag if it is available.
func cacheChangedAPIInfo(info configstore.EnvironInfo, hostPorts [][]network.HostPort, newEnvironTag string) error {
	var addrs []string
	for _, serverHostPorts := range hostPorts {
		for _, hostPort := range serverHostPorts {
			// Only cache addresses that are likely to be usable,
			// exclude localhost style ones.
			if hostPort.Scope != network.ScopeMachineLocal &&
				hostPort.Scope != network.ScopeLinkLocal {
				addrs = append(addrs, hostPort.NetAddr())
			}
		}
	}
	endpoint := info.APIEndpoint()
	changed := false
	if newEnvironTag != "" {
		tag, err := names.ParseEnvironTag(newEnvironTag)
		if err == nil {
			if environUUID := tag.Id(); endpoint.EnvironUUID != environUUID {
				changed = true
				endpoint.EnvironUUID = environUUID
			}
		} else {
			logger.Debugf("cannot parse environ tag: %v", err)
		}
	}
	if len(addrs) != 0 && addrsChanged(endpoint.Addresses, addrs) {
		logger.Debugf("API addresses changed from %q to %q", endpoint.Addresses, addrs)
		changed = true
		endpoint.Addresses = addrs
	}
	if !changed {
		return nil
	}
	info.SetAPIEndpoint(endpoint)
	if err := info.Write(); err != nil {
		return err
	}
	logger.Infof("updated API connection settings cache")
	return nil
}
Пример #10
0
// ensureAvailabilitySingle applies a single StateServersSpec specification to the current environment.
func (c *Client) ensureAvailabilitySingle(spec params.StateServersSpec) (params.StateServersChanges, error) {
	// Validate the environment tag if present.
	if spec.EnvironTag != "" {
		tag, err := names.ParseEnvironTag(spec.EnvironTag)
		if err != nil {
			return params.StateServersChanges{}, errors.Errorf("invalid environment tag: %v", err)
		}
		if _, err := c.api.state.FindEntity(tag); err != nil {
			return params.StateServersChanges{}, err
		}
	}

	series := spec.Series
	if series == "" {
		ssi, err := c.api.state.StateServerInfo()
		if err != nil {
			return params.StateServersChanges{}, err
		}

		// We should always have at least one voting machine
		// If we *really* wanted we could just pick whatever series is
		// in the majority, but really, if we always copy the value of
		// the first one, then they'll stay in sync.
		if len(ssi.VotingMachineIds) == 0 {
			// Better than a panic()?
			return params.StateServersChanges{}, fmt.Errorf("internal error, failed to find any voting machines")
		}
		templateMachine, err := c.api.state.Machine(ssi.VotingMachineIds[0])
		if err != nil {
			return params.StateServersChanges{}, err
		}
		series = templateMachine.Series()
	}
	changes, err := c.api.state.EnsureAvailability(spec.NumStateServers, spec.Constraints, series)
	if err != nil {
		return params.StateServersChanges{}, err
	}
	return stateServersChanges(changes), nil
}
Пример #11
0
// ServerTag returns the tag of the server we are connected to.
func (s *State) ServerTag() (names.EnvironTag, error) {
	return names.ParseEnvironTag(s.serverTag)
}
Пример #12
0
// EnvironTag returns the tag of the environment we are connected to.
func (s *State) EnvironTag() (names.EnvironTag, error) {
	return names.ParseEnvironTag(s.environTag)
}
Пример #13
0
// ControllerTag returns the tag of the server we are connected to.
func (s *state) ControllerTag() (names.EnvironTag, error) {
	return names.ParseEnvironTag(s.controllerTag)
}
Пример #14
0
func (formatter_1_18) unmarshal(data []byte) (*configInternal, error) {
	// NOTE: this needs to handle the absence of StatePort and get it from the
	// address
	var format format_1_18Serialization
	if err := goyaml.Unmarshal(data, &format); err != nil {
		return nil, err
	}
	if format.UpgradedToVersion == nil || *format.UpgradedToVersion == version.Zero {
		// Assume we upgrade from 1.16.
		upgradedToVersion := version.MustParse("1.16.0")
		format.UpgradedToVersion = &upgradedToVersion
	}
	tag, err := names.ParseTag(format.Tag)
	if err != nil {
		return nil, err
	}
	var envTag names.EnvironTag
	if format.Environment != "" {
		envTag, err = names.ParseEnvironTag(format.Environment)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	config := &configInternal{
		tag: tag,
		paths: NewPathsWithDefaults(Paths{
			DataDir:         format.DataDir,
			LogDir:          format.LogDir,
			MetricsSpoolDir: format.MetricsSpoolDir,
		}),
		jobs:              format.Jobs,
		upgradedToVersion: *format.UpgradedToVersion,
		nonce:             format.Nonce,
		environment:       envTag,
		caCert:            format.CACert,
		oldPassword:       format.OldPassword,
		values:            format.Values,
		preferIPv6:        format.PreferIPv6,
	}
	if len(format.StateAddresses) > 0 {
		config.stateDetails = &connectionDetails{
			format.StateAddresses,
			format.StatePassword,
		}
	}
	if len(format.APIAddresses) > 0 {
		config.apiDetails = &connectionDetails{
			format.APIAddresses,
			format.APIPassword,
		}
	}
	if len(format.StateServerKey) != 0 {
		config.servingInfo = &params.StateServingInfo{
			Cert:           format.StateServerCert,
			PrivateKey:     format.StateServerKey,
			CAPrivateKey:   format.CAPrivateKey,
			APIPort:        format.APIPort,
			StatePort:      format.StatePort,
			SharedSecret:   format.SharedSecret,
			SystemIdentity: format.SystemIdentity,
		}
		// There's a private key, then we need the state port,
		// which wasn't always in the  1.18 format. If it's not present
		// we can infer it from the ports in the state addresses.
		if config.servingInfo.StatePort == 0 {
			if len(format.StateAddresses) == 0 {
				return nil, fmt.Errorf("server key found but no state port")
			}

			_, portString, err := net.SplitHostPort(format.StateAddresses[0])
			if err != nil {
				return nil, err
			}
			statePort, err := strconv.Atoi(portString)
			if err != nil {
				return nil, err
			}
			config.servingInfo.StatePort = statePort
		}

	}
	return config, nil
}
Пример #15
0
func (s *fakeHomeSuite) TestEnvironmentTagValid(c *gc.C) {
	asString := testing.EnvironmentTag.String()
	tag, err := names.ParseEnvironTag(asString)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(tag, gc.Equals, testing.EnvironmentTag)
}
Пример #16
0
func Open(info *Info, opts DialOpts) (*State, error) {
	if len(info.Addrs) == 0 {
		return nil, fmt.Errorf("no API addresses to connect to")
	}
	pool := x509.NewCertPool()
	xcert, err := cert.ParseCert(info.CACert)
	if err != nil {
		return nil, err
	}
	pool.AddCert(xcert)

	var environUUID string
	if info.EnvironTag != "" {
		tag, err := names.ParseEnvironTag(info.EnvironTag)
		if err != nil {
			return nil, err
		}
		environUUID = tag.Id()
	}
	// Dial all addresses at reasonable intervals.
	try := parallel.NewTry(0, nil)
	defer try.Kill()
	var addrs []string
	for _, addr := range info.Addrs {
		if strings.HasPrefix(addr, "localhost:") {
			addrs = append(addrs, addr)
			break
		}
	}
	if len(addrs) == 0 {
		addrs = info.Addrs
	}
	for _, addr := range addrs {
		err := dialWebsocket(addr, environUUID, opts, pool, try)
		if err == parallel.ErrStopped {
			break
		}
		if err != nil {
			return nil, err
		}
		select {
		case <-time.After(opts.DialAddressInterval):
		case <-try.Dead():
		}
	}
	try.Close()
	result, err := try.Result()
	if err != nil {
		return nil, err
	}
	conn := result.(*websocket.Conn)
	logger.Infof("connection established to %q", conn.RemoteAddr())

	client := rpc.NewConn(jsoncodec.NewWebsocket(conn), nil)
	client.Start()
	st := &State{
		client:     client,
		conn:       conn,
		addr:       conn.Config().Location.Host,
		serverRoot: "https://" + conn.Config().Location.Host,
		tag:        info.Tag,
		password:   info.Password,
		certPool:   pool,
	}
	if info.Tag != "" || info.Password != "" {
		if err := st.Login(info.Tag, info.Password, info.Nonce); err != nil {
			conn.Close()
			return nil, err
		}
	}
	st.broken = make(chan struct{})
	st.closed = make(chan struct{})
	go st.heartbeatMonitor()
	return st, nil
}