github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/update_service_command.go (about) 1 package v6 2 3 import ( 4 "code.cloudfoundry.org/cli/actor/actionerror" 5 "code.cloudfoundry.org/cli/actor/sharedaction" 6 "code.cloudfoundry.org/cli/actor/v2action" 7 "code.cloudfoundry.org/cli/actor/v2action/composite" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" 9 "code.cloudfoundry.org/cli/command" 10 "code.cloudfoundry.org/cli/command/flag" 11 "code.cloudfoundry.org/cli/command/translatableerror" 12 "code.cloudfoundry.org/cli/command/v6/shared" 13 ) 14 15 //go:generate counterfeiter . UpdateServiceActor 16 17 type UpdateServiceActor interface { 18 CloudControllerAPIVersion() string 19 GetServiceInstanceByNameAndSpace(name string, spaceGUID string) (v2action.ServiceInstance, v2action.Warnings, error) 20 UpgradeServiceInstance(serviceInstance v2action.ServiceInstance) (v2action.Warnings, error) 21 } 22 23 type textData map[string]interface{} 24 25 type UpdateServiceCommand struct { 26 RequiredArgs flag.ServiceInstance `positional-args:"yes"` 27 ParametersAsJSON flag.Path `short:"c" description:"Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file. For a list of supported configuration parameters, see documentation for the particular service offering."` 28 Plan string `short:"p" description:"Change service plan for a service instance"` 29 Tags string `short:"t" description:"User provided tags"` 30 usage interface{} `usage:"CF_NAME update-service SERVICE_INSTANCE [-p NEW_PLAN] [-c PARAMETERS_AS_JSON] [-t TAGS] [--upgrade]\n\n Optionally provide service-specific configuration parameters in a valid JSON object in-line:\n CF_NAME update-service SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'\n\n Optionally provide a file containing service-specific configuration parameters in a valid JSON object. \n The path to the parameters file can be an absolute or relative path to a file:\n CF_NAME update-service SERVICE_INSTANCE -c PATH_TO_FILE\n\n Example of valid JSON object:\n {\n \"cluster_nodes\": {\n \"count\": 5,\n \"memory_mb\": 1024\n }\n }\n\n Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.\n\nEXAMPLES:\n CF_NAME update-service mydb -p gold\n CF_NAME update-service mydb -c '{\"ram_gb\":4}'\n CF_NAME update-service mydb -c ~/workspace/tmp/instance_config.json\n CF_NAME update-service mydb -t \"list, of, tags\"\n CF_NAME update-service mydb --upgrade\n CF_NAME update-service mydb --upgrade --force"` 31 relatedCommands interface{} `related_commands:"rename-service, services, update-user-provided-service"` 32 Upgrade bool `short:"u" long:"upgrade" description:"Upgrade the service instance to the latest version of the service plan available. It cannot be combined with flags: -c, -p, -t."` 33 ForceUpgrade bool `short:"f" long:"force" description:"Force the upgrade to the latest available version of the service plan. It can only be used with: -u, --upgrade."` 34 35 UI command.UI 36 Actor UpdateServiceActor 37 SharedActor command.SharedActor 38 Config command.Config 39 } 40 41 func (cmd *UpdateServiceCommand) Setup(config command.Config, ui command.UI) error { 42 cmd.UI = ui 43 cmd.Config = config 44 45 cmd.SharedActor = sharedaction.NewActor(config) 46 47 ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui) 48 if err != nil { 49 return err 50 } 51 52 baseActor := v2action.NewActor(ccClient, uaaClient, config) 53 cmd.Actor = &composite.UpdateServiceInstanceCompositeActor{ 54 GetAPIVersionActor: baseActor, 55 GetServicePlanActor: baseActor, 56 GetServiceInstanceActor: baseActor, 57 UpdateServiceInstanceMaintenanceInfoActor: baseActor, 58 } 59 60 return nil 61 } 62 63 func (cmd *UpdateServiceCommand) Execute(args []string) error { 64 if !cmd.Upgrade { 65 return translatableerror.UnrefactoredCommandError{} 66 } 67 68 if len(args) > 0 { 69 return translatableerror.TooManyArgumentsError{ 70 ExtraArgument: args[0], 71 } 72 } 73 74 if err := cmd.validateArgumentCombination(); err != nil { 75 return err 76 } 77 78 if err := command.MinimumCCAPIVersionCheck(cmd.Actor.CloudControllerAPIVersion(), ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2, "Option '--upgrade'"); err != nil { 79 return err 80 } 81 82 if err := cmd.SharedActor.CheckTarget(true, true); err != nil { 83 return err 84 } 85 86 instance, warnings, err := cmd.Actor.GetServiceInstanceByNameAndSpace(cmd.RequiredArgs.ServiceInstance, cmd.Config.TargetedSpace().GUID) 87 cmd.UI.DisplayWarnings(warnings) 88 if err != nil { 89 return err 90 } 91 92 proceed, err := cmd.promptForUpgrade() 93 if err != nil { 94 return err 95 } 96 97 if !proceed { 98 cmd.UI.DisplayText("Update cancelled") 99 return nil 100 } 101 102 return cmd.performUpgrade(instance) 103 } 104 105 func (cmd *UpdateServiceCommand) promptForUpgrade() (bool, error) { 106 if cmd.ForceUpgrade { 107 return true, nil 108 } 109 110 var serviceName = textData{"ServiceName": cmd.RequiredArgs.ServiceInstance} 111 112 cmd.UI.DisplayTextWithFlavor("You are about to update {{.ServiceName}}.", serviceName) 113 cmd.UI.DisplayText("Warning: This operation may be long running and will block further operations on the service until complete.") 114 115 return cmd.UI.DisplayBoolPrompt(false, "Really update service {{.ServiceName}}?", serviceName) 116 } 117 118 func (cmd *UpdateServiceCommand) performUpgrade(instance v2action.ServiceInstance) error { 119 currentUserName, err := cmd.Config.CurrentUserName() 120 if err != nil { 121 return err 122 } 123 124 cmd.printUpdatingServiceInstanceMessage(instance.Name, currentUserName) 125 126 warnings, err := cmd.Actor.UpgradeServiceInstance(instance) 127 cmd.UI.DisplayWarnings(warnings) 128 if err != nil { 129 if castedErr, ok := err.(actionerror.ServiceUpgradeNotAvailableError); ok { 130 return decorateUpgradeNotAvailableErrorWithTip(castedErr, instance) 131 } 132 return err 133 } 134 135 cmd.UI.DisplayOK() 136 return nil 137 } 138 139 func decorateUpgradeNotAvailableErrorWithTip(castedErr actionerror.ServiceUpgradeNotAvailableError, instance v2action.ServiceInstance) error { 140 return translatableerror.TipDecoratorError{ 141 BaseError: castedErr, 142 Tip: "To find out if upgrade is available run `cf service {{.ServiceName}}`.", 143 TipKeys: map[string]interface{}{ 144 "ServiceName": instance.Name, 145 }, 146 } 147 } 148 149 func (cmd *UpdateServiceCommand) printUpdatingServiceInstanceMessage(serviceInstanceName, currentUserName string) { 150 cmd.UI.DisplayTextWithFlavor("Updating service instance {{.ServiceName}} as {{.UserName}}...", 151 map[string]interface{}{ 152 "ServiceName": serviceInstanceName, 153 "UserName": currentUserName, 154 }) 155 } 156 157 func (cmd *UpdateServiceCommand) validateArgumentCombination() error { 158 if cmd.Tags != "" || cmd.ParametersAsJSON != "" || cmd.Plan != "" { 159 return translatableerror.ArgumentCombinationError{ 160 Args: []string{"--upgrade", "-t", "-c", "-p"}, 161 } 162 } 163 164 return nil 165 }