github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/cf/commands/service/create_service.go (about) 1 package service 2 3 import ( 4 "fmt" 5 6 "code.cloudfoundry.org/cli/cf/actors/servicebuilder" 7 "code.cloudfoundry.org/cli/cf/api" 8 "code.cloudfoundry.org/cli/cf/commandregistry" 9 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 10 "code.cloudfoundry.org/cli/cf/errors" 11 "code.cloudfoundry.org/cli/cf/flags" 12 . "code.cloudfoundry.org/cli/cf/i18n" 13 "code.cloudfoundry.org/cli/cf/models" 14 "code.cloudfoundry.org/cli/cf/requirements" 15 "code.cloudfoundry.org/cli/cf/terminal" 16 "code.cloudfoundry.org/cli/cf/uihelpers" 17 "code.cloudfoundry.org/cli/cf/util/json" 18 ) 19 20 type CreateService struct { 21 ui terminal.UI 22 config coreconfig.Reader 23 serviceRepo api.ServiceRepository 24 serviceBuilder servicebuilder.ServiceBuilder 25 } 26 27 func init() { 28 commandregistry.Register(&CreateService{}) 29 } 30 31 func (cmd *CreateService) MetaData() commandregistry.CommandMetadata { 32 fs := make(map[string]flags.FlagSet) 33 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.")} 34 fs["t"] = &flags.StringFlag{ShortName: "t", Usage: T("User provided tags")} 35 36 baseUsage := T("CF_NAME create-service SERVICE PLAN SERVICE_INSTANCE [-c PARAMETERS_AS_JSON] [-t TAGS]") 37 paramsUsage := T(` Optionally provide service-specific configuration parameters in a valid JSON object in-line: 38 39 CF_NAME create-service SERVICE PLAN SERVICE_INSTANCE -c '{"name":"value","name":"value"}' 40 41 Optionally provide a file containing service-specific configuration parameters in a valid JSON object. 42 The path to the parameters file can be an absolute or relative path to a file: 43 44 CF_NAME create-service SERVICE PLAN SERVICE_INSTANCE -c PATH_TO_FILE 45 46 Example of valid JSON object: 47 { 48 "cluster_nodes": { 49 "count": 5, 50 "memory_mb": 1024 51 } 52 }`) 53 tipsUsage := T(`TIP: 54 Use 'CF_NAME create-user-provided-service' to make user-provided services available to CF apps`) 55 return commandregistry.CommandMetadata{ 56 Name: "create-service", 57 ShortName: "cs", 58 Description: T("Create a service instance"), 59 Usage: []string{ 60 baseUsage, 61 "\n\n", 62 paramsUsage, 63 "\n\n", 64 tipsUsage, 65 }, 66 Examples: []string{ 67 fmt.Sprintf("%s:", T(`Linux/Mac`)), 68 ` CF_NAME create-service db-service silver mydb -c '{"ram_gb":4}'`, 69 ``, 70 fmt.Sprintf("%s:", T(`Windows Command Line`)), 71 ` CF_NAME create-service db-service silver mydb -c "{\"ram_gb\":4}"`, 72 ``, 73 fmt.Sprintf("%s:", T(`Windows PowerShell`)), 74 ` CF_NAME create-service db-service silver mydb -c '{\"ram_gb\":4}'`, 75 ``, 76 `CF_NAME create-service db-service silver mydb -c ~/workspace/tmp/instance_config.json`, 77 ``, 78 `CF_NAME create-service db-service silver mydb -t "list, of, tags"`, 79 }, 80 Flags: fs, 81 } 82 } 83 84 func (cmd *CreateService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) { 85 if len(fc.Args()) != 3 { 86 cmd.ui.Failed(T("Incorrect Usage. Requires service, service plan, service instance as arguments\n\n") + commandregistry.Commands.CommandUsage("create-service")) 87 return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 3) 88 } 89 90 reqs := []requirements.Requirement{ 91 requirementsFactory.NewLoginRequirement(), 92 requirementsFactory.NewTargetedSpaceRequirement(), 93 } 94 95 return reqs, nil 96 } 97 98 func (cmd *CreateService) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command { 99 cmd.ui = deps.UI 100 cmd.config = deps.Config 101 cmd.serviceRepo = deps.RepoLocator.GetServiceRepository() 102 cmd.serviceBuilder = deps.ServiceBuilder 103 return cmd 104 } 105 106 func (cmd *CreateService) Execute(c flags.FlagContext) error { 107 serviceName := c.Args()[0] 108 planName := c.Args()[1] 109 serviceInstanceName := c.Args()[2] 110 params := c.String("c") 111 tags := c.String("t") 112 113 tagsList := uihelpers.ParseTags(tags) 114 115 paramsMap, err := json.ParseJSONFromFileOrString(params) 116 if err != nil { 117 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.")) 118 } 119 120 cmd.ui.Say(T("Creating service instance {{.ServiceName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.CurrentUser}}...", 121 map[string]interface{}{ 122 "ServiceName": terminal.EntityNameColor(serviceInstanceName), 123 "OrgName": terminal.EntityNameColor(cmd.config.OrganizationFields().Name), 124 "SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name), 125 "CurrentUser": terminal.EntityNameColor(cmd.config.Username()), 126 })) 127 128 plan, err := cmd.CreateService(serviceName, planName, serviceInstanceName, paramsMap, tagsList) 129 130 switch err.(type) { 131 case nil: 132 err := printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui) 133 if err != nil { 134 return err 135 } 136 137 if !plan.Free { 138 cmd.ui.Say("") 139 cmd.ui.Say(T("Attention: The plan `{{.PlanName}}` of service `{{.ServiceName}}` is not free. The instance `{{.ServiceInstanceName}}` will incur a cost. Contact your administrator if you think this is in error.", 140 map[string]interface{}{ 141 "PlanName": terminal.EntityNameColor(plan.Name), 142 "ServiceName": terminal.EntityNameColor(serviceName), 143 "ServiceInstanceName": terminal.EntityNameColor(serviceInstanceName), 144 })) 145 cmd.ui.Say("") 146 } 147 case *errors.ModelAlreadyExistsError: 148 cmd.ui.Ok() 149 cmd.ui.Warn(err.Error()) 150 default: 151 return err 152 } 153 return nil 154 } 155 156 func (cmd CreateService) CreateService(serviceName, planName, serviceInstanceName string, params map[string]interface{}, tags []string) (models.ServicePlanFields, error) { 157 offerings, apiErr := cmd.serviceBuilder.GetServicesByNameForSpaceWithPlans(cmd.config.SpaceFields().GUID, serviceName) 158 if apiErr != nil { 159 return models.ServicePlanFields{}, apiErr 160 } 161 162 plan, apiErr := findPlanFromOfferings(offerings, planName) 163 if apiErr != nil { 164 return plan, apiErr 165 } 166 167 apiErr = cmd.serviceRepo.CreateServiceInstance(serviceInstanceName, plan.GUID, params, tags) 168 return plan, apiErr 169 } 170 171 func findPlanFromOfferings(offerings models.ServiceOfferings, name string) (plan models.ServicePlanFields, err error) { 172 for _, offering := range offerings { 173 for _, plan := range offering.Plans { 174 if name == plan.Name { 175 return plan, nil 176 } 177 } 178 } 179 180 err = errors.New(T("Could not find plan with name {{.ServicePlanName}}", 181 map[string]interface{}{"ServicePlanName": name}, 182 )) 183 return 184 }