github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/storage/volume.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/cmd/juju/common"
    15  	"github.com/juju/juju/status"
    16  )
    17  
    18  // VolumeInfo defines the serialization behaviour for storage volume.
    19  type VolumeInfo struct {
    20  	// from params.Volume. This is provider-supplied unique volume id.
    21  	ProviderVolumeId string `yaml:"provider-id,omitempty" json:"provider-id,omitempty"`
    22  
    23  	// Storage is the ID of the storage instance that the volume is
    24  	// assigned to, if any.
    25  	Storage string `yaml:"storage,omitempty" json:"storage,omitempty"`
    26  
    27  	// Attachments is the set of entities attached to the volume.
    28  	Attachments *VolumeAttachments `yaml:"attachments,omitempty" json:"attachments,omitempty"`
    29  
    30  	// from params.Volume
    31  	HardwareId string `yaml:"hardware-id,omitempty" json:"hardware-id,omitempty"`
    32  
    33  	// from params.Volume
    34  	Size uint64 `yaml:"size" json:"size"`
    35  
    36  	// from params.Volume
    37  	Persistent bool `yaml:"persistent" json:"persistent"`
    38  
    39  	// from params.Volume
    40  	Status EntityStatus `yaml:"status,omitempty" json:"status,omitempty"`
    41  }
    42  
    43  type EntityStatus struct {
    44  	Current status.Status `json:"current,omitempty" yaml:"current,omitempty"`
    45  	Message string        `json:"message,omitempty" yaml:"message,omitempty"`
    46  	Since   string        `json:"since,omitempty" yaml:"since,omitempty"`
    47  }
    48  
    49  type VolumeAttachments struct {
    50  	Machines map[string]MachineVolumeAttachment `yaml:"machines,omitempty" json:"machines,omitempty"`
    51  	Units    map[string]UnitStorageAttachment   `yaml:"units,omitempty" json:"units,omitempty"`
    52  }
    53  
    54  type MachineVolumeAttachment struct {
    55  	DeviceName string `yaml:"device,omitempty" json:"device,omitempty"`
    56  	DeviceLink string `yaml:"device-link,omitempty" json:"device-link,omitempty"`
    57  	BusAddress string `yaml:"bus-address,omitempty" json:"bus-address,omitempty"`
    58  	ReadOnly   bool   `yaml:"read-only" json:"read-only"`
    59  	// TODO(axw) add machine volume attachment status when we have it
    60  }
    61  
    62  //generateListVolumeOutput returns a map of volume info
    63  func (c *listCommand) generateListVolumeOutput(ctx *cmd.Context, api StorageListAPI) (output interface{}, err error) {
    64  
    65  	results, err := api.ListVolumes(c.ids)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	// filter out valid output, if any
    70  	var valid []params.VolumeDetails
    71  	for _, result := range results {
    72  		if result.Error == nil {
    73  			valid = append(valid, result.Result...)
    74  			continue
    75  		}
    76  		// display individual error
    77  		fmt.Fprintf(ctx.Stderr, "%v\n", result.Error)
    78  	}
    79  	if len(valid) == 0 {
    80  		return nil, nil
    81  	}
    82  	info, err := convertToVolumeInfo(valid)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	switch c.out.Name() {
    87  	case "yaml", "json":
    88  		output = map[string]map[string]VolumeInfo{"volumes": info}
    89  	default:
    90  		output = info
    91  	}
    92  	return output, nil
    93  }
    94  
    95  // convertToVolumeInfo returns a map of volume IDs to volume info.
    96  func convertToVolumeInfo(all []params.VolumeDetails) (map[string]VolumeInfo, error) {
    97  	result := make(map[string]VolumeInfo)
    98  	for _, one := range all {
    99  		volumeTag, info, err := createVolumeInfo(one)
   100  		if err != nil {
   101  			return nil, errors.Trace(err)
   102  		}
   103  		result[volumeTag.Id()] = info
   104  	}
   105  	return result, nil
   106  }
   107  
   108  var idFromTag = func(s string) (string, error) {
   109  	tag, err := names.ParseTag(s)
   110  	if err != nil {
   111  		return "", errors.Annotatef(err, "invalid tag %v", tag)
   112  	}
   113  	return tag.Id(), nil
   114  }
   115  
   116  func createVolumeInfo(details params.VolumeDetails) (names.VolumeTag, VolumeInfo, error) {
   117  	volumeTag, err := names.ParseVolumeTag(details.VolumeTag)
   118  	if err != nil {
   119  		return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
   120  	}
   121  
   122  	var info VolumeInfo
   123  	info.ProviderVolumeId = details.Info.VolumeId
   124  	info.HardwareId = details.Info.HardwareId
   125  	info.Size = details.Info.Size
   126  	info.Persistent = details.Info.Persistent
   127  	info.Status = EntityStatus{
   128  		details.Status.Status,
   129  		details.Status.Info,
   130  		// TODO(axw) we should support formatting as ISO time
   131  		common.FormatTime(details.Status.Since, false),
   132  	}
   133  
   134  	if len(details.MachineAttachments) > 0 {
   135  		machineAttachments := make(map[string]MachineVolumeAttachment)
   136  		for machineTag, attachment := range details.MachineAttachments {
   137  			machineId, err := idFromTag(machineTag)
   138  			if err != nil {
   139  				return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
   140  			}
   141  			machineAttachments[machineId] = MachineVolumeAttachment{
   142  				attachment.DeviceName,
   143  				attachment.DeviceLink,
   144  				attachment.BusAddress,
   145  				attachment.ReadOnly,
   146  			}
   147  		}
   148  		info.Attachments = &VolumeAttachments{
   149  			Machines: machineAttachments,
   150  		}
   151  	}
   152  
   153  	if details.Storage != nil {
   154  		storageTag, storageInfo, err := createStorageInfo(*details.Storage)
   155  		if err != nil {
   156  			return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
   157  		}
   158  		info.Storage = storageTag.Id()
   159  		if storageInfo.Attachments != nil {
   160  			info.Attachments.Units = storageInfo.Attachments.Units
   161  		}
   162  	}
   163  
   164  	return volumeTag, info, nil
   165  }