Skip to content

Commit b328963

Browse files
authored
Merge pull request #83 from PDOK/wr/validate-wms
Wr/validate wms
2 parents 96cb7e5 + d181193 commit b328963

29 files changed

+471
-569
lines changed

api/v2beta1/shared_conversion.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ func ConvertOptionsV2ToV3(src *WMSWFSOptions) *pdoknlv3.Options {
2020
}
2121

2222
return &pdoknlv3.Options{
23-
AutomaticCasing: src.AutomaticCasing,
24-
IncludeIngress: src.IncludeIngress,
25-
PrefetchData: smoothoperatorutils.PointerVal(src.PrefetchData, defaults.PrefetchData),
26-
ValidateRequests: smoothoperatorutils.PointerVal(src.ValidateRequests, defaults.ValidateRequests),
27-
RewriteGroupToDataLayers: smoothoperatorutils.PointerVal(src.RewriteGroupToDataLayers, defaults.RewriteGroupToDataLayers),
28-
DisableWebserviceProxy: smoothoperatorutils.PointerVal(src.DisableWebserviceProxy, defaults.DisableWebserviceProxy),
29-
ValidateChildStyleNameEqual: smoothoperatorutils.PointerVal(src.ValidateChildStyleNameEqual, defaults.ValidateChildStyleNameEqual),
23+
BaseOptions: pdoknlv3.BaseOptions{
24+
AutomaticCasing: src.AutomaticCasing,
25+
IncludeIngress: src.IncludeIngress,
26+
PrefetchData: smoothoperatorutils.PointerVal(src.PrefetchData, defaults.PrefetchData),
27+
},
28+
WMSOptions: pdoknlv3.WMSOptions{
29+
ValidateRequests: smoothoperatorutils.PointerVal(src.ValidateRequests, defaults.ValidateRequests),
30+
RewriteGroupToDataLayers: smoothoperatorutils.PointerVal(src.RewriteGroupToDataLayers, defaults.RewriteGroupToDataLayers),
31+
DisableWebserviceProxy: smoothoperatorutils.PointerVal(src.DisableWebserviceProxy, defaults.DisableWebserviceProxy),
32+
ValidateChildStyleNameEqual: smoothoperatorutils.PointerVal(src.ValidateChildStyleNameEqual, defaults.ValidateChildStyleNameEqual),
33+
},
3034
}
3135
}
3236

api/v2beta1/wfs_conversion.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
6363
dst.Spec.PodSpecPatch = ConvertResources(*src.Spec.Kubernetes.Resources)
6464
}
6565

66-
dst.Spec.Options = ConvertOptionsV2ToV3(src.Spec.Options)
66+
dst.Spec.Options = &ConvertOptionsV2ToV3(src.Spec.Options).BaseOptions
6767

