github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/filesystem.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  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/cmd/juju/common"
    15  )
    16  
    17  // FilesystemCommandBase is a helper base structure for filesystem commands.
    18  type FilesystemCommandBase struct {
    19  	StorageCommandBase
    20  }
    21  
    22  // FilesystemInfo defines the serialization behaviour for storage filesystem.
    23  type FilesystemInfo struct {
    24  	// from params.Filesystem. This is provider-supplied unique filesystem id.
    25  	ProviderFilesystemId string `yaml:"provider-id,omitempty" json:"provider-id,omitempty"`
    26  
    27  	// Volume is the ID of the volume that the filesystem is backed by, if any.
    28  	Volume string `yaml:"volume,omitempty" json:"volume,omitempty"`
    29  
    30  	// Storage is the ID of the storage instance that the filesystem is
    31  	// assigned to, if any.
    32  	Storage string `yaml:"storage,omitempty" json:"storage,omitempty"`
    33  
    34  	// Attachments is the set of entities attached to the filesystem.
    35  	Attachments *FilesystemAttachments
    36  
    37  	// Pool is the name of the storage pool that the filesystem came from.
    38  	Pool string `yaml:"pool,omitempty" json:"pool,omitempty"`
    39  
    40  	// from params.FilesystemInfo
    41  	Size uint64 `yaml:"size" json:"size"`
    42  
    43  	// Life is the lifecycle state of the filesystem.
    44  	Life string `yaml:"life,omitempty" json:"life,omitempty"`
    45  
    46  	// from params.FilesystemInfo.
    47  	Status EntityStatus `yaml:"status,omitempty" json:"status,omitempty"`
    48  }
    49  
    50  type FilesystemAttachments struct {
    51  	Machines   map[string]FilesystemAttachment  `yaml:"machines,omitempty" json:"machines,omitempty"`
    52  	Containers map[string]FilesystemAttachment  `yaml:"containers,omitempty" json:"containers,omitempty"`
    53  	Units      map[string]UnitStorageAttachment `yaml:"units,omitempty" json:"units,omitempty"`
    54  }
    55  
    56  type FilesystemAttachment struct {
    57  	MountPoint string `yaml:"mount-point" json:"mount-point"`
    58  	ReadOnly   bool   `yaml:"read-only" json:"read-only"`
    59  	Life       string `yaml:"life,omitempty" json:"life,omitempty"`
    60  }
    61  
    62  // generateListFilesystemOutput returns a map filesystem IDs to filesystem info
    63  func generateListFilesystemsOutput(ctx *cmd.Context, api StorageListAPI, ids []string) (map[string]FilesystemInfo, error) {
    64  
    65  	results, err := api.ListFilesystems(ids)
    66  	if err != nil {
    67  		return nil, errors.Trace(err)
    68  	}
    69  
    70  	// filter out valid output, if any
    71  	var valid []params.FilesystemDetails
    72  	for _, result := range results {
    73  		if result.Error == nil {
    74  			valid = append(valid, result.Result...)
    75  			continue
    76  		}
    77  		// display individual error
    78  		fmt.Fprintf(ctx.Stderr, "%v\n", result.Error)
    79  	}
    80  	if len(valid) == 0 {
    81  		return nil, nil
    82  	}
    83  	return convertToFilesystemInfo(valid)
    84  }
    85  
    86  // convertToFilesystemInfo returns a map of filesystem IDs to filesystem info.
    87  func convertToFilesystemInfo(all []params.FilesystemDetails) (map[string]FilesystemInfo, error) {
    88  	result := make(map[string]FilesystemInfo)
    89  	for _, one := range all {
    90  		filesystemTag, info, err := createFilesystemInfo(one)
    91  		if err != nil {
    92  			return nil, errors.Trace(err)
    93  		}
    94  		result[filesystemTag.Id()] = info
    95  	}
    96  	return result, nil
    97  }
    98  
    99  func createFilesystemInfo(details params.FilesystemDetails) (names.FilesystemTag, FilesystemInfo, error) {
   100  	filesystemTag, err := names.ParseFilesystemTag(details.FilesystemTag)
   101  	if err != nil {
   102  		return names.FilesystemTag{}, FilesystemInfo{}, errors.Trace(err)
   103  	}
   104  
   105  	var info FilesystemInfo
   106  	info.ProviderFilesystemId = details.Info.FilesystemId
   107  	info.Pool = details.Info.Pool
   108  	info.Size = details.Info.Size
   109  	info.Life = string(details.Life)
   110  	info.Status = EntityStatus{
   111  		details.Status.Status,
   112  		details.Status.Info,
   113  		// TODO(axw) we should support formatting as ISO time
   114  		common.FormatTime(details.Status.Since, false),
   115  	}
   116  
   117  	if details.VolumeTag != "" {
   118  		volumeId, err := idFromTag(details.VolumeTag)
   119  		if err != nil {
   120  			return names.FilesystemTag{}, FilesystemInfo{}, errors.Trace(err)
   121  		}
   122  		info.Volume = volumeId
   123  	}
   124  
   125  	attachmentsFromDetails := func(
   126  		in map[string]params.FilesystemAttachmentDetails,
   127  		out map[string]FilesystemAttachment,
   128  	) error {
   129  		for tag, attachment := range in {
   130  			id, err := idFromTag(tag)
   131  			if err != nil {
   132  				return errors.Trace(err)
   133  			}
   134  			out[id] = FilesystemAttachment{
   135  				attachment.MountPoint,
   136  				attachment.ReadOnly,
   137  				string(attachment.Life),
   138  			}
   139  		}
   140  		return nil
   141  	}
   142  
   143  	if len(details.MachineAttachments) > 0 {
   144  		machineAttachments := make(map[string]FilesystemAttachment)
   145  		if err := attachmentsFromDetails(details.MachineAttachments, machineAttachments); err != nil {
   146  			return names.FilesystemTag{}, FilesystemInfo{}, errors.Trace(err)
   147  		}
   148  		info.Attachments = &FilesystemAttachments{
   149  			Machines: machineAttachments,
   150  		}
   151  	}
   152  	if len(details.UnitAttachments) > 0 {
   153  		unitAttachments := make(map[string]FilesystemAttachment)
   154  		if err := attachmentsFromDetails(details.UnitAttachments, unitAttachments); err != nil {
   155  			return names.FilesystemTag{}, FilesystemInfo{}, errors.Trace(err)
   156  		}
   157  		if info.Attachments == nil {
   158  			info.Attachments = &FilesystemAttachments{}
   159  		}
   160  		info.Attachments.Containers = unitAttachments
   161  	}
   162  
   163  	if details.Storage != nil {
   164  		storageTag, storageInfo, err := createStorageInfo(*details.Storage)
   165  		if err != nil {
   166  			return names.FilesystemTag{}, FilesystemInfo{}, errors.Trace(err)
   167  		}
   168  		info.Storage = storageTag.Id()
   169  		if storageInfo.Attachments != nil {
   170  			if info.Attachments == nil {
   171  				info.Attachments = &FilesystemAttachments{}
   172  			}
   173  			info.Attachments.Units = storageInfo.Attachments.Units
   174  		}
   175  	}
   176  
   177  	return filesystemTag, info, nil
   178  }