Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/v2beta1/shared_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func ConvertV2DataToV3(v2 Data) pdoknlv3.Data {
if v2.Tif != nil {
v3.TIF = &pdoknlv3.TIF{
BlobKey: v2.Tif.BlobKey,
Resample: v2.Tif.Resample,
Resample: *v2.Tif.Resample,
Offsite: v2.Tif.Offsite,
GetFeatureInfoIncludesClass: smoothoperatorutils.PointerVal(v2.Tif.GetFeatureInfoIncludesClass, false),
}
Expand Down Expand Up @@ -201,7 +201,7 @@ func ConvertV3DataToV2(v3 pdoknlv3.Data) Data {
v2.Tif = &Tif{
BlobKey: v3.TIF.BlobKey,
Offsite: v3.TIF.Offsite,
Resample: v3.TIF.Resample,
Resample: &v3.TIF.Resample,
GetFeatureInfoIncludesClass: &v3.TIF.GetFeatureInfoIncludesClass,
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/v2beta1/wfs_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func convertV2FeatureTypeToV3(src FeatureType) pdoknlv3.FeatureType {

if src.Extent != nil {
featureTypeV3.Bbox = &pdoknlv3.FeatureBbox{
DefaultCRS: smoothoperatormodel.ExtentToBBox(*src.Extent),
DefaultCRS: smoothoperatorutils.Pointer(smoothoperatormodel.ExtentToBBox(*src.Extent)),
}
}

Expand Down
9 changes: 2 additions & 7 deletions api/v3/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ type Data struct {
type Gpkg struct {
// Blobkey identifies the location/bucket of the .gpkg file
// +kubebuilder:validation:Pattern:=^.+\/.+\/.+\.gpkg$
// +kubebuilder:validation:MinLength:=1
BlobKey string `json:"blobKey"`

// TableName is the table within the geopackage
Expand All @@ -180,7 +179,6 @@ type Gpkg struct {

// GeometryType of the table, must match an OGC type
// +kubebuilder:validation:Pattern:=`^(Multi)?(Point|LineString|Polygon)$`
// +kubebuilder:validation:MinLength:=1
GeometryType string `json:"geometryType"`

// Columns to visualize for this table
Expand Down Expand Up @@ -209,18 +207,15 @@ type Postgis struct {
// +kubebuilder:validation:Type=object
type TIF struct {
// BlobKey to the TIFF file
// +kubebuilder:validation:Pattern=`\.(tif?f|vrt)$`
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern:=`^.+\/.+\/.+\.(tif?f|vrt)$`
BlobKey string `json:"blobKey"`

// This option can be used to control the resampling kernel used sampling raster images, optional
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern=`(NEAREST|AVERAGE|BILINEAR)`
// +kubebuilder:default=NEAREST
Resample *string `json:"resample,omitempty"`
Resample string `json:"resample,omitempty"`

// Sets the color index to treat as transparent for raster layers, optional, hex or rgb
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern=`(#[0-9A-F]{6}([0-9A-F]{2})?)|([0-9]{1,3}\s[0-9]{1,3}\s[0-9]{1,3})`
Offsite *string `json:"offsite,omitempty"`

Expand Down
8 changes: 8 additions & 0 deletions api/v3/shared_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,12 @@ func ValidateInspire[O WMSWFS](obj O, allErrs *field.ErrorList) {
}
}

if obj.Type() == ServiceTypeWFS && len(datasetIDs) > 1 {
*allErrs = append(*allErrs, field.Invalid(
field.NewPath("spec").Child("service").Child("featureTypes[*]").Child("datasetMetadataUrl").Child("csw").Child("metadataIdentifier"),
datasetIDs,
"when Inspire, all featureTypes need use the same datasetMetadataUrl.csw.metadataIdentifier",
))
}

}
12 changes: 5 additions & 7 deletions api/v3/wfs_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ type WFSService struct {

// Default CRS (DataEPSG)
// +kubebuilder:validation:Pattern:="^EPSG:(28992|25831|25832|3034|3035|3857|4258|4326)$"
// +kubebuilder:validation:MinLength:=1
DefaultCrs string `json:"defaultCrs"`

// Other supported CRS
Expand Down Expand Up @@ -169,7 +168,6 @@ func (s WFSService) KeywordsIncludingInspireKeyword() []string {

// HealthCheck is the struct with all fields to configure custom healthchecks
type HealthCheckWFS struct {
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:XValidation:rule="self.contains('Service=WFS')",message="a valid healthcheck contains 'Service=WFS'"
// +kubebuilder:validation:XValidation:rule="self.contains('Request=')",message="a valid healthcheck contains 'Request='"
Querystring string `json:"querystring"`
Expand All @@ -187,7 +185,7 @@ type Bbox struct {
// FeatureType defines a WFS feature
type FeatureType struct {
// Name of the feature
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern:=`^\S+$`
Name string `json:"name"`

// Title of the feature
Expand Down Expand Up @@ -217,14 +215,14 @@ type FeatureType struct {
Data Data `json:"data"`
}

// FeatureType bounding box, if provided it overrides the default extent
// FeatureBbox is the optional featureType bounding box, if provided it overrides the default extent
type FeatureBbox struct {
// DefaultCRS defines the feature’s bounding box in the service’s own CRS
// DefaultCRS defines the EXTENT/wfs_extent for the featureType for use in the mapfile
//nolint:tagliatelle
// +kubebuilder:validation:Type=object
DefaultCRS smoothoperatormodel.BBox `json:"defaultCRS"`
DefaultCRS *smoothoperatormodel.BBox `json:"defaultCRS,omitempty"`

// WGS84, if provided, gives the same bounding box reprojected into EPSG:4326.
// WGS84, if provided, gives the same bounding box reprojected into EPSG:4326 for use in the capabilities.
// +kubebuilder:validation:Type=object
WGS84 *smoothoperatormodel.BBox `json:"wgs84,omitempty"`
}
Expand Down
61 changes: 61 additions & 0 deletions api/v3/wfs_validation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v3

import (
"slices"
"strings"

sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
Expand Down Expand Up @@ -69,4 +70,64 @@ func ValidateWFS(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {

podSpecPatch := wfs.Spec.PodSpecPatch
ValidateEphemeralStorage(podSpecPatch, allErrs)

ValidateFeatureTypes(wfs, warnings, allErrs)
}

func ValidateFeatureTypes(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {
names := []string{}
path := field.NewPath("spec").Child("service").Child("featureTypes")
for index, featureType := range wfs.Spec.Service.FeatureTypes {
if slices.Contains(names, featureType.Name) {
*allErrs = append(*allErrs, field.Duplicate(
path.Index(index).Child("name"),
featureType.Name,
))
} else {
names = append(names, featureType.Name)
}

if wfs.Spec.Service.Mapfile != nil && featureType.Bbox != nil && featureType.Bbox.DefaultCRS != nil {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("bbox").Child("defaultCrs"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

if tif := featureType.Data.TIF; tif != nil {
if tif.Resample != "NEAREST" {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("resample"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

if tif.Offsite != nil {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("offsite"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

if tif.GetFeatureInfoIncludesClass {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("getFeatureInfoIncludesClass"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}
}

}
}
11 changes: 5 additions & 6 deletions api/v3/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const (
defaultMultitoolImage = "acrpdokprodman.azurecr.io/pdok/docker-multitool:0.9.4"
defaultMapfileGeneratorImage = "acrpdokprodman.azurecr.io/pdok/mapfile-generator:1.9.5"
defaultMapserverImage = "acrpdokprodman.azurecr.io/mirror/docker.io/pdok/mapserver:8.4.0-4-nl"
defaultCapabilitiesGeneratorImage = "acrpdokprodman.azurecr.io/mirror/docker.io/pdok/ogc-capabilities-generator:1.0.0-beta8"
defaultCapabilitiesGeneratorImage = "acrpdokprodman.azurecr.io/mirror/docker.io/pdok/ogc-capabilities-generator:1.0.0-beta9"
defaultFeatureinfoGeneratorImage = "acrpdokprodman.azurecr.io/mirror/docker.io/pdok/featureinfo-generator:1.4.0-beta1"
defaultOgcWebserviceProxyImage = "acrpdokprodman.azurecr.io/pdok/ogc-webservice-proxy:0.1.8"
defaultApacheExporterImage = "acrpdokprodman.azurecr.io/mirror/docker.io/lusotycoon/apache-exporter:v0.7.0"
Expand Down
Loading
Loading