func (v *mockFilesystemAccessor) FilesystemParams(filesystems []names.FilesystemTag) ([]params.FilesystemParamsResult, error) { var result []params.FilesystemParamsResult for _, tag := range filesystems { if _, ok := v.provisionedFilesystems[tag.String()]; ok { result = append(result, params.FilesystemParamsResult{ Error: ¶ms.Error{Message: "already provisioned"}, }) } else { filesystemParams := params.FilesystemParams{ FilesystemTag: tag.String(), Size: 1024, Provider: "dummy", Tags: map[string]string{ "very": "fancy", }, } if _, ok := names.FilesystemMachine(tag); ok { // place all volume-backed filesystems on machine-scoped // volumes with the same ID as the filesystem. filesystemParams.VolumeTag = names.NewVolumeTag(tag.Id()).String() } result = append(result, params.FilesystemParamsResult{Result: filesystemParams}) } } return result, nil }
// SetFilesystemInfo sets the FilesystemInfo for the specified filesystem. func (st *State) SetFilesystemInfo(tag names.FilesystemTag, info FilesystemInfo) (err error) { defer errors.DeferredAnnotatef(&err, "cannot set info for filesystem %q", tag.Id()) if info.FilesystemId == "" { return errors.New("filesystem ID not set") } fs, err := st.Filesystem(tag) if err != nil { return errors.Trace(err) } // If the filesystem is volume-backed, the volume must be provisioned // and attachment first. if volumeTag, err := fs.Volume(); err == nil { machineTag, ok := names.FilesystemMachine(tag) if !ok { return errors.Errorf("filesystem %s is not machine-scoped, but volume-backed", tag.Id()) } volumeAttachment, err := st.VolumeAttachment(machineTag, volumeTag) if err != nil { return errors.Trace(err) } if _, err := volumeAttachment.Info(); err != nil { return errors.Trace(err) } } else if errors.Cause(err) != ErrNoBackingVolume { return errors.Trace(err) } buildTxn := func(attempt int) ([]txn.Op, error) { if attempt > 0 { fs, err = st.Filesystem(tag) if err != nil { return nil, errors.Trace(err) } } // If the filesystem has parameters, unset them // when we set info for the first time, ensuring // that params and info are mutually exclusive. var unsetParams bool if params, ok := fs.Params(); ok { info.Pool = params.Pool unsetParams = true } else { // Ensure immutable properties do not change. oldInfo, err := fs.Info() if err != nil { return nil, err } if err := validateFilesystemInfoChange(info, oldInfo); err != nil { return nil, err } } ops := setFilesystemInfoOps(tag, info, unsetParams) return ops, nil } return st.run(buildTxn) }
func (v *mockFilesystemAccessor) FilesystemParams(filesystems []names.FilesystemTag) ([]params.FilesystemParamsResult, error) { results := make([]params.FilesystemParamsResult, len(filesystems)) for i, tag := range filesystems { // Parameters are returned regardless of whether the filesystem // exists; this is to support destruction. filesystemParams := params.FilesystemParams{ FilesystemTag: tag.String(), Size: 1024, Provider: "dummy", Tags: map[string]string{ "very": "fancy", }, } if _, ok := names.FilesystemMachine(tag); ok { // place all volume-backed filesystems on machine-scoped // volumes with the same ID as the filesystem. filesystemParams.VolumeTag = names.NewVolumeTag(tag.Id()).String() } results[i] = params.FilesystemParamsResult{Result: filesystemParams} } return results, nil }
func assertFilesystemNoMachine(c *gc.C, id string) { _, ok := names.FilesystemMachine(names.NewFilesystemTag(id)) c.Assert(ok, gc.Equals, false) }
func assertFilesystemMachine(c *gc.C, id string, expect names.MachineTag) { t, ok := names.FilesystemMachine(names.NewFilesystemTag(id)) c.Assert(ok, gc.Equals, true) c.Assert(t, gc.Equals, expect) }
// NewStorageProvisionerAPI creates a new server-side StorageProvisionerAPI facade. func NewStorageProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*StorageProvisionerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } canAccessStorageMachine := func(tag names.MachineTag, allowEnvironManager bool) bool { authEntityTag := authorizer.GetAuthTag() if tag == authEntityTag { // Machine agents can access volumes // scoped to their own machine. return true } parentId := state.ParentId(tag.Id()) if parentId == "" { return allowEnvironManager && authorizer.AuthEnvironManager() } // All containers with the authenticated // machine as a parent are accessible by it. return names.NewMachineTag(parentId) == authEntityTag } getScopeAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { switch tag := tag.(type) { case names.EnvironTag: // Environment managers can access all volumes // and filesystems scoped to the environment. isEnvironManager := authorizer.AuthEnvironManager() return isEnvironManager && tag == st.EnvironTag() case names.MachineTag: return canAccessStorageMachine(tag, false) default: return false } }, nil } canAccessStorageEntity := func(tag names.Tag, allowMachines bool) bool { switch tag := tag.(type) { case names.VolumeTag: machineTag, ok := names.VolumeMachine(tag) if ok { return canAccessStorageMachine(machineTag, false) } return authorizer.AuthEnvironManager() case names.FilesystemTag: machineTag, ok := names.FilesystemMachine(tag) if ok { return canAccessStorageMachine(machineTag, false) } return authorizer.AuthEnvironManager() case names.MachineTag: return allowMachines && canAccessStorageMachine(tag, true) default: return false } } getStorageEntityAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { return canAccessStorageEntity(tag, false) }, nil } getLifeAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { return canAccessStorageEntity(tag, true) }, nil } getAttachmentAuthFunc := func() (func(names.MachineTag, names.Tag) bool, error) { // getAttachmentAuthFunc returns a function that validates // access by the authenticated user to an attachment. return func(machineTag names.MachineTag, attachmentTag names.Tag) bool { // Machine agents can access their own machine, and // machines contained. Environment managers can access // top-level machines. if !canAccessStorageMachine(machineTag, true) { return false } // Environment managers can access environment-scoped // volumes and volumes scoped to their own machines. // Other machine agents can access volumes regardless // of their scope. if !authorizer.AuthEnvironManager() { return true } var machineScope names.MachineTag var hasMachineScope bool switch attachmentTag := attachmentTag.(type) { case names.VolumeTag: machineScope, hasMachineScope = names.VolumeMachine(attachmentTag) case names.FilesystemTag: machineScope, hasMachineScope = names.FilesystemMachine(attachmentTag) } return !hasMachineScope || machineScope == authorizer.GetAuthTag() }, nil } getMachineAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if tag, ok := tag.(names.MachineTag); ok { return canAccessStorageMachine(tag, true) } return false }, nil } getBlockDevicesAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if tag, ok := tag.(names.MachineTag); ok { return canAccessStorageMachine(tag, false) } return false }, nil } stateInterface := getState(st) settings := getSettingsManager(st) return &StorageProvisionerAPI{ LifeGetter: common.NewLifeGetter(stateInterface, getLifeAuthFunc), DeadEnsurer: common.NewDeadEnsurer(stateInterface, getStorageEntityAuthFunc), EnvironWatcher: common.NewEnvironWatcher(stateInterface, resources, authorizer), InstanceIdGetter: common.NewInstanceIdGetter(st, getMachineAuthFunc), StatusSetter: common.NewStatusSetter(st, getStorageEntityAuthFunc), st: stateInterface, settings: settings, resources: resources, authorizer: authorizer, getScopeAuthFunc: getScopeAuthFunc, getStorageEntityAuthFunc: getStorageEntityAuthFunc, getAttachmentAuthFunc: getAttachmentAuthFunc, getMachineAuthFunc: getMachineAuthFunc, getBlockDevicesAuthFunc: getBlockDevicesAuthFunc, }, nil }