Skip to content

Commit dbf24c1

Browse files
authored
Merge pull request #25 from PDOK/do/openapi-v3
WFS/shared_types crd validation kubebuilder markers added
2 parents 93f9b29 + 5fbbf68 commit dbf24c1

File tree

4 files changed

+354
-50
lines changed

4 files changed

+354
-50
lines changed

api/v3/shared_types.go

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
ServiceTypeWFS ServiceType = "WFS"
2323
)
2424

25+
// WMSWFS is the common interface used for both WMS and WFS resources.
2526
// +kubebuilder:object:generate=false
2627
type WMSWFS interface {
2728
*WFS | *WMS
@@ -35,86 +36,177 @@ type WMSWFS interface {
3536
HasPostgisData() bool
3637
// Sha1 hash of the objects name
3738
ID() string
39+
// URLPath returns the configured service URL
3840
URLPath() string
3941

4042
GeoPackages() []*Gpkg
4143
}
4244

45+
// Mapfile references a ConfigMap key where an external mapfile is stored.
46+
// +kubebuilder:validation:Type=object
4347
type Mapfile struct {
48+
// +kubebuilder:validation:Type=object
4449
ConfigMapKeyRef corev1.ConfigMapKeySelector `json:"configMapKeyRef"`
4550
}
4651

52+
// Options configures optional behaviors of the operator, like ingress, casing, and data prefetching.
53+
// +kubebuilder:validation:Type=object
4754
type Options struct {
55+
// IncludeIngress dictates whether to deploy an Ingress or ensure none exists.
4856
// +kubebuilder:default:=true
4957
IncludeIngress bool `json:"includeIngress"`
5058

59+
// AutomaticCasing enables automatic conversion from snake_case to camelCase.
5160
// +kubebuilder:default:=true
5261
AutomaticCasing bool `json:"automaticCasing"`
5362

63+
// ValidateRequests enables request validation against the service schema.
5464
// +kubebuilder:default:=true
5565
ValidateRequests *bool `json:"validateRequests,omitempty"`
5666

67+
// RewriteGroupToDataLayers merges group layers into individual data layers.
5768
// +kubebuilder:default:=false
5869
RewriteGroupToDataLayers *bool `json:"rewriteGroupToDataLayers,omitempty"`
5970

71+
// DisableWebserviceProxy disables the built-in proxy for external web services.
6072
// +kubebuilder:default:=false
6173
DisableWebserviceProxy *bool `json:"disableWebserviceProxy,omitempty"`
6274

75+
// Whether to prefetch data from blob storage, and store it on the local filesystem.
76+
// If `false`, the data will be served directly out of blob storage
6377
// +kubebuilder:default:=true
6478
PrefetchData *bool `json:"prefetchData,omitempty"`
6579

80+
// ValidateChildStyleNameEqual ensures child style names match the parent style.
81+
// +kubebuilder:default=false
6682
ValidateChildStyleNameEqual *bool `json:"validateChildStyleNameEqual,omitempty"`
6783
}
6884

85+
// Inspire holds INSPIRE-specific metadata for the service.
86+
// +kubebuilder:validation:Type=object
6987
type Inspire struct {
70-
ServiceMetadataURL MetadataURL `json:"serviceMetadataUrl"`
71-
SpatialDatasetIdentifier string `json:"spatialDatasetIdentifier"`
72-
Language string `json:"language"`
88+
// ServiceMetadataURL references the CSW or custom metadata record.
89+
// +kubebuilder:validation:Type=object
90+
ServiceMetadataURL MetadataURL `json:"serviceMetadataUrl"`
91+
92+
// SpatialDatasetIdentifier is the ID uniquely identifying the dataset.
93+
// +kubebuilder:validation:MinLength:=1
94+
SpatialDatasetIdentifier string `json:"spatialDatasetIdentifier"`
95+
96+
// Language of the INSPIRE metadata record
97+
// +kubebuilder:validation:MinLength:=1
98+
Language string `json:"language"`
7399
}
74100

75101
type MetadataURL struct {
76-
CSW *Metadata `json:"csw"`
77-
Custom *Custom `json:"custom,omitempty"`
102+
// CSW describes a metadata record via a metadataIdentifier (UUID).
103+
CSW *Metadata `json:"csw"`
104+
105+
// Custom allows arbitrary href
106+
Custom *Custom `json:"custom,omitempty"`
78107
}
79108

109+
// Metadata holds the UUID of a CSW metadata record
80110
type Metadata struct {
111+
// MetadataIdentifier is the record's UUID
112+
// +kubebuilder:validation:Format:=uuid
113+
// +kubebuilder:validation:MinLength:=1
81114
MetadataIdentifier string `json:"metadataIdentifier"`
82115
}
83116

117+
// Custom represents a non-CSW metadata link with a href and MIME type.
118+
// +kubebuilder:validation:Type=object
84119
type Custom struct {
120+
// +kubebuilder:validation:Pattern=`^https?://.*$`
121+
// +kubebuilder:validation:MinLength=1
85122
Href string `json:"href"`
123+
124+
// MIME type of the custom link
125+
// +kubebuilder:validation:MinLength=1
86126
Type string `json:"type"`
87127
}
88128

129+
// Data holds the data source configuration
130+
// +kubebuilder:validation:XValidation:rule="has(self.gpkg) || has(self.tif) || has(self.postgis)", message="Atleast one of the datasource should be provided (postgis, gpkg, tif)"
89131
type Data struct {
90-
Gpkg *Gpkg `json:"gpkg,omitempty"`
132+
// Gpkg configures a GeoPackage file source
133+
Gpkg *Gpkg `json:"gpkg,omitempty"`
134+
135+
// Postgis configures a Postgis table source
91136
Postgis *Postgis `json:"postgis,omitempty"`
92-
TIF *TIF `json:"tif,omitempty"`
137+
138+
// TIF configures a GeoTIF raster source
139+
TIF *TIF `json:"tif,omitempty"`
93140
}
94141

142+
// Gpkg configures a Geopackage data source
143+
// +kubebuilder:validation:Type=object
95144
type Gpkg struct {
96-
BlobKey string `json:"blobKey"`
97-
TableName string `json:"tableName"`
98-
GeometryType string `json:"geometryType"`
99-
Columns []Column `json:"columns"`
145+
// Blobkey identifies the location/bucket of the .gpkg file
146+
// +kubebuilder:validation:Pattern=`\.gpkg$`
147+
// +kubebuilder:validation:MinLength:=1
148+
BlobKey string `json:"blobKey"`
149+
150+
// TableName is the table within the geopackage
151+
// +kubebuilder:validation:MinLength:=1
152+
TableName string `json:"tableName"`
153+
154+
// GeometryType of the table, must match an OGC type
155+
// +kubebuilder:validation:Pattern:=`^(Multi)?(Point|LineString|Polygon)$`
156+
// +kubebuilder:validation:MinLength:=1
157+
GeometryType string `json:"geometryType"`
158+
159+
// Columns to visualize for this table
160+
// +kubebuilder:validation:MinItems:=1
161+
Columns []Column `json:"columns"`
100162
}
101163

102164
// Postgis - reference to table in a Postgres database
165+
// +kubebuilder:validation:Type=object
103166
type Postgis struct {
104-
TableName string `json:"tableName"`
105-
GeometryType string `json:"geometryType"`
106-
Columns []Column `json:"columns"`
167+
// TableName in postGIS
168+
// +kubebuilder:validation:MinLength=1
169+
TableName string `json:"tableName"`
170+
171+
// GeometryType of the table
172+
// +kubebuilder:validation:Pattern=`^(Multi)?(Point|LineString|Polygon)$`
173+
// +kubebuilder:validation:MinLength:=1
174+
GeometryType string `json:"geometryType"`
175+
176+
// Columns to expose from table
177+
// +kubebuilder:validation:MinItems=1
178+
Columns []Column `json:"columns"`
107179
}
108180

181+
// TIF configures a GeoTIFF raster data source
182+
// +kubebuilder:validation:Type=object
109183
type TIF struct {
110-
BlobKey string `json:"blobKey"`
111-
Resample *string `json:"resample,omitempty"`
112-
Offsite *string `json:"offsite,omitempty"`
113-
GetFeatureInfoIncludesClass *bool `json:"getFeatureInfoIncludesClass,omitempty"`
184+
// BlobKey to the TIFF file
185+
// +kubebuilder:validation:Pattern=`\.(tif|tiff)$`
186+
// +kubebuilder:validation:MinLength:=1
187+
BlobKey string `json:"blobKey"`
188+
189+
// Resample method
190+
// +kubebuilder:validation:MinLength:=1
191+
Resample *string `json:"resample,omitempty"`
192+
193+
// Offsite color for nodata removal
194+
// +kubebuilder:validation:MinLength:=1
195+
Offsite *string `json:"offsite,omitempty"`
196+
197+
// Include class names in GetFeatureInfo responses
198+
GetFeatureInfoIncludesClass *bool `json:"getFeatureInfoIncludesClass,omitempty"`
114199
}
115200

201+
// Column maps a source column name to an optional alias for output.
202+
// +kubebuilder:validation:Type=object
116203
type Column struct {
117-
Name string `json:"name"`
204+
// Name of the column in the data source.
205+
// +kubebuilder:validation:MinLength=1
206+
Name string `json:"name"`
207+
208+
// Alias for the column in the service output.
209+
// +kubebuilder:validation:MinLength=1
118210
Alias *string `json:"alias,omitempty"`
119211
}
120212

api/v3/wfs_types.go

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,59 +66,134 @@ func init() {
6666

6767
// WFSSpec vertegenwoordigt de hoofdstruct voor de YAML-configuratie
6868
type WFSSpec struct {
69+
// Optional lifecycle settings
6970
Lifecycle *shared_model.Lifecycle `json:"lifecycle,omitempty"`
71+
7072
// +kubebuilder:validation:Type=object
7173
// +kubebuilder:validation:Schemaless
7274
// +kubebuilder:pruning:PreserveUnknownFields
7375
// Optional strategic merge patch for the pod in the deployment. E.g. to patch the resources or add extra env vars.
7476
PodSpecPatch *corev1.PodSpec `json:"podSpecPatch,omitempty"`
7577
HorizontalPodAutoscalerPatch *autoscalingv2.HorizontalPodAutoscalerSpec `json:"horizontalPodAutoscalerPatch,omitempty"`
7678
Options Options `json:"options,omitempty"`
77-
Service WFSService `json:"service"`
79+
80+
// service configuration
81+
Service WFSService `json:"service"`
7882
}
7983

8084
type WFSService struct {
8185
// Geonovum subdomein
8286
// +kubebuilder:validation:MinLength:=1
83-
Prefix string `json:"prefix"`
84-
URL string `json:"url"`
85-
Inspire *Inspire `json:"inspire,omitempty"`
86-
Mapfile *Mapfile `json:"mapfile,omitempty"`
87-
OwnerInfoRef string `json:"ownerInfoRef"`
88-
Title string `json:"title"`
89-
Abstract string `json:"abstract"`
90-
Keywords []string `json:"keywords"`
91-
Fees *string `json:"fees,omitempty"`
87+
Prefix string `json:"prefix"`
88+
89+
// URL of the service
90+
// +kubebuilder:validation:Pattern:=`^https?://.*$`
91+
// +kubebuilder:validation:MinLength:=1
92+
URL string `json:"url"`
93+
94+
// Config for Inspire services
95+
Inspire *Inspire `json:"inspire,omitempty"`
96+
97+
// External Mapfile reference
98+
Mapfile *Mapfile `json:"mapfile,omitempty"`
99+
100+
// Reference to OwnerInfo CR
101+
// +kubebuilder:validation:MinLength:=1
102+
OwnerInfoRef string `json:"ownerInfoRef"`
103+
104+
// Service title
105+
// +kubebuilder:validation:MinLength:=1
106+
Title string `json:"title"`
107+
108+
// Service abstract
109+
// +kubebuilder:validation:MinLength:=1
110+
Abstract string `json:"abstract"`
111+
112+
// Keywords for capabilities
113+
// +kubebuilder:validation:MinItems:=1
114+
Keywords []string `json:"keywords"`
115+
116+
// Optional Fees
117+
// +kubebuilder:validation:MinLength:=1
118+
Fees *string `json:"fees,omitempty"`
119+
120+
// AccessConstraints URL
121+
// +kubebuilder:validation:Pattern:="https?://"
92122
// +kubebuilder:default="https://creativecommons.org/publicdomain/zero/1.0/deed.nl"
93-
AccessConstraints string `json:"accessConstraints"`
94-
DefaultCrs string `json:"defaultCrs"`
95-
OtherCrs []string `json:"otherCrs,omitempty"`
96-
Bbox *Bbox `json:"bbox,omitempty"`
123+
// +kubebuilder:validation:MinLength:=1
124+
AccessConstraints string `json:"accessConstraints"`
125+
126+
// Default CRS (DataEPSG)
127+
// +kubebuilder:validation:Pattern:="^EPSG:(28992|25831|25832|3034|3035|3857|4258|4326)$"
128+
// +kubebuilder:validation:MinLength:=1
129+
DefaultCrs string `json:"defaultCrs"`
130+
131+
// Other supported CRS
132+
// +kubebuilder:validation:MinItems:=1
133+
OtherCrs []string `json:"otherCrs,omitempty"`
134+
135+
// Service bounding box
136+
Bbox *Bbox `json:"bbox,omitempty"`
137+
97138
// CountDefault -> wfs_maxfeatures in mapfile
98-
CountDefault *string `json:"countDefault,omitempty"`
139+
// +kubebuilder:validation:MinLength:=1
140+
CountDefault *string `json:"countDefault,omitempty"`
141+
142+
// FeatureTypes configurations
143+
// +kubebuilder:validation:MinItems:=1
144+
// +kubebuilder:validation:Type=array
99145
FeatureTypes []FeatureType `json:"featureTypes"`
100146
}
101147

102148
type Bbox struct {
103149
// EXTENT/wfs_extent in mapfile
104150
//nolint:tagliatelle
151+
// +kubebuilder:validation:Type=object
105152
DefaultCRS shared_model.BBox `json:"defaultCRS"`
106153
}
107154

155+
// FeatureType defines a WFS feature
108156
type FeatureType struct {
109-
Name string `json:"name"`
110-
Title string `json:"title"`
111-
Abstract string `json:"abstract"`
112-
Keywords []string `json:"keywords"`
113-
DatasetMetadataURL MetadataURL `json:"datasetMetadataUrl"`
114-
Bbox *FeatureBbox `json:"bbox,omitempty"`
115-
Data Data `json:"data"`
157+
// Name of the feature
158+
// +kubebuilder:validation:MinLength:=1
159+
Name string `json:"name"`
160+
161+
// Title of the feature
162+
// +kubebuilder:validation:MinLength:=1
163+
Title string `json:"title"`
164+
165+
// Abstract of the feature
166+
// +kubebuilder:validation:MinLength:=1
167+
Abstract string `json:"abstract"`
168+
169+
// Keywords of the feature
170+
// +kubebuilder:validation:MinItems:=1
171+
Keywords []string `json:"keywords"`
172+
173+
// Metadata URL
174+
// +kubebuilder:validation:Type=object
175+
DatasetMetadataURL MetadataURL `json:"datasetMetadataUrl"`
176+
177+
// Optional feature bbox
178+
// +kubebuilder:validation:Optional
179+
// +kubebuilder:validation:Type:=object
180+
Bbox *FeatureBbox `json:"bbox,omitempty"`
181+
182+
// FeatureType data connection
183+
// +kubebuilder:validation:Type=object
184+
Data Data `json:"data"`
116185
}
117186

187+
// FeatureType bounding box, if provided it overrides the default extent
118188
type FeatureBbox struct {
189+
// DefaultCRS defines the feature’s bounding box in the service’s own CRS
119190
//nolint:tagliatelle
120-
DefaultCRS shared_model.BBox `json:"defaultCRS"`
121-
WGS84 *shared_model.BBox `json:"wgs84,omitempty"`
191+
// +kubebuilder:validation:Type=object
192+
DefaultCRS shared_model.BBox `json:"defaultCRS"`
193+
194+
// WGS84, if provided, gives the same bounding box reprojected into EPSG:4326.
195+
// +kubebuilder:validation:Type=object
196+
WGS84 *shared_model.BBox `json:"wgs84,omitempty"`
122197
}
123198

124199
func (wfs *WFS) HasPostgisData() bool {

0 commit comments

Comments
 (0)