github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/volumes.go (about)

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