github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/payload/context/register.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package context
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/errors"
     9  	"gopkg.in/juju/charm.v6"
    10  
    11  	jujucmd "github.com/juju/juju/cmd"
    12  	"github.com/juju/juju/payload"
    13  )
    14  
    15  // RegisterCmdName is the name of the payload register command.
    16  const RegisterCmdName = "payload-register"
    17  
    18  // NewRegisterCmd returns a new RegisterCmd that wraps the given context.
    19  func NewRegisterCmd(ctx HookContext) (*RegisterCmd, error) {
    20  	return &RegisterCmd{hookContextFunc: componentHookContext(ctx)}, nil
    21  }
    22  
    23  // RegisterCmd is a command that registers a payload with juju.
    24  type RegisterCmd struct {
    25  	cmd.CommandBase
    26  
    27  	hookContextFunc func() (Component, error)
    28  	typ             string
    29  	class           string
    30  	id              string
    31  	labels          []string
    32  }
    33  
    34  // TODO(ericsnow) Change "tags" to "labels" in the help text?
    35  
    36  // Info implements cmd.Command.
    37  func (c RegisterCmd) Info() *cmd.Info {
    38  	return jujucmd.Info(&cmd.Info{
    39  		Name:    RegisterCmdName,
    40  		Args:    "<type> <class> <id> [tags...]",
    41  		Purpose: "register a charm payload with juju",
    42  		Doc: `
    43  "payload-register" is used while a hook is running to let Juju know that a
    44  payload has been started. The information used to start the payload must be
    45  provided when "register" is run.
    46  
    47  The payload class must correspond to one of the payloads defined in
    48  the charm's metadata.yaml.
    49  
    50  		`,
    51  	})
    52  }
    53  
    54  // Init implements cmd.Command.
    55  func (c *RegisterCmd) Init(args []string) error {
    56  	if len(args) < 3 {
    57  		return errors.Errorf("missing required arguments")
    58  	}
    59  	c.typ = args[0]
    60  	c.class = args[1]
    61  	c.id = args[2]
    62  	c.labels = args[3:]
    63  	return nil
    64  }
    65  
    66  // Run implements cmd.Command.
    67  func (c *RegisterCmd) Run(ctx *cmd.Context) error {
    68  	if err := c.validate(ctx); err != nil {
    69  		return errors.Trace(err)
    70  	}
    71  	pl := payload.Payload{
    72  		PayloadClass: charm.PayloadClass{
    73  			Name: c.class,
    74  			Type: c.typ,
    75  		},
    76  		ID:     c.id,
    77  		Status: payload.StateRunning,
    78  		Labels: c.labels,
    79  		Unit:   "a-application/0", // TODO(ericsnow) eliminate this!
    80  	}
    81  	hctx, err := c.hookContextFunc()
    82  	if err != nil {
    83  		return errors.Trace(err)
    84  	}
    85  	if err := hctx.Track(pl); err != nil {
    86  		return errors.Trace(err)
    87  	}
    88  
    89  	// We flush to state immediately so that status reflects the
    90  	// payload correctly.
    91  	if err := hctx.Flush(); err != nil {
    92  		return errors.Trace(err)
    93  	}
    94  
    95  	// TODO(ericsnow) Print out the full ID.
    96  
    97  	return nil
    98  }
    99  
   100  func (c *RegisterCmd) validate(ctx *cmd.Context) error {
   101  	meta, err := readMetadata(ctx)
   102  	if err != nil {
   103  		return errors.Trace(err)
   104  	}
   105  
   106  	found := false
   107  	for _, class := range meta.PayloadClasses {
   108  		if c.class == class.Name {
   109  			if c.typ != class.Type {
   110  				return errors.Errorf("incorrect type %q for payload %q, expected %q", c.typ, class.Name, class.Type)
   111  			}
   112  			found = true
   113  		}
   114  	}
   115  	if !found {
   116  		return errors.Errorf("payload %q not found in metadata.yaml", c.class)
   117  	}
   118  	return nil
   119  }