github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/uniter/runner/jujuc/state-set.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujuc
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/cmd/v3"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/gnuflag"
    12  	"github.com/juju/utils/v3/keyvalues"
    13  
    14  	jujucmd "github.com/juju/juju/cmd"
    15  	"github.com/juju/juju/core/quota"
    16  )
    17  
    18  // StateSetCommand implements the state-set command.
    19  type StateSetCommand struct {
    20  	cmd.CommandBase
    21  	ctx          Context
    22  	StateValues  map[string]string
    23  	keyValueFile cmd.FileVar
    24  }
    25  
    26  // NewStateSetCommand returns a state-set command.
    27  func NewStateSetCommand(ctx Context) (cmd.Command, error) {
    28  	return &StateSetCommand{ctx: ctx}, nil
    29  }
    30  
    31  // Info returns information about the Command.
    32  // Info implements part of the cmd.Command interface.
    33  func (c *StateSetCommand) Info() *cmd.Info {
    34  	doc := `
    35  state-set sets the value of the server side state specified by key.
    36  
    37  The --file option should be used when one or more key-value pairs
    38  are too long to fit within the command length limit of the shell
    39  or operating system. The file will contain a YAML map containing
    40  the settings as strings.  Settings in the file will be overridden
    41  by any duplicate key-value arguments. A value of "-" for the filename
    42  means <stdin>.
    43  
    44  The following fixed size limits apply:
    45  - Length of stored keys cannot exceed %d bytes.
    46  - Length of stored values cannot exceed %d bytes.
    47  
    48  See also:
    49      state-delete
    50      state-get
    51  `
    52  	return jujucmd.Info(&cmd.Info{
    53  		Name:    "state-set",
    54  		Args:    "key=value [key=value ...]",
    55  		Purpose: "set server-side-state values",
    56  		Doc: fmt.Sprintf(
    57  			doc,
    58  			quota.MaxCharmStateKeySize,
    59  			quota.MaxCharmStateValueSize,
    60  		),
    61  	})
    62  }
    63  
    64  // SetFlags adds command specific flags to the flag set.
    65  // SetFlags implements part of the cmd.Command interface.
    66  func (c *StateSetCommand) SetFlags(f *gnuflag.FlagSet) {
    67  	c.keyValueFile.SetStdin()
    68  	f.Var(&c.keyValueFile, "file", "file containing key-value pairs")
    69  }
    70  
    71  // Init initializes the Command before running.
    72  // Init implements part of the cmd.Command interface.
    73  func (c *StateSetCommand) Init(args []string) error {
    74  	if args == nil {
    75  		return nil
    76  	}
    77  
    78  	// The overrides will be applied during Run when c.keyValueFile is handled.
    79  	overrides, err := keyvalues.Parse(args, true)
    80  	if err != nil {
    81  		return errors.Trace(err)
    82  	}
    83  	c.StateValues = overrides
    84  	return nil
    85  }
    86  
    87  // Run will execute the Command as directed by the options and positional
    88  // arguments passed to Init.
    89  // Run implements part of the cmd.Command interface.
    90  func (c *StateSetCommand) Run(ctx *cmd.Context) error {
    91  	if err := c.handleKeyValueFile(ctx); err != nil {
    92  		return errors.Trace(err)
    93  	}
    94  
    95  	for k, v := range c.StateValues {
    96  		if err := c.ctx.SetCharmStateValue(k, v); err != nil {
    97  			return err
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  func (c *StateSetCommand) handleKeyValueFile(ctx *cmd.Context) error {
   104  	if c.keyValueFile.Path == "" {
   105  		return nil
   106  	}
   107  
   108  	file, err := c.keyValueFile.Open(ctx)
   109  	if err != nil {
   110  		return errors.Trace(err)
   111  	}
   112  	defer func() { _ = file.Close() }()
   113  
   114  	kvs, err := readSettings(file)
   115  	if err != nil {
   116  		return errors.Trace(err)
   117  	}
   118  
   119  	overrides := c.StateValues
   120  	for k, v := range overrides {
   121  		kvs[k] = v
   122  	}
   123  	c.StateValues = kvs
   124  	return nil
   125  }