Skip to content

Commit

Permalink
Merge pull request #29 from notmaxx/feature_locations
Browse files Browse the repository at this point in the history
feat(router): support locations in router
  • Loading branch information
Cryptophobia authored Oct 18, 2018
2 parents 9d28592 + 8c0d07d commit 186924e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 34 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ _Note that Kubernetes annotation maps are all of Go type `map[string]string`. A
| <a name="app-nginx-proxy-buffers-number"></a>routable application | service | [router.deis.io/nginx.proxyBuffers.number](#app-nginx-proxy-buffers-number) | `"8"` | `number` argument to the nginx `proxy_buffers` directive. This can be used to override the same option set globally on the router. |
| <a name="app-nginx-proxy-buffers-size"></a>routable application | service | [router.deis.io/nginx.proxyBuffers.size](#app-nginx-proxy-buffers-size) | `"4k"` | `size` argument to the nginx `proxy_buffers` directive expressed in bytes (no suffix), kilobytes (suffixes `k` and `K`), or megabytes (suffixes `m` and `M`). This can be used to override the same option set globally on the router. |
| <a name="app-nginx-proxy-buffers-busy-size"></a>routable application | service | [router.deis.io/nginx.proxyBuffers.busySize](#app-nginx-proxy-buffers-busy-size) | `"8k"` | nginx `proxy_busy_buffers_size` expressed in bytes (no suffix), kilobytes (suffixes `k` and `K`), or megabytes (suffixes `m` and `M`). This can be used to override the same option set globally on the router. |
|<a name="app-proxy-locations"></a>routable application | service | [router.deis.io/proxyLocations](#app-proxy-locations) | N/A | A list of locations of this service to plug-in into another service determined by `router.deis.io/proxyDomain` (see example below) |
|<a name="app-proxy-domain"></a>routable application | service | [router.deis.io/proxyDomain](#app-proxy-domain) | N/A | A reference to another service to plug-in `router.deis.io/proxyLocations` to (see example below) |

#### Annotations by example

Expand Down Expand Up @@ -337,6 +339,40 @@ metadata:
# ...
```

##### proxy locations:

Service of the application where we want `/webhooks` path to be handled by another service
```
apiVersion: v1
kind: Service
metadata:
name: app_with_overwritten_webhooks_location
labels:
router.deis.io/routable: "true"
namespace: router-examples
# ...
annotations:
router.deis.io/domains: app_with_overwritten_webhooks_location
# ...
```

Service of the application which should handle `/webhooks` path of the app above
```
apiVersion: v1
kind: Service
metadata:
name: app_webhooks_location_handler
labels:
router.deis.io/routable: "true"
namespace: router-examples
# ...
annotations:
...
router.deis.io/proxyDomain=app_with_overwritten_webhooks_location
router.deis.io/proxyLocations=/webhooks
# ...
```

### <a name="ssl"></a>SSL

Router has support for HTTPS with the ability to perform SSL termination using certificates supplied via Kubernetes secrets. Just as router utilizes the Kubernetes API to discover routable services, router also uses the API to discover cert-bearing secrets. This allows the router to dynamically refresh and reload configuration whenever such a certificate is added, updated, or removed. There is never a need to explicitly restart the router.
Expand Down
50 changes: 50 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package model
import (
"bytes"
"encoding/gob"
goerrors "errors"
"fmt"
"log"
"strings"
Expand Down Expand Up @@ -150,6 +151,14 @@ type AppConfig struct {
Maintenance bool `key:"maintenance" constraint:"(?i)^(true|false)$"`
SSLConfig *SSLConfig `key:"ssl"`
Nginx *NginxAppConfig `key:"nginx"`
ProxyLocations []string `key:"proxyLocations"`
ProxyDomain string `key:"proxyDomain"`
Locations []*Location
}

type Location struct {
App *AppConfig
Path string
}

func newAppConfig(routerConfig *RouterConfig) (*AppConfig, error) {
Expand Down Expand Up @@ -391,6 +400,11 @@ func build(kubeClient *kubernetes.Clientset, routerDeployment *v1beta1ext.Deploy
routerConfig.AppConfigs = append(routerConfig.AppConfigs, appConfig)
}
}
err = linkLocations(routerConfig.AppConfigs)
if err != nil {
return nil, err
}
addRootLocations(routerConfig.AppConfigs)
if builderService != nil {
builderConfig, err := buildBuilderConfig(builderService)
if err != nil {
Expand All @@ -403,6 +417,41 @@ func build(kubeClient *kubernetes.Clientset, routerDeployment *v1beta1ext.Deploy
return routerConfig, nil
}

func appByDomain(appConfigs []*AppConfig, domain string) *AppConfig {
for _, app := range appConfigs {
for _, appDomain := range app.Domains {
if domain == appDomain {
return app
}
}
}
return nil
}

func linkLocations(appConfigs []*AppConfig) error {
for _, app := range appConfigs {
if app.ProxyDomain != "" && len(app.ProxyLocations) > 0 {
targetApp := appByDomain(appConfigs, app.ProxyDomain)
if targetApp == nil {
return goerrors.New(fmt.Sprintf("Can't find ProxyDomain '%s' in any application", app.ProxyDomain))
}

for _, loc := range app.ProxyLocations {
location := &Location{App: app, Path: loc}
targetApp.Locations = append(targetApp.Locations, location)
}
}
}
return nil
}

func addRootLocations(appConfigs []*AppConfig) {
for _, app := range appConfigs {
rootLocation := &Location{App: app, Path: "/"}
app.Locations = append(app.Locations, rootLocation)
}
}

func buildRouterConfig(routerDeployment *v1beta1.Deployment, platformCertSecret *v1.Secret, dhParamSecret *v1.Secret) (*RouterConfig, error) {
routerConfig, err := newRouterConfig()
if err != nil {
Expand Down Expand Up @@ -449,6 +498,7 @@ func buildAppConfig(kubeClient *kubernetes.Clientset, service v1.Service, router
if err != nil {
return nil, err
}

// If no domains are found, we don't have the information we need to build routes
// to this application. Abort.
if len(appConfig.Domains) == 0 {
Expand Down
71 changes: 37 additions & 34 deletions nginx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,41 +270,44 @@ http {
vhost_traffic_status_filter_by_set_key {{ $appConfig.Name }} application::*;
location / {
{{ if $routerConfig.RequestIDs }}
add_header X-Request-Id $request_id always;
add_header X-Correlation-Id $correlation_id always;
{{end}}
{{ if $appConfig.Maintenance }}return 503;{{ else if $appConfig.Available }}
proxy_buffering {{ if $appConfig.Nginx.ProxyBuffersConfig.Enabled }}on{{ else }}off{{ end }};
proxy_buffer_size {{ $appConfig.Nginx.ProxyBuffersConfig.Size }};
proxy_buffers {{ $appConfig.Nginx.ProxyBuffersConfig.Number }} {{ $appConfig.Nginx.ProxyBuffersConfig.Size }};
proxy_busy_buffers_size {{ $appConfig.Nginx.ProxyBuffersConfig.BusySize }};
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $access_scheme;
proxy_set_header X-Forwarded-Port $forwarded_port;
proxy_redirect off;
proxy_connect_timeout {{ $appConfig.ConnectTimeout }};
proxy_send_timeout {{ $appConfig.TCPTimeout }};
proxy_read_timeout {{ $appConfig.TCPTimeout }};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{{ if $routerConfig.RequestIDs }}
proxy_set_header X-Request-Id $request_id;
proxy_set_header X-Correlation-Id $correlation_id;
{{ end }}
{{ if or $enforceSecure $appConfig.SSLConfig.Enforce }}if ($access_scheme !~* "^https|wss$") {
return 301 $uri_scheme://$host$request_uri;
}{{ end }}
{{ if $hstsConfig.Enabled }}add_header Strict-Transport-Security $sts always;{{ end }}
{{range $location := $appConfig.Locations}}
location {{ $location.Path }} {
{{ if $routerConfig.RequestIDs }}
add_header X-Request-Id $request_id always;
add_header X-Correlation-Id $correlation_id always;
{{end}}
{{ if $location.App.Maintenance }}return 503;{{ else if $location.App.Available }}
proxy_buffering {{ if $location.App.Nginx.ProxyBuffersConfig.Enabled }}on{{ else }}off{{ end }};
proxy_buffer_size {{ $location.App.Nginx.ProxyBuffersConfig.Size }};
proxy_buffers {{ $location.App.Nginx.ProxyBuffersConfig.Number }} {{ $location.App.Nginx.ProxyBuffersConfig.Size }};
proxy_busy_buffers_size {{ $location.App.Nginx.ProxyBuffersConfig.BusySize }};
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $access_scheme;
proxy_set_header X-Forwarded-Port $forwarded_port;
proxy_redirect off;
proxy_connect_timeout {{ $location.App.ConnectTimeout }};
proxy_send_timeout {{ $location.App.TCPTimeout }};
proxy_read_timeout {{ $location.App.TCPTimeout }};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{{ if $routerConfig.RequestIDs }}
proxy_set_header X-Request-Id $request_id;
proxy_set_header X-Correlation-Id $correlation_id;
{{ end }}
{{ if or $enforceSecure $location.App.SSLConfig.Enforce }}if ($access_scheme !~* "^https|wss$") {
return 301 $uri_scheme://$host$request_uri;
}{{ end }}
{{ if $hstsConfig.Enabled }}add_header Strict-Transport-Security $sts always;{{ end }}
proxy_pass http://{{$location.App.ServiceIP}}:80;{{ else }}return 503;{{ end }}
}
{{end}}
proxy_pass http://{{$appConfig.ServiceIP}}:80;{{ else }}return 503;{{ end }}
}
{{ if $appConfig.Maintenance }}error_page 503 @maintenance;
location @maintenance {
root /;
Expand Down

0 comments on commit 186924e

Please sign in to comment.