github.com/lukasheimann/cloudfoundrycli@v7.1.0+incompatible/actor/v7action/route.go (about) 1 package v7action 2 3 import ( 4 "sort" 5 "strconv" 6 "strings" 7 8 "code.cloudfoundry.org/cli/actor/actionerror" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 12 "code.cloudfoundry.org/cli/resources" 13 "code.cloudfoundry.org/cli/util/sorting" 14 ) 15 16 type RouteSummary struct { 17 resources.Route 18 AppNames []string 19 DomainName string 20 SpaceName string 21 } 22 23 func (actor Actor) CreateRoute(spaceGUID, domainName, hostname, path string, port int) (resources.Route, Warnings, error) { 24 allWarnings := Warnings{} 25 domain, warnings, err := actor.GetDomainByName(domainName) 26 allWarnings = append(allWarnings, warnings...) 27 28 if err != nil { 29 return resources.Route{}, allWarnings, err 30 } 31 32 route, apiWarnings, err := actor.CloudControllerClient.CreateRoute(resources.Route{ 33 SpaceGUID: spaceGUID, 34 DomainGUID: domain.GUID, 35 Host: hostname, 36 Path: path, 37 Port: port, 38 }) 39 40 actorWarnings := Warnings(apiWarnings) 41 allWarnings = append(allWarnings, actorWarnings...) 42 43 if _, ok := err.(ccerror.RouteNotUniqueError); ok { 44 return resources.Route{}, allWarnings, actionerror.RouteAlreadyExistsError{Err: err} 45 } 46 47 return route, allWarnings, err 48 } 49 50 func (actor Actor) GetRouteDestinations(routeGUID string) ([]resources.RouteDestination, Warnings, error) { 51 destinations, warnings, err := actor.CloudControllerClient.GetRouteDestinations(routeGUID) 52 53 var actorDestinations []resources.RouteDestination 54 for _, dst := range destinations { 55 actorDestinations = append(actorDestinations, resources.RouteDestination{ 56 GUID: dst.GUID, 57 App: resources.RouteDestinationApp(dst.App), 58 }) 59 } 60 61 return actorDestinations, Warnings(warnings), err 62 } 63 64 func (actor Actor) GetRouteDestinationByAppGUID(route resources.Route, appGUID string) (resources.RouteDestination, error) { 65 for _, destination := range route.Destinations { 66 if destination.App.GUID == appGUID && destination.App.Process.Type == constant.ProcessTypeWeb { 67 return destination, nil 68 } 69 } 70 71 return resources.RouteDestination{}, actionerror.RouteDestinationNotFoundError{ 72 AppGUID: appGUID, 73 ProcessType: constant.ProcessTypeWeb, 74 RouteGUID: route.GUID, 75 } 76 } 77 78 func (actor Actor) GetRoutesBySpace(spaceGUID string, labelSelector string) ([]resources.Route, Warnings, error) { 79 allWarnings := Warnings{} 80 queries := []ccv3.Query{ 81 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{spaceGUID}}, 82 } 83 if len(labelSelector) > 0 { 84 queries = append(queries, ccv3.Query{Key: ccv3.LabelSelectorFilter, Values: []string{labelSelector}}) 85 } 86 87 routes, warnings, err := actor.CloudControllerClient.GetRoutes(queries...) 88 allWarnings = append(allWarnings, warnings...) 89 if err != nil { 90 return nil, allWarnings, err 91 } 92 93 return routes, allWarnings, nil 94 } 95 96 func (actor Actor) parseRoutePath(routePath string) (string, string, string, resources.Domain, Warnings, error) { 97 var ( 98 warnings Warnings 99 host string 100 path string 101 port string 102 ) 103 104 routeParts := strings.SplitN(routePath, "/", 2) 105 domainAndPort := routeParts[0] 106 if len(routeParts) > 1 { 107 path = "/" + routeParts[1] 108 } 109 110 domainAndPortParts := strings.SplitN(domainAndPort, ":", 2) 111 domainName := domainAndPortParts[0] 112 if len(domainAndPortParts) > 1 { 113 port = domainAndPortParts[1] 114 } 115 116 domain, allWarnings, err := actor.GetDomainByName(domainName) 117 118 if err != nil { 119 _, domainNotFound := err.(actionerror.DomainNotFoundError) 120 domainParts := strings.SplitN(domainName, ".", 2) 121 needToCheckForHost := domainNotFound && len(domainParts) > 1 122 123 if !needToCheckForHost { 124 return "", "", "", resources.Domain{}, allWarnings, err 125 } 126 127 host = domainParts[0] 128 domainName = domainParts[1] 129 domain, warnings, err = actor.GetDomainByName(domainName) 130 allWarnings = append(allWarnings, warnings...) 131 if err != nil { 132 return "", "", "", resources.Domain{}, allWarnings, err 133 } 134 } 135 136 return host, path, port, domain, allWarnings, err 137 } 138 139 func (actor Actor) GetRoute(routePath string, spaceGUID string) (resources.Route, Warnings, error) { 140 filters := []ccv3.Query{ 141 { 142 Key: ccv3.SpaceGUIDFilter, 143 Values: []string{spaceGUID}, 144 }, 145 } 146 147 host, path, port, domain, allWarnings, err := actor.parseRoutePath(routePath) 148 if err != nil { 149 return resources.Route{}, allWarnings, err 150 } 151 152 filters = append(filters, ccv3.Query{Key: ccv3.DomainGUIDFilter, 153 Values: []string{domain.GUID}, 154 }) 155 filters = append(filters, ccv3.Query{Key: ccv3.HostsFilter, 156 Values: []string{host}, 157 }) 158 filters = append(filters, ccv3.Query{Key: ccv3.PathsFilter, 159 Values: []string{path}, 160 }) 161 162 if domain.IsTCP() { 163 filters = append(filters, ccv3.Query{Key: ccv3.PortsFilter, 164 Values: []string{port}, 165 }) 166 } 167 168 routes, warnings, err := actor.CloudControllerClient.GetRoutes(filters...) 169 allWarnings = append(allWarnings, warnings...) 170 if err != nil { 171 return resources.Route{}, allWarnings, err 172 } 173 if len(routes) == 0 { 174 return resources.Route{}, allWarnings, actionerror.RouteNotFoundError{ 175 Host: host, 176 DomainName: domain.Name, 177 Path: path, 178 } 179 } 180 181 return routes[0], allWarnings, nil 182 } 183 184 func (actor Actor) GetRoutesByOrg(orgGUID string, labelSelector string) ([]resources.Route, Warnings, error) { 185 allWarnings := Warnings{} 186 queries := []ccv3.Query{ 187 ccv3.Query{Key: ccv3.OrganizationGUIDFilter, Values: []string{orgGUID}}, 188 } 189 if len(labelSelector) > 0 { 190 queries = append(queries, ccv3.Query{Key: ccv3.LabelSelectorFilter, Values: []string{labelSelector}}) 191 } 192 193 routes, warnings, err := actor.CloudControllerClient.GetRoutes(queries...) 194 allWarnings = append(allWarnings, warnings...) 195 if err != nil { 196 return nil, allWarnings, err 197 } 198 199 return routes, allWarnings, nil 200 } 201 202 func (actor Actor) GetRouteSummaries(routes []resources.Route) ([]RouteSummary, Warnings, error) { 203 var allWarnings Warnings 204 var routeSummaries []RouteSummary 205 206 destinationAppGUIDsByRouteGUID := make(map[string][]string) 207 destinationAppGUIDs := make(map[string]bool) 208 var uniqueAppGUIDs []string 209 210 spaceGUIDs := make(map[string]struct{}) 211 var uniqueSpaceGUIDs []string 212 213 for _, route := range routes { 214 if _, seen := spaceGUIDs[route.SpaceGUID]; !seen { 215 spaceGUIDs[route.SpaceGUID] = struct{}{} 216 uniqueSpaceGUIDs = append(uniqueSpaceGUIDs, route.SpaceGUID) 217 } 218 219 for _, destination := range route.Destinations { 220 appGUID := destination.App.GUID 221 222 if _, ok := destinationAppGUIDs[appGUID]; !ok { 223 destinationAppGUIDs[appGUID] = true 224 uniqueAppGUIDs = append(uniqueAppGUIDs, appGUID) 225 } 226 227 destinationAppGUIDsByRouteGUID[route.GUID] = append(destinationAppGUIDsByRouteGUID[route.GUID], appGUID) 228 } 229 } 230 231 spaces, _, ccv3Warnings, err := actor.CloudControllerClient.GetSpaces(ccv3.Query{ 232 Key: ccv3.GUIDFilter, 233 Values: uniqueSpaceGUIDs, 234 }) 235 allWarnings = append(allWarnings, ccv3Warnings...) 236 if err != nil { 237 return nil, allWarnings, err 238 } 239 240 spaceNamesByGUID := make(map[string]string) 241 for _, space := range spaces { 242 spaceNamesByGUID[space.GUID] = space.Name 243 } 244 245 apps, warnings, err := actor.GetApplicationsByGUIDs(uniqueAppGUIDs) 246 allWarnings = append(allWarnings, warnings...) 247 if err != nil { 248 return nil, allWarnings, err 249 } 250 251 appNamesByGUID := make(map[string]string) 252 for _, app := range apps { 253 appNamesByGUID[app.GUID] = app.Name 254 } 255 256 for _, route := range routes { 257 var appNames []string 258 259 appGUIDs := destinationAppGUIDsByRouteGUID[route.GUID] 260 for _, appGUID := range appGUIDs { 261 appNames = append(appNames, appNamesByGUID[appGUID]) 262 } 263 264 routeSummaries = append(routeSummaries, RouteSummary{ 265 Route: route, 266 AppNames: appNames, 267 SpaceName: spaceNamesByGUID[route.SpaceGUID], 268 DomainName: getDomainName(route.URL, route.Host, route.Path, route.Port), 269 }) 270 } 271 272 sort.Slice(routeSummaries, func(i, j int) bool { 273 return sorting.LessIgnoreCase(routeSummaries[i].SpaceName, routeSummaries[j].SpaceName) 274 }) 275 276 return routeSummaries, allWarnings, nil 277 } 278 279 func (actor Actor) DeleteOrphanedRoutes(spaceGUID string) (Warnings, error) { 280 var allWarnings Warnings 281 282 jobURL, warnings, err := actor.CloudControllerClient.DeleteOrphanedRoutes(spaceGUID) 283 allWarnings = append(allWarnings, warnings...) 284 if err != nil { 285 return allWarnings, err 286 } 287 288 warnings, err = actor.CloudControllerClient.PollJob(jobURL) 289 allWarnings = append(allWarnings, warnings...) 290 291 return allWarnings, err 292 } 293 294 func (actor Actor) DeleteRoute(domainName, hostname, path string, port int) (Warnings, error) { 295 allWarnings := Warnings{} 296 domain, warnings, err := actor.GetDomainByName(domainName) 297 allWarnings = append(allWarnings, warnings...) 298 299 if _, ok := err.(actionerror.DomainNotFoundError); ok { 300 allWarnings = append(allWarnings, err.Error()) 301 return allWarnings, nil 302 } 303 304 if err != nil { 305 return allWarnings, err 306 } 307 308 route, actorWarnings, err := actor.GetRouteByAttributes(domain, hostname, path, port) 309 310 allWarnings = append(allWarnings, actorWarnings...) 311 312 if err != nil { 313 return allWarnings, err 314 } 315 316 jobURL, apiWarnings, err := actor.CloudControllerClient.DeleteRoute(route.GUID) 317 actorWarnings = Warnings(apiWarnings) 318 allWarnings = append(allWarnings, actorWarnings...) 319 320 if err != nil { 321 return allWarnings, err 322 } 323 324 pollJobWarnings, err := actor.CloudControllerClient.PollJob(jobURL) 325 allWarnings = append(allWarnings, Warnings(pollJobWarnings)...) 326 327 return allWarnings, err 328 } 329 330 func (actor Actor) GetRouteByAttributes(domain resources.Domain, hostname string, path string, port int) (resources.Route, Warnings, error) { 331 var ( 332 routes []resources.Route 333 ccWarnings ccv3.Warnings 334 err error 335 ) 336 337 queries := []ccv3.Query{ 338 {Key: ccv3.DomainGUIDFilter, Values: []string{domain.GUID}}, 339 {Key: ccv3.HostsFilter, Values: []string{hostname}}, 340 {Key: ccv3.PathsFilter, Values: []string{path}}, 341 } 342 343 if domain.IsTCP() { 344 queries = append(queries, ccv3.Query{Key: ccv3.PortsFilter, Values: []string{strconv.Itoa(port)}}) 345 } 346 347 routes, ccWarnings, err = actor.CloudControllerClient.GetRoutes(queries...) 348 if err != nil { 349 return resources.Route{}, Warnings(ccWarnings), err 350 } 351 352 if len(routes) < 1 { 353 return resources.Route{}, Warnings(ccWarnings), actionerror.RouteNotFoundError{ 354 DomainName: domain.Name, 355 DomainGUID: domain.GUID, 356 Host: hostname, 357 Path: path, 358 Port: port, 359 } 360 } 361 362 return routes[0], Warnings(ccWarnings), nil 363 } 364 365 func (actor Actor) MapRoute(routeGUID string, appGUID string) (Warnings, error) { 366 warnings, err := actor.CloudControllerClient.MapRoute(routeGUID, appGUID) 367 return Warnings(warnings), err 368 } 369 370 func (actor Actor) UnmapRoute(routeGUID string, destinationGUID string) (Warnings, error) { 371 warnings, err := actor.CloudControllerClient.UnmapRoute(routeGUID, destinationGUID) 372 return Warnings(warnings), err 373 } 374 375 func (actor Actor) GetApplicationRoutes(appGUID string) ([]resources.Route, Warnings, error) { 376 allWarnings := Warnings{} 377 378 routes, warnings, err := actor.CloudControllerClient.GetApplicationRoutes(appGUID) 379 allWarnings = append(allWarnings, warnings...) 380 if err != nil { 381 return nil, allWarnings, err 382 } 383 384 if len(routes) == 0 { 385 return nil, allWarnings, err 386 } 387 388 return routes, allWarnings, nil 389 } 390 391 func getDomainName(fullURL, host, path string, port int) string { 392 domainWithoutHost := strings.TrimPrefix(fullURL, host+".") 393 domainWithoutPath := strings.TrimSuffix(domainWithoutHost, path) 394 395 if port > 0 { 396 portString := strconv.Itoa(port) 397 domainWithoutPort := strings.TrimSuffix(domainWithoutPath, ":"+portString) 398 return domainWithoutPort 399 } 400 401 return domainWithoutPath 402 }