github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/runner/jujuc/relation-set.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujuc
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/gnuflag"
    14  	"github.com/juju/utils/keyvalues"
    15  	goyaml "gopkg.in/yaml.v2"
    16  
    17  	jujucmd "github.com/juju/juju/cmd"
    18  )
    19  
    20  const relationSetDoc = `
    21  "relation-set" writes the local unit's settings for some relation.
    22  If no relation is specified then the current relation is used. The
    23  setting values are not inspected and are stored as strings. Setting
    24  an empty string causes the setting to be removed. Duplicate settings
    25  are not allowed.
    26  
    27  The --file option should be used when one or more key-value pairs are
    28  too long to fit within the command length limit of the shell or
    29  operating system. The file will contain a YAML map containing the
    30  settings.  Settings in the file will be overridden by any duplicate
    31  key-value arguments. A value of "-" for the filename means <stdin>.
    32  `
    33  
    34  // RelationSetCommand implements the relation-set command.
    35  type RelationSetCommand struct {
    36  	cmd.CommandBase
    37  	ctx             Context
    38  	RelationId      int
    39  	relationIdProxy gnuflag.Value
    40  	Settings        map[string]string
    41  	settingsFile    cmd.FileVar
    42  	formatFlag      string // deprecated
    43  }
    44  
    45  func NewRelationSetCommand(ctx Context) (cmd.Command, error) {
    46  	c := &RelationSetCommand{ctx: ctx}
    47  
    48  	rV, err := NewRelationIdValue(ctx, &c.RelationId)
    49  	if err != nil {
    50  		return nil, errors.Trace(err)
    51  	}
    52  	c.relationIdProxy = rV
    53  
    54  	return c, nil
    55  }
    56  
    57  func (c *RelationSetCommand) Info() *cmd.Info {
    58  	return jujucmd.Info(&cmd.Info{
    59  		Name:    "relation-set",
    60  		Args:    "key=value [key=value ...]",
    61  		Purpose: "set relation settings",
    62  		Doc:     relationSetDoc,
    63  	})
    64  }
    65  
    66  func (c *RelationSetCommand) SetFlags(f *gnuflag.FlagSet) {
    67  	f.Var(c.relationIdProxy, "r", "specify a relation by id")
    68  	f.Var(c.relationIdProxy, "relation", "")
    69  
    70  	c.settingsFile.SetStdin()
    71  	f.Var(&c.settingsFile, "file", "file containing key-value pairs")
    72  
    73  	f.StringVar(&c.formatFlag, "format", "", "deprecated format flag")
    74  }
    75  
    76  func (c *RelationSetCommand) Init(args []string) error {
    77  	if c.RelationId == -1 {
    78  		return errors.Errorf("no relation id specified")
    79  	}
    80  
    81  	// The overrides will be applied during Run when c.settingsFile is handled.
    82  	overrides, err := keyvalues.Parse(args, true)
    83  	if err != nil {
    84  		return errors.Trace(err)
    85  	}
    86  	c.Settings = overrides
    87  	return nil
    88  }
    89  
    90  func (c *RelationSetCommand) readSettings(in io.Reader) (map[string]string, error) {
    91  	data, err := ioutil.ReadAll(in)
    92  	if err != nil {
    93  		return nil, errors.Trace(err)
    94  	}
    95  
    96  	kvs := make(map[string]string)
    97  	if err := goyaml.Unmarshal(data, kvs); err != nil {
    98  		return nil, errors.Trace(err)
    99  	}
   100  
   101  	return kvs, nil
   102  }
   103  
   104  func (c *RelationSetCommand) handleSettingsFile(ctx *cmd.Context) error {
   105  	if c.settingsFile.Path == "" {
   106  		return nil
   107  	}
   108  
   109  	file, err := c.settingsFile.Open(ctx)
   110  	if err != nil {
   111  		return errors.Trace(err)
   112  	}
   113  	defer file.Close()
   114  
   115  	settings, err := c.readSettings(file)
   116  	if err != nil {
   117  		return errors.Trace(err)
   118  	}
   119  
   120  	overrides := c.Settings
   121  	for k, v := range overrides {
   122  		settings[k] = v
   123  	}
   124  	c.Settings = settings
   125  	return nil
   126  }
   127  
   128  func (c *RelationSetCommand) Run(ctx *cmd.Context) (err error) {
   129  	if c.formatFlag != "" {
   130  		fmt.Fprintf(ctx.Stderr, "--format flag deprecated for command %q", c.Info().Name)
   131  	}
   132  	if err := c.handleSettingsFile(ctx); err != nil {
   133  		return errors.Trace(err)
   134  	}
   135  
   136  	r, err := c.ctx.Relation(c.RelationId)
   137  	if err != nil {
   138  		return errors.Trace(err)
   139  	}
   140  	settings, err := r.Settings()
   141  	if err != nil {
   142  		return errors.Annotate(err, "cannot read relation settings")
   143  	}
   144  	for k, v := range c.Settings {
   145  		if v != "" {
   146  			settings.Set(k, v)
   147  		} else {
   148  			settings.Delete(k)
   149  		}
   150  	}
   151  	return nil
   152  }