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  }