From 6d431b0338d0d400a5102c41a01786de63119d3c Mon Sep 17 00:00:00 2001 From: Florian Sandel <108098144+fsandel@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:07:12 +0200 Subject: [PATCH] feat: add service account authirosation and replace swagger with sdk (#37) * replace stackit dns client with stackit sdk * fix zone and repository tests * fix data races * linter * add new cnofig alteration for sa key path * fix linting * add unit tests for sa key path * fix test cases that changed each other due to global variable/env manipulation * make test cases parallel and add authetication config * solve race condition by allocating more memory * add sa in config * make relevant test cases parallel * add error casting in deleteRRSet * udpate readme and helm chart for new sa authentication * add error casting in deleteRRSet * fix linting --------- Co-authored-by: Patrick Koss --- .gitignore | 1 + README.md | 30 ++++- deploy/stackit/Chart.yaml | 2 +- deploy/stackit/templates/deployment.yaml | 14 ++ deploy/stackit/values.yaml | 6 + go.mod | 9 +- go.sum | 29 ++-- internal/repository/config.go | 2 + internal/repository/dns_client.go | 43 ++++-- internal/repository/mock/rrset_repository.go | 30 +++-- internal/repository/mock/zone_repository.go | 20 ++- internal/repository/rrset_repository.go | 112 ++++++++-------- internal/repository/rrset_repositry_test.go | 134 ++++++++++--------- internal/repository/zone_repository.go | 40 +++--- internal/repository/zone_repository_test.go | 9 +- internal/resolver/config.go | 1 + internal/resolver/config_test.go | 57 +++++++- internal/resolver/mock/config.go | 7 +- internal/resolver/mock/secrets.go | 7 +- internal/resolver/resolver.go | 97 +++++++++----- internal/resolver/resolver_test.go | 55 +++++--- 21 files changed, 461 insertions(+), 244 deletions(-) diff --git a/.gitignore b/.gitignore index e0d2a30..74e9c9c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ go.work out/ bin/ stackit-cert-manager-webhook-0.1.0.tgz +stackit-cert-manager-webhook-0.1.* index.yaml diff --git a/README.md b/README.md index 460fb82..0683710 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ACME Issuer with [cert-manager](https://cert-manager.io/docs/). ```bash helm install stackit-cert-manager-webhook \ --namespace cert-manager \ - https://github.com/stackitcloud/stackit-cert-manager-webhook/releases/download/v0.1.1/stackit-cert-manager-webhook-v0.1.1.tgz + https://github.com/stackitcloud/stackit-cert-manager-webhook/releases/download/v0.1.2/stackit-cert-manager-webhook-v0.1.2.tgz ``` ## Usage @@ -26,6 +26,34 @@ helm install stackit-cert-manager-webhook \ --namespace=cert-manager \ --from-literal=auth-token= ``` + Or alternatively we can utilize the STACKIT service account path authentication: + ``` + kubectl create secret generic stackit-sa-authentication -n cert-manager \ + --from-literal=sa.json='{ + "id": "4e1fe486-b463-4bcd-9210-288854268e34", + "publicKey": "-----BEGIN PUBLIC KEY-----\nPUBLIC_KEY\n-----END PUBLIC KEY-----", + "createdAt": "2024-04-02T13:12:17.678+00:00", + "validUntil": "2024-04-15T22:00:00.000+00:00", + "keyType": "USER_MANAGED", + "keyOrigin": "GENERATED", + "keyAlgorithm": "RSA_2048", + "active": true, + "credentials": { + "kid": "kid", + "iss": "iss", + "sub": "sub", + "aud": "aud", + "privateKey": "-----BEGIN PRIVATE KEY-----\nPRIVATE-KEY==\n-----END PRIVATE KEY-----" + } + }' + ``` + You now need to adjust the deployment via helm to use the secret: + ```bash + helm upgrade stackit-cert-manager-webhook \ + --namespace cert-manager \ + https://github.com/stackitcloud/stackit-cert-manager-webhook/releases/download/v0.1.2/stackit-cert-manager-webhook-v0.1.2.tgz \ + --set stackitSaAuthentication.enabled=true + ``` 2. ***Configuration of ClusterIssuer/Issuer:*** For scenarios wherein zones and record sets are encapsulated within a singular project, utilize a ClusterIssuer: diff --git a/deploy/stackit/Chart.yaml b/deploy/stackit/Chart.yaml index d3adc87..da7bfc7 100644 --- a/deploy/stackit/Chart.yaml +++ b/deploy/stackit/Chart.yaml @@ -2,4 +2,4 @@ apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: stackit-cert-manager-webhook -version: 0.1.0 +version: 0.1.2 diff --git a/deploy/stackit/templates/deployment.yaml b/deploy/stackit/templates/deployment.yaml index 0a084b5..64094e0 100644 --- a/deploy/stackit/templates/deployment.yaml +++ b/deploy/stackit/templates/deployment.yaml @@ -32,6 +32,10 @@ spec: env: - name: GROUP_NAME value: {{ .Values.groupName | quote }} + {{- if .Values.stackitSaAuthentication.enabled }} + - name: STACKIT_SERVICE_ACCOUNT_KEY_PATH + value: "{{ .Values.stackitSaAuthentication.mountPath}}/{{ .Values.stackitSaAuthentication.fileName}}" + {{- end }} ports: - name: https containerPort: 8443 @@ -54,12 +58,22 @@ spec: - name: certs mountPath: /tls readOnly: true + {{- if .Values.stackitSaAuthentication.enabled }} + - name: stackit-sa-authentication + mountPath: {{ .Values.stackitSaAuthentication.mountPath }} + readOnly: true + {{- end }} resources: {{ toYaml .Values.resources | indent 12 }} volumes: - name: certs secret: secretName: {{ include "stackit-cert-manager-webhook.servingCertificate" . }} + {{- if .Values.stackitSaAuthentication.enabled }} + - name: stackit-sa-authentication + secret: + secretName: {{ .Values.stackitSaAuthentication.secretName }} + {{- end }} {{- with .Values.podSecurityContext }} securityContext: {{ toYaml . | indent 8 }} diff --git a/deploy/stackit/values.yaml b/deploy/stackit/values.yaml index 5fbe89a..1238a68 100644 --- a/deploy/stackit/values.yaml +++ b/deploy/stackit/values.yaml @@ -22,6 +22,12 @@ image: nameOverride: "" fullnameOverride: "" +stackitSaAuthentication: + enabled: false + secretName: stackit-sa-authentication + fileName: sa.json + mountPath: /var/run/secrets/stackit + service: type: ClusterIP port: 443 diff --git a/go.mod b/go.mod index 06e5ef9..dc17776 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,10 @@ module github.com/stackitcloud/stackit-cert-manager-webhook go 1.21 require ( - github.com/antihax/optional v1.0.0 github.com/cert-manager/cert-manager v1.11.0 github.com/stackitcloud/stackit-dns-api-client-go v0.0.0-20240207124424-bdfd0c2f7009 + github.com/stackitcloud/stackit-sdk-go/core v0.10.0 + github.com/stackitcloud/stackit-sdk-go/services/dns v0.8.4 github.com/stretchr/testify v1.9.0 go.uber.org/mock v0.4.0 go.uber.org/zap v1.27.0 @@ -18,6 +19,7 @@ require ( require ( cloud.google.com/go/compute v1.7.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect + github.com/antihax/optional v1.0.0 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -37,13 +39,14 @@ require ( github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/cel-go v0.12.5 // indirect github.com/google/gnostic v0.6.9 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/imdario/mergo v0.3.12 // indirect diff --git a/go.sum b/go.sum index c068a9d..117a239 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,6 @@ github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwc github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -170,6 +168,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -228,8 +228,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -253,8 +253,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -384,6 +384,10 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stackitcloud/stackit-dns-api-client-go v0.0.0-20240207124424-bdfd0c2f7009 h1:/Ek2Z8ROQ+Id4HwyAcJkh1gCr63MRhd4vobCeEOsE0Q= github.com/stackitcloud/stackit-dns-api-client-go v0.0.0-20240207124424-bdfd0c2f7009/go.mod h1:gLPXU0qBgy+kT0XTzg3e+FBoE+V9i6rTGzDvfGXD2Ew= +github.com/stackitcloud/stackit-sdk-go/core v0.10.0 h1:IcY8xa/6wo8EhRE9mpCvz4EtTkkoiIa2ZwPHuc5zGyw= +github.com/stackitcloud/stackit-sdk-go/core v0.10.0/go.mod h1:B5dkVm2HlBRG7liBVIFNqncDb6TUHnJ7t0GsKhAFuRk= +github.com/stackitcloud/stackit-sdk-go/services/dns v0.8.4 h1:n/X2pVdETDXGHk+vCsg0p3b2zGxSRMJ065to/aAoncg= +github.com/stackitcloud/stackit-sdk-go/services/dns v0.8.4/go.mod h1:PvgUVFLgELRADWk2epZdCryk0fs8b4DN47ghEJjNWhk= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -394,8 +398,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= @@ -455,18 +457,14 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= -go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -512,8 +510,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/internal/repository/config.go b/internal/repository/config.go index 57f4154..a1dea1e 100644 --- a/internal/repository/config.go +++ b/internal/repository/config.go @@ -7,4 +7,6 @@ type Config struct { AuthToken string ProjectId string HttpClient *http.Client + SaKeyPath string + UseSaKey bool } diff --git a/internal/repository/dns_client.go b/internal/repository/dns_client.go index 39bf2ea..2ee140b 100644 --- a/internal/repository/dns_client.go +++ b/internal/repository/dns_client.go @@ -1,18 +1,41 @@ package repository import ( - "fmt" - - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" + stackitconfig "github.com/stackitcloud/stackit-sdk-go/core/config" + stackitdnsclient "github.com/stackitcloud/stackit-sdk-go/services/dns" ) func newStackitDnsClient( - config Config, -) *stackitdnsclient.APIClient { - configClient := stackitdnsclient.NewConfiguration() - configClient.DefaultHeader["Authorization"] = fmt.Sprintf("Bearer %s", config.AuthToken) - configClient.BasePath = config.ApiBasePath - configClient.HTTPClient = config.HttpClient + stackitConfig ...stackitconfig.ConfigurationOption, +) (*stackitdnsclient.APIClient, error) { + return stackitdnsclient.NewAPIClient(stackitConfig...) +} + +func newStackitDnsClientBearerToken(config Config) (*stackitdnsclient.APIClient, error) { + httpClient := *config.HttpClient + + return newStackitDnsClient( + stackitconfig.WithToken(config.AuthToken), + stackitconfig.WithHTTPClient(&httpClient), + stackitconfig.WithEndpoint(config.ApiBasePath), + ) +} + +func newStackitDnsClientKeyPath(config Config) (*stackitdnsclient.APIClient, error) { + httpClient := *config.HttpClient + + return newStackitDnsClient( + stackitconfig.WithServiceAccountKeyPath(config.SaKeyPath), + stackitconfig.WithHTTPClient(&httpClient), + stackitconfig.WithEndpoint(config.ApiBasePath), + ) +} - return stackitdnsclient.NewAPIClient(configClient) +func chooseNewStackitDnsClient(config Config) (*stackitdnsclient.APIClient, error) { + switch { + case config.UseSaKey: + return newStackitDnsClientKeyPath(config) + default: + return newStackitDnsClientBearerToken(config) + } } diff --git a/internal/repository/mock/rrset_repository.go b/internal/repository/mock/rrset_repository.go index 1158452..3998b8d 100644 --- a/internal/repository/mock/rrset_repository.go +++ b/internal/repository/mock/rrset_repository.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./rrset_repository.go +// +// Generated by this command: +// +// mockgen -destination=./mock/rrset_repository.go -source=./rrset_repository.go RRSetRepositoryFactory +// // Package mock_repository is a generated GoMock package. package mock_repository @@ -9,7 +14,7 @@ import ( reflect "reflect" repository "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository" - swagger "github.com/stackitcloud/stackit-dns-api-client-go" + dns "github.com/stackitcloud/stackit-sdk-go/services/dns" gomock "go.uber.org/mock/gomock" ) @@ -37,7 +42,7 @@ func (m *MockRRSetRepository) EXPECT() *MockRRSetRepositoryMockRecorder { } // CreateRRSet mocks base method. -func (m *MockRRSetRepository) CreateRRSet(ctx context.Context, rrSet swagger.RrsetRrSetPost) error { +func (m *MockRRSetRepository) CreateRRSet(ctx context.Context, rrSet dns.RecordSet) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateRRSet", ctx, rrSet) ret0, _ := ret[0].(error) @@ -45,7 +50,7 @@ func (m *MockRRSetRepository) CreateRRSet(ctx context.Context, rrSet swagger.Rrs } // CreateRRSet indicates an expected call of CreateRRSet. -func (mr *MockRRSetRepositoryMockRecorder) CreateRRSet(ctx, rrSet interface{}) *gomock.Call { +func (mr *MockRRSetRepositoryMockRecorder) CreateRRSet(ctx, rrSet any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRRSet", reflect.TypeOf((*MockRRSetRepository)(nil).CreateRRSet), ctx, rrSet) } @@ -59,28 +64,28 @@ func (m *MockRRSetRepository) DeleteRRSet(ctx context.Context, rrSetId string) e } // DeleteRRSet indicates an expected call of DeleteRRSet. -func (mr *MockRRSetRepositoryMockRecorder) DeleteRRSet(ctx, rrSetId interface{}) *gomock.Call { +func (mr *MockRRSetRepositoryMockRecorder) DeleteRRSet(ctx, rrSetId any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRRSet", reflect.TypeOf((*MockRRSetRepository)(nil).DeleteRRSet), ctx, rrSetId) } // FetchRRSetForZone mocks base method. -func (m *MockRRSetRepository) FetchRRSetForZone(ctx context.Context, rrSetName, rrSetType string) (*swagger.DomainRrSet, error) { +func (m *MockRRSetRepository) FetchRRSetForZone(ctx context.Context, rrSetName, rrSetType string) (*dns.RecordSet, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FetchRRSetForZone", ctx, rrSetName, rrSetType) - ret0, _ := ret[0].(*swagger.DomainRrSet) + ret0, _ := ret[0].(*dns.RecordSet) ret1, _ := ret[1].(error) return ret0, ret1 } // FetchRRSetForZone indicates an expected call of FetchRRSetForZone. -func (mr *MockRRSetRepositoryMockRecorder) FetchRRSetForZone(ctx, rrSetName, rrSetType interface{}) *gomock.Call { +func (mr *MockRRSetRepositoryMockRecorder) FetchRRSetForZone(ctx, rrSetName, rrSetType any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRRSetForZone", reflect.TypeOf((*MockRRSetRepository)(nil).FetchRRSetForZone), ctx, rrSetName, rrSetType) } // UpdateRRSet mocks base method. -func (m *MockRRSetRepository) UpdateRRSet(ctx context.Context, rrSet swagger.DomainRrSet) error { +func (m *MockRRSetRepository) UpdateRRSet(ctx context.Context, rrSet dns.RecordSet) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateRRSet", ctx, rrSet) ret0, _ := ret[0].(error) @@ -88,7 +93,7 @@ func (m *MockRRSetRepository) UpdateRRSet(ctx context.Context, rrSet swagger.Dom } // UpdateRRSet indicates an expected call of UpdateRRSet. -func (mr *MockRRSetRepositoryMockRecorder) UpdateRRSet(ctx, rrSet interface{}) *gomock.Call { +func (mr *MockRRSetRepositoryMockRecorder) UpdateRRSet(ctx, rrSet any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRRSet", reflect.TypeOf((*MockRRSetRepository)(nil).UpdateRRSet), ctx, rrSet) } @@ -117,15 +122,16 @@ func (m *MockRRSetRepositoryFactory) EXPECT() *MockRRSetRepositoryFactoryMockRec } // NewRRSetRepository mocks base method. -func (m *MockRRSetRepositoryFactory) NewRRSetRepository(config repository.Config, zoneId string) repository.RRSetRepository { +func (m *MockRRSetRepositoryFactory) NewRRSetRepository(config repository.Config, zoneId string) (repository.RRSetRepository, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewRRSetRepository", config, zoneId) ret0, _ := ret[0].(repository.RRSetRepository) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // NewRRSetRepository indicates an expected call of NewRRSetRepository. -func (mr *MockRRSetRepositoryFactoryMockRecorder) NewRRSetRepository(config, zoneId interface{}) *gomock.Call { +func (mr *MockRRSetRepositoryFactoryMockRecorder) NewRRSetRepository(config, zoneId any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewRRSetRepository", reflect.TypeOf((*MockRRSetRepositoryFactory)(nil).NewRRSetRepository), config, zoneId) } diff --git a/internal/repository/mock/zone_repository.go b/internal/repository/mock/zone_repository.go index 1cdb267..c7d31ff 100644 --- a/internal/repository/mock/zone_repository.go +++ b/internal/repository/mock/zone_repository.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./zone_repository.go +// +// Generated by this command: +// +// mockgen -destination=./mock/zone_repository.go -source=./zone_repository.go ZoneRepositoryFactory +// // Package mock_repository is a generated GoMock package. package mock_repository @@ -9,7 +14,7 @@ import ( reflect "reflect" repository "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository" - swagger "github.com/stackitcloud/stackit-dns-api-client-go" + dns "github.com/stackitcloud/stackit-sdk-go/services/dns" gomock "go.uber.org/mock/gomock" ) @@ -37,16 +42,16 @@ func (m *MockZoneRepository) EXPECT() *MockZoneRepositoryMockRecorder { } // FetchZone mocks base method. -func (m *MockZoneRepository) FetchZone(ctx context.Context, zoneDnsName string) (*swagger.DomainZone, error) { +func (m *MockZoneRepository) FetchZone(ctx context.Context, zoneDnsName string) (*dns.Zone, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FetchZone", ctx, zoneDnsName) - ret0, _ := ret[0].(*swagger.DomainZone) + ret0, _ := ret[0].(*dns.Zone) ret1, _ := ret[1].(error) return ret0, ret1 } // FetchZone indicates an expected call of FetchZone. -func (mr *MockZoneRepositoryMockRecorder) FetchZone(ctx, zoneDnsName interface{}) *gomock.Call { +func (mr *MockZoneRepositoryMockRecorder) FetchZone(ctx, zoneDnsName any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchZone", reflect.TypeOf((*MockZoneRepository)(nil).FetchZone), ctx, zoneDnsName) } @@ -75,15 +80,16 @@ func (m *MockZoneRepositoryFactory) EXPECT() *MockZoneRepositoryFactoryMockRecor } // NewZoneRepository mocks base method. -func (m *MockZoneRepositoryFactory) NewZoneRepository(config repository.Config) repository.ZoneRepository { +func (m *MockZoneRepositoryFactory) NewZoneRepository(config repository.Config) (repository.ZoneRepository, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewZoneRepository", config) ret0, _ := ret[0].(repository.ZoneRepository) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // NewZoneRepository indicates an expected call of NewZoneRepository. -func (mr *MockZoneRepositoryFactoryMockRecorder) NewZoneRepository(config interface{}) *gomock.Call { +func (mr *MockZoneRepositoryFactoryMockRecorder) NewZoneRepository(config any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewZoneRepository", reflect.TypeOf((*MockZoneRepositoryFactory)(nil).NewZoneRepository), config) } diff --git a/internal/repository/rrset_repository.go b/internal/repository/rrset_repository.go index 3113668..7a16c24 100644 --- a/internal/repository/rrset_repository.go +++ b/internal/repository/rrset_repository.go @@ -2,26 +2,29 @@ package repository import ( "context" + "errors" "fmt" - "strings" - "github.com/antihax/optional" - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" + stackitdnsclient "github.com/stackitcloud/stackit-sdk-go/services/dns" ) -var ErrRRSetNotFound = fmt.Errorf("rrset not found") +var ( + ErrRRSetNotFound = fmt.Errorf("rrset not found") + ErrEmptyRRSet = fmt.Errorf("empty rrset") +) //go:generate mockgen -destination=./mock/rrset_repository.go -source=./rrset_repository.go RRSetRepository type RRSetRepository interface { - FetchRRSetForZone(ctx context.Context, rrSetName string, rrSetType string) (*stackitdnsclient.DomainRrSet, error) - CreateRRSet(ctx context.Context, rrSet stackitdnsclient.RrsetRrSetPost) error - UpdateRRSet(ctx context.Context, rrSet stackitdnsclient.DomainRrSet) error + FetchRRSetForZone(ctx context.Context, rrSetName string, rrSetType string) (*stackitdnsclient.RecordSet, error) + CreateRRSet(ctx context.Context, rrSet stackitdnsclient.RecordSet) error + UpdateRRSet(ctx context.Context, rrSet stackitdnsclient.RecordSet) error DeleteRRSet(ctx context.Context, rrSetId string) error } //go:generate mockgen -destination=./mock/rrset_repository.go -source=./rrset_repository.go RRSetRepositoryFactory type RRSetRepositoryFactory interface { - NewRRSetRepository(config Config, zoneId string) RRSetRepository + NewRRSetRepository(config Config, zoneId string) (RRSetRepository, error) } type rrSetRepository struct { @@ -35,14 +38,17 @@ type rrSetRepositoryFactory struct{} func (r rrSetRepositoryFactory) NewRRSetRepository( config Config, zoneId string, -) RRSetRepository { - apiClient := newStackitDnsClient(config) +) (RRSetRepository, error) { + apiClient, err := chooseNewStackitDnsClient(config) + if err != nil { + return nil, err + } return &rrSetRepository{ apiClient: apiClient, projectId: config.ProjectId, zoneId: zoneId, - } + }, nil } func NewRRSetRepositoryFactory() RRSetRepositoryFactory { @@ -54,40 +60,45 @@ func (r *rrSetRepository) FetchRRSetForZone( ctx context.Context, rrSetName string, rrSetType string, -) (*stackitdnsclient.DomainRrSet, error) { - queryParams := stackitdnsclient.RecordSetApiV1ProjectsProjectIdZonesZoneIdRrsetsGetOpts{ - ActiveEq: optional.NewBool(true), - NameEq: optional.NewString(strings.ToLower(rrSetName)), - TypeEq: optional.NewString(rrSetType), - } +) (*stackitdnsclient.RecordSet, error) { + var pager int32 = 1 + listRequest := r.apiClient.ListRecordSets(ctx, r.projectId, r.zoneId). + Page(pager).PageSize(10000). + ActiveEq(true).NameEq(rrSetName).TypeEq(rrSetType) - rrSetResponse, _, err := r.apiClient.RecordSetApi.V1ProjectsProjectIdZonesZoneIdRrsetsGet( - ctx, - r.projectId, - r.zoneId, - &queryParams, - ) + rrSetResponse, err := listRequest.Execute() if err != nil { return nil, err } - if len(rrSetResponse.RrSets) == 0 { + if len(*rrSetResponse.RrSets) == 0 { return nil, ErrRRSetNotFound } - return &rrSetResponse.RrSets[0], nil + return &(*rrSetResponse.RrSets)[0], nil } func (r *rrSetRepository) CreateRRSet( ctx context.Context, - rrSet stackitdnsclient.RrsetRrSetPost, + rrSet stackitdnsclient.RecordSet, ) error { - _, _, err := r.apiClient.RecordSetApi.V1ProjectsProjectIdZonesZoneIdRrsetsPost( - ctx, - rrSet, - r.projectId, - r.zoneId, - ) + var records []stackitdnsclient.RecordPayload + if rrSet.Records != nil { + records = make([]stackitdnsclient.RecordPayload, len(*rrSet.Records)) + for i, record := range *rrSet.Records { + records[i] = stackitdnsclient.RecordPayload{ + Content: record.Content, + } + } + } + payload := stackitdnsclient.CreateRecordSetPayload{ + Comment: rrSet.Comment, + Name: rrSet.Name, + Ttl: rrSet.Ttl, + Type: rrSet.Type, + Records: &records, + } + _, err := r.apiClient.CreateRecordSet(ctx, r.projectId, r.zoneId).CreateRecordSetPayload(payload).Execute() if err != nil { return err } @@ -97,28 +108,23 @@ func (r *rrSetRepository) CreateRRSet( func (r *rrSetRepository) UpdateRRSet( ctx context.Context, - rrSet stackitdnsclient.DomainRrSet, + rrSet stackitdnsclient.RecordSet, ) error { - records := make([]stackitdnsclient.RrsetRecordPost, len(rrSet.Records)) - for i, record := range rrSet.Records { - records[i] = stackitdnsclient.RrsetRecordPost{ + records := make([]stackitdnsclient.RecordPayload, len(*rrSet.Records)) + for i, record := range *rrSet.Records { + records[i] = stackitdnsclient.RecordPayload{ Content: record.Content, } } - rrSetBody := stackitdnsclient.RrsetRrSetPatch{ + payload := stackitdnsclient.PartialUpdateRecordSetPayload{ Comment: rrSet.Comment, Name: rrSet.Name, - Records: records, + Records: &records, Ttl: rrSet.Ttl, } - _, _, err := r.apiClient.RecordSetApi.V1ProjectsProjectIdZonesZoneIdRrsetsRrSetIdPatch( - ctx, - rrSetBody, - r.projectId, - r.zoneId, - rrSet.Id, - ) + _, err := r.apiClient.PartialUpdateRecordSet(ctx, r.projectId, r.zoneId, *rrSet.Id). + PartialUpdateRecordSetPayload(payload).Execute() if err != nil { return err } @@ -127,15 +133,13 @@ func (r *rrSetRepository) UpdateRRSet( } func (r *rrSetRepository) DeleteRRSet(ctx context.Context, rrSetId string) error { - _, resp, err := r.apiClient.RecordSetApi.V1ProjectsProjectIdZonesZoneIdRrsetsRrSetIdDelete( - ctx, - r.projectId, - r.zoneId, - rrSetId, - ) - if resp != nil { - if resp.StatusCode == 404 || resp.StatusCode == 400 { - return ErrRRSetNotFound + _, err := r.apiClient.DeleteRecordSet(ctx, r.projectId, r.zoneId, rrSetId).Execute() + if err != nil { + var oapiError *oapierror.GenericOpenAPIError + if errors.As(err, &oapiError) { + if oapiError.StatusCode == 404 || oapiError.StatusCode == 400 { + return ErrRRSetNotFound + } } } diff --git a/internal/repository/rrset_repositry_test.go b/internal/repository/rrset_repositry_test.go index 548424f..55c14e9 100644 --- a/internal/repository/rrset_repositry_test.go +++ b/internal/repository/rrset_repositry_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository" - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" - "github.com/stretchr/testify/assert" + stackitdnsclient "github.com/stackitcloud/stackit-sdk-go/services/dns" + "github.com/stretchr/testify/require" ) const rrSetTypeTxt = "TXT" @@ -18,28 +18,28 @@ func TestRrSetRepository_FetchRRSetForZone(t *testing.T) { t.Run("FetchRRSetForZone success", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + require.NoError(t, err) rrSet, err := rrSetRepository.FetchRRSetForZone(ctx, "test.com.", rrSetTypeTxt) - assert.NoError(t, err) - assert.Equal(t, rrSet.Id, "1234") + require.NoError(t, err) + require.Equal(t, *rrSet.Id, "1234") }) t.Run("FetchRRSetForZone failure", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "5678") - _, err := rrSetRepository.FetchRRSetForZone(ctx, "test.com.", rrSetTypeTxt) - assert.Error(t, err) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "5678") + require.NoError(t, err) + _, err = rrSetRepository.FetchRRSetForZone(ctx, "test.com.", rrSetTypeTxt) + require.Error(t, err) }) t.Run("FetchRRSetForZone not found", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "9999") - _, err := rrSetRepository.FetchRRSetForZone(ctx, "test.com.", rrSetTypeTxt) - assert.Error(t, err) - assert.ErrorIs(t, err, repository.ErrRRSetNotFound) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "9999") + require.NoError(t, err) + _, err = rrSetRepository.FetchRRSetForZone(ctx, "test.com.", rrSetTypeTxt) + require.Error(t, err) + require.ErrorIs(t, err, repository.ErrRRSetNotFound) }) } @@ -50,18 +50,18 @@ func TestRrSetRepository_CreateRRSet(t *testing.T) { t.Run("CreateRRSet success", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "0000") - err := rrSetRepository.CreateRRSet(ctx, stackitdnsclient.RrsetRrSetPost{}) - assert.NoError(t, err) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "0000") + require.NoError(t, err) + err = rrSetRepository.CreateRRSet(ctx, stackitdnsclient.RecordSet{}) + require.NoError(t, err) }) t.Run("CreateRRSet failure", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1111") - err := rrSetRepository.CreateRRSet(ctx, stackitdnsclient.RrsetRrSetPost{}) - assert.Error(t, err) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1111") + require.NoError(t, err) + err = rrSetRepository.CreateRRSet(ctx, stackitdnsclient.RecordSet{}) + require.Error(t, err) }) } @@ -72,36 +72,48 @@ func TestRrSetRepository_UpdateRRSet(t *testing.T) { t.Run("UpdateRRSet success", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "2222") - err := rrSetRepository.UpdateRRSet( + comment := "comment1" + id := "0000" + name := "test.com." + ttl := int64(60) + content := "content1" + + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "2222") + require.NoError(t, err) + err = rrSetRepository.UpdateRRSet( ctx, - stackitdnsclient.DomainRrSet{ - Comment: "test", - Id: "0000", - Name: "test.com.", - Ttl: 60, - Records: []stackitdnsclient.DomainRecord{{Content: "test"}}, + stackitdnsclient.RecordSet{ + Comment: &comment, + Id: &id, + Name: &name, + Ttl: &ttl, + Records: &[]stackitdnsclient.Record{{Content: &content}}, }, ) - assert.NoError(t, err) + require.NoError(t, err) }) t.Run("UpdateRRSet failure", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "3333") - err := rrSetRepository.UpdateRRSet( + comment := "comment2" + id := "2222" + name := "test.com." + ttl := int64(60) + content := "content2" + + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "3333") + require.NoError(t, err) + err = rrSetRepository.UpdateRRSet( ctx, - stackitdnsclient.DomainRrSet{ - Comment: "test", - Id: "2222", - Name: "test.com.", - Ttl: 60, - Records: []stackitdnsclient.DomainRecord{{Content: "test"}}, + stackitdnsclient.RecordSet{ + Comment: &comment, + Id: &id, + Name: &name, + Ttl: &ttl, + Records: &[]stackitdnsclient.Record{{Content: &content}}, }, ) - assert.Error(t, err) + require.Error(t, err) }) } @@ -112,36 +124,36 @@ func TestRrSetRepository_DeleteRRSet(t *testing.T) { t.Run("DeleteRRSet success", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") - err := rrSetRepository.DeleteRRSet(ctx, "2222") - assert.NoError(t, err) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + require.NoError(t, err) + err = rrSetRepository.DeleteRRSet(ctx, "2222") + require.NoError(t, err) }) t.Run("DeleteRRSet failure", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") - err := rrSetRepository.DeleteRRSet(ctx, "3333") - assert.Error(t, err) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + require.NoError(t, err) + err = rrSetRepository.DeleteRRSet(ctx, "3333") + require.Error(t, err) }) t.Run("DeleteRRSet 400 return", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") - err := rrSetRepository.DeleteRRSet(ctx, "4444") - assert.Error(t, err) - assert.ErrorIs(t, err, repository.ErrRRSetNotFound) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + require.NoError(t, err) + err = rrSetRepository.DeleteRRSet(ctx, "4444") + require.Error(t, err) + require.ErrorIs(t, err, repository.ErrRRSetNotFound) }) t.Run("DeleteRRSet 404 return", func(t *testing.T) { t.Parallel() - - rrSetRepository := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") - err := rrSetRepository.DeleteRRSet(ctx, "5555") - assert.Error(t, err) - assert.ErrorIs(t, err, repository.ErrRRSetNotFound) + rrSetRepository, err := rrSetRepositoryFactory.NewRRSetRepository(config, "1234") + require.NoError(t, err) + err = rrSetRepository.DeleteRRSet(ctx, "5555") + require.Error(t, err) + require.ErrorIs(t, err, repository.ErrRRSetNotFound) }) } diff --git a/internal/repository/zone_repository.go b/internal/repository/zone_repository.go index f8176d1..9dd6e4e 100644 --- a/internal/repository/zone_repository.go +++ b/internal/repository/zone_repository.go @@ -5,20 +5,20 @@ import ( "fmt" "strings" - "github.com/antihax/optional" - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" + stackitconfig "github.com/stackitcloud/stackit-sdk-go/core/config" + stackitdnsclient "github.com/stackitcloud/stackit-sdk-go/services/dns" ) var ErrZoneNotFound = fmt.Errorf("zone not found") //go:generate mockgen -destination=./mock/zone_repository.go -source=./zone_repository.go ZoneRepository type ZoneRepository interface { - FetchZone(ctx context.Context, zoneDnsName string) (*stackitdnsclient.DomainZone, error) + FetchZone(ctx context.Context, zoneDnsName string) (*stackitdnsclient.Zone, error) } //go:generate mockgen -destination=./mock/zone_repository.go -source=./zone_repository.go ZoneRepositoryFactory type ZoneRepositoryFactory interface { - NewZoneRepository(config Config) ZoneRepository + NewZoneRepository(config Config) (ZoneRepository, error) } type zoneRepository struct { @@ -30,13 +30,22 @@ type zoneRepositoryFactory struct{} func (z zoneRepositoryFactory) NewZoneRepository( config Config, -) ZoneRepository { - apiClient := newStackitDnsClient(config) +) (ZoneRepository, error) { + httpClient := *config.HttpClient + + apiClient, err := newStackitDnsClient( + stackitconfig.WithToken(config.AuthToken), + stackitconfig.WithHTTPClient(&httpClient), + stackitconfig.WithEndpoint(config.ApiBasePath), + ) + if err != nil { + return nil, err + } return &zoneRepository{ apiClient: apiClient, projectId: config.ProjectId, - } + }, nil } func NewZoneRepositoryFactory() ZoneRepositoryFactory { @@ -46,24 +55,15 @@ func NewZoneRepositoryFactory() ZoneRepositoryFactory { func (z *zoneRepository) FetchZone( ctx context.Context, zoneDnsName string, -) (*stackitdnsclient.DomainZone, error) { - queryParams := stackitdnsclient.ZoneApiV1ProjectsProjectIdZonesGetOpts{ - ActiveEq: optional.NewBool(true), - DnsNameEq: optional.NewString(strings.ToLower(zoneDnsName)), - } - - zoneResponse, _, err := z.apiClient.ZoneApi.V1ProjectsProjectIdZonesGet( - ctx, - z.projectId, - &queryParams, - ) +) (*stackitdnsclient.Zone, error) { + zoneResponse, err := z.apiClient.ListZones(ctx, z.projectId).ActiveEq(true).DnsNameEq(strings.ToLower(zoneDnsName)).Execute() if err != nil { return nil, err } - if len(zoneResponse.Zones) == 0 { + if len(*zoneResponse.Zones) == 0 { return nil, ErrZoneNotFound } - return &zoneResponse.Zones[0], nil + return &(*zoneResponse.Zones)[0], nil } diff --git a/internal/repository/zone_repository_test.go b/internal/repository/zone_repository_test.go index 1854f78..0a562bc 100644 --- a/internal/repository/zone_repository_test.go +++ b/internal/repository/zone_repository_test.go @@ -6,6 +6,7 @@ import ( "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestZoneRepository_FetchZone(t *testing.T) { @@ -22,8 +23,10 @@ func TestZoneRepository_FetchZone(t *testing.T) { ProjectId: projectID, HttpClient: server.Client(), } + zoneRepository, err := repository.NewZoneRepositoryFactory().NewZoneRepository(config) + require.NoError(t, err) - return repository.NewZoneRepositoryFactory().NewZoneRepository(config) + return zoneRepository } testCases := []struct { @@ -40,9 +43,9 @@ func TestZoneRepository_FetchZone(t *testing.T) { for _, tc := range testCases { tc := tc + t.Run(tc.name, func(t *testing.T) { t.Parallel() - zoneRepository := createZoneRepo(tc.projectID) zone, err := zoneRepository.FetchZone(ctx, "test-zone") @@ -53,7 +56,7 @@ func TestZoneRepository_FetchZone(t *testing.T) { } } else { assert.NoError(t, err) - assert.Equal(t, tc.expectedID, zone.Id) + assert.Equal(t, tc.expectedID, *zone.Id) } }) } diff --git a/internal/resolver/config.go b/internal/resolver/config.go index f28ff86..01e3338 100644 --- a/internal/resolver/config.go +++ b/internal/resolver/config.go @@ -24,6 +24,7 @@ type StackitDnsProviderConfig struct { AuthTokenSecretRef string `json:"authTokenSecretRef"` AuthTokenSecretKey string `json:"authTokenSecretKey"` AuthTokenSecretNamespace string `json:"authTokenSecretNamespace"` + ServiceAccountKeyPath string `json:"serviceAccountKeyPath"` } func (d defaultConfigProvider) LoadConfig(cfgJSON *extapi.JSON) (StackitDnsProviderConfig, error) { diff --git a/internal/resolver/config_test.go b/internal/resolver/config_test.go index 209a238..c7f778e 100644 --- a/internal/resolver/config_test.go +++ b/internal/resolver/config_test.go @@ -1,12 +1,14 @@ package resolver import ( + "net/http" "os" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) func TestLoadConfig(t *testing.T) { @@ -134,3 +136,56 @@ func TestDefaultConfigProvider_LoadConfigNamespaceFile(t *testing.T) { assert.Contains(t, err.Error(), "failed to find the webhook pod namespace") }) } + +//nolint:paralleltest // changing env may lead to data races in parallel testing +func TestGetRepositoryConfig_WithSaKeyPath(t *testing.T) { + saKeyPath := "/path/to/sa/key" + + t.Setenv("STACKIT_SERVICE_ACCOUNT_KEY_PATH", saKeyPath) + defer func() { + t.Setenv("STACKIT_SERVICE_ACCOUNT_KEY_PATH", "") + }() + + r := &stackitDnsProviderResolver{ + httpClient: &http.Client{}, + } + + cfg := &StackitDnsProviderConfig{ + ApiBasePath: "https://api.stackit.cloud", + ProjectId: "test-project", + } + + config, err := r.getRepositoryConfig(cfg) + + require.NoError(t, err) + require.Equal(t, saKeyPath, config.SaKeyPath) + require.True(t, config.UseSaKey) +} + +//nolint:paralleltest // changing env may lead to data races in parallel testing +func TestGetRepositoryConfig_NoEnvSet(t *testing.T) { + oldAuthToken := stackitAuthToken + stackitAuthToken = "token" // global variable from resolver.go + + t.Setenv("STACKIT_SERVICE_ACCOUNT_KEY_PATH", "") + defer func() { + stackitAuthToken = oldAuthToken + }() + + s := NewSecretFetcher() + r := &stackitDnsProviderResolver{ + httpClient: &http.Client{}, + secretFetcher: s, + } + + cfg := &StackitDnsProviderConfig{ + ApiBasePath: "https://api.stackit.cloud", + ProjectId: "test-project", + } + + config, err := r.getRepositoryConfig(cfg) + + require.NoError(t, err) + require.False(t, config.UseSaKey) + require.Equal(t, stackitAuthToken, config.AuthToken) +} diff --git a/internal/resolver/mock/config.go b/internal/resolver/mock/config.go index e50ac4c..000cc07 100644 --- a/internal/resolver/mock/config.go +++ b/internal/resolver/mock/config.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./config.go +// +// Generated by this command: +// +// mockgen -destination=./mock/config.go -source=./config.go ConfigProvider +// // Package mock_resolver is a generated GoMock package. package mock_resolver @@ -45,7 +50,7 @@ func (m *MockConfigProvider) LoadConfig(cfgJSON *v1.JSON) (resolver.StackitDnsPr } // LoadConfig indicates an expected call of LoadConfig. -func (mr *MockConfigProviderMockRecorder) LoadConfig(cfgJSON interface{}) *gomock.Call { +func (mr *MockConfigProviderMockRecorder) LoadConfig(cfgJSON any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadConfig", reflect.TypeOf((*MockConfigProvider)(nil).LoadConfig), cfgJSON) } diff --git a/internal/resolver/mock/secrets.go b/internal/resolver/mock/secrets.go index 70b71fd..a414917 100644 --- a/internal/resolver/mock/secrets.go +++ b/internal/resolver/mock/secrets.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./secrets.go +// +// Generated by this command: +// +// mockgen -destination=./mock/secrets.go -source=./secrets.go SecretFetcher +// // Package mock_resolver is a generated GoMock package. package mock_resolver @@ -43,7 +48,7 @@ func (m *MockSecretFetcher) StringFromSecret(namespace, secretName, key string) } // StringFromSecret indicates an expected call of StringFromSecret. -func (mr *MockSecretFetcherMockRecorder) StringFromSecret(namespace, secretName, key interface{}) *gomock.Call { +func (mr *MockSecretFetcherMockRecorder) StringFromSecret(namespace, secretName, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StringFromSecret", reflect.TypeOf((*MockSecretFetcher)(nil).StringFromSecret), namespace, secretName, key) } diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index d18ea89..f54c9ca 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -10,7 +10,7 @@ import ( "github.com/cert-manager/cert-manager/pkg/acme/webhook" "github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository" - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" + stackitdnsclient "github.com/stackitcloud/stackit-sdk-go/services/dns" "go.uber.org/zap" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -135,53 +135,47 @@ func (s *stackitDnsProviderResolver) initializeResolverContext( return nil, "", err } - authToken, err := s.getAuthToken(&cfg) + config, err := s.getRepositoryConfig(&cfg) if err != nil { return nil, "", err } - config := s.getRepositoryConfig(cfg, authToken) - zoneDnsName, rrSetName := getZoneDnsNameAndRRSetName(ch) - zoneRepository := s.zoneRepositoryFactory.NewZoneRepository(config) + zoneRepository, err := s.zoneRepositoryFactory.NewZoneRepository(config) + if err != nil { + return nil, "", err + } zone, err := zoneRepository.FetchZone(s.ctx, zoneDnsName) if err != nil { return nil, "", err } - rrSetRepository := s.rrSetRepositoryFactory.NewRRSetRepository(config, zone.Id) - - return rrSetRepository, rrSetName, nil -} - -func (s *stackitDnsProviderResolver) getRepositoryConfig( - cfg StackitDnsProviderConfig, - authToken string, -) repository.Config { - config := repository.Config{ - ApiBasePath: cfg.ApiBasePath, - AuthToken: authToken, - ProjectId: cfg.ProjectId, - HttpClient: s.httpClient, + rrSetRepository, err := s.rrSetRepositoryFactory.NewRRSetRepository(config, *zone.Id) + if err != nil { + return nil, "", err } - return config + return rrSetRepository, rrSetName, nil } func (s *stackitDnsProviderResolver) createRRSet( repo repository.RRSetRepository, rrSetName, key string, ) error { - rrSet := stackitdnsclient.RrsetRrSetPost{ - Comment: "This record set is managed by stackit-cert-manager-webhook", - Name: rrSetName, - Records: []stackitdnsclient.RrsetRecordPost{ + comment := "This record set is managed by stackit-cert-manager-webhook" + ttl := int64(60) + rrSetType := typeTxtRecord + + rrSet := stackitdnsclient.RecordSet{ + Comment: &comment, + Name: &rrSetName, + Records: &[]stackitdnsclient.Record{ { - Content: key, + Content: &key, }, }, - Ttl: 60, - Type_: typeTxtRecord, + Ttl: &ttl, + Type: &rrSetType, } return repo.CreateRRSet(s.ctx, rrSet) @@ -205,6 +199,42 @@ func (s *stackitDnsProviderResolver) getAuthToken(cfg *StackitDnsProviderConfig) return token, nil } +// geSaKeyPath gets the Service Account Key Path from the environment. +func (s *stackitDnsProviderResolver) getSaKeyPath(cfg *StackitDnsProviderConfig) string { + if cfg.ServiceAccountKeyPath != "" { + return cfg.ServiceAccountKeyPath + } + + return os.Getenv("STACKIT_SERVICE_ACCOUNT_KEY_PATH") +} + +func (s *stackitDnsProviderResolver) checkUseSaAuthentication(cfg *StackitDnsProviderConfig) bool { + return s.getSaKeyPath(cfg) != "" +} + +func (s *stackitDnsProviderResolver) getRepositoryConfig(cfg *StackitDnsProviderConfig) (repository.Config, error) { + config := repository.Config{ + ApiBasePath: cfg.ApiBasePath, + ProjectId: cfg.ProjectId, + HttpClient: s.httpClient, + UseSaKey: false, + } + + switch { + case s.checkUseSaAuthentication(cfg): + config.SaKeyPath = s.getSaKeyPath(cfg) + config.UseSaKey = true + default: + authToken, err := s.getAuthToken(cfg) + if err != nil { + return repository.Config{}, err + } + config.AuthToken = authToken + } + + return config, nil +} + func getZoneDnsNameAndRRSetName(ch *v1alpha1.ChallengeRequest) (string, string) { // Remove trailing . from domain domain := strings.TrimSuffix(ch.ResolvedZone, ".") @@ -250,18 +280,21 @@ func (s *stackitDnsProviderResolver) handleFetchRRSetError(err error, rrSetName func (s *stackitDnsProviderResolver) deleteRRSet( rrSetRepository repository.RRSetRepository, - rrSet *stackitdnsclient.DomainRrSet, + rrSet *stackitdnsclient.RecordSet, rrSetName string, ) error { - err := rrSetRepository.DeleteRRSet(s.ctx, rrSet.Id) + if rrSet == nil { + return nil + } + err := rrSetRepository.DeleteRRSet(s.ctx, *rrSet.Id) if err != nil { - return s.handleDeleteRRSetError(err, rrSetName, rrSet.Id) + return s.handleDeleteRRSetError(err, rrSetName, *rrSet.Id) } s.logger.Info( "RRSet deleted", zap.String("rrSetName", rrSetName), - zap.String("rrSetId", rrSet.Id), + zap.String("rrSetId", *rrSet.Id), ) return nil @@ -314,7 +347,7 @@ func (s *stackitDnsProviderResolver) handleRRSetNotFound( func (s *stackitDnsProviderResolver) updateExistingRRSet( rrSetRepository repository.RRSetRepository, - rrSet *stackitdnsclient.DomainRrSet, + rrSet *stackitdnsclient.RecordSet, rrSetName string, ) error { s.logger.Info("RRSet found, updating RRSet", zap.String("rrSetName", rrSetName)) diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index be287f6..ebea25e 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -11,7 +11,7 @@ import ( repository_mock "github.com/stackitcloud/stackit-cert-manager-webhook/internal/repository/mock" "github.com/stackitcloud/stackit-cert-manager-webhook/internal/resolver" resolver_mock "github.com/stackitcloud/stackit-cert-manager-webhook/internal/resolver/mock" - stackitdnsclient "github.com/stackitcloud/stackit-dns-api-client-go" + stackitdnsclient_new "github.com/stackitcloud/stackit-sdk-go/services/dns" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "go.uber.org/mock/gomock" @@ -135,7 +135,7 @@ func (s *presentSuite) TestFailFetchZone() { Return("", nil) s.mockZoneRepositoryFactory.EXPECT(). NewZoneRepository(gomock.Any()). - Return(s.mockZoneRepository) + Return(s.mockZoneRepository, nil) s.mockZoneRepository.EXPECT(). FetchZone(gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("error fetching zone")) @@ -158,13 +158,13 @@ func (s *presentSuite) TestFailFetchRRSet() { Return("", nil) s.mockZoneRepositoryFactory.EXPECT(). NewZoneRepository(gomock.Any()). - Return(s.mockZoneRepository) + Return(s.mockZoneRepository, nil) s.mockZoneRepository.EXPECT(). FetchZone(gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainZone{Id: "test"}, nil) + Return(&stackitdnsclient_new.Zone{Id: toPtr("test")}, nil) s.mockRRSetRepositoryFactory.EXPECT(). NewRRSetRepository(gomock.Any(), gomock.Any()). - Return(s.mockRRSetRepository) + Return(s.mockRRSetRepository, nil) s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("error fetching rr set")) @@ -187,13 +187,13 @@ func (s *presentSuite) TestSuccessCreateRRSet() { Return("", nil) s.mockZoneRepositoryFactory.EXPECT(). NewZoneRepository(gomock.Any()). - Return(s.mockZoneRepository) + Return(s.mockZoneRepository, nil) s.mockZoneRepository.EXPECT(). FetchZone(gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainZone{Id: "test"}, nil) + Return(&stackitdnsclient_new.Zone{Id: toPtr("test")}, nil) s.mockRRSetRepositoryFactory.EXPECT(). NewRRSetRepository(gomock.Any(), gomock.Any()). - Return(s.mockRRSetRepository) + Return(s.mockRRSetRepository, nil) s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). Return(nil, repository.ErrRRSetNotFound) @@ -214,16 +214,16 @@ func (s *presentSuite) TestSuccessUpdateRRSet() { Return("", nil) s.mockZoneRepositoryFactory.EXPECT(). NewZoneRepository(gomock.Any()). - Return(s.mockZoneRepository) + Return(s.mockZoneRepository, nil) s.mockZoneRepository.EXPECT(). FetchZone(gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainZone{Id: "test"}, nil) + Return(&stackitdnsclient_new.Zone{Id: toPtr("test")}, nil) s.mockRRSetRepositoryFactory.EXPECT(). NewRRSetRepository(gomock.Any(), gomock.Any()). - Return(s.mockRRSetRepository) + Return(s.mockRRSetRepository, nil) s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainRrSet{}, nil) + Return(&stackitdnsclient_new.RecordSet{}, nil) s.mockRRSetRepository.EXPECT(). UpdateRRSet(gomock.Any(), gomock.Any()). Return(nil) @@ -254,13 +254,13 @@ func (s *cleanSuite) setupCommonMocks() { Return("", nil) s.mockZoneRepositoryFactory.EXPECT(). NewZoneRepository(gomock.Any()). - Return(s.mockZoneRepository) + Return(s.mockZoneRepository, nil) s.mockZoneRepository.EXPECT(). FetchZone(gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainZone{Id: "test"}, nil) + Return(&stackitdnsclient_new.Zone{Id: toPtr("test")}, nil) s.mockRRSetRepositoryFactory.EXPECT(). NewRRSetRepository(gomock.Any(), gomock.Any()). - Return(s.mockRRSetRepository) + Return(s.mockRRSetRepository, nil) } func (s *cleanSuite) TestFailFetchRRSet() { @@ -290,11 +290,14 @@ func (s *cleanSuite) TestFailFetchNoRRSet() { func (s *cleanSuite) TestFailDeleteNoRRSet() { s.setupCommonMocks() + rrset := stackitdnsclient_new.RecordSet{ + Id: toPtr("1234"), + } s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainRrSet{}, nil) + Return(&rrset, nil) s.mockRRSetRepository.EXPECT(). - DeleteRRSet(gomock.Any(), gomock.Any()). + DeleteRRSet(gomock.Any(), *rrset.Id). Return(repository.ErrRRSetNotFound) err := s.resolver.CleanUp(challengeRequest) @@ -303,11 +306,14 @@ func (s *cleanSuite) TestFailDeleteNoRRSet() { func (s *cleanSuite) TestFailDeleteRRSet() { s.setupCommonMocks() + rrset := stackitdnsclient_new.RecordSet{ + Id: toPtr("1234"), + } s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainRrSet{}, nil) + Return(&rrset, nil) s.mockRRSetRepository.EXPECT(). - DeleteRRSet(gomock.Any(), gomock.Any()). + DeleteRRSet(gomock.Any(), *rrset.Id). Return(fmt.Errorf("error deleting rr set")) err := s.resolver.CleanUp(challengeRequest) @@ -321,13 +327,20 @@ func (s *cleanSuite) TestFailDeleteRRSet() { func (s *cleanSuite) TestSuccessDeleteRRSet() { s.setupCommonMocks() + rrset := stackitdnsclient_new.RecordSet{ + Id: toPtr("1234"), + } s.mockRRSetRepository.EXPECT(). FetchRRSetForZone(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&stackitdnsclient.DomainRrSet{}, nil) + Return(&rrset, nil) s.mockRRSetRepository.EXPECT(). - DeleteRRSet(gomock.Any(), gomock.Any()). + DeleteRRSet(gomock.Any(), *rrset.Id). Return(nil) err := s.resolver.CleanUp(challengeRequest) s.NoError(err) } + +func toPtr(str string) *string { + return &str +}