github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/service/bind_service.go (about) 1 package service 2 3 import ( 4 "fmt" 5 6 "code.cloudfoundry.org/cli/cf" 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/util/json" 17 ) 18 19 //go:generate counterfeiter . Binder 20 21 type Binder interface { 22 BindApplication(app models.Application, serviceInstance models.ServiceInstance, paramsMap map[string]interface{}) (apiErr error) 23 } 24 25 type BindService struct { 26 ui terminal.UI 27 config coreconfig.Reader 28 serviceBindingRepo api.ServiceBindingRepository 29 appReq requirements.ApplicationRequirement 30 serviceInstanceReq requirements.ServiceInstanceRequirement 31 } 32 33 func init() { 34 commandregistry.Register(&BindService{}) 35 } 36 37 func (cmd *BindService) MetaData() commandregistry.CommandMetadata { 38 baseUsage := T("CF_NAME bind-service APP_NAME SERVICE_INSTANCE [-c PARAMETERS_AS_JSON]") 39 paramsUsage := T(` Optionally provide service-specific configuration parameters in a valid JSON object in-line: 40 41 CF_NAME bind-service APP_NAME SERVICE_INSTANCE -c '{"name":"value","name":"value"}' 42 43 Optionally provide a file containing service-specific configuration parameters in a valid JSON object. 44 The path to the parameters file can be an absolute or relative path to a file. 45 CF_NAME bind-service APP_NAME SERVICE_INSTANCE -c PATH_TO_FILE 46 47 Example of valid JSON object: 48 { 49 "permissions": "read-only" 50 }`) 51 52 fs := make(map[string]flags.FlagSet) 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 55 return commandregistry.CommandMetadata{ 56 Name: "bind-service", 57 ShortName: "bs", 58 Description: T("Bind a service instance to an app"), 59 Usage: []string{ 60 baseUsage, 61 "\n\n", 62 paramsUsage, 63 }, 64 Examples: []string{ 65 fmt.Sprintf("%s:", T(`Linux/Mac`)), 66 ` CF_NAME bind-service myapp mydb -c '{"permissions":"read-only"}'`, 67 ``, 68 fmt.Sprintf("%s:", T(`Windows Command Line`)), 69 ` CF_NAME bind-service myapp mydb -c "{\"permissions\":\"read-only\"}"`, 70 ``, 71 fmt.Sprintf("%s:", T(`Windows PowerShell`)), 72 ` CF_NAME bind-service myapp mydb -c '{\"permissions\":\"read-only\"}'`, 73 ``, 74 `CF_NAME bind-service myapp mydb -c ~/workspace/tmp/instance_config.json`, 75 }, 76 Flags: fs, 77 } 78 } 79 80 func (cmd *BindService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) { 81 if len(fc.Args()) != 2 { 82 cmd.ui.Failed(T("Incorrect Usage. Requires APP_NAME and SERVICE_INSTANCE as arguments\n\n") + commandregistry.Commands.CommandUsage("bind-service")) 83 return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 2) 84 } 85 86 serviceName := fc.Args()[1] 87 88 cmd.appReq = requirementsFactory.NewApplicationRequirement(fc.Args()[0]) 89 cmd.serviceInstanceReq = requirementsFactory.NewServiceInstanceRequirement(serviceName) 90 91 reqs := []requirements.Requirement{ 92 requirementsFactory.NewLoginRequirement(), 93 cmd.appReq, 94 cmd.serviceInstanceReq, 95 } 96 97 return reqs, nil 98 } 99 100 func (cmd *BindService) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command { 101 cmd.ui = deps.UI 102 cmd.config = deps.Config 103 cmd.serviceBindingRepo = deps.RepoLocator.GetServiceBindingRepository() 104 return cmd 105 } 106 107 func (cmd *BindService) Execute(c flags.FlagContext) error { 108 app := cmd.appReq.GetApplication() 109 serviceInstance := cmd.serviceInstanceReq.GetServiceInstance() 110 params := c.String("c") 111 112 paramsMap, err := json.ParseJSONFromFileOrString(params) 113 if err != nil { 114 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.")) 115 } 116 117 cmd.ui.Say(T("Binding service {{.ServiceInstanceName}} to app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.CurrentUser}}...", 118 map[string]interface{}{ 119 "ServiceInstanceName": terminal.EntityNameColor(serviceInstance.Name), 120 "AppName": terminal.EntityNameColor(app.Name), 121 "OrgName": terminal.EntityNameColor(cmd.config.OrganizationFields().Name), 122 "SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name), 123 "CurrentUser": terminal.EntityNameColor(cmd.config.Username()), 124 })) 125 126 err = cmd.BindApplication(app, serviceInstance, paramsMap) 127 if err != nil { 128 if httperr, ok := err.(errors.HTTPError); ok && httperr.ErrorCode() == errors.ServiceBindingAppServiceTaken { 129 cmd.ui.Ok() 130 cmd.ui.Warn(T("App {{.AppName}} is already bound to {{.ServiceName}}.", 131 map[string]interface{}{ 132 "AppName": app.Name, 133 "ServiceName": serviceInstance.Name, 134 })) 135 return nil 136 } 137 138 return err 139 } 140 141 cmd.ui.Ok() 142 cmd.ui.Say(T("TIP: Use '{{.CFCommand}} {{.AppName}}' to ensure your env variable changes take effect", 143 map[string]interface{}{"CFCommand": terminal.CommandColor(cf.Name + " restage"), "AppName": app.Name})) 144 return nil 145 } 146 147 func (cmd *BindService) BindApplication(app models.Application, serviceInstance models.ServiceInstance, paramsMap map[string]interface{}) error { 148 return cmd.serviceBindingRepo.Create(serviceInstance.GUID, app.GUID, paramsMap) 149 }