github.com/ablease/cli@v6.37.1-0.20180613014814-3adbb7d7fb19+incompatible/api/cloudcontroller/ccv2/route.go (about)

     1  package ccv2
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal"
    13  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
    14  	"code.cloudfoundry.org/cli/types"
    15  )
    16  
    17  // Route represents a Cloud Controller Route.
    18  type Route struct {
    19  
    20  	// GUID is the unique Route identifier.
    21  	GUID string `json:"-"`
    22  
    23  	// Host is the hostname of the route.
    24  	Host string `json:"host,omitempty"`
    25  
    26  	// Path is the path of the route.
    27  	Path string `json:"path,omitempty"`
    28  
    29  	// Port is the port number of the route.
    30  	Port types.NullInt `json:"port,omitempty"`
    31  
    32  	// DomainGUID is the unique Domain identifier.
    33  	DomainGUID string `json:"domain_guid"`
    34  
    35  	// SpaceGUID is the unique Space identifier.
    36  	SpaceGUID string `json:"space_guid"`
    37  }
    38  
    39  // UnmarshalJSON helps unmarshal a Cloud Controller Route response.
    40  func (route *Route) UnmarshalJSON(data []byte) error {
    41  	var ccRoute struct {
    42  		Metadata internal.Metadata `json:"metadata"`
    43  		Entity   struct {
    44  			Host       string        `json:"host"`
    45  			Path       string        `json:"path"`
    46  			Port       types.NullInt `json:"port"`
    47  			DomainGUID string        `json:"domain_guid"`
    48  			SpaceGUID  string        `json:"space_guid"`
    49  		} `json:"entity"`
    50  	}
    51  	err := cloudcontroller.DecodeJSON(data, &ccRoute)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	route.GUID = ccRoute.Metadata.GUID
    57  	route.Host = ccRoute.Entity.Host
    58  	route.Path = ccRoute.Entity.Path
    59  	route.Port = ccRoute.Entity.Port
    60  	route.DomainGUID = ccRoute.Entity.DomainGUID
    61  	route.SpaceGUID = ccRoute.Entity.SpaceGUID
    62  	return nil
    63  }
    64  
    65  // CreateRoute creates the route with the given properties; SpaceGUID and
    66  // DomainGUID are required Route properties. Additional configuration rules:
    67  // - generatePort = true to generate a random port on the cloud controller.
    68  // - generatePort takes precedence over the provided port. Setting the port and
    69  // generatePort only works with CC API 2.53.0 or higher and when TCP router
    70  // groups are enabled.
    71  func (client *Client) CreateRoute(route Route, generatePort bool) (Route, Warnings, error) {
    72  	body, err := json.Marshal(route)
    73  	if err != nil {
    74  		return Route{}, nil, err
    75  	}
    76  
    77  	request, err := client.newHTTPRequest(requestOptions{
    78  		RequestName: internal.PostRouteRequest,
    79  		Body:        bytes.NewReader(body),
    80  	})
    81  	if err != nil {
    82  		return Route{}, nil, err
    83  	}
    84  
    85  	if generatePort {
    86  		query := url.Values{}
    87  		query.Add("generate_port", "true")
    88  		request.URL.RawQuery = query.Encode()
    89  	}
    90  
    91  	var updatedRoute Route
    92  	response := cloudcontroller.Response{
    93  		Result: &updatedRoute,
    94  	}
    95  
    96  	err = client.connection.Make(request, &response)
    97  	return updatedRoute, response.Warnings, err
    98  }
    99  
   100  // DeleteRoute deletes the Route associated with the provided Route GUID.
   101  func (client *Client) DeleteRoute(routeGUID string) (Warnings, error) {
   102  	request, err := client.newHTTPRequest(requestOptions{
   103  		RequestName: internal.DeleteRouteRequest,
   104  		URIParams:   map[string]string{"route_guid": routeGUID},
   105  	})
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	var response cloudcontroller.Response
   111  	err = client.connection.Make(request, &response)
   112  	return response.Warnings, err
   113  }
   114  
   115  // DeleteRouteApplication removes the link between the route and application.
   116  func (client *Client) DeleteRouteApplication(routeGUID string, appGUID string) (Warnings, error) {
   117  	request, err := client.newHTTPRequest(requestOptions{
   118  		RequestName: internal.DeleteRouteAppRequest,
   119  		URIParams: map[string]string{
   120  			"app_guid":   appGUID,
   121  			"route_guid": routeGUID,
   122  		},
   123  	})
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	var response cloudcontroller.Response
   129  	err = client.connection.Make(request, &response)
   130  	return response.Warnings, err
   131  }
   132  
   133  // DoesRouteExist returns true if the route exists in the CF instance. DomainGUID
   134  // is required for check. This call will only work for CC API 2.55 or higher.
   135  func (client *Client) DoesRouteExist(route Route) (bool, Warnings, error) {
   136  	currentVersion := client.APIVersion()
   137  	switch {
   138  	case cloudcontroller.MinimumAPIVersionCheck(currentVersion, ccversion.MinVersionNoHostInReservedRouteEndpoint) == nil:
   139  		return client.checkRoute(route)
   140  	case cloudcontroller.MinimumAPIVersionCheck(currentVersion, ccversion.MinVersionHTTPRoutePath) == nil:
   141  		return client.checkRouteDeprecated(route.DomainGUID, route.Host, route.Path)
   142  	default:
   143  		return client.checkRouteDeprecated(route.DomainGUID, route.Host, "")
   144  	}
   145  }
   146  
   147  // GetApplicationRoutes returns a list of Routes associated with the provided
   148  // Application GUID, and filtered by the provided filters.
   149  func (client *Client) GetApplicationRoutes(appGUID string, filters ...Filter) ([]Route, Warnings, error) {
   150  	request, err := client.newHTTPRequest(requestOptions{
   151  		RequestName: internal.GetAppRoutesRequest,
   152  		URIParams:   map[string]string{"app_guid": appGUID},
   153  		Query:       ConvertFilterParameters(filters),
   154  	})
   155  	if err != nil {
   156  		return nil, nil, err
   157  	}
   158  
   159  	var fullRoutesList []Route
   160  	warnings, err := client.paginate(request, Route{}, func(item interface{}) error {
   161  		if route, ok := item.(Route); ok {
   162  			fullRoutesList = append(fullRoutesList, route)
   163  		} else {
   164  			return ccerror.UnknownObjectInListError{
   165  				Expected:   Route{},
   166  				Unexpected: item,
   167  			}
   168  		}
   169  		return nil
   170  	})
   171  
   172  	return fullRoutesList, warnings, err
   173  }
   174  
   175  // GetRoute returns a route with the provided guid.
   176  func (client *Client) GetRoute(guid string) (Route, Warnings, error) {
   177  	request, err := client.newHTTPRequest(requestOptions{
   178  		RequestName: internal.GetRouteRequest,
   179  		URIParams:   Params{"route_guid": guid},
   180  	})
   181  	if err != nil {
   182  		return Route{}, nil, err
   183  	}
   184  
   185  	var route Route
   186  	response := cloudcontroller.Response{
   187  		Result: &route,
   188  	}
   189  
   190  	err = client.connection.Make(request, &response)
   191  	return route, response.Warnings, err
   192  }
   193  
   194  // GetRoutes returns a list of Routes based off of the provided filters.
   195  func (client *Client) GetRoutes(filters ...Filter) ([]Route, Warnings, error) {
   196  	request, err := client.newHTTPRequest(requestOptions{
   197  		RequestName: internal.GetRoutesRequest,
   198  		Query:       ConvertFilterParameters(filters),
   199  	})
   200  	if err != nil {
   201  		return nil, nil, err
   202  	}
   203  
   204  	var fullRoutesList []Route
   205  	warnings, err := client.paginate(request, Route{}, func(item interface{}) error {
   206  		if route, ok := item.(Route); ok {
   207  			fullRoutesList = append(fullRoutesList, route)
   208  		} else {
   209  			return ccerror.UnknownObjectInListError{
   210  				Expected:   Route{},
   211  				Unexpected: item,
   212  			}
   213  		}
   214  		return nil
   215  	})
   216  
   217  	return fullRoutesList, warnings, err
   218  }
   219  
   220  // GetSpaceRoutes returns a list of Routes associated with the provided Space
   221  // GUID, and filtered by the provided filters.
   222  func (client *Client) GetSpaceRoutes(spaceGUID string, filters ...Filter) ([]Route, Warnings, error) {
   223  	request, err := client.newHTTPRequest(requestOptions{
   224  		RequestName: internal.GetSpaceRoutesRequest,
   225  		URIParams:   map[string]string{"space_guid": spaceGUID},
   226  		Query:       ConvertFilterParameters(filters),
   227  	})
   228  	if err != nil {
   229  		return nil, nil, err
   230  	}
   231  
   232  	var fullRoutesList []Route
   233  	warnings, err := client.paginate(request, Route{}, func(item interface{}) error {
   234  		if route, ok := item.(Route); ok {
   235  			fullRoutesList = append(fullRoutesList, route)
   236  		} else {
   237  			return ccerror.UnknownObjectInListError{
   238  				Expected:   Route{},
   239  				Unexpected: item,
   240  			}
   241  		}
   242  		return nil
   243  	})
   244  
   245  	return fullRoutesList, warnings, err
   246  }
   247  
   248  // UpdateRouteApplication creates a link between the route and application.
   249  func (client *Client) UpdateRouteApplication(routeGUID string, appGUID string) (Route, Warnings, error) {
   250  	request, err := client.newHTTPRequest(requestOptions{
   251  		RequestName: internal.PutRouteAppRequest,
   252  		URIParams: map[string]string{
   253  			"app_guid":   appGUID,
   254  			"route_guid": routeGUID,
   255  		},
   256  	})
   257  	if err != nil {
   258  		return Route{}, nil, err
   259  	}
   260  
   261  	var route Route
   262  	response := cloudcontroller.Response{
   263  		Result: &route,
   264  	}
   265  	err = client.connection.Make(request, &response)
   266  
   267  	return route, response.Warnings, err
   268  }
   269  
   270  func (client *Client) checkRoute(route Route) (bool, Warnings, error) {
   271  	request, err := client.newHTTPRequest(requestOptions{
   272  		RequestName: internal.GetRouteReservedRequest,
   273  		URIParams:   map[string]string{"domain_guid": route.DomainGUID},
   274  	})
   275  	if err != nil {
   276  		return false, nil, err
   277  	}
   278  
   279  	queryParams := url.Values{}
   280  	if route.Host != "" {
   281  		queryParams.Add("host", route.Host)
   282  	}
   283  	if route.Path != "" {
   284  		queryParams.Add("path", route.Path)
   285  	}
   286  	if route.Port.IsSet {
   287  		queryParams.Add("port", fmt.Sprint(route.Port.Value))
   288  	}
   289  	request.URL.RawQuery = queryParams.Encode()
   290  
   291  	var response cloudcontroller.Response
   292  	err = client.connection.Make(request, &response)
   293  	if _, ok := err.(ccerror.ResourceNotFoundError); ok {
   294  		return false, response.Warnings, nil
   295  	}
   296  
   297  	return response.HTTPResponse.StatusCode == http.StatusNoContent, response.Warnings, err
   298  }
   299  
   300  func (client *Client) checkRouteDeprecated(domainGUID string, host string, path string) (bool, Warnings, error) {
   301  	request, err := client.newHTTPRequest(requestOptions{
   302  		RequestName: internal.GetRouteReservedDeprecatedRequest,
   303  		URIParams:   map[string]string{"domain_guid": domainGUID, "host": host},
   304  	})
   305  	if err != nil {
   306  		return false, nil, err
   307  	}
   308  
   309  	queryParams := url.Values{}
   310  	if path != "" {
   311  		queryParams.Add("path", path)
   312  	}
   313  	request.URL.RawQuery = queryParams.Encode()
   314  
   315  	var response cloudcontroller.Response
   316  	err = client.connection.Make(request, &response)
   317  	if _, ok := err.(ccerror.ResourceNotFoundError); ok {
   318  		return false, response.Warnings, nil
   319  	}
   320  
   321  	return response.HTTPResponse.StatusCode == http.StatusNoContent, response.Warnings, err
   322  }