func constructStartInstanceParams( machine *apiprovisioner.Machine, instanceConfig *instancecfg.InstanceConfig, provisioningInfo *params.ProvisioningInfo, possibleTools coretools.List, ) (environs.StartInstanceParams, error) { volumes := make([]storage.VolumeParams, len(provisioningInfo.Volumes)) for i, v := range provisioningInfo.Volumes { volumeTag, err := names.ParseVolumeTag(v.VolumeTag) if err != nil { return environs.StartInstanceParams{}, errors.Trace(err) } if v.Attachment == nil { return environs.StartInstanceParams{}, errors.Errorf("volume params missing attachment") } machineTag, err := names.ParseMachineTag(v.Attachment.MachineTag) if err != nil { return environs.StartInstanceParams{}, errors.Trace(err) } if machineTag != machine.Tag() { return environs.StartInstanceParams{}, errors.Errorf("volume attachment params has invalid machine tag") } if v.Attachment.InstanceId != "" { return environs.StartInstanceParams{}, errors.Errorf("volume attachment params specifies instance ID") } volumes[i] = storage.VolumeParams{ volumeTag, v.Size, storage.ProviderType(v.Provider), v.Attributes, v.Tags, &storage.VolumeAttachmentParams{ AttachmentParams: storage.AttachmentParams{ Machine: machineTag, ReadOnly: v.Attachment.ReadOnly, }, Volume: volumeTag, }, } } var subnetsToZones map[network.Id][]string if provisioningInfo.SubnetsToZones != nil { // Convert subnet provider ids from string to network.Id. subnetsToZones = make(map[network.Id][]string, len(provisioningInfo.SubnetsToZones)) for providerId, zones := range provisioningInfo.SubnetsToZones { subnetsToZones[network.Id(providerId)] = zones } } return environs.StartInstanceParams{ Constraints: provisioningInfo.Constraints, Tools: possibleTools, InstanceConfig: instanceConfig, Placement: provisioningInfo.Placement, DistributionGroup: machine.DistributionGroup, Volumes: volumes, SubnetsToZones: subnetsToZones, }, nil }
// Volumes returns details of volumes with the specified tags. func (s *StorageProvisionerAPI) Volumes(args params.Entities) (params.VolumeResults, error) { canAccess, err := s.getStorageEntityAuthFunc() if err != nil { return params.VolumeResults{}, common.ServerError(common.ErrPerm) } results := params.VolumeResults{ Results: make([]params.VolumeResult, len(args.Entities)), } one := func(arg params.Entity) (params.Volume, error) { tag, err := names.ParseVolumeTag(arg.Tag) if err != nil || !canAccess(tag) { return params.Volume{}, common.ErrPerm } volume, err := s.st.Volume(tag) if errors.IsNotFound(err) { return params.Volume{}, common.ErrPerm } else if err != nil { return params.Volume{}, err } return storagecommon.VolumeFromState(volume) } for i, arg := range args.Entities { var result params.VolumeResult volume, err := one(arg) if err != nil { result.Error = common.ServerError(err) } else { result.Result = volume } results.Results[i] = result } return results, nil }
// blobVolumeId returns the volume ID for a blob, and a boolean reporting // whether or not the blob's name matches the scheme we use. func blobVolumeId(blob azurestorage.Blob) (string, bool) { if !strings.HasSuffix(blob.Name, vhdExtension) { return "", false } volumeId := blob.Name[:len(blob.Name)-len(vhdExtension)] if _, err := names.ParseVolumeTag(volumeId); err != nil { return "", false } return volumeId, true }
func createVolumeInfo(result params.VolumeDetailsResult) (names.VolumeTag, VolumeInfo, error) { details := result.Details if details == nil { details = volumeDetailsFromLegacy(result) } volumeTag, err := names.ParseVolumeTag(details.VolumeTag) if err != nil { return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err) } var info VolumeInfo info.ProviderVolumeId = details.Info.VolumeId info.HardwareId = details.Info.HardwareId info.Size = details.Info.Size info.Persistent = details.Info.Persistent info.Status = EntityStatus{ details.Status.Status, details.Status.Info, // TODO(axw) we should support formatting as ISO time common.FormatTime(details.Status.Since, false), } if len(details.MachineAttachments) > 0 { machineAttachments := make(map[string]MachineVolumeAttachment) for machineTag, attachment := range details.MachineAttachments { machineId, err := idFromTag(machineTag) if err != nil { return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err) } machineAttachments[machineId] = MachineVolumeAttachment{ attachment.DeviceName, attachment.DeviceLink, attachment.BusAddress, attachment.ReadOnly, } } info.Attachments = &VolumeAttachments{ Machines: machineAttachments, } } if details.Storage != nil { storageTag, storageInfo, err := createStorageInfo(*details.Storage) if err != nil { return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err) } info.Storage = storageTag.Id() if storageInfo.Attachments != nil { info.Attachments.Units = storageInfo.Attachments.Units } } return volumeTag, info, nil }
// VolumeAttachmentInfosToState converts a map of volume tags to // params.VolumeAttachmentInfo to a map of volume tags to // state.VolumeAttachmentInfo. func VolumeAttachmentInfosToState(in map[string]params.VolumeAttachmentInfo) (map[names.VolumeTag]state.VolumeAttachmentInfo, error) { m := make(map[names.VolumeTag]state.VolumeAttachmentInfo) for k, v := range in { volumeTag, err := names.ParseVolumeTag(k) if err != nil { return nil, errors.Trace(err) } m[volumeTag] = VolumeAttachmentInfoToState(v) } return m, nil }
func (lvs *loopVolumeSource) destroyVolume(volumeId string) error { tag, err := names.ParseVolumeTag(volumeId) if err != nil { return errors.Errorf("invalid loop volume ID %q", volumeId) } loopFilePath := lvs.volumeFilePath(tag) err = os.Remove(loopFilePath) if err != nil && !os.IsNotExist(err) { return errors.Annotate(err, "removing loop backing file") } return nil }
// VolumeAttachmentToState converts a params.VolumeAttachment // to a state.VolumeAttachmentInfo and tags. func VolumeAttachmentToState(in params.VolumeAttachment) (names.MachineTag, names.VolumeTag, state.VolumeAttachmentInfo, error) { machineTag, err := names.ParseMachineTag(in.MachineTag) if err != nil { return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err } volumeTag, err := names.ParseVolumeTag(in.VolumeTag) if err != nil { return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err } info := VolumeAttachmentInfoToState(in.Info) return machineTag, volumeTag, info, nil }
func volumeFromParams(in params.Volume) (storage.Volume, error) { volumeTag, err := names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.Volume{}, errors.Trace(err) } return storage.Volume{ volumeTag, storage.VolumeInfo{ in.Info.VolumeId, in.Info.HardwareId, in.Info.Size, in.Info.Persistent, }, }, nil }
// VolumeToState converts a params.Volume to state.VolumeInfo // and names.VolumeTag. func VolumeToState(v params.Volume) (names.VolumeTag, state.VolumeInfo, error) { if v.VolumeTag == "" { return names.VolumeTag{}, state.VolumeInfo{}, errors.New("Tag is empty") } volumeTag, err := names.ParseVolumeTag(v.VolumeTag) if err != nil { return names.VolumeTag{}, state.VolumeInfo{}, errors.Trace(err) } return volumeTag, state.VolumeInfo{ v.Info.HardwareId, v.Info.Size, "", // pool is set by state v.Info.VolumeId, v.Info.Persistent, }, nil }
func volumeParamsFromParams(in params.VolumeParams) (storage.VolumeParams, error) { volumeTag, err := names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.VolumeParams{}, errors.Trace(err) } providerType := storage.ProviderType(in.Provider) var attachment *storage.VolumeAttachmentParams if in.Attachment != nil { if in.Attachment.Provider != in.Provider { return storage.VolumeParams{}, errors.Errorf( "storage provider mismatch: volume (%q), attachment (%q)", in.Provider, in.Attachment.Provider, ) } if in.Attachment.VolumeTag != in.VolumeTag { return storage.VolumeParams{}, errors.Errorf( "volume tag mismatch: volume (%q), attachment (%q)", in.VolumeTag, in.Attachment.VolumeTag, ) } machineTag, err := names.ParseMachineTag(in.Attachment.MachineTag) if err != nil { return storage.VolumeParams{}, errors.Annotate( err, "parsing attachment machine tag", ) } attachment = &storage.VolumeAttachmentParams{ AttachmentParams: storage.AttachmentParams{ Provider: providerType, Machine: machineTag, InstanceId: instance.Id(in.Attachment.InstanceId), ReadOnly: in.Attachment.ReadOnly, }, Volume: volumeTag, } } return storage.VolumeParams{ volumeTag, in.Size, providerType, in.Attributes, in.Tags, attachment, }, nil }
// volumeAttachmentsToState converts a slice of storage.VolumeAttachment to a // mapping of volume names to state.VolumeAttachmentInfo. func volumeAttachmentsToState(in []params.VolumeAttachment) (map[names.VolumeTag]state.VolumeAttachmentInfo, error) { m := make(map[names.VolumeTag]state.VolumeAttachmentInfo) for _, v := range in { if v.VolumeTag == "" { return nil, errors.New("Tag is empty") } volumeTag, err := names.ParseVolumeTag(v.VolumeTag) if err != nil { return nil, errors.Trace(err) } m[volumeTag] = state.VolumeAttachmentInfo{ v.Info.DeviceName, v.Info.ReadOnly, } } return m, nil }
func volumeAttachmentFromParams(in params.VolumeAttachment) (storage.VolumeAttachment, error) { volumeTag, err := names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.VolumeAttachment{}, errors.Trace(err) } machineTag, err := names.ParseMachineTag(in.MachineTag) if err != nil { return storage.VolumeAttachment{}, errors.Trace(err) } return storage.VolumeAttachment{ volumeTag, machineTag, storage.VolumeAttachmentInfo{ in.Info.DeviceName, in.Info.ReadOnly, }, }, nil }
func volumeAttachmentParamsFromParams(in params.VolumeAttachmentParams) (storage.VolumeAttachmentParams, error) { machineTag, err := names.ParseMachineTag(in.MachineTag) if err != nil { return storage.VolumeAttachmentParams{}, errors.Trace(err) } volumeTag, err := names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.VolumeAttachmentParams{}, errors.Trace(err) } return storage.VolumeAttachmentParams{ AttachmentParams: storage.AttachmentParams{ Provider: storage.ProviderType(in.Provider), Machine: machineTag, InstanceId: instance.Id(in.InstanceId), ReadOnly: in.ReadOnly, }, Volume: volumeTag, VolumeId: in.VolumeId, }, nil }
func filesystemFromParams(in params.Filesystem) (storage.Filesystem, error) { filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) if err != nil { return storage.Filesystem{}, errors.Trace(err) } var volumeTag names.VolumeTag if in.VolumeTag != "" { volumeTag, err = names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.Filesystem{}, errors.Trace(err) } } return storage.Filesystem{ filesystemTag, volumeTag, storage.FilesystemInfo{ in.Info.FilesystemId, in.Info.Size, }, }, nil }
func (a *API) createVolumeItem(volumeTag string, attachments []params.VolumeAttachment) params.VolumeItem { result := params.VolumeItem{Attachments: attachments} tag, err := names.ParseVolumeTag(volumeTag) if err != nil { result.Error = common.ServerError(errors.Annotatef(err, "parsing volume tag %v", volumeTag)) return result } st, err := a.storage.Volume(tag) if err != nil { result.Error = common.ServerError(errors.Annotatef(err, "getting volume for tag %v", tag)) return result } volume, err := a.convertStateVolumeToParams(st) if err != nil { result.Error = common.ServerError(errors.Trace(err)) return result } result.Volume = volume return result }
func filesystemParamsFromParams(in params.FilesystemParams) (storage.FilesystemParams, error) { filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) if err != nil { return storage.FilesystemParams{}, errors.Trace(err) } var volumeTag names.VolumeTag if in.VolumeTag != "" { volumeTag, err = names.ParseVolumeTag(in.VolumeTag) if err != nil { return storage.FilesystemParams{}, errors.Trace(err) } } providerType := storage.ProviderType(in.Provider) return storage.FilesystemParams{ filesystemTag, volumeTag, in.Size, providerType, in.Attributes, in.Tags, }, nil }
func (s *StorageProvisionerAPI) oneVolumeAttachment( id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool, ) (state.VolumeAttachment, error) { machineTag, err := names.ParseMachineTag(id.MachineTag) if err != nil { return nil, err } volumeTag, err := names.ParseVolumeTag(id.AttachmentTag) if err != nil { return nil, err } if !canAccess(machineTag, volumeTag) { return nil, common.ErrPerm } volumeAttachment, err := s.st.VolumeAttachment(machineTag, volumeTag) if errors.IsNotFound(err) { return nil, common.ErrPerm } else if err != nil { return nil, err } return volumeAttachment, nil }
func assertParseVolumeTag(c *gc.C, tag string, expect names.VolumeTag) { t, err := names.ParseVolumeTag(tag) c.Assert(err, gc.IsNil) c.Assert(t, gc.Equals, expect) }
// VolumeParams returns the parameters for creating or destroying // the volumes with the specified tags. func (s *StorageProvisionerAPI) VolumeParams(args params.Entities) (params.VolumeParamsResults, error) { canAccess, err := s.getStorageEntityAuthFunc() if err != nil { return params.VolumeParamsResults{}, err } envConfig, err := s.st.EnvironConfig() if err != nil { return params.VolumeParamsResults{}, err } results := params.VolumeParamsResults{ Results: make([]params.VolumeParamsResult, len(args.Entities)), } poolManager := poolmanager.New(s.settings) one := func(arg params.Entity) (params.VolumeParams, error) { tag, err := names.ParseVolumeTag(arg.Tag) if err != nil || !canAccess(tag) { return params.VolumeParams{}, common.ErrPerm } volume, err := s.st.Volume(tag) if errors.IsNotFound(err) { return params.VolumeParams{}, common.ErrPerm } else if err != nil { return params.VolumeParams{}, err } volumeAttachments, err := s.st.VolumeAttachments(tag) if err != nil { return params.VolumeParams{}, err } storageInstance, err := storagecommon.MaybeAssignedStorageInstance( volume.StorageInstance, s.st.StorageInstance, ) if err != nil { return params.VolumeParams{}, err } volumeParams, err := storagecommon.VolumeParams(volume, storageInstance, envConfig, poolManager) if err != nil { return params.VolumeParams{}, err } if len(volumeAttachments) == 1 { // There is exactly one attachment to be made, so make // it immediately. Otherwise we will defer attachments // until later. volumeAttachment := volumeAttachments[0] volumeAttachmentParams, ok := volumeAttachment.Params() if !ok { return params.VolumeParams{}, errors.Errorf( "volume %q is already attached to machine %q", volumeAttachment.Volume().Id(), volumeAttachment.Machine().Id(), ) } machineTag := volumeAttachment.Machine() instanceId, err := s.st.MachineInstanceId(machineTag) if errors.IsNotProvisioned(err) { // Leave the attachment until later. instanceId = "" } else if err != nil { return params.VolumeParams{}, err } volumeParams.Attachment = ¶ms.VolumeAttachmentParams{ tag.String(), machineTag.String(), "", // volume ID string(instanceId), volumeParams.Provider, volumeAttachmentParams.ReadOnly, } } return volumeParams, nil } for i, arg := range args.Entities { var result params.VolumeParamsResult volumeParams, err := one(arg) if err != nil { result.Error = common.ServerError(err) } else { result.Result = volumeParams } results.Results[i] = result } return results, nil }
func constructStartInstanceParams( machine *apiprovisioner.Machine, instanceConfig *instancecfg.InstanceConfig, provisioningInfo *params.ProvisioningInfo, possibleTools coretools.List, ) (environs.StartInstanceParams, error) { volumes := make([]storage.VolumeParams, len(provisioningInfo.Volumes)) for i, v := range provisioningInfo.Volumes { volumeTag, err := names.ParseVolumeTag(v.VolumeTag) if err != nil { return environs.StartInstanceParams{}, errors.Trace(err) } if v.Attachment == nil { return environs.StartInstanceParams{}, errors.Errorf("volume params missing attachment") } machineTag, err := names.ParseMachineTag(v.Attachment.MachineTag) if err != nil { return environs.StartInstanceParams{}, errors.Trace(err) } if machineTag != machine.Tag() { return environs.StartInstanceParams{}, errors.Errorf("volume attachment params has invalid machine tag") } if v.Attachment.InstanceId != "" { return environs.StartInstanceParams{}, errors.Errorf("volume attachment params specifies instance ID") } volumes[i] = storage.VolumeParams{ volumeTag, v.Size, storage.ProviderType(v.Provider), v.Attributes, v.Tags, &storage.VolumeAttachmentParams{ AttachmentParams: storage.AttachmentParams{ Machine: machineTag, ReadOnly: v.Attachment.ReadOnly, }, Volume: volumeTag, }, } } var subnetsToZones map[network.Id][]string if provisioningInfo.SubnetsToZones != nil { // Convert subnet provider ids from string to network.Id. subnetsToZones = make(map[network.Id][]string, len(provisioningInfo.SubnetsToZones)) for providerId, zones := range provisioningInfo.SubnetsToZones { subnetsToZones[network.Id(providerId)] = zones } } var endpointBindings map[string]network.Id if len(provisioningInfo.EndpointBindings) != 0 { endpointBindings = make(map[string]network.Id) for endpoint, space := range provisioningInfo.EndpointBindings { endpointBindings[endpoint] = network.Id(space) } } possibleImageMetadata := make([]*imagemetadata.ImageMetadata, len(provisioningInfo.ImageMetadata)) for i, metadata := range provisioningInfo.ImageMetadata { possibleImageMetadata[i] = &imagemetadata.ImageMetadata{ Id: metadata.ImageId, Arch: metadata.Arch, RegionAlias: metadata.Region, RegionName: metadata.Region, Storage: metadata.RootStorageType, Stream: metadata.Stream, VirtType: metadata.VirtType, Version: metadata.Version, } } return environs.StartInstanceParams{ Constraints: provisioningInfo.Constraints, Tools: possibleTools, InstanceConfig: instanceConfig, Placement: provisioningInfo.Placement, DistributionGroup: machine.DistributionGroup, Volumes: volumes, SubnetsToZones: subnetsToZones, EndpointBindings: endpointBindings, ImageMetadata: possibleImageMetadata, StatusCallback: machine.SetInstanceStatus, }, nil }
func assertParseVolumeTagInvalid(c *gc.C, tag string, expect error) { _, err := names.ParseVolumeTag(tag) c.Assert(err, gc.ErrorMatches, expect.Error()) }