Skip to content

Commit 458f4de

Browse files
authored
Merge pull request #72 from PDOK/wr/validation
Wr/validation
2 parents a6db5dd + 8eb8cca commit 458f4de

File tree

18 files changed

+169
-140
lines changed

18 files changed

+169
-140
lines changed

api/v2beta1/shared_conversion.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func ConvertAutoscaling(src Autoscaling) *pdoknlv3.HorizontalPodAutoscalerPatch
7575

7676
return &pdoknlv3.HorizontalPodAutoscalerPatch{
7777
MinReplicas: minReplicas,
78-
MaxReplicas: maxReplicas,
78+
MaxReplicas: &maxReplicas,
7979
Metrics: metrics,
8080
}
8181
}
@@ -221,8 +221,10 @@ func NewV2KubernetesObject(lifecycle *smoothoperatormodel.Lifecycle, podSpecPatc
221221
kub.Resources = &podSpecPatch.Containers[0].Resources
222222

223223
if scalingSpec != nil {
224-
kub.Autoscaling = &Autoscaling{
225-
MaxReplicas: smoothoperatorutils.Pointer(int(scalingSpec.MaxReplicas)),
224+
kub.Autoscaling = &Autoscaling{}
225+
226+
if scalingSpec.MaxReplicas != nil {
227+
kub.Autoscaling.MaxReplicas = smoothoperatorutils.Pointer(int(*scalingSpec.MaxReplicas))
226228
}
227229

228230
if scalingSpec.MinReplicas != nil {

api/v2beta1/wfs_conversion.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ package v2beta1
2626

2727
import (
2828
"log"
29+
"strconv"
2930

3031
pdoknlv3 "github.com/pdok/mapserver-operator/api/v3"
3132
smoothoperatormodel "github.com/pdok/smooth-operator/model"
@@ -43,7 +44,7 @@ func (src *WFS) ConvertTo(dstRaw conversion.Hub) error {
4344
return src.ToV3(dst)
4445
}
4546

46-
//nolint:gosec
47+
//nolint:gosec,funlen,cyclop
4748
func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
4849
dst.ObjectMeta = src.ObjectMeta
4950

@@ -76,6 +77,20 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
7677
return err
7778
}
7879

80+
accessConstraints, err := url.Parse("https://creativecommons.org/publicdomain/zero/1.0/deed.nl")
81+
if err != nil {
82+
return err
83+
}
84+
if src.Spec.Service.AccessConstraints != nil {
85+
accessConstraints, err = url.Parse(*src.Spec.Service.AccessConstraints)
86+
if err != nil {
87+
return err
88+
}
89+
}
90+
91+
if err != nil {
92+
return err
93+
}
7994
service := pdoknlv3.WFSService{
8095
Prefix: src.Spec.General.Dataset,
8196
URL: *url,
@@ -84,7 +99,7 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
8499
Abstract: src.Spec.Service.Abstract,
85100
Keywords: src.Spec.Service.Keywords,
86101
Fees: nil,
87-
AccessConstraints: src.Spec.Service.AccessConstraints,
102+
AccessConstraints: smoothoperatormodel.URL{URL: accessConstraints},
88103
DefaultCrs: src.Spec.Service.DataEPSG,
89104
OtherCrs: []string{
90105
"EPSG::25831",
@@ -95,10 +110,17 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
95110
"EPSG::4258",
96111
"EPSG::4326",
97112
},
98-
CountDefault: src.Spec.Service.Maxfeatures,
99113
FeatureTypes: make([]pdoknlv3.FeatureType, 0),
100114
}
101115

116+
if src.Spec.Service.Maxfeatures != nil {
117+
maxFeatures, err := strconv.Atoi(*src.Spec.Service.Maxfeatures)
118+
if err != nil {
119+
return err
120+
}
121+
service.CountDefault = &maxFeatures
122+
}
123+
102124
if src.Spec.Service.Mapfile != nil {
103125
service.Mapfile = &pdoknlv3.Mapfile{
104126
ConfigMapKeyRef: src.Spec.Service.Mapfile.ConfigMapKeyRef,
@@ -148,7 +170,7 @@ func convertV2FeatureTypeToV3(src FeatureType) pdoknlv3.FeatureType {
148170
Title: src.Title,
149171
Abstract: src.Abstract,
150172
Keywords: src.Keywords,
151-
DatasetMetadataURL: pdoknlv3.MetadataURL{
173+
DatasetMetadataURL: &pdoknlv3.MetadataURL{
152174
CSW: &pdoknlv3.Metadata{
153175
MetadataIdentifier: src.DatasetMetadataIdentifier,
154176
},
@@ -190,19 +212,24 @@ func (dst *WFS) ConvertFrom(srcRaw conversion.Hub) error {
190212
}
191213
}
192214

215+
accessConstraints := src.Spec.Service.AccessConstraints.String()
216+
193217
service := WFSService{
194218
Title: src.Spec.Service.Title,
195219
Abstract: src.Spec.Service.Abstract,
196220
Keywords: src.Spec.Service.Keywords,
197-
AccessConstraints: src.Spec.Service.AccessConstraints,
221+
AccessConstraints: &accessConstraints,
198222
DataEPSG: src.Spec.Service.DefaultCrs,
199-
Maxfeatures: src.Spec.Service.CountDefault,
200223
Authority: Authority{
201224
Name: "",
202225
URL: "",
203226
},
204227
}
205228

229+
if src.Spec.Service.CountDefault != nil {
230+
service.Maxfeatures = smoothoperatorutils.Pointer(strconv.Itoa(*src.Spec.Service.CountDefault))
231+
}
232+
206233
if src.Spec.Service.Bbox != nil {
207234
service.Extent = smoothoperatorutils.Pointer(src.Spec.Service.Bbox.DefaultCRS.ToExtent())
208235
} else {

api/v3/shared_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const (
2525
// This way we don't have to specify the scaleTargetRef field in the CRD.
2626
type HorizontalPodAutoscalerPatch struct {
2727
MinReplicas *int32 `json:"minReplicas,omitempty"`
28-
MaxReplicas int32 `json:"maxReplicas"`
28+
MaxReplicas *int32 `json:"maxReplicas,omitempty"`
2929
Metrics []autoscalingv2.MetricSpec `json:"metrics,omitempty"`
3030
Behavior *autoscalingv2.HorizontalPodAutoscalerBehavior `json:"behavior,omitempty"`
3131
}
@@ -167,7 +167,7 @@ type Data struct {
167167
// +kubebuilder:validation:Type=object
168168
type Gpkg struct {
169169
// Blobkey identifies the location/bucket of the .gpkg file
170-
// +kubebuilder:validation:Pattern=`\.gpkg$`
170+
// +kubebuilder:validation:Pattern:=^.+\/.+\/.+\.gpkg$
171171
// +kubebuilder:validation:MinLength:=1
172172
BlobKey string `json:"blobKey"`
173173

api/v3/shared_validation.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package v3
22

33
import (
4+
"fmt"
5+
46
sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
7+
v1 "k8s.io/api/core/v1"
58

69
apierrors "k8s.io/apimachinery/pkg/api/errors"
710
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -34,3 +37,41 @@ func ValidateUpdate[W WMSWFS](newW, oldW W, validate func(W, *[]string, *field.E
3437
newW.GroupKind(),
3538
newW.GetName(), allErrs)
3639
}
40+
41+
func ValidateHorizontalPodAutoscalerPatch(patch HorizontalPodAutoscalerPatch, allErrs *field.ErrorList) {
42+
path := field.NewPath("spec").Child("horizontalPodAutoscaler")
43+
// TODO: replace hardcoded defaults with dynamic defaults from cli options or ownerInfo
44+
var minReplicas, maxReplicas int32 = 2, 32
45+
if patch.MinReplicas != nil {
46+
minReplicas = *patch.MinReplicas
47+
}
48+
if patch.MaxReplicas != nil {
49+
maxReplicas = *patch.MaxReplicas
50+
}
51+
52+
if maxReplicas < minReplicas {
53+
replicas := fmt.Sprintf("minReplicas: %d, maxReplicas: %d", minReplicas, maxReplicas)
54+
55+
*allErrs = append(*allErrs, field.Invalid(path, replicas, "maxReplicas cannot be less than minReplicas"))
56+
}
57+
58+
}
59+
60+
func ValidateEphemeralStorage(podSpecPatch v1.PodSpec, allErrs *field.ErrorList) {
61+
path := field.NewPath("spec").
62+
Child("podSpecPatch").
63+
Child("containers").
64+
Key("mapserver").
65+
Child("resources").
66+
Child("limits").
67+
Child(v1.ResourceEphemeralStorage.String())
68+
storageSet := false
69+
for _, container := range podSpecPatch.Containers {
70+
if container.Name == "mapserver" {
71+
_, storageSet = container.Resources.Limits[v1.ResourceEphemeralStorage]
72+
}
73+
}
74+
if !storageSet {
75+
*allErrs = append(*allErrs, field.Required(path, ""))
76+
}
77+
}

api/v3/wfs_types.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,16 @@ type WFSService struct {
118118

119119
// Keywords for capabilities
120120
// +kubebuilder:validation:MinItems:=1
121+
// +kubebuilder:validation:items:MinLength:=1
121122
Keywords []string `json:"keywords"`
122123

123124
// Optional Fees
124125
// +kubebuilder:validation:MinLength:=1
125126
Fees *string `json:"fees,omitempty"`
126127

127128
// AccessConstraints URL
128-
// +kubebuilder:validation:Pattern:="https?://"
129129
// +kubebuilder:default="https://creativecommons.org/publicdomain/zero/1.0/deed.nl"
130-
// +kubebuilder:validation:MinLength:=1
131-
AccessConstraints *string `json:"accessConstraints,omitempty"`
130+
AccessConstraints smoothoperatormodel.URL `json:"accessConstraints,omitempty"`
132131

133132
// Default CRS (DataEPSG)
134133
// +kubebuilder:validation:Pattern:="^EPSG:(28992|25831|25832|3034|3035|3857|4258|4326)$"
@@ -143,8 +142,8 @@ type WFSService struct {
143142
Bbox *Bbox `json:"bbox,omitempty"`
144143

145144
// CountDefault -> wfs_maxfeatures in mapfile
146-
// +kubebuilder:validation:MinLength:=1
147-
CountDefault *string `json:"countDefault,omitempty"`
145+
// +kubebuilder:validation:Minimum:=1
146+
CountDefault *int `json:"countDefault,omitempty"`
148147

149148
// FeatureTypes configurations
150149
// +kubebuilder:validation:MinItems:=1
@@ -164,6 +163,8 @@ func (s WFSService) KeywordsIncludingInspireKeyword() []string {
164163
// HealthCheck is the struct with all fields to configure custom healthchecks
165164
type HealthCheckWFS struct {
166165
// +kubebuilder:validation:MinLength:=1
166+
// +kubebuilder:validation:XValidation:rule="self.contains('Service=WFS')",message="a valid healthcheck contains 'Service=WFS'"
167+
// +kubebuilder:validation:XValidation:rule="self.contains('Request=')",message="a valid healthcheck contains 'Request='"
167168
Querystring string `json:"querystring"`
168169
// +kubebuilder:validation:Pattern=(image/png|text/xml|text/html)
169170
Mimetype string `json:"mimetype"`
@@ -192,11 +193,12 @@ type FeatureType struct {
192193

193194
// Keywords of the feature
194195
// +kubebuilder:validation:MinItems:=1
196+
// +kubebuilder:validation:items:MinLength:=1
195197
Keywords []string `json:"keywords"`
196198

197199
// Metadata URL
198200
// +kubebuilder:validation:Type=object
199-
DatasetMetadataURL MetadataURL `json:"datasetMetadataUrl"`
201+
DatasetMetadataURL *MetadataURL `json:"datasetMetadataUrl,omitempty"`
200202

201203
// Optional feature bbox
202204
// +kubebuilder:validation:Optional

api/v3/wfs_validation.go

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package v3
33
import (
44
"strings"
55

6-
corev1 "k8s.io/api/core/v1"
7-
86
sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
97

108
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -58,25 +56,10 @@ func ValidateWFS(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {
5856
sharedValidation.AddWarning(warnings, *path.Child("bbox"), "is not used when service.mapfile is configured", wfs.GroupVersionKind(), wfs.GetName())
5957
}
6058

59+
if wfs.Spec.HorizontalPodAutoscalerPatch != nil {
60+
ValidateHorizontalPodAutoscalerPatch(*wfs.Spec.HorizontalPodAutoscalerPatch, allErrs)
61+
}
62+
6163
podSpecPatch := wfs.Spec.PodSpecPatch
6264
ValidateEphemeralStorage(podSpecPatch, allErrs)
6365
}
64-
65-
func ValidateEphemeralStorage(podSpecPatch corev1.PodSpec, allErrs *field.ErrorList) {
66-
path := field.NewPath("spec").
67-
Child("podSpecPatch").
68-
Child("containers").
69-
Key("mapserver").
70-
Child("resources").
71-
Child("limits").
72-
Child(corev1.ResourceEphemeralStorage.String())
73-
storageSet := false
74-
for _, container := range podSpecPatch.Containers {
75-
if container.Name == "mapserver" {
76-
_, storageSet = container.Resources.Limits[corev1.ResourceEphemeralStorage]
77-
}
78-
}
79-
if !storageSet {
80-
*allErrs = append(*allErrs, field.Required(path, ""))
81-
}
82-
}

api/v3/wms_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type WMSService struct {
9090

9191
// Keywords of the service
9292
// +kubebuilder:validation:MinItems:=1
93+
// +kubebuilder:validation:items:MinLength:=1
9394
Keywords []string `json:"keywords"`
9495

9596
// Reference to a CR of Kind OwnerInfo

api/v3/wms_validation.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ func ValidateWMS(wms *WMS, warnings *[]string, allErrs *field.ErrorList) {
291291
))
292292
}
293293

294+
if wms.Spec.HorizontalPodAutoscalerPatch != nil {
295+
ValidateHorizontalPodAutoscalerPatch(*wms.Spec.HorizontalPodAutoscalerPatch, allErrs)
296+
}
297+
294298
podSpecPatch := wms.Spec.PodSpecPatch
295299
ValidateEphemeralStorage(podSpecPatch, allErrs)
296300
}

api/v3/zz_generated.deepcopy.go

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

0 commit comments

Comments
 (0)