github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/resource/context/cmd/get.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cmd 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 12 jujucmd "github.com/juju/juju/cmd" 13 "github.com/juju/juju/worker/uniter/runner/jujuc" 14 ) 15 16 // GetCmdName is the name of the resource-get command. 17 const GetCmdName = "resource-get" 18 19 // NewGetCmd creates a new GetCmd for the given hook context. 20 func NewGetCmd(c jujuc.ContextComponent) (*GetCmd, error) { 21 return &GetCmd{ 22 compContext: c, 23 }, nil 24 } 25 26 // GetCmd provides the functionality of the resource-get command. 27 type GetCmd struct { 28 cmd.CommandBase 29 30 compContext jujuc.ContextComponent 31 resourceName string 32 } 33 34 // TODO(ericsnow) Also provide an indicator of whether or not 35 // the resource has changed (in addition to the file path)? 36 37 // Info implements cmd.Command. 38 func (c GetCmd) Info() *cmd.Info { 39 return jujucmd.Info(&cmd.Info{ 40 Name: GetCmdName, 41 Args: "<resource name>", 42 Purpose: "get the path to the locally cached resource file", 43 Doc: ` 44 "resource-get" is used while a hook is running to get the local path 45 to the file for the identified resource. This file is an fs-local copy, 46 unique to the unit for which the hook is running. It is downloaded from 47 the controller, if necessary. 48 49 If "resource-get" for a resource has not been run before (for the unit) 50 then the resource is downloaded from the controller at the revision 51 associated with the unit's application. That file is stored in the unit's 52 local cache. If "resource-get" *has* been run before then each 53 subsequent run syncs the resource with the controller. This ensures 54 that the revision of the unit-local copy of the resource matches the 55 revision of the resource associated with the unit's application. 56 57 Either way, the path provided by "resource-get" references the 58 up-to-date file for the resource. Note that the resource may get 59 updated on the controller for the application at any time, meaning the 60 cached copy *may* be out of date at any time after you call 61 "resource-get". Consequently, the command should be run at every 62 point where it is critical that the resource be up to date. 63 64 The "upgrade-charm" hook is useful for keeping your charm's resources 65 on a unit up to date. Run "resource-get" there for each of your 66 charm's resources to do so. The hook fires whenever the the file for 67 one of the application's resources changes on the controller (in addition 68 to when the charm itself changes). That means it happens in response 69 to "juju upgrade-charm" as well as to "juju push-resource". 70 71 Note that the "upgrade-charm" hook does not run when the unit is 72 started up. So be sure to run "resource-get" for your resources in the 73 "install" hook (or "config-changed", etc.). 74 75 Note that "resource-get" only provides an FS path to the resource file. 76 It does not provide any information about the resource (e.g. revision). 77 `, 78 }) 79 } 80 81 // Init implements cmd.Command. 82 func (c *GetCmd) Init(args []string) error { 83 if len(args) < 1 { 84 return errors.Errorf("missing required resource name") 85 } else if err := cmd.CheckEmpty(args[1:]); err != nil { 86 return errors.Trace(err) 87 } 88 c.resourceName = args[0] 89 return nil 90 } 91 92 // Run implements cmd.Command. 93 func (c GetCmd) Run(ctx *cmd.Context) error { 94 hookContext, ok := c.compContext.(downloader) 95 if !ok { 96 return errors.Errorf("invalid component context") 97 } 98 filePath, err := hookContext.Download(c.resourceName) 99 if err != nil { 100 return errors.Annotate(err, "could not download resource") 101 } 102 103 if _, err := fmt.Fprintf(ctx.Stdout, filePath); err != nil { 104 return errors.Annotate(err, "could not write resource path to stdout") 105 } 106 return nil 107 } 108 109 type downloader interface { 110 Download(name string) (string, error) 111 }