github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/storagecommon/volumes.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storagecommon
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/apiserver/params"
    11  	"github.com/juju/juju/environs/config"
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/juju/storage"
    14  	"github.com/juju/juju/storage/poolmanager"
    15  )
    16  
    17  type volumeAlreadyProvisionedError struct {
    18  	error
    19  }
    20  
    21  // IsVolumeAlreadyProvisioned returns true if the specified error
    22  // is caused by a volume already being provisioned.
    23  func IsVolumeAlreadyProvisioned(err error) bool {
    24  	_, ok := err.(*volumeAlreadyProvisionedError)
    25  	return ok
    26  }
    27  
    28  // VolumeParams returns the parameters for creating or destroying
    29  // the given volume.
    30  func VolumeParams(
    31  	v state.Volume,
    32  	storageInstance state.StorageInstance,
    33  	modelUUID, controllerUUID string,
    34  	environConfig *config.Config,
    35  	poolManager poolmanager.PoolManager,
    36  	registry storage.ProviderRegistry,
    37  ) (params.VolumeParams, error) {
    38  
    39  	var pool string
    40  	var size uint64
    41  	if stateVolumeParams, ok := v.Params(); ok {
    42  		pool = stateVolumeParams.Pool
    43  		size = stateVolumeParams.Size
    44  	} else {
    45  		volumeInfo, err := v.Info()
    46  		if err != nil {
    47  			return params.VolumeParams{}, errors.Trace(err)
    48  		}
    49  		pool = volumeInfo.Pool
    50  		size = volumeInfo.Size
    51  	}
    52  
    53  	volumeTags, err := storageTags(storageInstance, modelUUID, controllerUUID, environConfig)
    54  	if err != nil {
    55  		return params.VolumeParams{}, errors.Annotate(err, "computing storage tags")
    56  	}
    57  
    58  	providerType, cfg, err := StoragePoolConfig(pool, poolManager, registry)
    59  	if err != nil {
    60  		return params.VolumeParams{}, errors.Trace(err)
    61  	}
    62  	return params.VolumeParams{
    63  		v.Tag().String(),
    64  		size,
    65  		string(providerType),
    66  		cfg.Attrs(),
    67  		volumeTags,
    68  		nil, // attachment params set by the caller
    69  	}, nil
    70  }
    71  
    72  // StoragePoolConfig returns the storage provider type and
    73  // configuration for a named storage pool. If there is no
    74  // such pool with the specified name, but it identifies a
    75  // storage provider, then that type will be returned with a
    76  // nil configuration.
    77  func StoragePoolConfig(name string, poolManager poolmanager.PoolManager, registry storage.ProviderRegistry) (storage.ProviderType, *storage.Config, error) {
    78  	pool, err := poolManager.Get(name)
    79  	if errors.IsNotFound(err) {
    80  		// If not a storage pool, then maybe a provider type.
    81  		providerType := storage.ProviderType(name)
    82  		if _, err1 := registry.StorageProvider(providerType); err1 != nil {
    83  			return "", nil, errors.Trace(err)
    84  		}
    85  		return providerType, &storage.Config{}, nil
    86  	} else if err != nil {
    87  		return "", nil, errors.Annotatef(err, "getting pool %q", name)
    88  	}
    89  	return pool.Provider(), pool, nil
    90  }
    91  
    92  // VolumesToState converts a slice of params.Volume to a mapping
    93  // of volume tags to state.VolumeInfo.
    94  func VolumesToState(in []params.Volume) (map[names.VolumeTag]state.VolumeInfo, error) {
    95  	m := make(map[names.VolumeTag]state.VolumeInfo)
    96  	for _, v := range in {
    97  		tag, volumeInfo, err := VolumeToState(v)
    98  		if err != nil {
    99  			return nil, errors.Trace(err)
   100  		}
   101  		m[tag] = volumeInfo
   102  	}
   103  	return m, nil
   104  }
   105  
   106  // VolumeToState converts a params.Volume to state.VolumeInfo
   107  // and names.VolumeTag.
   108  func VolumeToState(v params.Volume) (names.VolumeTag, state.VolumeInfo, error) {
   109  	if v.VolumeTag == "" {
   110  		return names.VolumeTag{}, state.VolumeInfo{}, errors.New("Tag is empty")
   111  	}
   112  	volumeTag, err := names.ParseVolumeTag(v.VolumeTag)
   113  	if err != nil {
   114  		return names.VolumeTag{}, state.VolumeInfo{}, errors.Trace(err)
   115  	}
   116  	return volumeTag, state.VolumeInfo{
   117  		v.Info.HardwareId,
   118  		v.Info.Size,
   119  		"", // pool is set by state
   120  		v.Info.VolumeId,
   121  		v.Info.Persistent,
   122  	}, nil
   123  }
   124  
   125  // VolumeFromState converts a state.Volume to params.Volume.
   126  func VolumeFromState(v state.Volume) (params.Volume, error) {
   127  	info, err := v.Info()
   128  	if err != nil {
   129  		return params.Volume{}, errors.Trace(err)
   130  	}
   131  	return params.Volume{
   132  		v.VolumeTag().String(),
   133  		VolumeInfoFromState(info),
   134  	}, nil
   135  }
   136  
   137  // VolumeInfoFromState converts a state.VolumeInfo to params.VolumeInfo.
   138  func VolumeInfoFromState(info state.VolumeInfo) params.VolumeInfo {
   139  	return params.VolumeInfo{
   140  		info.VolumeId,
   141  		info.HardwareId,
   142  		info.Size,
   143  		info.Persistent,
   144  	}
   145  }
   146  
   147  // VolumeAttachmentFromState converts a state.VolumeAttachment to params.VolumeAttachment.
   148  func VolumeAttachmentFromState(v state.VolumeAttachment) (params.VolumeAttachment, error) {
   149  	info, err := v.Info()
   150  	if err != nil {
   151  		return params.VolumeAttachment{}, errors.Trace(err)
   152  	}
   153  	return params.VolumeAttachment{
   154  		v.Volume().String(),
   155  		v.Machine().String(),
   156  		VolumeAttachmentInfoFromState(info),
   157  	}, nil
   158  }
   159  
   160  // VolumeAttachmentInfoFromState converts a state.VolumeAttachmentInfo to params.VolumeAttachmentInfo.
   161  func VolumeAttachmentInfoFromState(info state.VolumeAttachmentInfo) params.VolumeAttachmentInfo {
   162  	return params.VolumeAttachmentInfo{
   163  		info.DeviceName,
   164  		info.DeviceLink,
   165  		info.BusAddress,
   166  		info.ReadOnly,
   167  	}
   168  }
   169  
   170  // VolumeAttachmentInfosToState converts a map of volume tags to
   171  // params.VolumeAttachmentInfo to a map of volume tags to
   172  // state.VolumeAttachmentInfo.
   173  func VolumeAttachmentInfosToState(in map[string]params.VolumeAttachmentInfo) (map[names.VolumeTag]state.VolumeAttachmentInfo, error) {
   174  	m := make(map[names.VolumeTag]state.VolumeAttachmentInfo)
   175  	for k, v := range in {
   176  		volumeTag, err := names.ParseVolumeTag(k)
   177  		if err != nil {
   178  			return nil, errors.Trace(err)
   179  		}
   180  		m[volumeTag] = VolumeAttachmentInfoToState(v)
   181  	}
   182  	return m, nil
   183  }
   184  
   185  // VolumeAttachmentToState converts a params.VolumeAttachment
   186  // to a state.VolumeAttachmentInfo and tags.
   187  func VolumeAttachmentToState(in params.VolumeAttachment) (names.MachineTag, names.VolumeTag, state.VolumeAttachmentInfo, error) {
   188  	machineTag, err := names.ParseMachineTag(in.MachineTag)
   189  	if err != nil {
   190  		return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err
   191  	}
   192  	volumeTag, err := names.ParseVolumeTag(in.VolumeTag)
   193  	if err != nil {
   194  		return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err
   195  	}
   196  	info := VolumeAttachmentInfoToState(in.Info)
   197  	return machineTag, volumeTag, info, nil
   198  }
   199  
   200  // VolumeAttachmentInfoToState converts a params.VolumeAttachmentInfo
   201  // to a state.VolumeAttachmentInfo.
   202  func VolumeAttachmentInfoToState(in params.VolumeAttachmentInfo) state.VolumeAttachmentInfo {
   203  	return state.VolumeAttachmentInfo{
   204  		in.DeviceName,
   205  		in.DeviceLink,
   206  		in.BusAddress,
   207  		in.ReadOnly,
   208  	}
   209  }
   210  
   211  // ParseVolumeAttachmentIds parses the strings, returning machine storage IDs.
   212  func ParseVolumeAttachmentIds(stringIds []string) ([]params.MachineStorageId, error) {
   213  	ids := make([]params.MachineStorageId, len(stringIds))
   214  	for i, s := range stringIds {
   215  		m, v, err := state.ParseVolumeAttachmentId(s)
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  		ids[i] = params.MachineStorageId{
   220  			MachineTag:    m.String(),
   221  			AttachmentTag: v.String(),
   222  		}
   223  	}
   224  	return ids, nil
   225  }