Exemple #1
0
// NewModelManagerAPI creates a new api server endpoint for managing
// models.
func NewModelManagerAPI(
	st common.ModelManagerBackend,
	configGetter environs.EnvironConfigGetter,
	authorizer facade.Authorizer,
) (*ModelManagerAPI, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}
	// Since we know this is a user tag (because AuthClient is true),
	// we just do the type assertion to the UserTag.
	apiUser, _ := authorizer.GetAuthTag().(names.UserTag)
	// Pretty much all of the user manager methods have special casing for admin
	// users, so look once when we start and remember if the user is an admin.
	isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag())
	if err != nil {
		return nil, errors.Trace(err)
	}
	urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st)
	return &ModelManagerAPI{
		ModelStatusAPI: common.NewModelStatusAPI(st, authorizer, apiUser),
		state:          st,
		check:          common.NewBlockChecker(st),
		authorizer:     authorizer,
		toolsFinder:    common.NewToolsFinder(configGetter, st, urlGetter),
		apiUser:        apiUser,
		isAdmin:        isAdmin,
	}, nil
}
Exemple #2
0
func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool, develVersion bool) {
	var called bool
	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) {
		called = true
		c.Assert(filter.Number, gc.Equals, version.Current)
		c.Assert(filter.Series, gc.Equals, series.HostSeries())
		c.Assert(filter.Arch, gc.Equals, arch.HostArch())
		if develVersion {
			c.Assert(stream, gc.Equals, "devel")
		} else {
			c.Assert(stream, gc.Equals, "released")
		}
		return nil, errors.NotFoundf("tools")
	})
	toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s"))
	result, err := toolsFinder.FindTools(params.FindToolsParams{
		Number:       version.Current,
		MajorVersion: -1,
		MinorVersion: -1,
		Series:       series.HostSeries(),
		Arch:         arch.HostArch(),
	})
	c.Assert(err, jc.ErrorIsNil)
	if inStorage {
		c.Assert(result.Error, gc.IsNil)
		c.Assert(called, jc.IsFalse)
	} else {
		c.Assert(result.Error, gc.ErrorMatches, "tools not found")
		c.Assert(called, jc.IsTrue)
	}
}
Exemple #3
0
func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool) {
	var called bool
	s.PatchValue(common.EnvtoolsFindTools, func(g environs.ConfigGetter, major, minor int, filter coretools.Filter, allowRetry bool) (list coretools.List, err error) {
		called = true
		c.Assert(filter.Number, gc.Equals, version.Current.Number)
		c.Assert(filter.Series, gc.Equals, version.Current.Series)
		c.Assert(filter.Arch, gc.Equals, version.Current.Arch)
		return nil, errors.NotFoundf("tools")
	})
	toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s"))
	result, err := toolsFinder.FindTools(params.FindToolsParams{
		Number:       version.Current.Number,
		MajorVersion: -1,
		MinorVersion: -1,
		Series:       version.Current.Series,
		Arch:         version.Current.Arch,
	})
	c.Assert(err, gc.IsNil)
	if inStorage {
		c.Assert(result.Error, gc.IsNil)
		c.Assert(called, jc.IsFalse)
	} else {
		c.Assert(result.Error, gc.ErrorMatches, "tools not found")
		c.Assert(called, jc.IsTrue)
	}
}
Exemple #4
0
func (s *toolsSuite) TestFindToolsNotFound(c *gc.C) {
	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) {
		return nil, errors.NotFoundf("tools")
	})
	toolsFinder := common.NewToolsFinder(s.State, s.State, sprintfURLGetter("%s"))
	result, err := toolsFinder.FindTools(params.FindToolsParams{})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Error, jc.Satisfies, params.IsCodeNotFound)
}
Exemple #5
0
// NewProvisionerAPI creates a new server-side ProvisionerAPI facade.
func NewProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ProvisionerAPI, error) {
	if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() {
		return nil, common.ErrPerm
	}
	getAuthFunc := func() (common.AuthFunc, error) {
		isEnvironManager := authorizer.AuthEnvironManager()
		isMachineAgent := authorizer.AuthMachineAgent()
		authEntityTag := authorizer.GetAuthTag()

		return func(tag names.Tag) bool {
			if isMachineAgent && tag == authEntityTag {
				// A machine agent can always access its own machine.
				return true
			}
			switch tag := tag.(type) {
			case names.MachineTag:
				parentId := state.ParentId(tag.Id())
				if parentId == "" {
					// All top-level machines are accessible by the
					// environment manager.
					return isEnvironManager
				}
				// All containers with the authenticated machine as a
				// parent are accessible by it.
				// TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is
				// only equal to nil, but it suggests someone is passing an authorizer
				// with a nil tag.
				return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag
			default:
				return false
			}
		}, nil
	}
	env, err := st.Environment()
	if err != nil {
		return nil, err
	}
	urlGetter := common.NewToolsURLGetter(env.UUID(), st)
	return &ProvisionerAPI{
		Remover:                common.NewRemover(st, false, getAuthFunc),
		StatusSetter:           common.NewStatusSetter(st, getAuthFunc),
		StatusGetter:           common.NewStatusGetter(st, getAuthFunc),
		DeadEnsurer:            common.NewDeadEnsurer(st, getAuthFunc),
		PasswordChanger:        common.NewPasswordChanger(st, getAuthFunc),
		LifeGetter:             common.NewLifeGetter(st, getAuthFunc),
		StateAddresser:         common.NewStateAddresser(st),
		APIAddresser:           common.NewAPIAddresser(st, resources),
		EnvironWatcher:         common.NewEnvironWatcher(st, resources, authorizer),
		EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, resources, authorizer),
		InstanceIdGetter:       common.NewInstanceIdGetter(st, getAuthFunc),
		ToolsFinder:            common.NewToolsFinder(st, st, urlGetter),
		st:                     st,
		resources:              resources,
		authorizer:             authorizer,
		getAuthFunc:            getAuthFunc,
	}, nil
}
Exemple #6
0
func (s *toolsSuite) TestFindTools(c *gc.C) {
	envtoolsList := coretools.List{
		&coretools.Tools{
			Version: version.MustParseBinary("123.456.0-win81-alpha"),
			Size:    2048,
			SHA256:  "badf00d",
		},
		&coretools.Tools{
			Version: version.MustParseBinary("123.456.1-win81-alpha"),
		},
	}
	storageMetadata := []binarystorage.Metadata{{
		Version: "123.456.0-win81-alpha",
		Size:    1024,
		SHA256:  "feedface",
	}}

	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (coretools.List, error) {
		c.Assert(major, gc.Equals, 123)
		c.Assert(minor, gc.Equals, 456)
		c.Assert(stream, gc.Equals, "released")
		c.Assert(filter.Series, gc.Equals, "win81")
		c.Assert(filter.Arch, gc.Equals, "alpha")
		return envtoolsList, nil
	})
	toolsFinder := common.NewToolsFinder(
		stateenvirons.EnvironConfigGetter{s.State}, &mockToolsStorage{metadata: storageMetadata}, sprintfURLGetter("tools:%s"),
	)
	result, err := toolsFinder.FindTools(params.FindToolsParams{
		MajorVersion: 123,
		MinorVersion: 456,
		Series:       "win81",
		Arch:         "alpha",
	})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Error, gc.IsNil)
	c.Check(result.List, jc.DeepEquals, coretools.List{
		&coretools.Tools{
			Version: version.MustParseBinary(storageMetadata[0].Version),
			Size:    storageMetadata[0].Size,
			SHA256:  storageMetadata[0].SHA256,
			URL:     "tools:" + storageMetadata[0].Version,
		},
		&coretools.Tools{
			Version: version.MustParseBinary("123.456.1-win81-alpha"),
			URL:     "tools:123.456.1-win81-alpha",
		},
	})
}
Exemple #7
0
// NewClient creates a new instance of the Client Facade.
func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}
	urlGetter := common.NewToolsURLGetter(st.EnvironUUID(), st)
	return &Client{
		api: &API{
			state:        st,
			auth:         authorizer,
			resources:    resources,
			statusSetter: common.NewStatusSetter(st, common.AuthAlways()),
			toolsFinder:  common.NewToolsFinder(st, st, urlGetter),
		},
		check: common.NewBlockChecker(st)}, nil
}
Exemple #8
0
// NewEnvironmentManagerAPI creates a new api server endpoint for managing
// environments.
func NewEnvironmentManagerAPI(
	st *state.State,
	resources *common.Resources,
	authorizer common.Authorizer,
) (*EnvironmentManagerAPI, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	urlGetter := common.NewToolsURLGetter(st.EnvironUUID(), st)
	return &EnvironmentManagerAPI{
		state:       getState(st),
		authorizer:  authorizer,
		toolsFinder: common.NewToolsFinder(st, st, urlGetter),
	}, nil
}
Exemple #9
0
// NewClient creates a new instance of the Client Facade.
func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}
	apiState := getState(st)
	urlGetter := common.NewToolsURLGetter(apiState.ModelUUID(), apiState)
	client := &Client{
		api: &API{
			stateAccessor: apiState,
			auth:          authorizer,
			resources:     resources,
			statusSetter:  common.NewStatusSetter(st, common.AuthAlways()),
			toolsFinder:   common.NewToolsFinder(st, st, urlGetter),
		},
		check: common.NewBlockChecker(st)}
	return client, nil
}
Exemple #10
0
// NewClient creates a new instance of the Client Facade.
func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}
	env, err := st.Environment()
	if err != nil {
		return nil, err
	}
	urlGetter := common.NewToolsURLGetter(env.UUID(), st)
	return &Client{api: &API{
		state:        st,
		auth:         authorizer,
		resources:    resources,
		statusSetter: common.NewStatusSetter(st, common.AuthAlways()),
		toolsFinder:  common.NewToolsFinder(st, st, urlGetter),
	}}, nil
}
Exemple #11
0
func (s *toolsSuite) TestFindToolsToolsStorageError(c *gc.C) {
	var called bool
	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) {
		called = true
		return nil, errors.NotFoundf("tools")
	})
	toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{
		err: errors.New("AllMetadata failed"),
	}, sprintfURLGetter("tools:%s"))
	result, err := toolsFinder.FindTools(params.FindToolsParams{
		MajorVersion: 1,
		MinorVersion: -1,
	})
	c.Assert(err, jc.ErrorIsNil)
	// ToolsStorage errors always cause FindTools to bail. Only
	// if AllMetadata succeeds but returns nothing that matches
	// do we continue on to searching simplestreams.
	c.Assert(result.Error, gc.ErrorMatches, "AllMetadata failed")
	c.Assert(called, jc.IsFalse)
}
Exemple #12
0
// NewModelManagerAPI creates a new api server endpoint for managing
// models.
func NewModelManagerAPI(st Backend, authorizer common.Authorizer) (*ModelManagerAPI, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}
	// Since we know this is a user tag (because AuthClient is true),
	// we just do the type assertion to the UserTag.
	apiUser, _ := authorizer.GetAuthTag().(names.UserTag)
	// Pretty much all of the user manager methods have special casing for admin
	// users, so look once when we start and remember if the user is an admin.
	isAdmin, err := st.IsControllerAdministrator(apiUser)
	if err != nil {
		return nil, errors.Trace(err)
	}
	urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st)
	return &ModelManagerAPI{
		state:       st,
		authorizer:  authorizer,
		toolsFinder: common.NewToolsFinder(st, st, urlGetter),
		apiUser:     apiUser,
		isAdmin:     isAdmin,
	}, nil
}
Exemple #13
0
func (s *serverSuite) SetUpTest(c *gc.C) {
	s.ConfigAttrs = map[string]interface{}{
		"authorized-keys": coretesting.FakeAuthKeys,
	}
	s.baseSuite.SetUpTest(c)

	var err error
	auth := testing.FakeAuthorizer{
		Tag:            s.AdminUserTag(c),
		EnvironManager: true,
	}
	urlGetter := common.NewToolsURLGetter(s.State.ModelUUID(), s.State)
	configGetter := stateenvirons.EnvironConfigGetter{s.State}
	statusSetter := common.NewStatusSetter(s.State, common.AuthAlways())
	toolsFinder := common.NewToolsFinder(configGetter, s.State, urlGetter)
	s.newEnviron = func() (environs.Environ, error) {
		return environs.GetEnviron(configGetter, environs.New)
	}
	newEnviron := func() (environs.Environ, error) {
		return s.newEnviron()
	}
	blockChecker := common.NewBlockChecker(s.State)
	modelConfigAPI, err := modelconfig.NewModelConfigAPI(s.State, auth)
	c.Assert(err, jc.ErrorIsNil)
	s.client, err = client.NewClient(
		client.NewStateBackend(s.State),
		modelConfigAPI,
		common.NewResources(),
		auth,
		statusSetter,
		toolsFinder,
		newEnviron,
		blockChecker,
	)
	c.Assert(err, jc.ErrorIsNil)
}
Exemple #14
0
func newClient(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*Client, error) {
	urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st)
	configGetter := stateenvirons.EnvironConfigGetter{st}
	statusSetter := common.NewStatusSetter(st, common.AuthAlways())
	toolsFinder := common.NewToolsFinder(configGetter, st, urlGetter)
	newEnviron := func() (environs.Environ, error) {
		return environs.GetEnviron(configGetter, environs.New)
	}
	blockChecker := common.NewBlockChecker(st)
	modelConfigAPI, err := modelconfig.NewModelConfigAPI(st, authorizer)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return NewClient(
		NewStateBackend(st),
		modelConfigAPI,
		resources,
		authorizer,
		statusSetter,
		toolsFinder,
		newEnviron,
		blockChecker,
	)
}
Exemple #15
0
// InstanceConfig returns information from the environment config that
// is needed for machine cloud-init (for non-controllers only). It
// is exposed for testing purposes.
// TODO(rog) fix environs/manual tests so they do not need to call this, or move this elsewhere.
func InstanceConfig(st *state.State, machineId, nonce, dataDir string) (*instancecfg.InstanceConfig, error) {
	environConfig, err := st.ModelConfig()
	if err != nil {
		return nil, err
	}

	// Get the machine so we can get its series and arch.
	// If the Arch is not set in hardware-characteristics,
	// an error is returned.
	machine, err := st.Machine(machineId)
	if err != nil {
		return nil, err
	}
	hc, err := machine.HardwareCharacteristics()
	if err != nil {
		return nil, err
	}
	if hc.Arch == nil {
		return nil, fmt.Errorf("arch is not set for %q", machine.Tag())
	}

	// Find the appropriate tools information.
	agentVersion, ok := environConfig.AgentVersion()
	if !ok {
		return nil, errors.New("no agent version set in model configuration")
	}
	environment, err := st.Model()
	if err != nil {
		return nil, err
	}
	urlGetter := common.NewToolsURLGetter(environment.UUID(), st)
	toolsFinder := common.NewToolsFinder(st, st, urlGetter)
	findToolsResult, err := toolsFinder.FindTools(params.FindToolsParams{
		Number:       agentVersion,
		MajorVersion: -1,
		MinorVersion: -1,
		Series:       machine.Series(),
		Arch:         *hc.Arch,
	})
	if err != nil {
		return nil, err
	}
	if findToolsResult.Error != nil {
		return nil, findToolsResult.Error
	}
	tools := findToolsResult.List[0]

	// Find the API endpoints.
	env, err := environs.New(environConfig)
	if err != nil {
		return nil, err
	}
	apiInfo, err := environs.APIInfo(env)
	if err != nil {
		return nil, err
	}

	auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo)
	mongoInfo, apiInfo, err := auth.SetupAuthentication(machine)
	if err != nil {
		return nil, err
	}

	// Find requested networks.
	networks, err := machine.RequestedNetworks()
	if err != nil {
		return nil, err
	}

	// Figure out if secure connections are supported.
	info, err := st.StateServingInfo()
	if err != nil {
		return nil, err
	}
	secureServerConnection := info.CAPrivateKey != ""
	icfg, err := instancecfg.NewInstanceConfig(machineId, nonce, env.Config().ImageStream(), machine.Series(), "",
		secureServerConnection, networks, mongoInfo, apiInfo,
	)
	if err != nil {
		return nil, err
	}
	if dataDir != "" {
		icfg.DataDir = dataDir
	}
	icfg.Tools = tools
	err = instancecfg.FinishInstanceConfig(icfg, environConfig)
	if err != nil {
		return nil, err
	}
	return icfg, nil
}
Exemple #16
0
// InstanceConfig returns information from the environment config that
// is needed for machine cloud-init (for non-controllers only). It
// is exposed for testing purposes.
// TODO(rog) fix environs/manual tests so they do not need to call this, or move this elsewhere.
func InstanceConfig(st *state.State, machineId, nonce, dataDir string) (*instancecfg.InstanceConfig, error) {
	environConfig, err := st.ModelConfig()
	if err != nil {
		return nil, errors.Annotate(err, "getting model config")
	}

	// Get the machine so we can get its series and arch.
	// If the Arch is not set in hardware-characteristics,
	// an error is returned.
	machine, err := st.Machine(machineId)
	if err != nil {
		return nil, errors.Annotate(err, "getting machine")
	}
	hc, err := machine.HardwareCharacteristics()
	if err != nil {
		return nil, errors.Annotate(err, "getting machine hardware characteristics")
	}
	if hc.Arch == nil {
		return nil, fmt.Errorf("arch is not set for %q", machine.Tag())
	}

	// Find the appropriate tools information.
	agentVersion, ok := environConfig.AgentVersion()
	if !ok {
		return nil, errors.New("no agent version set in model configuration")
	}
	environment, err := st.Model()
	if err != nil {
		return nil, errors.Annotate(err, "getting state model")
	}
	urlGetter := common.NewToolsURLGetter(environment.UUID(), st)
	toolsFinder := common.NewToolsFinder(st, st, urlGetter)
	findToolsResult, err := toolsFinder.FindTools(params.FindToolsParams{
		Number:       agentVersion,
		MajorVersion: -1,
		MinorVersion: -1,
		Series:       machine.Series(),
		Arch:         *hc.Arch,
	})
	if err != nil {
		return nil, errors.Annotate(err, "finding tools")
	}
	if findToolsResult.Error != nil {
		return nil, errors.Annotate(findToolsResult.Error, "finding tools")
	}
	tools := findToolsResult.List[0]

	// Get the API connection info; attempt all API addresses.
	apiHostPorts, err := st.APIHostPorts()
	if err != nil {
		return nil, errors.Annotate(err, "getting API addresses")
	}
	apiAddrs := make(set.Strings)
	for _, hostPorts := range apiHostPorts {
		for _, hp := range hostPorts {
			apiAddrs.Add(hp.NetAddr())
		}
	}
	apiInfo := &api.Info{
		Addrs:    apiAddrs.SortedValues(),
		CACert:   st.CACert(),
		ModelTag: st.ModelTag(),
	}

	auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo)
	mongoInfo, apiInfo, err := auth.SetupAuthentication(machine)
	if err != nil {
		return nil, errors.Annotate(err, "setting up machine authentication")
	}

	// Find requested networks.
	networks, err := machine.RequestedNetworks()
	if err != nil {
		return nil, errors.Annotate(err, "getting requested networks for machine")
	}

	// Figure out if secure connections are supported.
	info, err := st.StateServingInfo()
	if err != nil {
		return nil, errors.Annotate(err, "getting state serving info")
	}
	secureServerConnection := info.CAPrivateKey != ""
	icfg, err := instancecfg.NewInstanceConfig(machineId, nonce, environConfig.ImageStream(), machine.Series(), "",
		secureServerConnection, networks, mongoInfo, apiInfo,
	)
	if err != nil {
		return nil, errors.Annotate(err, "initializing instance config")
	}
	if dataDir != "" {
		icfg.DataDir = dataDir
	}
	icfg.Tools = tools
	err = instancecfg.FinishInstanceConfig(icfg, environConfig)
	if err != nil {
		return nil, errors.Annotate(err, "finishing instance config")
	}
	return icfg, nil
}