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