github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+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 if err := json.Unmarshal(data, &ccRoute); err != nil { 52 return err 53 } 54 55 route.GUID = ccRoute.Metadata.GUID 56 route.Host = ccRoute.Entity.Host 57 route.Path = ccRoute.Entity.Path 58 route.Port = ccRoute.Entity.Port 59 route.DomainGUID = ccRoute.Entity.DomainGUID 60 route.SpaceGUID = ccRoute.Entity.SpaceGUID 61 return nil 62 } 63 64 // UpdateRouteApplication creates a link between the route and application. 65 func (client *Client) UpdateRouteApplication(routeGUID string, appGUID string) (Route, Warnings, error) { 66 request, err := client.newHTTPRequest(requestOptions{ 67 RequestName: internal.PutRouteAppRequest, 68 URIParams: map[string]string{ 69 "app_guid": appGUID, 70 "route_guid": routeGUID, 71 }, 72 }) 73 if err != nil { 74 return Route{}, nil, err 75 } 76 77 var route Route 78 response := cloudcontroller.Response{ 79 Result: &route, 80 } 81 err = client.connection.Make(request, &response) 82 83 return route, response.Warnings, err 84 } 85 86 // DeleteRouteApplication removes the link between the route and application. 87 func (client *Client) DeleteRouteApplication(routeGUID string, appGUID string) (Warnings, error) { 88 request, err := client.newHTTPRequest(requestOptions{ 89 RequestName: internal.DeleteRouteAppRequest, 90 URIParams: map[string]string{ 91 "app_guid": appGUID, 92 "route_guid": routeGUID, 93 }, 94 }) 95 if err != nil { 96 return nil, err 97 } 98 99 var response cloudcontroller.Response 100 err = client.connection.Make(request, &response) 101 return response.Warnings, err 102 } 103 104 // CreateRoute creates the route with the given properties; SpaceGUID and 105 // DomainGUID are required Route properties. Additional configuration rules: 106 // - generatePort = true to generate a random port on the cloud controller. 107 // - generatePort takes precedence over the provided port. Setting the port and 108 // generatePort only works with CC API 2.53.0 or higher and when TCP router 109 // groups are enabled. 110 func (client *Client) CreateRoute(route Route, generatePort bool) (Route, Warnings, error) { 111 body, err := json.Marshal(route) 112 if err != nil { 113 return Route{}, nil, err 114 } 115 116 request, err := client.newHTTPRequest(requestOptions{ 117 RequestName: internal.PostRouteRequest, 118 Body: bytes.NewReader(body), 119 }) 120 if err != nil { 121 return Route{}, nil, err 122 } 123 124 if generatePort { 125 query := url.Values{} 126 query.Add("generate_port", "true") 127 request.URL.RawQuery = query.Encode() 128 } 129 130 var updatedRoute Route 131 response := cloudcontroller.Response{ 132 Result: &updatedRoute, 133 } 134 135 err = client.connection.Make(request, &response) 136 return updatedRoute, response.Warnings, err 137 } 138 139 // GetApplicationRoutes returns a list of Routes associated with the provided 140 // Application GUID, and filtered by the provided filters. 141 func (client *Client) GetApplicationRoutes(appGUID string, filters ...Filter) ([]Route, Warnings, error) { 142 request, err := client.newHTTPRequest(requestOptions{ 143 RequestName: internal.GetAppRoutesRequest, 144 URIParams: map[string]string{"app_guid": appGUID}, 145 Query: ConvertFilterParameters(filters), 146 }) 147 if err != nil { 148 return nil, nil, err 149 } 150 151 var fullRoutesList []Route 152 warnings, err := client.paginate(request, Route{}, func(item interface{}) error { 153 if route, ok := item.(Route); ok { 154 fullRoutesList = append(fullRoutesList, route) 155 } else { 156 return ccerror.UnknownObjectInListError{ 157 Expected: Route{}, 158 Unexpected: item, 159 } 160 } 161 return nil 162 }) 163 164 return fullRoutesList, warnings, err 165 } 166 167 // GetSpaceRoutes returns a list of Routes associated with the provided Space 168 // GUID, and filtered by the provided filters. 169 func (client *Client) GetSpaceRoutes(spaceGUID string, filters ...Filter) ([]Route, Warnings, error) { 170 request, err := client.newHTTPRequest(requestOptions{ 171 RequestName: internal.GetSpaceRoutesRequest, 172 URIParams: map[string]string{"space_guid": spaceGUID}, 173 Query: ConvertFilterParameters(filters), 174 }) 175 if err != nil { 176 return nil, nil, err 177 } 178 179 var fullRoutesList []Route 180 warnings, err := client.paginate(request, Route{}, func(item interface{}) error { 181 if route, ok := item.(Route); ok { 182 fullRoutesList = append(fullRoutesList, route) 183 } else { 184 return ccerror.UnknownObjectInListError{ 185 Expected: Route{}, 186 Unexpected: item, 187 } 188 } 189 return nil 190 }) 191 192 return fullRoutesList, warnings, err 193 } 194 195 // GetRoutes returns a list of Routes based off of the provided filters. 196 func (client *Client) GetRoutes(filters ...Filter) ([]Route, Warnings, error) { 197 request, err := client.newHTTPRequest(requestOptions{ 198 RequestName: internal.GetRoutesRequest, 199 Query: ConvertFilterParameters(filters), 200 }) 201 if err != nil { 202 return nil, nil, err 203 } 204 205 var fullRoutesList []Route 206 warnings, err := client.paginate(request, Route{}, func(item interface{}) error { 207 if route, ok := item.(Route); ok { 208 fullRoutesList = append(fullRoutesList, route) 209 } else { 210 return ccerror.UnknownObjectInListError{ 211 Expected: Route{}, 212 Unexpected: item, 213 } 214 } 215 return nil 216 }) 217 218 return fullRoutesList, warnings, err 219 } 220 221 // DeleteRoute deletes the Route associated with the provided Route GUID. 222 func (client *Client) DeleteRoute(routeGUID string) (Warnings, error) { 223 request, err := client.newHTTPRequest(requestOptions{ 224 RequestName: internal.DeleteRouteRequest, 225 URIParams: map[string]string{"route_guid": routeGUID}, 226 }) 227 if err != nil { 228 return nil, err 229 } 230 231 var response cloudcontroller.Response 232 err = client.connection.Make(request, &response) 233 return response.Warnings, err 234 } 235 236 // CheckRoute returns true if the route exists in the CF instance. DomainGUID 237 // is required for check. This call will only work for CC API 2.55 or higher. 238 func (client *Client) CheckRoute(route Route) (bool, Warnings, error) { 239 currentVersion := client.APIVersion() 240 switch { 241 case cloudcontroller.MinimumAPIVersionCheck(currentVersion, ccversion.MinVersionNoHostInReservedRouteEndpoint) == nil: 242 return client.checkRoute(route) 243 case cloudcontroller.MinimumAPIVersionCheck(currentVersion, ccversion.MinVersionHTTPRoutePath) == nil: 244 return client.checkRouteDeprecated(route.DomainGUID, route.Host, route.Path) 245 default: 246 return client.checkRouteDeprecated(route.DomainGUID, route.Host, "") 247 } 248 } 249 250 func (client *Client) checkRoute(route Route) (bool, Warnings, error) { 251 request, err := client.newHTTPRequest(requestOptions{ 252 RequestName: internal.GetRouteReservedRequest, 253 URIParams: map[string]string{"domain_guid": route.DomainGUID}, 254 }) 255 if err != nil { 256 return false, nil, err 257 } 258 259 queryParams := url.Values{} 260 if route.Host != "" { 261 queryParams.Add("host", route.Host) 262 } 263 if route.Path != "" { 264 queryParams.Add("path", route.Path) 265 } 266 if route.Port.IsSet { 267 queryParams.Add("port", fmt.Sprint(route.Port.Value)) 268 } 269 request.URL.RawQuery = queryParams.Encode() 270 271 var response cloudcontroller.Response 272 err = client.connection.Make(request, &response) 273 if _, ok := err.(ccerror.ResourceNotFoundError); ok { 274 return false, response.Warnings, nil 275 } 276 277 return response.HTTPResponse.StatusCode == http.StatusNoContent, response.Warnings, err 278 } 279 280 func (client *Client) checkRouteDeprecated(domainGUID string, host string, path string) (bool, Warnings, error) { 281 request, err := client.newHTTPRequest(requestOptions{ 282 RequestName: internal.GetRouteReservedDeprecatedRequest, 283 URIParams: map[string]string{"domain_guid": domainGUID, "host": host}, 284 }) 285 if err != nil { 286 return false, nil, err 287 } 288 289 queryParams := url.Values{} 290 if path != "" { 291 queryParams.Add("path", path) 292 } 293 request.URL.RawQuery = queryParams.Encode() 294 295 var response cloudcontroller.Response 296 err = client.connection.Make(request, &response) 297 if _, ok := err.(ccerror.ResourceNotFoundError); ok { 298 return false, response.Warnings, nil 299 } 300 301 return response.HTTPResponse.StatusCode == http.StatusNoContent, response.Warnings, err 302 }