github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/service/unbind_route_service.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "strings" 6 7 "code.cloudfoundry.org/cli/cf" 8 "code.cloudfoundry.org/cli/cf/api" 9 "code.cloudfoundry.org/cli/cf/commandregistry" 10 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 11 "code.cloudfoundry.org/cli/cf/errors" 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 ) 18 19 //go:generate counterfeiter . RouteServiceUnbinder 20 21 type RouteServiceUnbinder interface { 22 UnbindRoute(route models.Route, serviceInstance models.ServiceInstance) error 23 } 24 25 type UnbindRouteService struct { 26 ui terminal.UI 27 config coreconfig.Reader 28 routeRepo api.RouteRepository 29 routeServiceBindingRepo api.RouteServiceBindingRepository 30 domainReq requirements.DomainRequirement 31 serviceInstanceReq requirements.ServiceInstanceRequirement 32 } 33 34 func init() { 35 commandregistry.Register(&UnbindRouteService{}) 36 } 37 38 func (cmd *UnbindRouteService) MetaData() commandregistry.CommandMetadata { 39 fs := make(map[string]flags.FlagSet) 40 fs["hostname"] = &flags.StringFlag{Name: "hostname", ShortName: "n", Usage: T("Hostname used in combination with DOMAIN to specify the route to unbind")} 41 fs["path"] = &flags.StringFlag{Name: "path", Usage: T("Path for HTTP route")} 42 fs["f"] = &flags.BoolFlag{ShortName: "f", Usage: T("Force unbinding without confirmation")} 43 44 return commandregistry.CommandMetadata{ 45 Name: "unbind-route-service", 46 ShortName: "urs", 47 Description: T("Unbind a service instance from an HTTP route"), 48 Usage: []string{ 49 T("CF_NAME unbind-route-service DOMAIN SERVICE_INSTANCE [--hostname HOSTNAME] [--path PATH] [-f]"), 50 }, 51 Examples: []string{ 52 "CF_NAME unbind-route-service example.com myratelimiter --hostname myapp --path foo", 53 }, 54 Flags: fs, 55 } 56 } 57 58 func (cmd *UnbindRouteService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) { 59 if len(fc.Args()) != 2 { 60 cmd.ui.Failed(T("Incorrect Usage. Requires DOMAIN and SERVICE_INSTANCE as arguments\n\n") + commandregistry.Commands.CommandUsage("unbind-route-service")) 61 return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 2) 62 } 63 64 serviceName := fc.Args()[1] 65 cmd.serviceInstanceReq = requirementsFactory.NewServiceInstanceRequirement(serviceName) 66 67 domainName := fc.Args()[0] 68 cmd.domainReq = requirementsFactory.NewDomainRequirement(domainName) 69 70 minAPIVersionRequirement := requirementsFactory.NewMinAPIVersionRequirement( 71 "unbind-route-service", 72 cf.MultipleAppPortsMinimumAPIVersion, 73 ) 74 75 reqs := []requirements.Requirement{ 76 minAPIVersionRequirement, 77 requirementsFactory.NewLoginRequirement(), 78 cmd.domainReq, 79 cmd.serviceInstanceReq, 80 } 81 return reqs, nil 82 } 83 84 func (cmd *UnbindRouteService) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command { 85 cmd.ui = deps.UI 86 cmd.config = deps.Config 87 cmd.routeRepo = deps.RepoLocator.GetRouteRepository() 88 cmd.routeServiceBindingRepo = deps.RepoLocator.GetRouteServiceBindingRepository() 89 return cmd 90 } 91 92 func (cmd *UnbindRouteService) Execute(c flags.FlagContext) error { 93 var port int 94 95 host := c.String("hostname") 96 domain := cmd.domainReq.GetDomain() 97 path := c.String("path") 98 if !strings.HasPrefix(path, "/") && len(path) > 0 { 99 path = fmt.Sprintf("/%s", path) 100 } 101 102 route, err := cmd.routeRepo.Find(host, domain, path, port) 103 if err != nil { 104 return err 105 } 106 107 serviceInstance := cmd.serviceInstanceReq.GetServiceInstance() 108 confirmed := c.Bool("f") 109 if !confirmed { 110 confirmed = cmd.ui.Confirm(T("Unbinding may leave apps mapped to route {{.URL}} vulnerable; e.g. if service instance {{.ServiceInstanceName}} provides authentication. Do you want to proceed?", 111 map[string]interface{}{ 112 "URL": route.URL(), 113 "ServiceInstanceName": serviceInstance.Name, 114 })) 115 116 if !confirmed { 117 cmd.ui.Warn(T("Unbind cancelled")) 118 return nil 119 } 120 } 121 122 cmd.ui.Say(T("Unbinding route {{.URL}} from service instance {{.ServiceInstanceName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.CurrentUser}}...", 123 map[string]interface{}{ 124 "ServiceInstanceName": terminal.EntityNameColor(serviceInstance.Name), 125 "URL": terminal.EntityNameColor(route.URL()), 126 "OrgName": terminal.EntityNameColor(cmd.config.OrganizationFields().Name), 127 "SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name), 128 "CurrentUser": terminal.EntityNameColor(cmd.config.Username()), 129 })) 130 131 err = cmd.UnbindRoute(route, serviceInstance) 132 if err != nil { 133 httpError, ok := err.(errors.HTTPError) 134 if ok && httpError.ErrorCode() == errors.InvalidRelation { 135 cmd.ui.Warn(T("Route {{.Route}} was not bound to service instance {{.ServiceInstance}}.", map[string]interface{}{"Route": route.URL(), "ServiceInstance": serviceInstance.Name})) 136 } else { 137 return err 138 } 139 } 140 141 cmd.ui.Ok() 142 return nil 143 } 144 145 func (cmd *UnbindRouteService) UnbindRoute(route models.Route, serviceInstance models.ServiceInstance) error { 146 return cmd.routeServiceBindingRepo.Unbind(serviceInstance.GUID, route.GUID, serviceInstance.IsUserProvided()) 147 }