From 80aa5f03a72215184b7aab223275419136d04597 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Tue, 4 Jul 2023 12:37:47 +0200 Subject: [PATCH] Allow customize route via spec.Override.Route Allows to customize the service route vie the `spec.Override.Route`. This allows e.g. to add custom labels, configure the route via annotations as in [1], or set TLS parameters. ~~~ apiVersion: keystone.openstack.org/v1beta1 kind: KeystoneAPI metadata: name: keystone namespace: openstack spec: ... override: routeOverride: metadata: annotations: haproxy.router.openshift.io/timeout: "60" labels: mylabel: boo ~~~ [1] https://docs.openshift.com/container-platform/4.13/networking/routes/route-configuration.html#nw-route-specific-annotations_route-configuration Jira: OSP-21715 --- .../keystone.openstack.org_keystoneapis.yaml | 199 ++++++++++++++++++ api/go.mod | 2 + api/go.sum | 4 +- api/v1beta1/keystoneapi_types.go | 11 + api/v1beta1/zz_generated.deepcopy.go | 22 ++ .../keystone.openstack.org_keystoneapis.yaml | 199 ++++++++++++++++++ controllers/keystoneapi_controller.go | 3 +- go.mod | 2 + go.sum | 4 +- 9 files changed, 441 insertions(+), 5 deletions(-) diff --git a/api/bases/keystone.openstack.org_keystoneapis.yaml b/api/bases/keystone.openstack.org_keystoneapis.yaml index 67698799d..5a2bddd30 100644 --- a/api/bases/keystone.openstack.org_keystoneapis.yaml +++ b/api/bases/keystone.openstack.org_keystoneapis.yaml @@ -158,6 +158,205 @@ spec: description: NodeSelector to target subset of worker nodes running this service type: object + override: + description: Override, provides the ability to override the generated + manifest of several child resources. + properties: + routeOverride: + description: Override configuration for the Route created to serve + traffic to the service + properties: + metadata: + description: EmbeddedLabelsAnnotations is an embedded subset + of the fields included in k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta. + Only labels and annotations are included. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. They + are not queryable and should be preserved when modifying + objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be + used to organize and categorize (scope and select) objects. + May match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels' + type: object + type: object + spec: + description: Spec defines the behavior of a Route. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + alternateBackends: + description: alternateBackends allows up to 3 additional + backends to be assigned to the route. Only the Service + kind is allowed, and it will be defaulted to Service. + Use the weight field in RouteTargetReference object + to specify relative preference. + items: + description: RouteTargetReference specifies the target + that resolve into endpoints. Only the 'Service' kind + is allowed. Use 'weight' field to emphasize one over + others. + properties: + kind: + description: The kind of target that the route is + referring to. Currently, only 'Service' is allowed + type: string + name: + description: name of the service/target that is + being referred to. e.g. name of the service + type: string + weight: + description: weight as an integer between 0 and + 256, default 1, that specifies the target's relative + weight against other target reference objects. + 0 suppresses requests to this backend. + format: int32 + type: integer + required: + - kind + - name + - weight + type: object + maxItems: 3 + type: array + host: + description: host is an alias/DNS that points to the service. + Optional. If not specified a route name will typically + be automatically chosen. Must follow DNS952 subdomain + conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + description: path that the router watches for, to route + traffic for to the service. Optional + pattern: ^/ + type: string + port: + description: If specified, the port to be used by the + router. Most routers will use all endpoints exposed + by the service by default - set this value to instruct + routers which port to use. + properties: + targetPort: + anyOf: + - type: integer + - type: string + description: The target port on pods selected by the + service this route points to. If this is a string, + it will be looked up as a named port in the target + endpoints port list. Required + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + description: "subdomain is a DNS subdomain that is requested + within the ingress controller's domain (as a subdomain). + If host is set this field is ignored. An ingress controller + may choose to ignore this suggested name, in which case + the controller will report the assigned name in the + status.ingress array or refuse to admit the route. If + this value is set and the server does not support this + field host will be populated automatically. Otherwise + host is left empty. The field may have multiple parts + separated by a dot, but not all ingress controllers + may honor the request. This field may not be changed + after creation except by a user with the update routes/custom-host + permission. \n Example: subdomain `frontend` automatically + receives the router subdomain `apps.mycluster.com` to + have a full hostname `frontend.apps.mycluster.com`." + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: The tls field provides the ability to configure + certificates and termination for the route. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: certificate provides certificate contents + type: string + destinationCACertificate: + description: destinationCACertificate provides the + contents of the ca certificate of the final destination. When + using reencrypt termination this file should be + provided in order to have routers use it for health + checks on the secure connection. If this field is + not specified, the router may provide its own destination + CA and perform hostname validation using the short + service name (service.namespace.svc), which allows + infrastructure generated certificates to automatically + verify. + type: string + insecureEdgeTerminationPolicy: + description: "insecureEdgeTerminationPolicy indicates + the desired behavior for insecure connections to + a route. While each router may make its own decisions + on which ports to expose, this is normally port + 80. \n * Allow - traffic is sent to the server on + the insecure port (default) * Disable - no traffic + is allowed on the insecure port. * Redirect - clients + are redirected to the secure port." + type: string + key: + description: key provides key file contents + type: string + termination: + description: termination indicates termination type. + type: string + required: + - termination + type: object + to: + description: to is an object the route should use as the + primary backend. Only the Service kind is allowed, and + it will be defaulted to Service. If the weight field + (0-256 default 100) is set to zero, no traffic will + be sent to this backend. + properties: + kind: + description: The kind of target that the route is + referring to. Currently, only 'Service' is allowed + type: string + name: + description: name of the service/target that is being + referred to. e.g. name of the service + type: string + weight: + description: weight as an integer between 0 and 256, + default 1, that specifies the target's relative + weight against other target reference objects. 0 + suppresses requests to this backend. + format: int32 + type: integer + required: + - kind + - name + - weight + type: object + wildcardPolicy: + default: None + description: Wildcard policy if any for the route. Currently + only 'Subdomain' or 'None' is allowed. + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object passwordSelectors: default: admin: AdminPassword diff --git a/api/go.mod b/api/go.mod index 5a549baeb..f3cc4f1a0 100644 --- a/api/go.mod +++ b/api/go.mod @@ -79,3 +79,5 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49 diff --git a/api/go.sum b/api/go.sum index cd6beae08..dfaf3fc57 100644 --- a/api/go.sum +++ b/api/go.sum @@ -232,8 +232,6 @@ github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs= github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= -github.com/openstack-k8s-operators/lib-common/modules/common v0.0.0-20230522113906-6f4206cbf317 h1:/PTeRcBjnLdwUf5iFeKRvOAgX2e7+HUNMx+2hKTzQgk= -github.com/openstack-k8s-operators/lib-common/modules/common v0.0.0-20230522113906-6f4206cbf317/go.mod h1:qO1YjgynYksN3GYFrIcrwvAwws22zCzYmn0kOYBn1/A= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.0.0-20230522113906-6f4206cbf317 h1:1gQSTk3ereXLrhb9BhqbYn5kKIemplc8tyzvonXyKGk= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.0.0-20230522113906-6f4206cbf317/go.mod h1:doFbVg0WhS++gy17cbP9/BrCySjCpuqKx7TbvmKPChY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -293,6 +291,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49 h1:GUdsPDKo8PdZAh94neUDo+gpU9HWYmQBVglnYSBtWok= +github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49/go.mod h1:fNpMKjraLivVIwdBgyLqXp3igvBF3UBFbhNKdFJ9yRc= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/api/v1beta1/keystoneapi_types.go b/api/v1beta1/keystoneapi_types.go index 9c36ce616..eae0964a5 100644 --- a/api/v1beta1/keystoneapi_types.go +++ b/api/v1beta1/keystoneapi_types.go @@ -21,6 +21,7 @@ import ( condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" + "github.com/openstack-k8s-operators/lib-common/modules/common/route" "github.com/openstack-k8s-operators/lib-common/modules/common/util" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -147,6 +148,16 @@ type KeystoneAPISpec struct { // +kubebuilder:validation:Optional // ExternalEndpoints, expose a VIP using a pre-created IPAddressPool ExternalEndpoints []MetalLBConfig `json:"externalEndpoints,omitempty"` + + // +kubebuilder:validation:Optional + // Override, provides the ability to override the generated manifest of several child resources. + Override KeystoneAPIOverrideSpec `json:"override,omitempty"` +} + +// KeystoneAPIOverrideSpec to override the generated manifest of several child resources. +type KeystoneAPIOverrideSpec struct { + // Override configuration for the Route created to serve traffic to the service + Route *route.OverrideSpec `json:"route,omitempty"` } // MetalLBConfig to configure the MetalLB loadbalancer service diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 18294d182..be45983b7 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -23,6 +23,7 @@ package v1beta1 import ( "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/route" "k8s.io/apimachinery/pkg/runtime" ) @@ -100,6 +101,26 @@ func (in *KeystoneAPIList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeystoneAPIOverrideSpec) DeepCopyInto(out *KeystoneAPIOverrideSpec) { + *out = *in + if in.Route != nil { + in, out := &in.Route, &out.Route + *out = new(route.OverrideSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeystoneAPIOverrideSpec. +func (in *KeystoneAPIOverrideSpec) DeepCopy() *KeystoneAPIOverrideSpec { + if in == nil { + return nil + } + out := new(KeystoneAPIOverrideSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeystoneAPISpec) DeepCopyInto(out *KeystoneAPISpec) { *out = *in @@ -132,6 +153,7 @@ func (in *KeystoneAPISpec) DeepCopyInto(out *KeystoneAPISpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.Override.DeepCopyInto(&out.Override) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeystoneAPISpec. diff --git a/config/crd/bases/keystone.openstack.org_keystoneapis.yaml b/config/crd/bases/keystone.openstack.org_keystoneapis.yaml index 67698799d..5a2bddd30 100644 --- a/config/crd/bases/keystone.openstack.org_keystoneapis.yaml +++ b/config/crd/bases/keystone.openstack.org_keystoneapis.yaml @@ -158,6 +158,205 @@ spec: description: NodeSelector to target subset of worker nodes running this service type: object + override: + description: Override, provides the ability to override the generated + manifest of several child resources. + properties: + routeOverride: + description: Override configuration for the Route created to serve + traffic to the service + properties: + metadata: + description: EmbeddedLabelsAnnotations is an embedded subset + of the fields included in k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta. + Only labels and annotations are included. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. They + are not queryable and should be preserved when modifying + objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be + used to organize and categorize (scope and select) objects. + May match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels' + type: object + type: object + spec: + description: Spec defines the behavior of a Route. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + alternateBackends: + description: alternateBackends allows up to 3 additional + backends to be assigned to the route. Only the Service + kind is allowed, and it will be defaulted to Service. + Use the weight field in RouteTargetReference object + to specify relative preference. + items: + description: RouteTargetReference specifies the target + that resolve into endpoints. Only the 'Service' kind + is allowed. Use 'weight' field to emphasize one over + others. + properties: + kind: + description: The kind of target that the route is + referring to. Currently, only 'Service' is allowed + type: string + name: + description: name of the service/target that is + being referred to. e.g. name of the service + type: string + weight: + description: weight as an integer between 0 and + 256, default 1, that specifies the target's relative + weight against other target reference objects. + 0 suppresses requests to this backend. + format: int32 + type: integer + required: + - kind + - name + - weight + type: object + maxItems: 3 + type: array + host: + description: host is an alias/DNS that points to the service. + Optional. If not specified a route name will typically + be automatically chosen. Must follow DNS952 subdomain + conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + description: path that the router watches for, to route + traffic for to the service. Optional + pattern: ^/ + type: string + port: + description: If specified, the port to be used by the + router. Most routers will use all endpoints exposed + by the service by default - set this value to instruct + routers which port to use. + properties: + targetPort: + anyOf: + - type: integer + - type: string + description: The target port on pods selected by the + service this route points to. If this is a string, + it will be looked up as a named port in the target + endpoints port list. Required + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + description: "subdomain is a DNS subdomain that is requested + within the ingress controller's domain (as a subdomain). + If host is set this field is ignored. An ingress controller + may choose to ignore this suggested name, in which case + the controller will report the assigned name in the + status.ingress array or refuse to admit the route. If + this value is set and the server does not support this + field host will be populated automatically. Otherwise + host is left empty. The field may have multiple parts + separated by a dot, but not all ingress controllers + may honor the request. This field may not be changed + after creation except by a user with the update routes/custom-host + permission. \n Example: subdomain `frontend` automatically + receives the router subdomain `apps.mycluster.com` to + have a full hostname `frontend.apps.mycluster.com`." + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: The tls field provides the ability to configure + certificates and termination for the route. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: certificate provides certificate contents + type: string + destinationCACertificate: + description: destinationCACertificate provides the + contents of the ca certificate of the final destination. When + using reencrypt termination this file should be + provided in order to have routers use it for health + checks on the secure connection. If this field is + not specified, the router may provide its own destination + CA and perform hostname validation using the short + service name (service.namespace.svc), which allows + infrastructure generated certificates to automatically + verify. + type: string + insecureEdgeTerminationPolicy: + description: "insecureEdgeTerminationPolicy indicates + the desired behavior for insecure connections to + a route. While each router may make its own decisions + on which ports to expose, this is normally port + 80. \n * Allow - traffic is sent to the server on + the insecure port (default) * Disable - no traffic + is allowed on the insecure port. * Redirect - clients + are redirected to the secure port." + type: string + key: + description: key provides key file contents + type: string + termination: + description: termination indicates termination type. + type: string + required: + - termination + type: object + to: + description: to is an object the route should use as the + primary backend. Only the Service kind is allowed, and + it will be defaulted to Service. If the weight field + (0-256 default 100) is set to zero, no traffic will + be sent to this backend. + properties: + kind: + description: The kind of target that the route is + referring to. Currently, only 'Service' is allowed + type: string + name: + description: name of the service/target that is being + referred to. e.g. name of the service + type: string + weight: + description: weight as an integer between 0 and 256, + default 1, that specifies the target's relative + weight against other target reference objects. 0 + suppresses requests to this backend. + format: int32 + type: integer + required: + - kind + - name + - weight + type: object + wildcardPolicy: + default: None + description: Wildcard policy if any for the route. Currently + only 'Subdomain' or 'None' is allowed. + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object passwordSelectors: default: admin: AdminPassword diff --git a/controllers/keystoneapi_controller.go b/controllers/keystoneapi_controller.go index 6088a5404..11106af60 100644 --- a/controllers/keystoneapi_controller.go +++ b/controllers/keystoneapi_controller.go @@ -379,7 +379,8 @@ func (r *KeystoneAPIReconciler) reconcileInit( // var keystonePorts = map[endpoint.Endpoint]endpoint.Data{ endpoint.EndpointPublic: { - Port: keystone.KeystonePublicPort, + Port: keystone.KeystonePublicPort, + RouteOverride: instance.Spec.Override.Route, }, endpoint.EndpointInternal: { Port: keystone.KeystoneInternalPort, diff --git a/go.mod b/go.mod index 8f37b049b..bf925b599 100644 --- a/go.mod +++ b/go.mod @@ -86,3 +86,5 @@ require ( ) replace github.com/openstack-k8s-operators/keystone-operator/api => ./api + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49 diff --git a/go.sum b/go.sum index ce93050be..3498fc44d 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,6 @@ github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDD github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/openstack-k8s-operators/infra-operator/apis v0.0.0-20230522133301-4c8ff4fc4489 h1:Ck86S42Kw2uO57ZyhhV1wxYsiIxwMtC1gKUNOVcBWgw= github.com/openstack-k8s-operators/infra-operator/apis v0.0.0-20230522133301-4c8ff4fc4489/go.mod h1:NwdN9nYa9YDes5jsgTFlNP86DdjjqOyJDtNmAi+qVoA= -github.com/openstack-k8s-operators/lib-common/modules/common v0.0.0-20230522113906-6f4206cbf317 h1:/PTeRcBjnLdwUf5iFeKRvOAgX2e7+HUNMx+2hKTzQgk= -github.com/openstack-k8s-operators/lib-common/modules/common v0.0.0-20230522113906-6f4206cbf317/go.mod h1:qO1YjgynYksN3GYFrIcrwvAwws22zCzYmn0kOYBn1/A= github.com/openstack-k8s-operators/lib-common/modules/database v0.0.0-20230522113906-6f4206cbf317 h1:sLXPRm663pf4OtaGltEq3dD+UsY7CLsQx55tPPYPr34= github.com/openstack-k8s-operators/lib-common/modules/database v0.0.0-20230522113906-6f4206cbf317/go.mod h1:XAqqe3VVzpGbo27KXBVaOx0F1WCx0Eo0E6kXCxcaIhU= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.0.0-20230522113906-6f4206cbf317 h1:1gQSTk3ereXLrhb9BhqbYn5kKIemplc8tyzvonXyKGk= @@ -300,6 +298,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49 h1:GUdsPDKo8PdZAh94neUDo+gpU9HWYmQBVglnYSBtWok= +github.com/stuggi/lib-common/modules/common v0.0.0-20230704155018-5e9085e27d49/go.mod h1:fNpMKjraLivVIwdBgyLqXp3igvBF3UBFbhNKdFJ9yRc= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=