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
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
lint:
name: Run on Ubuntu
name: Linting on Ubuntu
runs-on: ubuntu-latest
steps:
- name: Clone the code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
test-e2e:
name: Run on Ubuntu
name: End-2-End on Ubuntu
runs-on: ubuntu-latest
steps:
- name: Clone the code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
test:
name: Run on Ubuntu
name: Testing on Ubuntu
runs-on: ubuntu-latest
steps:
- name: Clone the code
Expand Down
1 change: 1 addition & 0 deletions api/v3/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type WMSWFS interface {
TypedName() string
Options() Options
HasPostgisData() bool
OwnerInfoRef() string

// URL returns the configured service URL
URL() smoothoperatormodel.URL
Expand Down
73 changes: 72 additions & 1 deletion api/v3/shared_validation.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
package v3

import (
"context"
"fmt"
"slices"

smoothoperatorv1 "github.com/pdok/smooth-operator/api/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
v1 "k8s.io/api/core/v1"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/validation/field"
)

func ValidateUpdate[W WMSWFS](newW, oldW W, validate func(W, *[]string, *field.ErrorList)) ([]string, error) {
func ValidateCreate[W WMSWFS](c client.Client, obj W, validate func(W, *[]string, *field.ErrorList)) ([]string, error) {
warnings := []string{}
allErrs := field.ErrorList{}

err := sharedValidation.ValidateLabelsOnCreate(obj.GetLabels())
if err != nil {
allErrs = append(allErrs, err)
}

err = sharedValidation.ValidateIngressRouteURLsContainsBaseURL(obj.IngressRouteURLs(false), obj.URL(), nil)
if err != nil {
allErrs = append(allErrs, err)
}

validate(obj, &warnings, &allErrs)
ValidateOwnerInfo(c, obj, &allErrs)

if len(allErrs) == 0 {
return warnings, nil
}

return warnings, apierrors.NewInvalid(
obj.GroupKind(),
obj.GetName(), allErrs)
}

func ValidateUpdate[W WMSWFS](c client.Client, newW, oldW W, validate func(W, *[]string, *field.ErrorList)) ([]string, error) {
warnings := []string{}
allErrs := field.ErrorList{}

Expand Down Expand Up @@ -47,6 +77,7 @@ func ValidateUpdate[W WMSWFS](newW, oldW W, validate func(W, *[]string, *field.E
}

validate(newW, &warnings, &allErrs)
ValidateOwnerInfo(c, newW, &allErrs)

if len(allErrs) == 0 {
return warnings, nil
Expand Down Expand Up @@ -137,3 +168,43 @@ func ValidateInspire[O WMSWFS](obj O, allErrs *field.ErrorList) {
}

}

func ValidateOwnerInfo[O WMSWFS](c client.Client, obj O, allErrs *field.ErrorList) {
ownerInfoRef := obj.OwnerInfoRef()
ownerInfo := &smoothoperatorv1.OwnerInfo{}
objectKey := client.ObjectKey{
Namespace: obj.GetNamespace(),
Name: ownerInfoRef,
}
ctx := context.Background()
err := c.Get(ctx, objectKey, ownerInfo)
fieldPath := field.NewPath("spec").Child("service").Child("ownerInfoRef")
if err != nil {
*allErrs = append(*allErrs, field.NotFound(fieldPath, ownerInfoRef))
return
}

if ownerInfo.Spec.NamespaceTemplate == nil {
*allErrs = append(*allErrs, field.Required(fieldPath, "spec.namespaceTemplate missing in "+ownerInfo.Name))
return
}

if ((obj.Inspire() != nil && obj.Inspire().ServiceMetadataURL.CSW != nil) ||
len(obj.DatasetMetadataIDs()) > 0) &&
(ownerInfo.Spec.MetadataUrls == nil || ownerInfo.Spec.MetadataUrls.CSW == nil) {
*allErrs = append(*allErrs, field.Required(fieldPath, "spec.metadataUrls.csw missing in "+ownerInfo.Name))
return
}

switch obj.Type() {
case ServiceTypeWFS:
if ownerInfo.Spec.WFS == nil {
*allErrs = append(*allErrs, field.Required(fieldPath, "spec.WFS missing in "+ownerInfo.Name))
}
case ServiceTypeWMS:
if ownerInfo.Spec.WMS == nil {
*allErrs = append(*allErrs, field.Required(fieldPath, "spec.WMS missing in "+ownerInfo.Name))
}
}

}
4 changes: 4 additions & 0 deletions api/v3/wfs_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,7 @@ func (wfs *WFS) IngressRouteURLs(includeServiceURLWhenEmpty bool) smoothoperator

return wfs.Spec.IngressRouteURLs
}

func (wfs *WFS) OwnerInfoRef() string {
return wfs.Spec.Service.OwnerInfoRef
}
33 changes: 6 additions & 27 deletions api/v3/wfs_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,19 @@ import (
"slices"
"strings"

"sigs.k8s.io/controller-runtime/pkg/client"

sharedValidation "github.com/pdok/smooth-operator/pkg/validation"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
)

func (wfs *WFS) ValidateCreate() ([]string, error) {
warnings := []string{}
allErrs := field.ErrorList{}

err := sharedValidation.ValidateLabelsOnCreate(wfs.Labels)
if err != nil {
allErrs = append(allErrs, err)
}

err = sharedValidation.ValidateIngressRouteURLsContainsBaseURL(wfs.Spec.IngressRouteURLs, wfs.URL(), nil)
if err != nil {
allErrs = append(allErrs, err)
}

ValidateWFS(wfs, &warnings, &allErrs)

if len(allErrs) == 0 {
return warnings, nil
}

return warnings, apierrors.NewInvalid(
schema.GroupKind{Group: "pdok.nl", Kind: "WFS"},
wfs.Name, allErrs)
func (wfs *WFS) ValidateCreate(c client.Client) ([]string, error) {
return ValidateCreate(c, wfs, ValidateWFS)
}

func (wfs *WFS) ValidateUpdate(wfsOld *WFS) ([]string, error) {
return ValidateUpdate(wfs, wfsOld, ValidateWFS)
func (wfs *WFS) ValidateUpdate(c client.Client, wfsOld *WFS) ([]string, error) {
return ValidateUpdate(c, wfs, wfsOld, ValidateWFS)
}

func ValidateWFS(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {
Expand Down
4 changes: 4 additions & 0 deletions api/v3/wms_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,3 +701,7 @@ func (wms *WMS) IngressRouteURLs(includeServiceURLWhenEmpty bool) smoothoperator

return wms.Spec.IngressRouteURLs
}

func (wms *WMS) OwnerInfoRef() string {
return wms.Spec.Service.OwnerInfoRef
}
33 changes: 6 additions & 27 deletions api/v3/wms_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,19 @@ import (
"maps"
"strings"

"sigs.k8s.io/controller-runtime/pkg/client"

sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/strings/slices"
)

func (wms *WMS) ValidateCreate() ([]string, error) {
warnings := []string{}
allErrs := field.ErrorList{}

err := sharedValidation.ValidateLabelsOnCreate(wms.Labels)
if err != nil {
allErrs = append(allErrs, err)
}

err = sharedValidation.ValidateIngressRouteURLsContainsBaseURL(wms.Spec.IngressRouteURLs, wms.URL(), nil)
if err != nil {
allErrs = append(allErrs, err)
}

ValidateWMS(wms, &warnings, &allErrs)

if len(allErrs) == 0 {
return warnings, nil
}

return warnings, apierrors.NewInvalid(
schema.GroupKind{Group: "pdok.nl", Kind: "WMS"},
wms.Name, allErrs)
func (wms *WMS) ValidateCreate(c client.Client) ([]string, error) {
return ValidateCreate(c, wms, ValidateWMS)
}

func (wms *WMS) ValidateUpdate(wmsOld *WMS) ([]string, error) {
return ValidateUpdate(wms, wmsOld, ValidateWMS)
func (wms *WMS) ValidateUpdate(c client.Client, wmsOld *WMS) ([]string, error) {
return ValidateUpdate(c, wms, wmsOld, ValidateWMS)
}

// TODO fix linting (cyclop,funlen)
Expand Down
7 changes: 5 additions & 2 deletions internal/controller/shared_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,16 +239,19 @@ func testMutates[R Reconciler, O pdoknlv3.WMSWFS](reconcilerFn func() R, resourc
Expect(err).NotTo(HaveOccurred())
Expect(owner.Name).Should(Equal("owner"))

Expect(k8sClient.Create(ctx, &owner)).To(Succeed())

var validationError error
switch any(resource).(type) {
case *pdoknlv3.WMS:
wms := any(resource).(*pdoknlv3.WMS)
_, validationError = wms.ValidateCreate()
_, validationError = wms.ValidateCreate(k8sClient)
case *pdoknlv3.WFS:
wfs := any(resource).(*pdoknlv3.WFS)
_, validationError = wfs.ValidateCreate()
_, validationError = wfs.ValidateCreate(k8sClient)
}
Expect(validationError).NotTo(HaveOccurred())
Expect(k8sClient.Delete(ctx, &owner)).To(Succeed())
})

configMapNames := types.HashedConfigMapNames{}
Expand Down
65 changes: 65 additions & 0 deletions internal/webhook/v3/shared_webhook.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package v3

import (
"context"
"encoding/json"
"errors"
"os"

smoothoperatorv1 "github.com/pdok/smooth-operator/api/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
k8stypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

pdoknlv3 "github.com/pdok/mapserver-operator/api/v3"
"sigs.k8s.io/yaml"
)
Expand All @@ -13,6 +19,65 @@ const (
samplesPath = "test_data/"
)

func readOwnerInfo(ownerInfo *smoothoperatorv1.OwnerInfo) error {
data, err := os.ReadFile(samplesPath + "ownerinfo.yaml")
if err != nil {
return err
}
err = yaml.UnmarshalStrict(data, ownerInfo)
if err != nil {
return err
}
return err
}

func createOwnerInfo(ctx context.Context, c client.Client, ownerInfo *smoothoperatorv1.OwnerInfo) error {
clusterOwner := &smoothoperatorv1.OwnerInfo{}
objectKeyOwner := k8stypes.NamespacedName{
Namespace: ownerInfo.GetNamespace(),
Name: ownerInfo.GetName(),
}

err := c.Get(ctx, objectKeyOwner, clusterOwner)
if client.IgnoreNotFound(err) != nil {
return err
}
if err != nil && apierrors.IsNotFound(err) {
resource := ownerInfo.DeepCopy()
err = c.Create(ctx, resource)
if err != nil {
return err
}
err = c.Get(ctx, objectKeyOwner, clusterOwner)
if err != nil {
return err
}
}
return nil
}

func updateOwnerInfo(ctx context.Context, c client.Client, ownerInfo *smoothoperatorv1.OwnerInfo) error {
clusterOwner := &smoothoperatorv1.OwnerInfo{}
objectKeyOwner := k8stypes.NamespacedName{
Namespace: ownerInfo.GetNamespace(),
Name: ownerInfo.GetName(),
}

err := c.Get(ctx, objectKeyOwner, clusterOwner)
if err != nil {
return err
}

ownerInfo.ResourceVersion = clusterOwner.ResourceVersion

err = c.Update(ctx, ownerInfo)
if err != nil {
return err
}

return nil
}

func getSampleFilename[W pdoknlv3.WMSWFS](webservice W) (string, error) {
switch any(webservice).(type) {
case *pdoknlv3.WFS:
Expand Down
33 changes: 33 additions & 0 deletions internal/webhook/v3/test_data/ownerinfo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: pdok.nl/v1
kind: OwnerInfo
metadata:
name: owner
namespace: default
spec:
metadataUrls:
csw:
hrefTemplate: "https://www.nationaalgeoregister.nl/geonetwork/srv/dut/csw?service=CSW&version=2.0.2&request=GetRecordById&outputschema=http://www.isotc211.org/2005/gmd&elementsetname=full&id={{identifier}}"
type: alternate
namespaceTemplate: "http://{{prefix}}.geonovum.nl"
wfs:
serviceprovider:
providername: PDOK
providersite:
type: simple
href: https://pdok.nl
wms:
contactinformation:
contactpersonprimary:
contactperson: KlantContactCenter PDOK
contactorganization: PDOK
contactposition: pointOfContact
contactaddress:
addresstype:
address:
city: Apeldoorn
stateorprovince:
postcode:
country: Netherlands
contactvoicetelephone:
contactfacsimiletelephone:
contactelectronicmailAddress: BeheerPDOK@kadaster.nl
1 change: 1 addition & 0 deletions internal/webhook/v3/test_data/v3_wfs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: pdok.nl/v3
kind: WFS
metadata:
name: sample
namespace: default
labels:
sample: sample
spec:
Expand Down
Loading
Loading