github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+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 !cmd.ensureThereAreChanges(planName, params, tagsSet) { 105 return nil 106 } 107 108 serviceInstanceName := c.Args()[0] 109 serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName) 110 if err != nil { 111 return err 112 } 113 114 paramsMap, err := json.ParseJSONFromFileOrString(params) 115 if err != nil { 116 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.")) 117 } 118 119 tags := uihelpers.ParseTags(tagsList) 120 121 var plan models.ServicePlanFields 122 if planName != "" { 123 foundPlan, err := cmd.findPlan(serviceInstance, planName) 124 if err != nil { 125 return err 126 } 127 128 if planIsTheSame(serviceInstance, foundPlan) { 129 planName = "" 130 } else { 131 plan = foundPlan 132 } 133 } 134 135 cmd.printUpdatingServiceInstanceMessage(serviceInstanceName) 136 137 if !cmd.ensureThereAreChanges(planName, params, tagsSet) { 138 return nil 139 } 140 141 err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.GUID, plan.GUID, paramsMap, tags) 142 if err != nil { 143 return err 144 } 145 err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui) 146 if err != nil { 147 return err 148 } 149 return nil 150 } 151 152 func (cmd *UpdateService) findPlan(serviceInstance models.ServiceInstance, planName string) (plan models.ServicePlanFields, err error) { 153 plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.GUID, cmd.config.OrganizationFields().Name) 154 if err != nil { 155 return 156 } 157 158 for _, p := range plans { 159 if p.Name == planName { 160 plan = p 161 return 162 } 163 } 164 err = errors.New(T("Plan does not exist for the {{.ServiceName}} service", 165 map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label})) 166 return 167 } 168 169 func (cmd *UpdateService) printUpdatingServiceInstanceMessage(serviceInstanceName string) { 170 cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...", 171 map[string]interface{}{ 172 "ServiceName": terminal.EntityNameColor(serviceInstanceName), 173 "UserName": terminal.EntityNameColor(cmd.config.Username()), 174 })) 175 } 176 177 func (cmd *UpdateService) ensureThereAreChanges(planName string, params string, tagsSet bool) bool { 178 if planName == "" && params == "" && tagsSet == false { 179 cmd.ui.Ok() 180 cmd.ui.Say(T("No changes were made")) 181 return false 182 } 183 184 return true 185 } 186 187 func planIsTheSame(serviceInstance models.ServiceInstance, plan models.ServicePlanFields) bool { 188 oldPlanGUID := serviceInstance.ServicePlan.GUID 189 newPlanGUID := plan.GUID 190 191 return oldPlanGUID == newPlanGUID 192 } 193 194 func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error { 195 instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName) 196 if apiErr != nil { 197 return apiErr 198 } 199 200 if instance.ServiceInstanceFields.LastOperation.State == "in progress" { 201 ui.Ok() 202 ui.Say("") 203 ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.", 204 map[string]interface{}{ 205 "State": strings.Title(instance.ServiceInstanceFields.LastOperation.Type), 206 "ServicesCommand": terminal.CommandColor("cf services"), 207 "ServiceCommand": terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)), 208 })) 209 } else { 210 ui.Ok() 211 } 212 213 return nil 214 }