Skip to content

Commit 577a911

Browse files
author
Jelle Dijkstra
committed
URL aliases
1 parent fc7394e commit 577a911

File tree

10 files changed

+139
-68
lines changed

10 files changed

+139
-68
lines changed

api/v3/atom_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@ var baseURL string
3535
var blobEndpoint string
3636

3737
// AtomSpec defines the desired state of Atom.
38+
// +kubebuilder:validation:XValidation:rule="!has(self.ingressRouteUrls) || self.ingressRouteUrls.exists_one(x, x.url == self.service.baseUrl)",messageExpression="'ingressRouteUrls should include service.baseUrl '+self.service.baseUrl"
3839
type AtomSpec struct {
3940
// Optional lifecycle settings
4041
Lifecycle *smoothoperatormodel.Lifecycle `json:"lifecycle,omitempty"`
4142

43+
// Optional list of URLs where the service can be reached
44+
// By default only the spec.service.baseUrl is used
45+
IngressRouteURLs smoothoperatormodel.IngressRouteURLs `json:"ingressRouteUrls,omitempty"`
46+
4247
// Service specification
4348
Service Service `json:"service"`
4449
}

api/v3/atom_validation.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ func (atom *Atom) ValidateUpdate(c client.Client, atomOld *Atom) ([]string, erro
4848
field.NewPath("spec").Child("service").Child("baseUrl"),
4949
)
5050

51+
smoothoperatorvalidation.ValidateIngressRouteURLsNotRemoved(atomOld.Spec.IngressRouteURLs, atom.Spec.IngressRouteURLs, &allErrs, nil)
52+
5153
ValidateAtom(c, atom, &warnings, &allErrs)
5254

