github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/storage/add.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  	"strings"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names"
    13  
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/cmd/modelcmd"
    16  	"github.com/juju/juju/storage"
    17  )
    18  
    19  // NewAddCommand returns a command used to add unit storage.
    20  func NewAddCommand() cmd.Command {
    21  	cmd := &addCommand{}
    22  	cmd.newAPIFunc = func() (StorageAddAPI, error) {
    23  		return cmd.NewStorageAPI()
    24  	}
    25  	return modelcmd.Wrap(cmd)
    26  }
    27  
    28  const (
    29  	addCommandDoc = `
    30  Add storage instances to a unit dynamically using provided storage directives.
    31  Specify a unit and a storage specification in the same format 
    32  as passed to juju deploy --storage=”...”.
    33  
    34  A storage directive consists of a storage name as per charm specification
    35  and storage constraints, e.g. pool, count, size.
    36  
    37  The acceptable format for storage constraints is a comma separated
    38  sequence of: POOL, COUNT, and SIZE, where
    39  
    40      POOL identifies the storage pool. POOL can be a string
    41      starting with a letter, followed by zero or more digits
    42      or letters optionally separated by hyphens.
    43  
    44      COUNT is a positive integer indicating how many instances
    45      of the storage to create. If unspecified, and SIZE is
    46      specified, COUNT defaults to 1.
    47  
    48      SIZE describes the minimum size of the storage instances to
    49      create. SIZE is a floating point number and multiplier from
    50      the set (M, G, T, P, E, Z, Y), which are all treated as
    51      powers of 1024.
    52  
    53  Storage constraints can be optionally ommitted.
    54  Model default values will be used for all ommitted constraint values.
    55  There is no need to comma-separate ommitted constraints. 
    56  
    57  Example:
    58      Add 3 ebs storage instances for "data" storage to unit u/0:
    59  
    60        juju add-storage u/0 data=ebs,1024,3 
    61      or
    62        juju add-storage u/0 data=ebs,3
    63      or
    64        juju add-storage u/0 data=ebs,,3 
    65      
    66      
    67      Add 1 storage instances for "data" storage to unit u/0 
    68      using default model provider pool:
    69  
    70        juju add-storage u/0 data=1 
    71      or
    72        juju add-storage u/0 data 
    73  `
    74  	addCommandAgs = `
    75  <unit name> <storage directive> ...
    76      where storage directive is 
    77          <charm storage name>=<storage constraints> 
    78      or
    79          <charm storage name>
    80  `
    81  )
    82  
    83  // addCommand adds unit storage instances dynamically.
    84  type addCommand struct {
    85  	StorageCommandBase
    86  	unitTag string
    87  
    88  	// storageCons is a map of storage constraints, keyed on the storage name
    89  	// defined in charm storage metadata.
    90  	storageCons map[string]storage.Constraints
    91  	newAPIFunc  func() (StorageAddAPI, error)
    92  }
    93  
    94  // Init implements Command.Init.
    95  func (c *addCommand) Init(args []string) (err error) {
    96  	if len(args) < 2 {
    97  		return errors.New("add-storage requires a unit and a storage directive")
    98  	}
    99  
   100  	u := args[0]
   101  	if !names.IsValidUnit(u) {
   102  		return errors.NotValidf("unit name %q", u)
   103  	}
   104  	c.unitTag = names.NewUnitTag(u).String()
   105  
   106  	c.storageCons, err = storage.ParseConstraintsMap(args[1:], false)
   107  	return
   108  }
   109  
   110  // Info implements Command.Info.
   111  func (c *addCommand) Info() *cmd.Info {
   112  	return &cmd.Info{
   113  		Name:    "add-storage",
   114  		Purpose: "adds unit storage dynamically",
   115  		Doc:     addCommandDoc,
   116  		Args:    addCommandAgs,
   117  	}
   118  }
   119  
   120  // Run implements Command.Run.
   121  func (c *addCommand) Run(ctx *cmd.Context) (err error) {
   122  	api, err := c.newAPIFunc()
   123  	if err != nil {
   124  		return err
   125  	}
   126  	defer api.Close()
   127  
   128  	storages := c.createStorageAddParams()
   129  	results, err := api.AddToUnit(storages)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	// If there are any failures, display them first.
   134  	// Then display all added storage.
   135  	// If there are no failures, then there is no need to display all successes.
   136  	var added []string
   137  
   138  	for i, one := range results {
   139  		us := storages[i]
   140  		if one.Error != nil {
   141  			fmt.Fprintf(ctx.Stderr, fail+": %v\n", us.StorageName, one.Error)
   142  			continue
   143  		}
   144  		added = append(added, fmt.Sprintf(success, us.StorageName))
   145  	}
   146  	if len(added) < len(storages) {
   147  		fmt.Fprintf(ctx.Stderr, strings.Join(added, "\n"))
   148  	}
   149  	return nil
   150  }
   151  
   152  var (
   153  	storageName = "storage %q"
   154  	success     = "success: " + storageName
   155  	fail        = "fail: " + storageName
   156  )
   157  
   158  // StorageAddAPI defines the API methods that the storage commands use.
   159  type StorageAddAPI interface {
   160  	Close() error
   161  	AddToUnit(storages []params.StorageAddParams) ([]params.ErrorResult, error)
   162  }
   163  
   164  func (c *addCommand) createStorageAddParams() []params.StorageAddParams {
   165  	all := make([]params.StorageAddParams, 0, len(c.storageCons))
   166  	for one, cons := range c.storageCons {
   167  		all = append(all,
   168  			params.StorageAddParams{
   169  				UnitTag:     c.unitTag,
   170  				StorageName: one,
   171  				Constraints: params.StorageConstraints{
   172  					cons.Pool,
   173  					&cons.Size,
   174  					&cons.Count,
   175  				},
   176  			})
   177  	}
   178  	return all
   179  }