github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/cf/commands/service/update_service.go (about) 1 package service 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 "github.com/cloudfoundry/cli/cf/actors/plan_builder" 9 "github.com/cloudfoundry/cli/cf/api" 10 "github.com/cloudfoundry/cli/cf/command_registry" 11 "github.com/cloudfoundry/cli/cf/configuration/core_config" 12 . "github.com/cloudfoundry/cli/cf/i18n" 13 "github.com/cloudfoundry/cli/cf/models" 14 "github.com/cloudfoundry/cli/cf/requirements" 15 "github.com/cloudfoundry/cli/cf/terminal" 16 "github.com/cloudfoundry/cli/cf/ui_helpers" 17 "github.com/cloudfoundry/cli/flags" 18 "github.com/cloudfoundry/cli/flags/flag" 19 "github.com/cloudfoundry/cli/json" 20 ) 21 22 type UpdateService struct { 23 ui terminal.UI 24 config core_config.Reader 25 serviceRepo api.ServiceRepository 26 planBuilder plan_builder.PlanBuilder 27 } 28 29 func init() { 30 command_registry.Register(&UpdateService{}) 31 } 32 33 func (cmd *UpdateService) MetaData() command_registry.CommandMetadata { 34 baseUsage := T("CF_NAME update-service SERVICE_INSTANCE [-p NEW_PLAN] [-c PARAMETERS_AS_JSON] [-t TAGS]") 35 paramsUsage := T(` Optionally provide service-specific configuration parameters in a valid JSON object in-line. 36 CF_NAME update-service -c '{"name":"value","name":"value"}' 37 38 Optionally provide a file containing service-specific configuration parameters in a valid JSON object. 39 The path to the parameters file can be an absolute or relative path to a file. 40 CF_NAME update-service -c PATH_TO_FILE 41 42 Example of valid JSON object: 43 { 44 "cluster_nodes": { 45 "count": 5, 46 "memory_mb": 1024 47 } 48 }`) 49 tagsUsage := T(` Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.`) 50 exampleUsage := T(`EXAMPLE: 51 CF_NAME update-service mydb -p gold 52 CF_NAME update-service mydb -c '{"ram_gb":4}' 53 CF_NAME update-service mydb -c ~/workspace/tmp/instance_config.json 54 CF_NAME update-service mydb -t "list,of, tags"`) 55 56 fs := make(map[string]flags.FlagSet) 57 fs["p"] = &cliFlags.StringFlag{Name: "p", Usage: T("Change service plan for a service instance")} 58 fs["c"] = &cliFlags.StringFlag{Name: "c", Usage: T("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.")} 59 fs["t"] = &cliFlags.StringFlag{Name: "t", Usage: T("User provided tags")} 60 61 return command_registry.CommandMetadata{ 62 Name: "update-service", 63 Description: T("Update a service instance"), 64 Usage: T(strings.Join([]string{baseUsage, paramsUsage, tagsUsage, exampleUsage}, "\n\n")), 65 Flags: fs, 66 } 67 } 68 69 func (cmd *UpdateService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) (reqs []requirements.Requirement, err error) { 70 if len(fc.Args()) != 1 { 71 cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + command_registry.Commands.CommandUsage("update-service")) 72 } 73 74 reqs = []requirements.Requirement{ 75 requirementsFactory.NewLoginRequirement(), 76 requirementsFactory.NewTargetedSpaceRequirement(), 77 } 78 79 return 80 } 81 82 func (cmd *UpdateService) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command { 83 cmd.ui = deps.Ui 84 cmd.config = deps.Config 85 cmd.serviceRepo = deps.RepoLocator.GetServiceRepository() 86 cmd.planBuilder = deps.PlanBuilder 87 return cmd 88 } 89 90 func (cmd *UpdateService) Execute(c flags.FlagContext) { 91 planName := c.String("p") 92 params := c.String("c") 93 94 tagsSet := c.IsSet("t") 95 tagsList := c.String("t") 96 97 if planName == "" && params == "" && tagsSet == false { 98 cmd.ui.Ok() 99 cmd.ui.Say(T("No changes were made")) 100 return 101 } 102 103 serviceInstanceName := c.Args()[0] 104 serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName) 105 if err != nil { 106 cmd.ui.Failed(err.Error()) 107 } 108 109 paramsMap, err := json.ParseJsonFromFileOrString(params) 110 if err != nil { 111 cmd.ui.Failed(T("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.")) 112 } 113 114 tags := ui_helpers.ParseTags(tagsList) 115 116 var plan models.ServicePlanFields 117 if planName != "" { 118 cmd.checkUpdateServicePlanApiVersion() 119 err, plan = cmd.findPlan(serviceInstance, planName) 120 if err != nil { 121 cmd.ui.Failed(err.Error()) 122 } 123 } 124 125 cmd.printUpdatingServiceInstanceMessage(serviceInstanceName) 126 127 err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.Guid, plan.Guid, paramsMap, tags) 128 if err != nil { 129 cmd.ui.Failed(err.Error()) 130 } 131 err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui) 132 if err != nil { 133 cmd.ui.Failed(err.Error()) 134 } 135 } 136 137 func (cmd *UpdateService) findPlan(serviceInstance models.ServiceInstance, planName string) (err error, plan models.ServicePlanFields) { 138 plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.Guid, cmd.config.OrganizationFields().Name) 139 if err != nil { 140 return 141 } 142 143 for _, p := range plans { 144 if p.Name == planName { 145 plan = p 146 return 147 } 148 } 149 err = errors.New(T("Plan does not exist for the {{.ServiceName}} service", 150 map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label})) 151 return 152 } 153 154 func (cmd *UpdateService) checkUpdateServicePlanApiVersion() { 155 if !cmd.config.IsMinApiVersion("2.16.0") { 156 cmd.ui.Failed(T("Updating a plan requires API v{{.RequiredCCAPIVersion}} or newer. Your current target is v{{.CurrentCCAPIVersion}}.", 157 map[string]interface{}{ 158 "RequiredCCAPIVersion": "2.16.0", 159 "CurrentCCAPIVersion": cmd.config.ApiVersion(), 160 })) 161 } 162 } 163 164 func (cmd *UpdateService) printUpdatingServiceInstanceMessage(serviceInstanceName string) { 165 cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...", 166 map[string]interface{}{ 167 "ServiceName": terminal.EntityNameColor(serviceInstanceName), 168 "UserName": terminal.EntityNameColor(cmd.config.Username()), 169 })) 170 } 171 172 func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error { 173 instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName) 174 if apiErr != nil { 175 return apiErr 176 } 177 178 if instance.ServiceInstanceFields.LastOperation.State == "in progress" { 179 ui.Ok() 180 ui.Say("") 181 ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.", 182 map[string]interface{}{ 183 "State": strings.Title(instance.ServiceInstanceFields.LastOperation.Type), 184 "ServicesCommand": terminal.CommandColor("cf services"), 185 "ServiceCommand": terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)), 186 })) 187 } else { 188 ui.Ok() 189 } 190 191 return nil 192 }