github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/actor/v2action/route.go (about) 1 package v2action 2 3 import ( 4 "fmt" 5 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 8 log "github.com/sirupsen/logrus" 9 ) 10 11 // OrphanedRoutesNotFoundError is an error wrapper that represents the case 12 // when no orphaned routes are found. 13 type OrphanedRoutesNotFoundError struct{} 14 15 // Error method to display the error message. 16 func (_ OrphanedRoutesNotFoundError) Error() string { 17 return "No orphaned routes were found." 18 } 19 20 // RouteInDifferentSpaceError is returned when the route exists in a different 21 // space than the one requesting it. 22 type RouteInDifferentSpaceError struct { 23 Route string 24 } 25 26 func (_ RouteInDifferentSpaceError) Error() string { 27 return "route registered to another space" 28 } 29 30 // RouteNotFoundError is returned when a route cannot be found 31 type RouteNotFoundError struct { 32 Host string 33 DomainGUID string 34 } 35 36 func (e RouteNotFoundError) Error() string { 37 return fmt.Sprintf("Route with host %s and domain guid %s not found", e.Host, e.DomainGUID) 38 } 39 40 // Route represents a CLI Route. 41 type Route struct { 42 Domain Domain 43 GUID string 44 Host string 45 Path string 46 Port int 47 SpaceGUID string 48 } 49 50 // String formats the route in a human readable format. 51 func (r Route) String() string { 52 routeString := r.Domain.Name 53 54 if r.Port != 0 { 55 routeString = fmt.Sprintf("%s:%d", routeString, r.Port) 56 return routeString 57 } 58 59 if r.Host != "" { 60 routeString = fmt.Sprintf("%s.%s", r.Host, routeString) 61 } 62 63 if r.Path != "" { 64 routeString = fmt.Sprintf("%s%s", routeString, r.Path) 65 } 66 67 return routeString 68 } 69 70 func (actor Actor) BindRouteToApplication(routeGUID string, appGUID string) (Warnings, error) { 71 _, warnings, err := actor.CloudControllerClient.BindRouteToApplication(routeGUID, appGUID) 72 if _, ok := err.(ccerror.InvalidRelationError); ok { 73 return Warnings(warnings), RouteInDifferentSpaceError{} 74 } 75 return Warnings(warnings), err 76 } 77 78 func (actor Actor) CreateRoute(route Route, generatePort bool) (Route, Warnings, error) { 79 returnedRoute, warnings, err := actor.CloudControllerClient.CreateRoute(ActorToCCRoute(route), generatePort) 80 return CCToActorRoute(returnedRoute, route.Domain), Warnings(warnings), err 81 } 82 83 // GetOrphanedRoutesBySpace returns a list of orphaned routes associated with 84 // the provided Space GUID. 85 func (actor Actor) GetOrphanedRoutesBySpace(spaceGUID string) ([]Route, Warnings, error) { 86 var ( 87 orphanedRoutes []Route 88 allWarnings Warnings 89 ) 90 91 routes, warnings, err := actor.GetSpaceRoutes(spaceGUID) 92 allWarnings = append(allWarnings, warnings...) 93 if err != nil { 94 return nil, allWarnings, err 95 } 96 97 for _, route := range routes { 98 apps, warnings, err := actor.GetRouteApplications(route.GUID, nil) 99 allWarnings = append(allWarnings, warnings...) 100 if err != nil { 101 return nil, allWarnings, err 102 } 103 104 if len(apps) == 0 { 105 orphanedRoutes = append(orphanedRoutes, route) 106 } 107 } 108 109 if len(orphanedRoutes) == 0 { 110 return nil, allWarnings, OrphanedRoutesNotFoundError{} 111 } 112 113 return orphanedRoutes, allWarnings, nil 114 } 115 116 // GetApplicationRoutes returns a list of routes associated with the provided 117 // Application GUID. 118 func (actor Actor) GetApplicationRoutes(applicationGUID string) ([]Route, Warnings, error) { 119 var allWarnings Warnings 120 ccv2Routes, warnings, err := actor.CloudControllerClient.GetApplicationRoutes(applicationGUID, nil) 121 allWarnings = append(allWarnings, warnings...) 122 if err != nil { 123 return nil, allWarnings, err 124 } 125 126 routes, domainWarnings, err := actor.applyDomain(ccv2Routes) 127 128 return routes, append(allWarnings, domainWarnings...), err 129 } 130 131 // GetSpaceRoutes returns a list of routes associated with the provided Space 132 // GUID. 133 func (actor Actor) GetSpaceRoutes(spaceGUID string) ([]Route, Warnings, error) { 134 var allWarnings Warnings 135 ccv2Routes, warnings, err := actor.CloudControllerClient.GetSpaceRoutes(spaceGUID, nil) 136 allWarnings = append(allWarnings, warnings...) 137 if err != nil { 138 return nil, allWarnings, err 139 } 140 141 routes, domainWarnings, err := actor.applyDomain(ccv2Routes) 142 143 return routes, append(allWarnings, domainWarnings...), err 144 } 145 146 // DeleteRoute deletes the Route associated with the provided Route GUID. 147 func (actor Actor) DeleteRoute(routeGUID string) (Warnings, error) { 148 warnings, err := actor.CloudControllerClient.DeleteRoute(routeGUID) 149 return Warnings(warnings), err 150 } 151 152 func (actor Actor) CheckRoute(route Route) (bool, Warnings, error) { 153 exists, warnings, err := actor.CloudControllerClient.CheckRoute(ActorToCCRoute(route)) 154 return exists, Warnings(warnings), err 155 } 156 157 // FindRouteBoundToSpaceWithSettings finds the route with the given host, 158 // domain and space. If it is unable to find the route, it will check if it 159 // exists anywhere in the system. When the route exists in another space, 160 // RouteInDifferentSpaceError is returned. 161 func (actor Actor) FindRouteBoundToSpaceWithSettings(route Route) (Route, Warnings, error) { 162 // TODO: Use a more generic search mechanism to support path, port, and no host 163 existingRoute, warnings, err := actor.GetRouteByHostAndDomain(route.Host, route.Domain.GUID) 164 if routeNotFoundErr, ok := err.(RouteNotFoundError); ok { 165 // This check only works for API versions 2.55 or higher. It will return 166 // false for anything below that. 167 log.Infoln("checking route existance for:", route.String()) 168 exists, checkRouteWarnings, chkErr := actor.CheckRoute(route) 169 if chkErr != nil { 170 log.Errorln("check route:", err) 171 return Route{}, append(Warnings(warnings), checkRouteWarnings...), chkErr 172 } 173 174 if exists { 175 log.Errorf("unable to find route %s in current space", route.String()) 176 return Route{}, append(Warnings(warnings), checkRouteWarnings...), RouteInDifferentSpaceError{Route: route.String()} 177 } else { 178 log.Warnf("negative existence check for route %s - returning partial route", route.String()) 179 log.Debugf("partialRoute: %#v", route) 180 return Route{}, append(Warnings(warnings), checkRouteWarnings...), routeNotFoundErr 181 } 182 } else if err != nil { 183 log.Errorln("finding route:", err) 184 return Route{}, Warnings(warnings), err 185 } 186 187 if existingRoute.SpaceGUID != route.SpaceGUID { 188 log.WithFields(log.Fields{ 189 "targeted_space_guid": route.SpaceGUID, 190 "existing_space_guid": existingRoute.SpaceGUID, 191 }).Errorf("route exists in different space the user has access to") 192 return Route{}, Warnings(warnings), RouteInDifferentSpaceError{Route: route.String()} 193 } 194 195 log.Debugf("found route: %#v", existingRoute) 196 return existingRoute, Warnings(warnings), err 197 } 198 199 // GetRouteByHostAndDomain returns the HTTP route with the matching host and 200 // the associate domain GUID. 201 func (actor Actor) GetRouteByHostAndDomain(host string, domainGUID string) (Route, Warnings, error) { 202 ccv2Routes, warnings, err := actor.CloudControllerClient.GetRoutes([]ccv2.Query{ 203 {Filter: ccv2.HostFilter, Operator: ccv2.EqualOperator, Value: host}, 204 {Filter: ccv2.DomainGUIDFilter, Operator: ccv2.EqualOperator, Value: domainGUID}, 205 }) 206 if err != nil { 207 return Route{}, Warnings(warnings), err 208 } 209 210 if len(ccv2Routes) == 0 { 211 return Route{}, Warnings(warnings), RouteNotFoundError{Host: host, DomainGUID: domainGUID} 212 } 213 214 routes, domainWarnings, err := actor.applyDomain(ccv2Routes) 215 if err != nil { 216 return Route{}, append(Warnings(warnings), domainWarnings...), err 217 } 218 219 return routes[0], append(Warnings(warnings), domainWarnings...), err 220 } 221 222 func ActorToCCRoute(route Route) ccv2.Route { 223 return ccv2.Route{ 224 DomainGUID: route.Domain.GUID, 225 GUID: route.GUID, 226 Host: route.Host, 227 Path: route.Path, 228 Port: route.Port, 229 SpaceGUID: route.SpaceGUID, 230 } 231 } 232 233 func CCToActorRoute(ccv2Route ccv2.Route, domain Domain) Route { 234 return Route{ 235 Domain: domain, 236 GUID: ccv2Route.GUID, 237 Host: ccv2Route.Host, 238 Path: ccv2Route.Path, 239 Port: ccv2Route.Port, 240 SpaceGUID: ccv2Route.SpaceGUID, 241 } 242 } 243 244 func (actor Actor) applyDomain(ccv2Routes []ccv2.Route) ([]Route, Warnings, error) { 245 var routes []Route 246 var allWarnings Warnings 247 248 for _, ccv2Route := range ccv2Routes { 249 domain, warnings, err := actor.GetDomain(ccv2Route.DomainGUID) 250 allWarnings = append(allWarnings, warnings...) 251 if err != nil { 252 return nil, allWarnings, err 253 } 254 routes = append(routes, CCToActorRoute(ccv2Route, domain)) 255 } 256 257 return routes, allWarnings, nil 258 }