Skip to content

Commit 97098ec

Browse files
committed
Setup capabilities generator config
1 parent 8119171 commit 97098ec

File tree

9 files changed

+405
-130
lines changed

9 files changed

+405
-130
lines changed

cmd/main.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ import (
4646
)
4747

4848
const (
49-
defaultMultitoolImage = "docker.io/pdok/docker-multitool:0.9.1"
50-
defaultMapfileGeneratorImage = "docker.io/pdok/mapfile-generator:1.9.3"
49+
defaultMultitoolImage = "docker.io/pdok/docker-multitool:0.9.1"
50+
defaultMapfileGeneratorImage = "docker.io/pdok/mapfile-generator:1.9.3"
51+
defaultCapabilitiesGeneratorImage = "acrpdokprodman.azurecr.io/pdok/ogc-capabilities-generator:0.2.7"
5152
)
5253

5354
var (
@@ -76,6 +77,7 @@ func main() {
7677
var baseURL string
7778
var multitoolImage string
7879
var mapfileGeneratorImage string
80+
var capabilitiesGeneratorImage string
7981
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
8082
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
8183
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
@@ -96,6 +98,7 @@ func main() {
9698
flag.StringVar(&baseURL, "baseurl", "", "The base url which is used in the mapserver service.")
9799
flag.StringVar(&multitoolImage, "multitool-image", defaultMultitoolImage, "The image to use in the blob download init-container.")
98100
flag.StringVar(&mapfileGeneratorImage, "mapfile-generator-image", defaultMapfileGeneratorImage, "The image to use in the mapfile generator init-container.")
101+
flag.StringVar(&capabilitiesGeneratorImage, "capabilities-generator-image", defaultCapabilitiesGeneratorImage, "The image to use in the capabilities generator init-container.")
99102

100103
opts := zap.Options{
101104
Development: true,
@@ -232,10 +235,11 @@ func main() {
232235
os.Exit(1)
233236
}
234237
if err = (&controller.WFSReconciler{
235-
Client: mgr.GetClient(),
236-
Scheme: mgr.GetScheme(),
237-
MultitoolImage: multitoolImage,
238-
MapfileGeneratorImage: mapfileGeneratorImage,
238+
Client: mgr.GetClient(),
239+
Scheme: mgr.GetScheme(),
240+
MultitoolImage: multitoolImage,
241+
MapfileGeneratorImage: mapfileGeneratorImage,
242+
CapabilitiesGeneratorImage: capabilitiesGeneratorImage,
239243
}).SetupWithManager(mgr); err != nil {
240244
setupLog.Error(err, "unable to create controller", "controller", "WFS")
241245
os.Exit(1)

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
module github.com/pdok/mapserver-operator
22

3-
go 1.23.0
3+
go 1.24
4+
5+
toolchain go1.24.1
46

57
godebug default=go1.23
68

79
require (
810
github.com/onsi/ginkgo/v2 v2.21.0
911
github.com/onsi/gomega v1.35.1
12+
github.com/pdok/ogc-specifications v1.0.0-beta2
13+
github.com/pdok/smooth-operator v0.0.6
1014
k8s.io/api v0.32.0
1115
k8s.io/apimachinery v0.32.0
1216
k8s.io/client-go v0.32.0
1317
sigs.k8s.io/controller-runtime v0.20.0
1418
sigs.k8s.io/yaml v1.4.0
1519
)
1620

17-
require github.com/pdok/smooth-operator v0.0.6
18-
1921
require (
2022
cel.dev/expr v0.18.0 // indirect
2123
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM
9999
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
100100
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
101101
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
102+
github.com/pdok/ogc-specifications v1.0.0-beta2 h1:BSMd8HiABpKTQButuMaHDj9XKrisnd5ifL1/fM5AwyE=
103+
github.com/pdok/ogc-specifications v1.0.0-beta2/go.mod h1:rkrIwIBIUl4oyn3aMVtJLipDRtFHp3oa9dSu/MyDt1o=
102104
github.com/pdok/smooth-operator v0.0.6 h1:IwgY3X2zYA2XLw0eKmBBN1Md6gNWnoVl0i1R8/wFHvs=
103105
github.com/pdok/smooth-operator v0.0.6/go.mod h1:oZWFuIKJGjN/C6ocgMNfMZ7SbLQi+N0qaWj7j95Wdec=
104106
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -219,6 +221,7 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWM
219221
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
220222
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
221223
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
224+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
222225
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
223226
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
224227
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=

internal/controller/blobdownload/blob_download_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func TestGetArgsForWFS(t *testing.T) {
8282
Title: "wfs-prefetch-service-title",
8383
},
8484
Options: &v3.Options{
85-
PrefetchData: smoothoperatorutils.BoolPtr(true),
85+
PrefetchData: smoothoperatorutils.Pointer(true),
8686
},
8787
},
8888
},
@@ -99,7 +99,7 @@ func TestGetArgsForWFS(t *testing.T) {
9999
Title: "wfs-noprefetch-service-title",
100100
},
101101
Options: &v3.Options{
102-
PrefetchData: smoothoperatorutils.BoolPtr(false),
102+
PrefetchData: smoothoperatorutils.Pointer(false),
103103
},
104104
},
105105
},
@@ -205,7 +205,7 @@ func TestGetArgsForWMS(t *testing.T) {
205205
},
206206
},
207207
Options: &v3.Options{
208-
PrefetchData: smoothoperatorutils.BoolPtr(true),
208+
PrefetchData: smoothoperatorutils.Pointer(true),
209209
},
210210
},
211211
},
@@ -272,7 +272,7 @@ func TestGetArgsForWMS(t *testing.T) {
272272
},
273273
},
274274
Options: &v3.Options{
275-
PrefetchData: smoothoperatorutils.BoolPtr(true),
275+
PrefetchData: smoothoperatorutils.Pointer(true),
276276
},
277277
},
278278
},
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package capabilitiesgenerator
2+
3+
import (
4+
"encoding/xml"
5+
pdoknlv3 "github.com/pdok/mapserver-operator/api/v3"
6+
"github.com/pdok/mapserver-operator/internal/controller/mapperutils"
7+
"github.com/pdok/ogc-specifications/pkg/wfs200"
8+
"github.com/pdok/ogc-specifications/pkg/wsc110"
9+
smoothoperatorv1 "github.com/pdok/smooth-operator/api/v1"
10+
)
11+
12+
const (
13+
inspireSchemaLocations = "http://inspire.ec.europa.eu/schemas/inspire_dls/1.0 http://inspire.ec.europa.eu/schemas/inspire_dls/1.0/inspire_dls.xsd"
14+
capabilitiesFilename = "/var/www/config/capabilities_wfs_200.xml"
15+
)
16+
17+
func MapWFSToCapabilitiesGeneratorInput(wfs *pdoknlv3.WFS, ownerInfo *smoothoperatorv1.OwnerInfo) (Config, error) {
18+
config := Config{
19+
Global: Global{
20+
Namespace: mapperutils.GetNamespaceURI(wfs.Spec.Service.Prefix, ownerInfo),
21+
Prefix: wfs.Spec.Service.Prefix,
22+
OnlineResourceurl: pdoknlv3.GetBaseURL(),
23+
Path: mapperutils.GetPath(wfs),
24+
Version: *mapperutils.GetLabelValueByKey(wfs.ObjectMeta.Labels, "service-version"),
25+
},
26+
Services: Services{
27+
WFS200Config: WFS200Config{
28+
Filename: capabilitiesFilename,
29+
Wfs200: wfs200.GetCapabilitiesResponse{
30+
31+
ServiceProvider: wfs200.ServiceProvider{
32+
ProviderSite: struct {
33+
Type string `xml:"xlink:type,attr" yaml:"type"`
34+
Href string `xml:"xlink:href,attr" yaml:"href"`
35+
}(struct {
36+
Type string
37+
Href string
38+
}{
39+
Type: "simple",
40+
Href: pdoknlv3.GetBaseURL(),
41+
}),
42+
},
43+
ServiceIdentification: wfs200.ServiceIdentification{
44+
Title: mapperutils.EscapeQuotes(wfs.Spec.Service.Title),
45+
Abstract: mapperutils.EscapeQuotes(wfs.Spec.Service.Abstract),
46+
AccessConstraints: wfs.Spec.Service.AccessConstraints,
47+
Keywords: &wsc110.Keywords{
48+
Keyword: wfs.Spec.Service.Keywords,
49+
},
50+
},
51+
52+
Capabilities: wfs200.Capabilities{
53+
FeatureTypeList: getFeatureTypeList(wfs),
54+
},
55+
XMLName: xml.Name{},
56+
Namespaces: wfs200.Namespaces{ // TODO
57+
XmlnsGML: "",
58+
XmlnsWFS: "",
59+
XmlnsOWS: "",
60+
XmlnsXlink: "",
61+
XmlnsXSI: "",
62+
XmlnsFes: "",
63+
XmlnsInspireCommon: "",
64+
XmlnsInspireDls: "",
65+
XmlnsPrefix: "",
66+
Version: "",
67+
SchemaLocation: "",
68+
},
69+
},
70+
},
71+
},
72+
}
73+
74+
if wfs.Spec.Service.Inspire != nil {
75+
config.Global.AdditionalSchemaLocations = inspireSchemaLocations
76+
77+
// Todo set extended capabilities
78+
config.Services.WFS200Config.Wfs200.Capabilities.OperationsMetadata = wfs200.OperationsMetadata{}
79+
}
80+
81+
return config, nil
82+
}
83+
84+
func getFeatureTypeList(wfs *pdoknlv3.WFS) (typeList wfs200.FeatureTypeList) {
85+
typeList.FeatureType = []wfs200.FeatureType{}
86+
87+
for _, fType := range wfs.Spec.Service.FeatureTypes {
88+
featureType := wfs200.FeatureType{
89+
Name: wfs.Spec.Service.Prefix + fType.Name,
90+
Title: mapperutils.EscapeQuotes(fType.Title),
91+
Abstract: mapperutils.EscapeQuotes(fType.Abstract),
92+
DefaultCRS: &wfs200.CRS{Namespace: "", Code: 1}, // Todo
93+
OtherCRS: &[]wfs200.CRS{ // Todo
94+
{Namespace: "", Code: 2},
95+
},
96+
}
97+
typeList.FeatureType = append(typeList.FeatureType, featureType)
98+
}
99+
return
100+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// TODO Replace this by using the ogc-capabilities-generator from Github
2+
3+
package capabilitiesgenerator
4+
5+
import (
6+
"github.com/pdok/ogc-specifications/pkg/wcs201"
7+
"github.com/pdok/ogc-specifications/pkg/wfs200"
8+
"github.com/pdok/ogc-specifications/pkg/wms130"
9+
"github.com/pdok/ogc-specifications/pkg/wmts100"
10+
)
11+
12+
// Config is the base struct for the config yaml
13+
type Config struct {
14+
Global Global `yaml:"global"`
15+
Services Services `yaml:"services"`
16+
}
17+
18+
// Global contains a collection of base var that are globally usable for the generation of the capabilities
19+
type Global struct {
20+
Prefix string `yaml:"prefix"`
21+
Namespace string `yaml:"namespace"`
22+
OnlineResourceurl string `yaml:"onlineResourceUrl"`
23+
Path string `yaml:"path"`
24+
Version string `yaml:"version"`
25+
AdditionalSchemaLocations string `yaml:"additionalSchemaLocations"`
26+
Empty string
27+
}
28+
29+
// Services contain a single service struct for every service type
30+
type Services struct {
31+
WFS200Config WFS200Config `yaml:"wfs200"`
32+
WMS130Config WMS130Config `yaml:"wms130"`
33+
WMTS100Config WMTS100Config `yaml:"wmts100"`
34+
WCS201Config WCS201Config `yaml:"wcs201"`
35+
}
36+
37+
// The WFS200Config service struct
38+
type WFS200Config struct {
39+
Filename string `yaml:"filename"`
40+
Wfs200 wfs200.GetCapabilitiesResponse `yaml:"definition"`
41+
}
42+
43+
// The WMS130Config service struct
44+
type WMS130Config struct {
45+
Filename string `yaml:"filename"`
46+
Wms130 wms130.GetCapabilitiesResponse `yaml:"definition"`
47+
}
48+
49+
// The WMTS100Config service struct
50+
type WMTS100Config struct {
51+
Filename string `yaml:"filename"`
52+
Wmts100 wmts100.GetCapabilitiesResponse `yaml:"definition"`
53+
}
54+
55+
// The WCS201Config service struct
56+
type WCS201Config struct {
57+
Filename string `yaml:"filename"`
58+
Wcs201 wcs201.GetCapabilitiesResponse `yaml:"definition"`
59+
}
Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package mapfilegenerator
22

33
import (
4-
"fmt"
54
pdoknlv3 "github.com/pdok/mapserver-operator/api/v3"
5+
"github.com/pdok/mapserver-operator/internal/controller/mapperutils"
66
smoothoperatorv1 "github.com/pdok/smooth-operator/api/v1"
77
smoothoperatorutils "github.com/pdok/smooth-operator/pkg/util"
88
"strconv"
@@ -16,16 +16,16 @@ const (
1616

1717
func MapWFSToMapfileGeneratorInput(wfs *pdoknlv3.WFS, ownerInfo *smoothoperatorv1.OwnerInfo) (Input, error) {
1818
input := Input{
19-
Title: escapeQuotes(wfs.Spec.Service.Title),
20-
Abstract: escapeQuotes(wfs.Spec.Service.Abstract),
19+
Title: mapperutils.EscapeQuotes(wfs.Spec.Service.Title),
20+
Abstract: mapperutils.EscapeQuotes(wfs.Spec.Service.Abstract),
2121
Keywords: strings.Join(wfs.Spec.Service.Keywords, ","),
2222
AccessConstraints: wfs.Spec.Service.AccessConstraints,
2323
Extent: wfs.Spec.Service.Bbox.DefaultCRS.ToExtent(),
2424
WFSMaxFeatures: getMaxFeatures(wfs.Spec.Service.CountDefault),
2525
NamespacePrefix: wfs.Spec.Service.Prefix,
26-
NamespaceURI: getNamespaceURI(wfs.Spec.Service.Prefix, ownerInfo),
26+
NamespaceURI: mapperutils.GetNamespaceURI(wfs.Spec.Service.Prefix, ownerInfo),
2727
OnlineResource: pdoknlv3.GetBaseURL(),
28-
Path: getPath(wfs),
28+
Path: mapperutils.GetPath(wfs),
2929
MetadataId: wfs.Spec.Service.Inspire.ServiceMetadataURL.CSW.MetadataIdentifier,
3030
AutomaticCasing: wfs.Spec.Options.AutomaticCasing,
3131
DataEPSG: wfs.Spec.Service.DefaultCrs,
@@ -43,45 +43,12 @@ func getMaxFeatures(countDefault *string) string {
4343
return strconv.Itoa(defaultMaxFeatures)
4444
}
4545

46-
func getLabelValueByKey(labels map[string]string, key string) *string {
47-
for k, v := range labels {
48-
if k == key {
49-
return &v
50-
}
51-
}
52-
return nil
53-
}
54-
55-
func getNamespaceURI(prefix string, ownerInfo *smoothoperatorv1.OwnerInfo) string {
56-
return strings.ReplaceAll(ownerInfo.Spec.NamespaceTemplate, "{{prefix}}", prefix)
57-
}
58-
59-
func getPath(WFS *pdoknlv3.WFS) (path string) {
60-
// TODO make this generic for WMS
61-
webserviceType := "wfs"
62-
datasetOwner := getLabelValueByKey(WFS.ObjectMeta.Labels, "dataset-owner")
63-
dataset := getLabelValueByKey(WFS.ObjectMeta.Labels, "dataset")
64-
theme := getLabelValueByKey(WFS.ObjectMeta.Labels, "theme")
65-
serviceVersion := getLabelValueByKey(WFS.ObjectMeta.Labels, "service-version")
66-
67-
path = fmt.Sprintf("/%s/%s", *datasetOwner, *dataset)
68-
if theme != nil {
69-
path += "/" + *theme
70-
}
71-
path += "/" + webserviceType
72-
if serviceVersion != nil {
73-
path += "/" + *serviceVersion
74-
}
75-
76-
return path
77-
}
78-
7946
func getLayers(featureTypes []pdoknlv3.FeatureType) (layers []Layer) {
8047
for _, featureType := range featureTypes {
8148
layer := Layer{
8249
Name: featureType.Name,
83-
Title: escapeQuotes(featureType.Title),
84-
Abstract: escapeQuotes(featureType.Abstract),
50+
Title: mapperutils.EscapeQuotes(featureType.Title),
51+
Abstract: mapperutils.EscapeQuotes(featureType.Abstract),
8552
Keywords: strings.Join(featureType.Keywords, ","),
8653
Extent: featureType.Bbox.DefaultCRS.ToExtent(),
8754
MetadataId: featureType.DatasetMetadataURL.CSW.MetadataIdentifier,
@@ -116,7 +83,3 @@ func getGeopackagePath(featureType pdoknlv3.FeatureType) *string {
11683
blobName := featureType.Data.Gpkg.BlobKey[index:]
11784
return smoothoperatorutils.Pointer(geopackagePath + "/" + blobName)
11885
}
119-
120-
func escapeQuotes(s string) string {
121-
return strings.ReplaceAll(s, "\"", "\\\"")
122-
}

0 commit comments

Comments
 (0)