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