github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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  	"github.com/juju/errors"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/api/storage"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/cmd/juju/common"
    16  	"github.com/juju/juju/cmd/modelcmd"
    17  )
    18  
    19  // StorageCommandBase is a helper base structure that has a method to get the
    20  // storage managing client.
    21  type StorageCommandBase struct {
    22  	modelcmd.ModelCommandBase
    23  }
    24  
    25  // NewStorageAPI returns a storage api for the root api endpoint
    26  // that the environment command returns.
    27  func (c *StorageCommandBase) NewStorageAPI() (*storage.Client, error) {
    28  	root, err := c.NewAPIRoot()
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  	return storage.NewClient(root), nil
    33  }
    34  
    35  // StorageInfo defines the serialization behaviour of the storage information.
    36  type StorageInfo struct {
    37  	Kind        string              `yaml:"kind" json:"kind"`
    38  	Life        string              `yaml:"life,omitempty" json:"life,omitempty"`
    39  	Status      EntityStatus        `yaml:"status" json:"status"`
    40  	Persistent  bool                `yaml:"persistent" json:"persistent"`
    41  	Attachments *StorageAttachments `yaml:"attachments,omitempty" json:"attachments,omitempty"`
    42  }
    43  
    44  // StorageAttachments contains details about all attachments to a storage
    45  // instance.
    46  type StorageAttachments struct {
    47  	// Units is a mapping from unit ID to unit storage attachment details.
    48  	Units map[string]UnitStorageAttachment `yaml:"units" json:"units"`
    49  }
    50  
    51  // UnitStorageAttachment contains details of a unit storage attachment.
    52  type UnitStorageAttachment struct {
    53  	// MachineId is the ID of the machine that the unit is assigned to.
    54  	//
    55  	// This is omitempty to cater for legacy results, where the machine
    56  	// information is not available.
    57  	MachineId string `yaml:"machine,omitempty" json:"machine,omitempty"`
    58  
    59  	// Location is the location of the storage attachment.
    60  	Location string `yaml:"location,omitempty" json:"location,omitempty"`
    61  
    62  	// Life is the lifecycle state of the storage attachment.
    63  	Life string `yaml:"life,omitempty" json:"life,omitempty"`
    64  
    65  	// TODO(axw) per-unit status when we have it in state.
    66  }
    67  
    68  // formatStorageDetails takes a set of StorageDetail and
    69  // creates a mapping from storage ID to storage details.
    70  func formatStorageDetails(storages []params.StorageDetails) (map[string]StorageInfo, error) {
    71  	if len(storages) == 0 {
    72  		return nil, nil
    73  	}
    74  	output := make(map[string]StorageInfo)
    75  	for _, details := range storages {
    76  		storageTag, storageInfo, err := createStorageInfo(details)
    77  		if err != nil {
    78  			return nil, errors.Trace(err)
    79  		}
    80  		output[storageTag.Id()] = storageInfo
    81  	}
    82  	return output, nil
    83  }
    84  
    85  func createStorageInfo(details params.StorageDetails) (names.StorageTag, StorageInfo, error) {
    86  	storageTag, err := names.ParseStorageTag(details.StorageTag)
    87  	if err != nil {
    88  		return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
    89  	}
    90  
    91  	info := StorageInfo{
    92  		Kind: details.Kind.String(),
    93  		Life: string(details.Life),
    94  		Status: EntityStatus{
    95  			details.Status.Status,
    96  			details.Status.Info,
    97  			// TODO(axw) we should support formatting as ISO time
    98  			common.FormatTime(details.Status.Since, false),
    99  		},
   100  		Persistent: details.Persistent,
   101  	}
   102  
   103  	if len(details.Attachments) > 0 {
   104  		unitStorageAttachments := make(map[string]UnitStorageAttachment)
   105  		for unitTagString, attachmentDetails := range details.Attachments {
   106  			unitTag, err := names.ParseUnitTag(unitTagString)
   107  			if err != nil {
   108  				return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
   109  			}
   110  			var machineId string
   111  			if attachmentDetails.MachineTag != "" {
   112  				machineTag, err := names.ParseMachineTag(attachmentDetails.MachineTag)
   113  				if err != nil {
   114  					return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
   115  				}
   116  				machineId = machineTag.Id()
   117  			}
   118  			unitStorageAttachments[unitTag.Id()] = UnitStorageAttachment{
   119  				machineId,
   120  				attachmentDetails.Location,
   121  				string(attachmentDetails.Life),
   122  			}
   123  		}
   124  		info.Attachments = &StorageAttachments{unitStorageAttachments}
   125  	}
   126  
   127  	return storageTag, info, nil
   128  }