5355
if len(allErrs) == 0 {
@@ -87,9 +89,19 @@ func ValidateAtomWithoutClusterChecks(atom *Atom, warnings *[]string, allErrs *f
8789
fieldPath = field.NewPath("metadata").Child("name")
8890
smoothoperatorvalidation.AddWarning(warnings, *fieldPath, "should not contain atom", atom.GroupVersionKind(), atom.GetName())
8991
}
92+
93+
validateDatasetFeeds(atom, allErrs)
94+
95+
err := smoothoperatorvalidation.ValidateIngressRouteURLsContainsBaseURL(atom.Spec.IngressRouteURLs, atom.Spec.Service.BaseURL, nil)
96+
if err != nil {
97+
*allErrs = append(*allErrs, err)
98+
}
99+
}
100+
101+
func validateDatasetFeeds(atom *Atom, allErrs *field.ErrorList) {
90102
var feedNames []string
91103
for i, datasetFeed := range atom.Spec.Service.DatasetFeeds {
92-
fieldPath = field.NewPath("spec").Child("service").Child("datasetFeeds").Index(i)
104+
fieldPath := field.NewPath("spec").Child("service").Child("datasetFeeds").Index(i)
93105

94106
if slices.Contains(feedNames, datasetFeed.TechnicalName) {
95107
*allErrs = append(*allErrs, field.Duplicate(fieldPath.Child("technicalName"), datasetFeed.TechnicalName))

api/v3/zz_generated.deepcopy.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/pdok.nl_atoms.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,21 @@ spec:
348348
spec:
349349
description: AtomSpec defines the desired state of Atom.
350350
properties:
351+
ingressRouteUrls:
352+
description: |-
353+
Optional list of URLs where the service can be reached
354+
By default only the spec.service.baseUrl is used
355+
items:
356+
properties:
357+
url:
358+
pattern: ^https?://.+/.+
359+
type: string
360+
required:
361+
- url
362+
type: object
363+
maxItems: 30
364+
minItems: 1
365+
type: array
351366
lifecycle:
352367
description: Optional lifecycle settings
353368
properties:
@@ -704,6 +719,11 @@ spec:
704719
required:
705720
- service
706721
type: object
722+
x-kubernetes-validations:
723+
- messageExpression: '''ingressRouteUrls should include service.baseUrl
724+
''+self.service.baseUrl'
725+
rule: '!has(self.ingressRouteUrls) || self.ingressRouteUrls.exists_one(x,
726+
x.url == self.service.baseUrl)'
707727
status:
708728
description: OperatorStatus defines the observed state of an Atom/WFS/WMS/....
709729
properties:

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/onsi/ginkgo/v2 v2.22.1
1212
github.com/onsi/gomega v1.36.2
1313
github.com/pdok/atom-generator v0.6.4
14-
github.com/pdok/smooth-operator v0.1.1
14+
github.com/pdok/smooth-operator v0.1.2
1515
github.com/peterbourgon/ff v1.7.1
1616
github.com/pkg/errors v0.9.1
1717
github.com/stretchr/testify v1.10.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
152152
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
153153
github.com/pdok/atom-generator v0.6.4 h1:UpTTSKskdWLnxTAhSNOlz8dF2tBousD97V03kWzCV2k=
154154
github.com/pdok/atom-generator v0.6.4/go.mod h1:IlPwti5ocXDTjB4xmz0ZpHCOW/suuW5gQMfjfwPX6uM=
155-
github.com/pdok/smooth-operator v0.1.1 h1:rmsup4HmzJsxt4ZT9GWfj498dKLRfDhyuILeEkjju/A=
156-
github.com/pdok/smooth-operator v0.1.1/go.mod h1:przwM7mBGmNPqabyhImKVZ15WL4zbqLqH4ExbuWKhWE=
155+
github.com/pdok/smooth-operator v0.1.2 h1:ibGRgFjKysu665IUToQhs34hHhptftI+7RBFrGNw4nQ=
156+
github.com/pdok/smooth-operator v0.1.2/go.mod h1:przwM7mBGmNPqabyhImKVZ15WL4zbqLqH4ExbuWKhWE=
157157
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
158158
github.com/peterbourgon/ff v1.7.1 h1:xt1lxTG+Nr2+tFtysY7abFgPoH3Lug8CwYJMOmJRXhk=
159159
github.com/peterbourgon/ff v1.7.1/go.mod h1:fYI5YA+3RDqQRExmFbHnBjEeWzh9TrS8rnRpEq7XIg0=

internal/controller/ingressroute.go

Lines changed: 49 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"sort"
88
"strconv"
99

10+
smoothoperatormodel "github.com/pdok/smooth-operator/model"
11+
1012
pdoknlv3 "github.com/pdok/atom-operator/api/v3"
1113
smoothutil "github.com/pdok/smooth-operator/pkg/util"
1214
traefikiov1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
@@ -40,61 +42,8 @@ func (r *AtomReconciler) mutateIngressRoute(atom *pdoknlv3.Atom, ingressRoute *t
4042
"uptime.pdok.nl/tags": "public-stats,atom",
4143
}
4244

43-
ingressRoute.Spec = traefikiov1alpha1.IngressRouteSpec{
44-
Routes: []traefikiov1alpha1.Route{
45-
{
46-
Kind: "Rule",
47-
Match: getMatchRule(baseURL.JoinPath("index.xml"), false),
48-
Services: []traefikiov1alpha1.Service{
49-
{
50-
LoadBalancerSpec: traefikiov1alpha1.LoadBalancerSpec{
51-
Name: getBareService(atom).GetName(),
52-
Kind: "Service",
53-
Port: intstr.FromInt32(atomPortNr),
54-
},
55-
},
56-
},
57-
Middlewares: []traefikiov1alpha1.MiddlewareRef{
58-
{
59-
Name: atom.Name + headersSuffix,
60-
},
61-
{
62-
Name: atom.Name + stripPrefixSuffix,
63-
},
64-
},
65-
},
66-
},
67-
}
68-
69-
// Set additional routes per datasetFeed
70-
for _, datasetFeed := range atom.Spec.Service.DatasetFeeds {
71-
matchRule := getMatchRule(baseURL.JoinPath(datasetFeed.TechnicalName+".xml"), false)
72-
rule := getDefaultRule(atom, matchRule)
73-
ingressRoute.Spec.Routes = append(ingressRoute.Spec.Routes, rule)
74-
}
75-
76-
azureStorageRule := traefikiov1alpha1.Route{
77-
Kind: "Rule",
78-
Match: getMatchRule(baseURL.JoinPath("downloads/"), true),
79-
Services: []traefikiov1alpha1.Service{
80-
{
81-
LoadBalancerSpec: traefikiov1alpha1.LoadBalancerSpec{
82-
Name: "azure-storage",
83-
Port: intstr.IntOrString{Type: intstr.String, StrVal: "azure-storage"},
84-
PassHostHeader: smoothutil.Pointer(false),
85-
Kind: "Service",
86-
},
87-
},
88-
},
89-
Middlewares: []traefikiov1alpha1.MiddlewareRef{
90-
{
91-
Name: atom.Name + headersSuffix,
92-
},
93-
},
94-
}
95-
96-
var downloadMiddlewares []traefikiov1alpha1.MiddlewareRef
9745
// Set additional Azure storage middleware per download link
46+
var downloadMiddlewares []traefikiov1alpha1.MiddlewareRef
9847
for _, group := range getDownloadLinkGroups(atom.GetDownloadLinks()) {
9948
middlewareRef := traefikiov1alpha1.MiddlewareRef{
10049
Name: atom.Name + downloadsSuffix + strconv.Itoa(*group.index),
@@ -106,12 +55,14 @@ func (r *AtomReconciler) mutateIngressRoute(atom *pdoknlv3.Atom, ingressRoute *t
10655
return downloadMiddlewares[i].Name < downloadMiddlewares[j].Name
10756
})
10857

109-
azureStorageRule.Middlewares = append(azureStorageRule.Middlewares, downloadMiddlewares...)
110-
111-
ingressRoute.Spec.Routes = append(ingressRoute.Spec.Routes, azureStorageRule)
112-
113-
// Add finalizers
114-
ingressRoute.Finalizers = []string{"uptime.pdok.nl/finalizer"}
58+
ingressRoute.Spec.Routes = []traefikiov1alpha1.Route{}
59+
if len(atom.Spec.IngressRouteURLs) > 0 {
60+
for _, ingressRouteURL := range atom.Spec.IngressRouteURLs {
61+
ingressRoute.Spec.Routes = append(ingressRoute.Spec.Routes, getRoutesForURL(atom, ingressRouteURL.URL, downloadMiddlewares)...)
62+
}
63+
} else {
64+
ingressRoute.Spec.Routes = getRoutesForURL(atom, atom.Spec.Service.BaseURL, downloadMiddlewares)
65+
}
11566

11667
if err := smoothutil.EnsureSetGVK(r.Client, ingressRoute, ingressRoute); err != nil {
11768
return err
@@ -152,3 +103,41 @@ func getDefaultRule(atom *pdoknlv3.Atom, matchRule string) traefikiov1alpha1.Rou
152103
},
153104
}
154105
}
106+
107+
func getRoutesForURL(atom *pdoknlv3.Atom, url smoothoperatormodel.URL, downloadMiddlewares []traefikiov1alpha1.MiddlewareRef) []traefikiov1alpha1.Route {
108+
routes := []traefikiov1alpha1.Route{
109+
getDefaultRule(atom, getMatchRule(url.JoinPath("index.xml"), false)),
110+
}
111+
112+
// Set additional routes per datasetFeed
113+
for _, datasetFeed := range atom.Spec.Service.DatasetFeeds {
114+
matchRule := getMatchRule(url.JoinPath(datasetFeed.TechnicalName+".xml"), false)
115+
rule := getDefaultRule(atom, matchRule)
116+
routes = append(routes, rule)
117+
}
118+
119+
// Add Azure storage rule
120+
azureStorageRule := traefikiov1alpha1.Route{
121+
Kind: "Rule",
122+
Match: getMatchRule(url.JoinPath("downloads/"), true),
123+
Services: []traefikiov1alpha1.Service{
124+
{
125+
LoadBalancerSpec: traefikiov1alpha1.LoadBalancerSpec{
126+
Name: "azure-storage",
127+
Port: intstr.IntOrString{Type: intstr.String, StrVal: "azure-storage"},
128+
PassHostHeader: smoothutil.Pointer(false),
129+
Kind: "Service",
130+
},
131+
},
132+
},
133+
Middlewares: append([]traefikiov1alpha1.MiddlewareRef{
134+
{
135+
Name: atom.Name + headersSuffix,
136+
}},
137+
downloadMiddlewares...,
138+
),
139+
}
140+
routes = append(routes, azureStorageRule)
141+
142+
return routes
143+
}

internal/controller/test_data/maximum-atom/expected-output/ingressroute.yaml

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ metadata:
1818
uid: ""
1919
blockOwnerDeletion: true
2020
controller: true
21-
finalizers:
22-
- uptime.pdok.nl/finalizer
2321
spec:
2422
routes:
2523
- kind: Rule
@@ -61,3 +59,42 @@ spec:
6159
- name: maximum-atom-downloads-0
6260
- name: maximum-atom-downloads-1
6361
- name: maximum-atom-downloads-2
62+
- kind: Rule
63+
match: (Host(`localhost`) || Host(`test.com`)) && Path(`/path/other/index.xml`)
64+
services:
65+
- kind: Service
66+
name: maximum-atom
67+
port: 80
68+
middlewares:
69+
- name: maximum-atom-headers
70+
- name: maximum-atom-prefixstrip
71+
- kind: Rule
72+
match: (Host(`localhost`) || Host(`test.com`)) && Path(`/path/other/feed-1.xml`)
73+
services:
74+
- kind: Service
75+
name: maximum-atom
76+
port: 80
77+
middlewares:
78+
- name: maximum-atom-headers
79+
- name: maximum-atom-prefixstrip
80+
- kind: Rule
81+
match: (Host(`localhost`) || Host(`test.com`)) && Path(`/path/other/feed-2.xml`)
82+
services:
83+
- kind: Service
84+
name: maximum-atom
85+
port: 80
86+
middlewares:
87+
- name: maximum-atom-headers
88+
- name: maximum-atom-prefixstrip
89+
- kind: Rule
90+
match: (Host(`localhost`) || Host(`test.com`)) && PathPrefix(`/path/other/downloads/`)
91+
services:
92+
- kind: Service
93+
name: azure-storage
94+
port: azure-storage
95+
passHostHeader: false
96+
middlewares:
97+
- name: maximum-atom-headers
98+
- name: maximum-atom-downloads-0
99+
- name: maximum-atom-downloads-1
100+
- name: maximum-atom-downloads-2

internal/controller/test_data/maximum-atom/input/atom.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ metadata:
66
labels:
77
test: test
88
spec:
9+
ingressRouteUrls:
10+
- url: https://test.com/path/
11+
- url: https://test.com/path/other/
912
service:
1013
baseUrl: https://test.com/path/
1114
stylesheet: https://test.com/stylesheet

internal/controller/test_data/minimal-atom/expected-output/ingressroute.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ metadata:
1818
uid: ""
1919
blockOwnerDeletion: true
2020
controller: true
21-
finalizers:
22-
- uptime.pdok.nl/finalizer
2321
spec:
2422
routes:
2523
- kind: Rule

0 commit comments

Comments
 (0)