github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/storage/storage.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The storage command provides a storage management interface,
     5  // for manipulating and inspecting storage entities (volumes,
     6  // filesystems, charm storage).
     7  package storage
     8  
     9  import (
    10  	"time"
    11  
    12  	"github.com/juju/cmd"
    13  	"github.com/juju/errors"
    14  	"github.com/juju/loggo"
    15  	"github.com/juju/names"
    16  
    17  	"github.com/juju/juju/api/storage"
    18  	"github.com/juju/juju/apiserver/params"
    19  	"github.com/juju/juju/cmd/envcmd"
    20  	"github.com/juju/juju/cmd/juju/common"
    21  )
    22  
    23  var logger = loggo.GetLogger("juju.cmd.juju.storage")
    24  
    25  const storageCmdDoc = `
    26  "juju storage" is used to manage storage instances in
    27   the Juju environment.
    28  `
    29  
    30  const storageCmdPurpose = "manage storage instances"
    31  
    32  // NewSuperCommand creates the storage supercommand and
    33  // registers the subcommands that it supports.
    34  func NewSuperCommand() cmd.Command {
    35  	storagecmd := cmd.NewSuperCommand(
    36  		cmd.SuperCommandParams{
    37  			Name:        "storage",
    38  			Doc:         storageCmdDoc,
    39  			UsagePrefix: "juju",
    40  			Purpose:     storageCmdPurpose,
    41  		})
    42  	storagecmd.Register(envcmd.Wrap(&ShowCommand{}))
    43  	storagecmd.Register(envcmd.Wrap(&ListCommand{}))
    44  	storagecmd.Register(envcmd.Wrap(&AddCommand{}))
    45  	storagecmd.Register(NewPoolSuperCommand())
    46  	storagecmd.Register(NewVolumeSuperCommand())
    47  	storagecmd.Register(NewFilesystemSuperCommand())
    48  	return storagecmd
    49  }
    50  
    51  // StorageCommandBase is a helper base structure that has a method to get the
    52  // storage managing client.
    53  type StorageCommandBase struct {
    54  	envcmd.EnvCommandBase
    55  }
    56  
    57  // NewStorageAPI returns a storage api for the root api endpoint
    58  // that the environment command returns.
    59  func (c *StorageCommandBase) NewStorageAPI() (*storage.Client, error) {
    60  	root, err := c.NewAPIRoot()
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	return storage.NewClient(root), nil
    65  }
    66  
    67  // StorageInfo defines the serialization behaviour of the storage information.
    68  type StorageInfo struct {
    69  	Kind        string              `yaml:"kind" json:"kind"`
    70  	Status      EntityStatus        `yaml:"status" json:"status"`
    71  	Persistent  bool                `yaml:"persistent" json:"persistent"`
    72  	Attachments *StorageAttachments `yaml:"attachments" json:"attachments"`
    73  }
    74  
    75  // StorageAttachments contains details about all attachments to a storage
    76  // instance.
    77  type StorageAttachments struct {
    78  	// Units is a mapping from unit ID to unit storage attachment details.
    79  	Units map[string]UnitStorageAttachment `yaml:"units" json:"units"`
    80  }
    81  
    82  // UnitStorageAttachment contains details of a unit storage attachment.
    83  type UnitStorageAttachment struct {
    84  	// MachineId is the ID of the machine that the unit is assigned to.
    85  	//
    86  	// This is omitempty to cater for legacy results, where the machine
    87  	// information is not available.
    88  	MachineId string `yaml:"machine,omitempty" json:"machine,omitempty"`
    89  
    90  	// Location is the location of the storage attachment.
    91  	Location string `yaml:"location,omitempty" json:"location,omitempty"`
    92  
    93  	// TODO(axw) per-unit status when we have it in state.
    94  }
    95  
    96  // formatStorageDetails takes a set of StorageDetail and
    97  // creates a mapping from storage ID to storage details.
    98  func formatStorageDetails(storages []params.StorageDetails) (map[string]StorageInfo, error) {
    99  	if len(storages) == 0 {
   100  		return nil, nil
   101  	}
   102  	output := make(map[string]StorageInfo)
   103  	for _, details := range storages {
   104  		storageTag, storageInfo, err := createStorageInfo(details)
   105  		if err != nil {
   106  			return nil, errors.Trace(err)
   107  		}
   108  		output[storageTag.Id()] = storageInfo
   109  	}
   110  	return output, nil
   111  }
   112  
   113  func createStorageInfo(details params.StorageDetails) (names.StorageTag, StorageInfo, error) {
   114  	storageTag, err := names.ParseStorageTag(details.StorageTag)
   115  	if err != nil {
   116  		return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
   117  	}
   118  
   119  	info := StorageInfo{
   120  		Kind: details.Kind.String(),
   121  		Status: EntityStatus{
   122  			details.Status.Status,
   123  			details.Status.Info,
   124  			// TODO(axw) we should support formatting as ISO time
   125  			common.FormatTime(details.Status.Since, false),
   126  		},
   127  		Persistent: details.Persistent,
   128  	}
   129  
   130  	if len(details.Attachments) > 0 {
   131  		unitStorageAttachments := make(map[string]UnitStorageAttachment)
   132  		for unitTagString, attachmentDetails := range details.Attachments {
   133  			unitTag, err := names.ParseUnitTag(unitTagString)
   134  			if err != nil {
   135  				return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
   136  			}
   137  			var machineId string
   138  			if attachmentDetails.MachineTag != "" {
   139  				machineTag, err := names.ParseMachineTag(attachmentDetails.MachineTag)
   140  				if err != nil {
   141  					return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
   142  				}
   143  				machineId = machineTag.Id()
   144  			}
   145  			unitStorageAttachments[unitTag.Id()] = UnitStorageAttachment{
   146  				machineId,
   147  				attachmentDetails.Location,
   148  			}
   149  		}
   150  		info.Attachments = &StorageAttachments{unitStorageAttachments}
   151  	}
   152  
   153  	return storageTag, info, nil
   154  }
   155  
   156  func storageDetailsFromLegacy(legacy params.LegacyStorageDetails) params.StorageDetails {
   157  	nowUTC := time.Now().UTC()
   158  	details := params.StorageDetails{
   159  		legacy.StorageTag,
   160  		legacy.OwnerTag,
   161  		legacy.Kind,
   162  		params.EntityStatus{
   163  			Status: params.Status(legacy.Status),
   164  			Since:  &nowUTC,
   165  		},
   166  		legacy.Persistent,
   167  		nil,
   168  	}
   169  	if legacy.UnitTag != "" {
   170  		details.Attachments = map[string]params.StorageAttachmentDetails{
   171  			legacy.UnitTag: params.StorageAttachmentDetails{
   172  				legacy.StorageTag,
   173  				legacy.UnitTag,
   174  				"", // machine is unknown in legacy
   175  				legacy.Location,
   176  			},
   177  		}
   178  	}
   179  	return details
   180  }