6868
if src.Spec.Kubernetes.HealthCheck != nil {
6969
dst.Spec.HealthCheck = &pdoknlv3.HealthCheckWFS{
@@ -92,15 +92,17 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
9292
return err
9393
}
9494
service := pdoknlv3.WFSService{
95-
Prefix: src.Spec.General.Dataset,
96-
URL: *url,
97-
OwnerInfoRef: "pdok",
98-
Title: src.Spec.Service.Title,
99-
Abstract: src.Spec.Service.Abstract,
100-
Keywords: src.Spec.Service.Keywords,
101-
Fees: nil,
102-
AccessConstraints: smoothoperatormodel.URL{URL: accessConstraints},
103-
DefaultCrs: src.Spec.Service.DataEPSG,
95+
BaseService: pdoknlv3.BaseService{
96+
Prefix: src.Spec.General.Dataset,
97+
URL: *url,
98+
OwnerInfoRef: "pdok",
99+
Title: src.Spec.Service.Title,
100+
Abstract: src.Spec.Service.Abstract,
101+
Keywords: src.Spec.Service.Keywords,
102+
Fees: nil,
103+
AccessConstraints: smoothoperatormodel.URL{URL: accessConstraints},
104+
},
105+
DefaultCrs: src.Spec.Service.DataEPSG,
104106
OtherCrs: []string{
105107
"EPSG:25831",
106108
"EPSG:25832",
@@ -144,14 +146,14 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
144146

145147
// TODO - where to place the MetadataIdentifier and FeatureTypes[0].SourceMetadataIdentifier if the service is not inspire?
146148
if src.Spec.Service.Inspire {
147-
service.Inspire = &pdoknlv3.Inspire{
149+
service.Inspire = &pdoknlv3.WFSInspire{Inspire: pdoknlv3.Inspire{
148150
ServiceMetadataURL: pdoknlv3.MetadataURL{
149151
CSW: &pdoknlv3.Metadata{
150152
MetadataIdentifier: src.Spec.Service.MetadataIdentifier,
151153
},
152154
},
155+
Language: "dut"},
153156
SpatialDatasetIdentifier: src.Spec.Service.FeatureTypes[0].SourceMetadataIdentifier,
154-
Language: "dut",
155157
}
156158
}
157159

@@ -203,7 +205,7 @@ func (dst *WFS) ConvertFrom(srcRaw conversion.Hub) error {
203205

204206
dst.Spec.Kubernetes = NewV2KubernetesObject(src.Spec.Lifecycle, src.Spec.PodSpecPatch, src.Spec.HorizontalPodAutoscalerPatch)
205207

206-
dst.Spec.Options = ConvertOptionsV3ToV2(src.Spec.Options)
208+
dst.Spec.Options = ConvertOptionsV3ToV2(&pdoknlv3.Options{BaseOptions: *src.Spec.Options})
207209

208210
if src.Spec.HealthCheck != nil {
209211
dst.Spec.Kubernetes.HealthCheck = &HealthCheck{

api/v2beta1/wms_conversion.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
"strconv"
3131
"strings"
3232

33+
"k8s.io/utils/ptr"
34+
3335
pdoknlv3 "github.com/pdok/mapserver-operator/api/v3"
3436
smoothoperatormodel "github.com/pdok/smooth-operator/model"
3537
smoothoperatorutils "github.com/pdok/smooth-operator/pkg/util"
@@ -47,7 +49,7 @@ func (src *WMS) ConvertTo(dstRaw conversion.Hub) error {
4749
return src.ToV3(dst)
4850
}
4951

50-
//nolint:gosec
52+
//nolint:gosec,cyclop,funlen
5153
func (src *WMS) ToV3(target *pdoknlv3.WMS) error {
5254
dst := target
5355

@@ -79,20 +81,32 @@ func (src *WMS) ToV3(target *pdoknlv3.WMS) error {
7981
return err
8082
}
8183

82-
service := pdoknlv3.WMSService{
84+
accessConstraints, err := url.Parse("https://creativecommons.org/publicdomain/zero/1.0/deed.nl")
85+
if err != nil {
86+
return err
87+
}
88+
if src.Spec.Service.AccessConstraints != nil {
89+
accessConstraints, err = url.Parse(*src.Spec.Service.AccessConstraints)
90+
if err != nil {
91+
return err
92+
}
93+
}
94+
95+
service := pdoknlv3.WMSService{BaseService: pdoknlv3.BaseService{
8396
Prefix: src.Spec.General.Dataset,
8497
URL: *url,
8598
OwnerInfoRef: "pdok",
8699
Title: src.Spec.Service.Title,
87100
Abstract: src.Spec.Service.Abstract,
88101
Keywords: src.Spec.Service.Keywords,
89-
AccessConstraints: smoothoperatorutils.PointerVal(src.Spec.Service.AccessConstraints, "https://creativecommons.org/publicdomain/zero/1.0/deed.nl"),
90-
MaxSize: nil,
91-
Resolution: nil,
92-
DefResolution: nil,
93-
Inspire: nil,
94-
DataEPSG: src.Spec.Service.DataEPSG,
95-
Layer: src.Spec.Service.MapLayersToV3(),
102+
AccessConstraints: smoothoperatormodel.URL{URL: accessConstraints},
103+
},
104+
Inspire: nil,
105+
MaxSize: nil,
106+
Resolution: nil,
107+
DefResolution: nil,
108+
DataEPSG: src.Spec.Service.DataEPSG,
109+
Layer: src.Spec.Service.MapLayersToV3(),
96110
}
97111

98112
if src.Spec.Service.Maxsize != nil {
@@ -120,8 +134,7 @@ func (src *WMS) ToV3(target *pdoknlv3.WMS) error {
120134
MetadataIdentifier: src.Spec.Service.MetadataIdentifier,
121135
},
122136
},
123-
SpatialDatasetIdentifier: *src.Spec.Service.Layers[0].SourceMetadataIdentifier,
124-
Language: "dut",
137+
Language: "dut",
125138
}
126139
} else {
127140
// Annotation to be able to convert back to v2
@@ -185,7 +198,7 @@ func (dst *WMS) ConvertFrom(srcRaw conversion.Hub) error {
185198
Title: src.Spec.Service.Title,
186199
Abstract: src.Spec.Service.Abstract,
187200
Keywords: src.Spec.Service.Keywords,
188-
AccessConstraints: &src.Spec.Service.AccessConstraints,
201+
AccessConstraints: ptr.To(src.Spec.Service.AccessConstraints.String()),
189202
Extent: nil,
190203
DataEPSG: src.Spec.Service.DataEPSG,
191204
Layers: []WMSLayer{},

api/v3/shared_types.go

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type WMSWFS interface {
3737
metav1.Object
3838

3939
GroupKind() schema.GroupKind
40-
Inspire() *Inspire
40+
Inspire() *WFSInspire
4141
Mapfile() *Mapfile
4242
PodSpecPatch() corev1.PodSpec
4343
HorizontalPodAutoscalerPatch() *HorizontalPodAutoscalerPatch
@@ -66,9 +66,8 @@ type Mapfile struct {
6666
ConfigMapKeyRef corev1.ConfigMapKeySelector `json:"configMapKeyRef"`
6767
}
6868

69-
// Options configures optional behaviors of the operator, like ingress, casing, and data prefetching.
70-
// +kubebuilder:validation:Type=object
71-
type Options struct {
69+
// BaseOptions for all apis
70+
type BaseOptions struct {
7271
// IncludeIngress dictates whether to deploy an Ingress or ensure none exists.
7372
// +kubebuilder:default:=true
7473
IncludeIngress bool `json:"includeIngress"`
@@ -77,51 +76,80 @@ type Options struct {
7776
// +kubebuilder:default:=true
7877
AutomaticCasing bool `json:"automaticCasing"`
7978

80-
// ValidateRequests enables request validation against the service schema.
81-
// +kubebuilder:default:=true
82-
ValidateRequests bool `json:"validateRequests"`
83-
84-
// RewriteGroupToDataLayers merges group layers into individual data layers.
85-
// +kubebuilder:default:=false
86-
RewriteGroupToDataLayers bool `json:"rewriteGroupToDataLayers"`
87-
88-
// DisableWebserviceProxy disables the built-in proxy for external web services.
89-
// +kubebuilder:default:=false
90-
DisableWebserviceProxy bool `json:"disableWebserviceProxy"`
91-
9279
// Whether to prefetch data from blob storage, and store it on the local filesystem.
9380
// If `false`, the data will be served directly out of blob storage
9481
// +kubebuilder:default:=true
9582
PrefetchData bool `json:"prefetchData"`
83+
}
9684

97-
// ValidateChildStyleNameEqual ensures child style names match the parent style.
98-
// +kubebuilder:default=false
99-
ValidateChildStyleNameEqual bool `json:"validateChildStyleNameEqual"`
85+
// Options configures optional behaviors of the operator, like ingress, casing, and data prefetching.
86+
// +kubebuilder:validation:Type=object
87+
type Options struct {
88+
BaseOptions `json:",inline"`
89+
WMSOptions `json:",inline"`
10090
}
10191

10292
func GetDefaultOptions() *Options {
10393
return &Options{
104-
IncludeIngress: true,
105-
AutomaticCasing: true,
106-
ValidateRequests: true,
107-
RewriteGroupToDataLayers: false,
108-
DisableWebserviceProxy: false,
109-
PrefetchData: true,
110-
ValidateChildStyleNameEqual: false,
94+
BaseOptions: BaseOptions{
95+
IncludeIngress: true,
96+
AutomaticCasing: true,
97+
PrefetchData: true,
98+
},
99+
WMSOptions: WMSOptions{
100+
ValidateRequests: true,
101+
RewriteGroupToDataLayers: false,
102+
DisableWebserviceProxy: false,
103+
ValidateChildStyleNameEqual: false,
104+
},
111105
}
112106
}
113107

108+
// BaseService holds all shared Services field for all apis
109+
type BaseService struct {
110+
// Geonovum subdomein
111+
// +kubebuilder:validation:MinLength:=1
112+
Prefix string `json:"prefix"`
113+
114+
// URL of the service
115+
URL smoothoperatormodel.URL `json:"url"`
116+
117+
// External Mapfile reference
118+
Mapfile *Mapfile `json:"mapfile,omitempty"`
119+
120+
// Reference to OwnerInfo CR
121+
// +kubebuilder:validation:MinLength:=1
122+
OwnerInfoRef string `json:"ownerInfoRef"`
123+
124+
// Service title
125+
// +kubebuilder:validation:MinLength:=1
126+
Title string `json:"title"`
127+
128+
// Service abstract
129+
// +kubebuilder:validation:MinLength:=1
130+
Abstract string `json:"abstract"`
131+
132+
// Keywords for capabilities
133+
// +kubebuilder:validation:MinItems:=1
134+
// +kubebuilder:validation:items:MinLength:=1
135+
Keywords []string `json:"keywords"`
136+
137+
// Optional Fees
138+
// +kubebuilder:validation:MinLength:=1
139+
Fees *string `json:"fees,omitempty"`
140+
141+
// AccessConstraints URL
142+
// +kubebuilder:default="https://creativecommons.org/publicdomain/zero/1.0/deed.nl"
143+
AccessConstraints smoothoperatormodel.URL `json:"accessConstraints,omitempty"`
144+
}
145+
114146
// Inspire holds INSPIRE-specific metadata for the service.
115147
// +kubebuilder:validation:Type=object
116148
type Inspire struct {
117149
// ServiceMetadataURL references the CSW or custom metadata record.
118150
// +kubebuilder:validation:Type=object
119151
ServiceMetadataURL MetadataURL `json:"serviceMetadataUrl"`
120152

121-
// SpatialDatasetIdentifier is the ID uniquely identifying the dataset.
122-
// +kubebuilder:validation:Pattern:=`^[0-9a-zA-Z]{8}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{12}$`
123-
SpatialDatasetIdentifier string `json:"spatialDatasetIdentifier"`
124-
125153
// Language of the INSPIRE metadata record
126154
// +kubebuilder:validation:Pattern:=`bul|cze|dan|dut|eng|est|fin|fre|ger|gre|hun|gle|ita|lav|lit|mlt|pol|por|rum|slo|slv|spa|swe`
127155
Language string `json:"language"`
@@ -196,7 +224,6 @@ type Postgis struct {
196224

197225
// GeometryType of the table
198226
// +kubebuilder:validation:Pattern=`^(Multi)?(Point|LineString|Polygon)$`
199-
// +kubebuilder:validation:MinLength:=1
200227
GeometryType string `json:"geometryType"`
201228

202229
// Columns to expose from table

api/v3/wfs_types.go

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ type WFSSpec struct {
8282
PodSpecPatch corev1.PodSpec `json:"podSpecPatch"`
8383
HorizontalPodAutoscalerPatch *HorizontalPodAutoscalerPatch `json:"horizontalPodAutoscalerPatch,omitempty"`
8484
// TODO omitting the options field or setting an empty value results in incorrect defaulting of the options
85-
Options *Options `json:"options,omitempty"`
85+
// Options configures optional behaviors of the operator, like ingress, casing, and data prefetching.
86+
Options *BaseOptions `json:"options,omitempty"`
8687

8788
// Custom healthcheck options
8889
HealthCheck *HealthCheckWFS `json:"healthCheck,omitempty"`
@@ -97,43 +98,10 @@ type WFSSpec struct {
9798

9899
// +kubebuilder:validation:XValidation:message="otherCrs can't contain the defaultCrs",rule="!has(self.otherCrs) || (has(self.otherCrs) && !(self.defaultCrs in self.otherCrs))",fieldPath=".otherCrs"
99100
type WFSService struct {
100-
// Geonovum subdomein
101-
// +kubebuilder:validation:MinLength:=1
102-
Prefix string `json:"prefix"`
103-
104-
// URL of the service
105-
URL smoothoperatormodel.URL `json:"url"`
106-
107-
// Config for Inspire services
108-
Inspire *Inspire `json:"inspire,omitempty"`
109-
110-
// External Mapfile reference
111-
Mapfile *Mapfile `json:"mapfile,omitempty"`
112-
113-
// Reference to OwnerInfo CR
114-
// +kubebuilder:validation:MinLength:=1
115-
OwnerInfoRef string `json:"ownerInfoRef"`
116-
117-
// Service title
118-
// +kubebuilder:validation:MinLength:=1
119-
Title string `json:"title"`
120-
121-
// Service abstract
122-
// +kubebuilder:validation:MinLength:=1
123-
Abstract string `json:"abstract"`
124-
125-
// Keywords for capabilities
126-
// +kubebuilder:validation:MinItems:=1
127-
// +kubebuilder:validation:items:MinLength:=1
128-
Keywords []string `json:"keywords"`
129-
130-
// Optional Fees
131-
// +kubebuilder:validation:MinLength:=1
132-
Fees *string `json:"fees,omitempty"`
101+
BaseService `json:",inline"`
133102

134-
// AccessConstraints URL
135-
// +kubebuilder:default="https://creativecommons.org/publicdomain/zero/1.0/deed.nl"
136-
AccessConstraints smoothoperatormodel.URL `json:"accessConstraints,omitempty"`
103+
// Inspire holds INSPIRE-specific metadata for the service.
104+
Inspire *WFSInspire `json:"inspire,omitempty"`
137105

138106
// Default CRS (DataEPSG)
139107
// +kubebuilder:validation:Pattern:="^EPSG:(28992|25831|25832|3034|3035|3857|4258|4326)$"
@@ -175,6 +143,13 @@ type HealthCheckWFS struct {
175143
Mimetype string `json:"mimetype"`
176144
}
177145

146+
type WFSInspire struct {
147+
Inspire `json:",inline"`
148+
// SpatialDatasetIdentifier is the ID uniquely identifying the dataset.
149+
// +kubebuilder:validation:Pattern:=`^[0-9a-zA-Z]{8}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{12}$`
150+
SpatialDatasetIdentifier string `json:"spatialDatasetIdentifier"`
151+
}
152+
178153
type Bbox struct {
179154
// EXTENT/wfs_extent in mapfile
180155
//nolint:tagliatelle
@@ -240,7 +215,7 @@ func (wfs *WFS) GroupKind() schema.GroupKind {
240215
return schema.GroupKind{Group: GroupVersion.Group, Kind: wfs.Kind}
241216
}
242217

243-
func (wfs *WFS) Inspire() *Inspire {
218+
func (wfs *WFS) Inspire() *WFSInspire {
244219
return wfs.Spec.Service.Inspire
245220
}
246221

@@ -276,7 +251,7 @@ func (wfs *WFS) Options() Options {
276251
return *GetDefaultOptions()
277252
}
278253

279-
return *wfs.Spec.Options
254+
return Options{BaseOptions: *wfs.Spec.Options}
280255
}
281256

282257
func (wfs *WFS) URL() smoothoperatormodel.URL {

0 commit comments

Comments
 (0)