github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v7/update_buildpack_command.go (about) 1 package v7 2 3 import ( 4 "io/ioutil" 5 "os" 6 "time" 7 8 "code.cloudfoundry.org/cli/actor/sharedaction" 9 "code.cloudfoundry.org/cli/actor/v7action" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 12 "code.cloudfoundry.org/cli/command" 13 "code.cloudfoundry.org/cli/command/flag" 14 "code.cloudfoundry.org/cli/command/translatableerror" 15 "code.cloudfoundry.org/cli/command/v7/shared" 16 "code.cloudfoundry.org/cli/types" 17 "code.cloudfoundry.org/cli/util/configv3" 18 "code.cloudfoundry.org/cli/util/download" 19 "code.cloudfoundry.org/clock" 20 ) 21 22 //go:generate counterfeiter . UpdateBuildpackActor 23 24 type UpdateBuildpackActor interface { 25 UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack v7action.Buildpack) (v7action.Buildpack, v7action.Warnings, error) 26 UploadBuildpack(guid string, pathToBuildpackBits string, progressBar v7action.SimpleProgressBar) (ccv3.JobURL, v7action.Warnings, error) 27 PrepareBuildpackBits(inputPath string, tmpDirPath string, downloader v7action.Downloader) (string, error) 28 PollUploadBuildpackJob(jobURL ccv3.JobURL) (v7action.Warnings, error) 29 } 30 31 type UpdateBuildpackCommand struct { 32 RequiredArgs flag.BuildpackName `positional-args:"Yes"` 33 usage interface{} `usage:"CF_NAME update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--enable|--disable] [--lock|--unlock] [--rename]\n\nTIP:\nPath should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\nUse '--assign-stack' with caution. Associating a buildpack with a stack that it does not support may result in undefined behavior. Additionally, changing this association once made may require a local copy of the buildpack.\n\n"` 34 relatedCommands interface{} `related_commands:"buildpacks, create-buildpack, delete-buildpack"` 35 NewStack string `long:"assign-stack" description:"Assign a stack to a buildpack that does not have a stack association"` 36 Disable bool `long:"disable" description:"Disable the buildpack from being used for staging"` 37 Enable bool `long:"enable" description:"Enable the buildpack to be used for staging"` 38 Lock bool `long:"lock" description:"Lock the buildpack to prevent updates"` 39 Path flag.PathWithExistenceCheckOrURL `long:"path" short:"p" description:"Path to directory or zip file"` 40 Position types.NullInt `long:"position" short:"i" description:"The order in which the buildpacks are checked during buildpack auto-detection"` 41 NewName string `long:"rename" description:"Rename an existing buildpack"` 42 CurrentStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` 43 Unlock bool `long:"unlock" description:"Unlock the buildpack to enable updates"` 44 45 UI command.UI 46 Config command.Config 47 ProgressBar v7action.SimpleProgressBar 48 SharedActor command.SharedActor 49 Actor UpdateBuildpackActor 50 } 51 52 func (cmd *UpdateBuildpackCommand) Setup(config command.Config, ui command.UI) error { 53 cmd.UI = ui 54 cmd.Config = config 55 sharedActor := sharedaction.NewActor(config) 56 cmd.SharedActor = sharedActor 57 58 ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui, "") 59 if err != nil { 60 return err 61 } 62 cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient, clock.NewClock()) 63 cmd.ProgressBar = v7action.NewProgressBar() 64 65 return nil 66 } 67 68 func (cmd UpdateBuildpackCommand) Execute(args []string) error { 69 var buildpackBitsPath, tmpDirPath string 70 71 user, err := cmd.validateSetup() 72 if err != nil { 73 return err 74 } 75 76 cmd.printInitialText(user.Name) 77 78 if cmd.Path != "" { 79 buildpackBitsPath, tmpDirPath, err = cmd.prepareBuildpackBits() 80 if err != nil { 81 return err 82 } 83 defer os.RemoveAll(tmpDirPath) 84 } 85 86 updatedBuildpack, err := cmd.updateBuildpack() 87 if err != nil { 88 return err 89 } 90 91 if buildpackBitsPath != "" { 92 return cmd.uploadBits(user, updatedBuildpack, buildpackBitsPath) 93 } 94 95 return nil 96 } 97 98 func (cmd UpdateBuildpackCommand) validateSetup() (configv3.User, error) { 99 var user configv3.User 100 101 err := cmd.validateFlagCombinations() 102 if err != nil { 103 return user, err 104 } 105 106 err = cmd.SharedActor.CheckTarget(false, false) 107 if err != nil { 108 return user, err 109 } 110 111 return cmd.Config.CurrentUser() 112 } 113 114 func (cmd UpdateBuildpackCommand) prepareBuildpackBits() (string, string, error) { 115 downloader := download.NewDownloader(time.Second * 30) 116 tmpDirPath, err := ioutil.TempDir("", "buildpack-dir-") 117 if err != nil { 118 return "", "", err 119 } 120 121 buildpackBits, err := cmd.Actor.PrepareBuildpackBits(string(cmd.Path), tmpDirPath, downloader) 122 return buildpackBits, tmpDirPath, err 123 } 124 125 func (cmd UpdateBuildpackCommand) updateBuildpack() (v7action.Buildpack, error) { 126 var desiredBuildpack v7action.Buildpack 127 128 desiredBuildpack.Enabled = types.NullBool{IsSet: cmd.Enable || cmd.Disable, Value: cmd.Enable} 129 desiredBuildpack.Locked = types.NullBool{IsSet: cmd.Lock || cmd.Unlock, Value: cmd.Lock} 130 desiredBuildpack.Position = cmd.Position 131 132 if cmd.NewStack != "" { 133 desiredBuildpack.Stack = cmd.NewStack 134 } 135 136 if cmd.NewName != "" { 137 desiredBuildpack.Name = cmd.NewName 138 } 139 140 updatedBuildpack, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStack( 141 cmd.RequiredArgs.Buildpack, 142 cmd.CurrentStack, 143 desiredBuildpack, 144 ) 145 cmd.UI.DisplayWarnings(warnings) 146 if err != nil { 147 return updatedBuildpack, err 148 } 149 cmd.UI.DisplayOK() 150 151 return updatedBuildpack, nil 152 } 153 154 func (cmd UpdateBuildpackCommand) uploadBits(user configv3.User, updatedBuildpack v7action.Buildpack, buildpackBitsPath string) error { 155 cmd.UI.DisplayTextWithFlavor("Uploading buildpack {{.Buildpack}} as {{.Username}}...", map[string]interface{}{ 156 "Buildpack": cmd.RequiredArgs.Buildpack, 157 "Username": user.Name, 158 }) 159 160 jobURL, warnings, err := cmd.Actor.UploadBuildpack( 161 updatedBuildpack.GUID, 162 buildpackBitsPath, 163 cmd.ProgressBar, 164 ) 165 if _, ok := err.(ccerror.InvalidAuthTokenError); ok { 166 cmd.UI.DisplayWarnings([]string{"Failed to upload buildpack due to auth token expiration, retrying..."}) 167 jobURL, warnings, err = cmd.Actor.UploadBuildpack(updatedBuildpack.GUID, buildpackBitsPath, cmd.ProgressBar) 168 } 169 cmd.UI.DisplayWarnings(warnings) 170 if err != nil { 171 return err 172 } 173 cmd.UI.DisplayOK() 174 175 cmd.UI.DisplayTextWithFlavor("Processing uploaded buildpack {{.BuildpackName}}...", map[string]interface{}{ 176 "BuildpackName": cmd.RequiredArgs.Buildpack, 177 }) 178 179 warnings, err = cmd.Actor.PollUploadBuildpackJob(jobURL) 180 cmd.UI.DisplayWarnings(warnings) 181 if err != nil { 182 return err 183 } 184 185 cmd.UI.DisplayOK() 186 return nil 187 } 188 189 func (cmd UpdateBuildpackCommand) printInitialText(userName string) { 190 var originalBuildpackName = cmd.RequiredArgs.Buildpack 191 var buildpackName = originalBuildpackName 192 193 if cmd.NewName != "" { 194 buildpackName = cmd.NewName 195 cmd.UI.DisplayTextWithFlavor("Renaming buildpack {{.Buildpack}} to {{.DesiredBuildpackName}} as {{.CurrentUser}}...\n", map[string]interface{}{ 196 "Buildpack": originalBuildpackName, 197 "CurrentUser": userName, 198 "DesiredBuildpackName": cmd.NewName, 199 }) 200 } 201 202 switch { 203 case cmd.NewStack != "": 204 cmd.UI.DisplayTextWithFlavor("Assigning stack {{.Stack}} to {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ 205 "Buildpack": buildpackName, 206 "CurrentUser": userName, 207 "Stack": cmd.NewStack, 208 }) 209 if cmd.Position.IsSet || cmd.Lock || cmd.Unlock || cmd.Enable || cmd.Disable { 210 cmd.UI.DisplayTextWithFlavor("\nUpdating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ 211 "Buildpack": buildpackName, 212 "CurrentUser": userName, 213 "Stack": cmd.NewStack, 214 }) 215 } 216 case cmd.CurrentStack == "": 217 cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ 218 "Buildpack": buildpackName, 219 "CurrentUser": userName, 220 }) 221 default: 222 cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ 223 "Buildpack": buildpackName, 224 "CurrentUser": userName, 225 "Stack": cmd.CurrentStack, 226 }) 227 } 228 } 229 230 func (cmd UpdateBuildpackCommand) validateFlagCombinations() error { 231 if cmd.Lock && cmd.Unlock { 232 return translatableerror.ArgumentCombinationError{ 233 Args: []string{"--lock", "--unlock"}, 234 } 235 } 236 237 if cmd.Enable && cmd.Disable { 238 return translatableerror.ArgumentCombinationError{ 239 Args: []string{"--enable", "--disable"}, 240 } 241 } 242 243 if cmd.Path != "" && cmd.Lock { 244 return translatableerror.ArgumentCombinationError{ 245 Args: []string{"--path", "--lock"}, 246 } 247 } 248 249 if cmd.Path != "" && cmd.NewStack != "" { 250 return translatableerror.ArgumentCombinationError{ 251 Args: []string{"--path", "--assign-stack"}, 252 } 253 } 254 255 if cmd.CurrentStack != "" && cmd.NewStack != "" { 256 return translatableerror.ArgumentCombinationError{ 257 Args: []string{"--stack", "--assign-stack"}, 258 } 259 } 260 return nil 261 }