github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/service/update_service.go (about) 1 package service 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 "code.cloudfoundry.org/cli/cf" 9 "code.cloudfoundry.org/cli/cf/actors/planbuilder" 10 "code.cloudfoundry.org/cli/cf/api" 11 "code.cloudfoundry.org/cli/cf/commandregistry" 12 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 13 "code.cloudfoundry.org/cli/cf/flags" 14 . "code.cloudfoundry.org/cli/cf/i18n" 15 "code.cloudfoundry.org/cli/cf/models" 16 "code.cloudfoundry.org/cli/cf/requirements" 17 "code.cloudfoundry.org/cli/cf/terminal" 18 "code.cloudfoundry.org/cli/cf/uihelpers" 19 "code.cloudfoundry.org/cli/util/json" 20 ) 21 22 type UpdateService struct { 23 ui terminal.UI 24 config coreconfig.Reader 25 serviceRepo api.ServiceRepository 26 planBuilder planbuilder.PlanBuilder 27 } 28 29 func init() { 30 commandregistry.Register(&UpdateService{}) 31 } 32 33 func (cmd *UpdateService) MetaData() commandregistry.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 51 fs := make(map[string]flags.FlagSet) 52 fs["p"] = &flags.StringFlag{ShortName: "p", Usage: T("Change service plan for a service instance")} 53 fs["c"] = &flags.StringFlag{ShortName: "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.")} 54 fs["t"] = &flags.StringFlag{ShortName: "t", Usage: T("User provided tags")} 55 56 return commandregistry.CommandMetadata{ 57 Name: "update-service", 58 Description: T("Update a service instance"), 59 Usage: []string{ 60 baseUsage, 61 "\n\n", 62 paramsUsage, 63 "\n\n", 64 tagsUsage, 65 }, 66 Examples: []string{ 67 `CF_NAME update-service mydb -p gold`, 68 `CF_NAME update-service mydb -c '{"ram_gb":4}'`, 69 `CF_NAME update-service mydb -c ~/workspace/tmp/instance_config.json`, 70 `CF_NAME update-service mydb -t "list,of, tags"`, 71 }, 72 Flags: fs, 73 } 74 } 75 76 func (cmd *UpdateService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) { 77 if len(fc.Args()) != 1 { 78 cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + commandregistry.Commands.CommandUsage("update-service")) 79 return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1) 80 } 81 82 reqs := []requirements.Requirement{ 83 requirementsFactory.NewLoginRequirement(), 84 requirementsFactory.NewTargetedSpaceRequirement(), 85 } 86 87 if fc.String("p") != "" { 88 reqs = append(reqs, requirementsFactory.NewMinAPIVersionRequirement("Updating a plan", cf.UpdateServicePlanMinimumAPIVersion)) 89 } 90 91 return reqs, nil 92 } 93 94 func (cmd *UpdateService) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command { 95 cmd.ui = deps.UI 96 cmd.config = deps.Config 97 cmd.serviceRepo = deps.RepoLocator.GetServiceRepository() 98 cmd.planBuilder = deps.PlanBuilder 99 return cmd 100 } 101 102 func (cmd *UpdateService) Execute(c flags.FlagContext) error { 103 planName := c.String("p") 104 params := c.String("c") 105 106 tagsSet := c.IsSet("t") 107 tagsList := c.String("t") 108 109 if planName == "" && params == "" && tagsSet == false { 110 cmd.ui.Ok() 111 cmd.ui.Say(T("No changes were made")) 112 return nil 113 } 114 115 serviceInstanceName := c.Args()[0] 116 serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName) 117 if err != nil { 118 return err 119 } 120 121 paramsMap, err := json.ParseJSONFromFileOrString(params) 122 if err != nil { 123 return errors.New(T("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.")) 124 } 125 126 tags := uihelpers.ParseTags(tagsList) 127 128 var plan models.ServicePlanFields 129 if planName != "" { 130 plan, err = cmd.findPlan(serviceInstance, planName) 131 if err != nil { 132 return err 133 } 134 } 135 136 cmd.printUpdatingServiceInstanceMessage(serviceInstanceName) 137 138 err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.GUID, plan.GUID, paramsMap, tags) 139 if err != nil { 140 return err 141 } 142 err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui) 143 if err != nil { 144 return err 145 } 146 return nil 147 } 148 149 func (cmd *UpdateService) findPlan(serviceInstance models.ServiceInstance, planName string) (plan models.ServicePlanFields, err error) { 150 plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.GUID, cmd.config.OrganizationFields().Name) 151 if err != nil { 152 return 153 } 154 155 for _, p := range plans { 156 if p.Name == planName { 157 plan = p 158 return 159 } 160 } 161 err = errors.New(T("Plan does not exist for the {{.ServiceName}} service", 162 map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label})) 163 return 164 } 165 166 func (cmd *UpdateService) printUpdatingServiceInstanceMessage(serviceInstanceName string) { 167 cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...", 168 map[string]interface{}{ 169 "ServiceName": terminal.EntityNameColor(serviceInstanceName), 170 "UserName": terminal.EntityNameColor(cmd.config.Username()), 171 })) 172 } 173 174 func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error { 175 instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName) 176 if apiErr != nil { 177 return apiErr 178 } 179 180 if instance.ServiceInstanceFields.LastOperation.State == "in progress" { 181 ui.Ok() 182 ui.Say("") 183 ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.", 184 map[string]interface{}{ 185 "State": strings.Title(instance.ServiceInstanceFields.LastOperation.Type), 186 "ServicesCommand": terminal.CommandColor("cf services"), 187 "ServiceCommand": terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)), 188 })) 189 } else { 190 ui.Ok() 191 } 192 193 return nil 194 }