From c1d3e847ad1cf0c142a281736753a030b31edd1c Mon Sep 17 00:00:00 2001 From: chiragkyal Date: Fri, 26 Apr 2024 21:08:40 +0530 Subject: [PATCH 1/2] CFE-1020: Bump library-go and update deps Vendoring https://github.com/openshift/library-go/pull/1626 Signed-off-by: chiragkyal --- go.mod | 6 +- go.sum | 12 +- .../openshift/api/route/.codegen.yaml | 5 - .../api/route/v1/custom.route.testsuite.yaml | 103 --- .../openshift/api/route/v1/generated.proto | 4 +- .../route/v1/route-CustomNoUpgrade.crd.yaml | 618 ---------------- .../v1/route-TechPreviewNoUpgrade.crd.yaml | 618 ---------------- .../openshift/api/route/v1/route.crd.yaml | 655 ----------------- .../api/route/v1/route.crd.yaml-patch | 67 -- .../api/route/v1/stable.route.testsuite.yaml | 675 ------------------ .../route/v1/techpreview.route.testsuite.yaml | 103 --- .../openshift/api/route/v1/types.go | 10 +- ..._generated.featuregated-crd-manifests.yaml | 34 + .../project/clientset/versioned/clientset.go | 3 +- .../project/clientset/versioned/doc.go | 4 - .../clientset/versioned/fake/register.go | 14 +- .../clientset/versioned/scheme/register.go | 14 +- .../typed/project/v1/fake/fake_project.go | 71 +- .../project/v1/fake/fake_projectrequest.go | 21 +- .../applyconfigurations/internal/internal.go | 72 ++ .../route/v1/localobjectreference.go | 23 + .../route/v1/routehttpheader.go | 32 + .../route/v1/routehttpheaderactions.go | 42 ++ .../route/v1/routehttpheaderactionunion.go | 36 + .../route/v1/routehttpheaders.go | 23 + .../route/v1/routesethttpheader.go | 23 + .../applyconfigurations/route/v1/routespec.go | 9 + .../applyconfigurations/route/v1/tlsconfig.go | 21 +- .../route/clientset/versioned/clientset.go | 3 +- .../route/clientset/versioned/doc.go | 4 - .../clientset/versioned/fake/register.go | 14 +- .../clientset/versioned/scheme/register.go | 14 +- .../typed/route/v1/fake/fake_route.go | 71 +- .../authorizationutil/subject.go | 56 ++ .../authorization/authorizationutil/util.go | 50 ++ .../openshift/library-go/pkg/crypto/crypto.go | 113 ++- .../library-go/pkg/proc/proc_linux.go | 3 +- .../route/secretmanager/fake/fake_manager.go | 33 + .../pkg/route/secretmanager/manager.go | 147 ++++ .../openshift/library-go/pkg/secret/OWNERS | 9 + .../library-go/pkg/secret/monitor.go | 139 ++++ .../library-go/pkg/secret/secret_monitor.go | 217 ++++++ vendor/modules.txt | 14 +- 43 files changed, 1140 insertions(+), 3065 deletions(-) delete mode 100644 vendor/github.com/openshift/api/route/v1/custom.route.testsuite.yaml delete mode 100644 vendor/github.com/openshift/api/route/v1/route-CustomNoUpgrade.crd.yaml delete mode 100644 vendor/github.com/openshift/api/route/v1/route-TechPreviewNoUpgrade.crd.yaml delete mode 100644 vendor/github.com/openshift/api/route/v1/route.crd.yaml delete mode 100644 vendor/github.com/openshift/api/route/v1/route.crd.yaml-patch delete mode 100644 vendor/github.com/openshift/api/route/v1/stable.route.testsuite.yaml delete mode 100644 vendor/github.com/openshift/api/route/v1/techpreview.route.testsuite.yaml create mode 100644 vendor/github.com/openshift/api/route/v1/zz_generated.featuregated-crd-manifests.yaml delete mode 100644 vendor/github.com/openshift/client-go/project/clientset/versioned/doc.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go create mode 100644 vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go delete mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/doc.go create mode 100644 vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go create mode 100644 vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go create mode 100644 vendor/github.com/openshift/library-go/pkg/route/secretmanager/fake/fake_manager.go create mode 100644 vendor/github.com/openshift/library-go/pkg/route/secretmanager/manager.go create mode 100644 vendor/github.com/openshift/library-go/pkg/secret/OWNERS create mode 100644 vendor/github.com/openshift/library-go/pkg/secret/monitor.go create mode 100644 vendor/github.com/openshift/library-go/pkg/secret/secret_monitor.go diff --git a/go.mod b/go.mod index 39f761c8d..1aa49de43 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ require ( github.com/gocarina/gocsv v0.0.0-20190927101021-3ecffd272576 github.com/google/go-cmp v0.6.0 github.com/haproxytech/config-parser/v4 v4.0.0-rc1 - github.com/openshift/api v0.0.0-20240202140003-8b34b9854c7f - github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 - github.com/openshift/library-go v0.0.0-20230120202744-256994f916c4 + github.com/openshift/api v0.0.0-20240424142232-29a704bf5aa2 + github.com/openshift/client-go v0.0.0-20240405120947-c67c8325cdd8 + github.com/openshift/library-go v0.0.0-20240426144148-0690e4a4602d github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 diff --git a/go.sum b/go.sum index 9fa5db23a..056fed875 100644 --- a/go.sum +++ b/go.sum @@ -176,12 +176,12 @@ github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4 github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/openshift/api v0.0.0-20240202140003-8b34b9854c7f h1:yJ8mEpEW2aJo+97wguYL+ehCsJe/pbeKjFsbdMuuEJI= -github.com/openshift/api v0.0.0-20240202140003-8b34b9854c7f/go.mod h1:CxgbWAlvu2iQB0UmKTtRu1YfepRg1/vJ64n2DlIEVz4= -github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 h1:66uaqNwA+qYyQDwsMWUfjjau8ezmg1dzCqub13KZOcE= -github.com/openshift/client-go v0.0.0-20230120202327-72f107311084/go.mod h1:M3h9m001PWac3eAudGG3isUud6yBjr5XpzLYLLTlHKo= -github.com/openshift/library-go v0.0.0-20230120202744-256994f916c4 h1:cFYg18OROQMHlrGWL9HpV1elDKbnRFLz/ED5VvP3qvw= -github.com/openshift/library-go v0.0.0-20230120202744-256994f916c4/go.mod h1:wrrjvk/CK+nte9Wxend9/K6apy6Zep28lzM27/aJar8= +github.com/openshift/api v0.0.0-20240424142232-29a704bf5aa2 h1:U1BsjJoTsvYjymeMseC8apZnvCgExIIRolpc/xJ7jhM= +github.com/openshift/api v0.0.0-20240424142232-29a704bf5aa2/go.mod h1:CxgbWAlvu2iQB0UmKTtRu1YfepRg1/vJ64n2DlIEVz4= +github.com/openshift/client-go v0.0.0-20240405120947-c67c8325cdd8 h1:HGfbllzRcrJBSiwzNjBCs7sExLUxC5/1evnvlNGB0Cg= +github.com/openshift/client-go v0.0.0-20240405120947-c67c8325cdd8/go.mod h1:+VvvaMSTUhOt+rBq7NwRLSNxq06hTeRCBqm0j0PQEq8= +github.com/openshift/library-go v0.0.0-20240426144148-0690e4a4602d h1:PVCZvkSfUEwiMEYQ5AL+FIN4HpUUkpduUSkC/1U43H4= +github.com/openshift/library-go v0.0.0-20240426144148-0690e4a4602d/go.mod h1:lFwyRj0XjUf25Da3Q00y+KuaxCWTJ6YzYPDX1+96nco= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/vendor/github.com/openshift/api/route/.codegen.yaml b/vendor/github.com/openshift/api/route/.codegen.yaml index d2791f7b5..65cf5d814 100644 --- a/vendor/github.com/openshift/api/route/.codegen.yaml +++ b/vendor/github.com/openshift/api/route/.codegen.yaml @@ -1,8 +1,3 @@ schemapatch: - requiredFeatureSets: - - '' - - 'Default' - - 'TechPreviewNoUpgrade' - - 'CustomNoUpgrade' swaggerdocs: commentPolicy: Warn diff --git a/vendor/github.com/openshift/api/route/v1/custom.route.testsuite.yaml b/vendor/github.com/openshift/api/route/v1/custom.route.testsuite.yaml deleted file mode 100644 index 4a8042fc1..000000000 --- a/vendor/github.com/openshift/api/route/v1/custom.route.testsuite.yaml +++ /dev/null @@ -1,103 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this -name: '[CustomNoUpgrade] Route' -crd: route-CustomNoUpgrade.crd.yaml -tests: - onCreate: - - name: Should be able to create a minimal Route - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - weight: 100 - wildcardPolicy: None - - name: 'cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Allow - expectedError: 'cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow' - - name: 'spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: Redirect' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - wildcardPolicy: None - - name: 'spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: None' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - wildcardPolicy: None - - name: 'cannot have both spec.tls.certificate and spec.tls.externalCertificate' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - tls: - termination: edge - key: |- - -----BEGIN RSA PRIVATE KEY----- - -----END RSA PRIVATE KEY----- - certificate: |- - -----BEGIN CERTIFICATE----- - -----END CERTIFICATE----- - externalCertificate: - name: "my-local-secret" - expectedError: 'Invalid value: "object": cannot have both spec.tls.certificate and spec.tls.externalCertificate' diff --git a/vendor/github.com/openshift/api/route/v1/generated.proto b/vendor/github.com/openshift/api/route/v1/generated.proto index 66b35420e..1797fe770 100644 --- a/vendor/github.com/openshift/api/route/v1/generated.proto +++ b/vendor/github.com/openshift/api/route/v1/generated.proto @@ -404,7 +404,7 @@ message RouterShard { // TLSConfig defines config used to secure a route and provide termination // // +kubebuilder:validation:XValidation:rule="has(self.termination) && has(self.insecureEdgeTerminationPolicy) ? !((self.termination=='passthrough') && (self.insecureEdgeTerminationPolicy=='Allow')) : true", message="cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow" -// +openshift:validation:FeatureSetAwareXValidation:featureSet=TechPreviewNoUpgrade;CustomNoUpgrade,rule="!(has(self.certificate) && has(self.externalCertificate))", message="cannot have both spec.tls.certificate and spec.tls.externalCertificate" +// +openshift:validation:FeatureGateAwareXValidation:featureGate=ExternalRouteCertificate,rule="!(has(self.certificate) && has(self.externalCertificate))", message="cannot have both spec.tls.certificate and spec.tls.externalCertificate" message TLSConfig { // termination indicates termination type. // @@ -449,7 +449,7 @@ message TLSConfig { // be present in the same namespace as that of the Route. // Forbidden when `certificate` is set. // - // +openshift:enable:FeatureSets=CustomNoUpgrade;TechPreviewNoUpgrade + // +openshift:enable:FeatureGate=ExternalRouteCertificate // +optional optional LocalObjectReference externalCertificate = 7; } diff --git a/vendor/github.com/openshift/api/route/v1/route-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/route/v1/route-CustomNoUpgrade.crd.yaml deleted file mode 100644 index d46b07910..000000000 --- a/vendor/github.com/openshift/api/route/v1/route-CustomNoUpgrade.crd.yaml +++ /dev/null @@ -1,618 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/1228 - release.openshift.io/feature-set: CustomNoUpgrade - name: routes.route.openshift.io -spec: - group: route.openshift.io - names: - kind: Route - plural: routes - singular: route - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.ingress[0].host - name: Host - type: string - - jsonPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status - name: Admitted - type: string - - jsonPath: .spec.to.name - name: Service - type: string - - jsonPath: .spec.tls.type - name: TLS - type: string - name: v1 - schema: - openAPIV3Schema: - description: "A route allows developers to expose services through an HTTP(S) - aware load balancing and proxy layer via a public DNS entry. The route may - further specify TLS options and a certificate, or specify a public CNAME - that the router should also accept for HTTP and HTTPS traffic. An administrator - typically configures their router to be visible outside the cluster firewall, - and may also add additional security, caching, or traffic controls on the - service content. Routers usually talk directly to the service endpoints. - \n Once a route is created, the `host` field may not be changed. Generally, - routers use the oldest route with a given host when resolving conflicts. - \n Routers are subject to additional customization and may support additional - controls via the annotations field. \n Because administrators may configure - multiple routers, the route status field is used to return information to - clients about the names and states of the route under each router. If a - client chooses a duplicate name, for instance, the route status conditions - are used to indicate the route cannot be chosen. \n To enable HTTP/2 ALPN - on a route it requires a custom (non-wildcard) certificate. This prevents - connection coalescing by clients, notably web browsers. We do not support - HTTP/2 ALPN on routes that use the default certificate because of the risk - of connection re-use/coalescing. Routes that do not have their own custom - certificate will not be HTTP/2 ALPN-enabled on either the frontend or the - backend. \n Compatibility level 1: Stable within a major release for a minimum - of 12 months or 3 minor releases (whichever is longer)." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: spec is the desired state of the route - 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: - default: Service - description: The kind of target that the route is referring - to. Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default - 100, that specifies the target's relative weight against other - target reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - httpHeaders: - description: httpHeaders defines policy for HTTP headers. - properties: - actions: - description: 'actions specifies options for modifying headers - and their values. Note that this option only applies to cleartext - HTTP connections and to secure HTTP connections for which the - ingress controller terminates encryption (that is, edge-terminated - or reencrypt connections). Headers cannot be modified for TLS - passthrough connections. Setting the HSTS (`Strict-Transport-Security`) - header is not supported via actions. `Strict-Transport-Security` - may only be configured using the "haproxy.router.openshift.io/hsts_header" - route annotation, and only in accordance with the policy specified - in Ingress.Spec.RequiredHSTSPolicies. In case of HTTP request - headers, the actions specified in spec.httpHeaders.actions on - the Route will be executed after the actions specified in the - IngressController''s spec.httpHeaders.actions field. In case - of HTTP response headers, the actions specified in spec.httpHeaders.actions - on the IngressController will be executed after the actions - specified in the Route''s spec.httpHeaders.actions field. The - headers set via this API will not appear in access logs. Any - actions defined here are applied after any actions related to - the following other fields: cache-control, spec.clientTLS, spec.httpHeaders.forwardedHeaderPolicy, - spec.httpHeaders.uniqueId, and spec.httpHeaders.headerNameCaseAdjustments. - The following header names are reserved and may not be modified - via this API: Strict-Transport-Security, Proxy, Cookie, Set-Cookie. - Note that the total size of all net added headers *after* interpolating - dynamic values must not exceed the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. Please refer to the documentation - for that API field for more details.' - properties: - request: - description: 'request is a list of HTTP request headers to - modify. Currently, actions may define to either `Set` or - `Delete` headers values. Actions defined here will modify - the request headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Currently, - actions may define to either `Set` or `Delete` headers values. - Route actions will be executed after IngressController actions - for request headers. Actions are applied in sequence as - defined in this list. A maximum of 20 request header actions - may be configured. You can use this field to specify HTTP - request headers that should be set or deleted when forwarding - connections from the client to your application. Sample - fetchers allowed are "req.hdr" and "ssl_c_der". Converters - allowed are "lower" and "base64". Example header values: - "%[req.hdr(X-target),lower]", "%{+Q}[ssl_c_der,base64]". - Any request header configuration applied directly via a - Route resource using this API will override header configuration - for a header of the same name applied via spec.httpHeaders.actions - on the IngressController or route annotation. Note: This - field cannot be used if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are req.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:req\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - response: - description: 'response is a list of HTTP response headers - to modify. Currently, actions may define to either `Set` - or `Delete` headers values. Actions defined here will modify - the response headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Route actions - will be executed before IngressController actions for response - headers. Actions are applied in sequence as defined in this - list. A maximum of 20 response header actions may be configured. - You can use this field to specify HTTP response headers - that should be set or deleted when forwarding responses - from your application to the client. Sample fetchers allowed - are "res.hdr" and "ssl_c_der". Converters allowed are "lower" - and "base64". Example header values: "%[res.hdr(X-target),lower]", - "%{+Q}[ssl_c_der,base64]". Note: This field cannot be used - if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are res.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:res\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - type: object - type: object - 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. This should - be a single serving certificate, not a certificate chain. Do - not include a CA certificate. - 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 - externalCertificate: - description: externalCertificate provides certificate contents - as a secret reference. This should be a single serving certificate, - not a certificate chain. Do not include a CA certificate. The - secret referenced should be present in the same namespace as - that of the Route. Forbidden when `certificate` is set. - properties: - name: - description: 'name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - type: object - x-kubernetes-map-type: atomic - 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 (edge/reencrypt terminations only) (default). - * None - no traffic is allowed on the insecure port. * Redirect - - clients are redirected to the secure port." - enum: - - Allow - - None - - Redirect - - "" - type: string - key: - description: key provides key file contents - type: string - termination: - description: "termination indicates termination type. \n * edge - - TLS termination is done by the router and http is used to - communicate with the backend (default) * passthrough - Traffic - is sent straight to the destination without the router providing - TLS termination * reencrypt - TLS termination is done by the - router and https is used to communicate with the backend \n - Note: passthrough termination is incompatible with httpHeader - actions" - enum: - - edge - - reencrypt - - passthrough - type: string - required: - - termination - type: object - x-kubernetes-validations: - - message: cannot have both spec.tls.certificate and spec.tls.externalCertificate - rule: '!(has(self.certificate) && has(self.externalCertificate))' - - message: 'cannot have both spec.tls.termination: passthrough and - spec.tls.insecureEdgeTerminationPolicy: Allow' - rule: 'has(self.termination) && has(self.insecureEdgeTerminationPolicy) - ? !((self.termination==''passthrough'') && (self.insecureEdgeTerminationPolicy==''Allow'')) - : true' - 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: - default: Service - description: The kind of target that the route is referring to. - Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default 100, - that specifies the target's relative weight against other target - reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - required: - - to - type: object - x-kubernetes-validations: - - message: header actions are not permitted when tls termination is passthrough. - rule: '!has(self.tls) || self.tls.termination != ''passthrough'' || - !has(self.httpHeaders)' - status: - description: status is the current state of the route - properties: - ingress: - description: ingress describes the places where the route may be exposed. - The list of ingress points may contain duplicate Host or RouterName - values. Routes are considered live once they are `Ready` - items: - description: RouteIngress holds information about the places where - a route is exposed. - properties: - conditions: - description: Conditions is the state of the route, may be empty. - items: - description: RouteIngressCondition contains details for the - current condition of this route on a particular router. - properties: - lastTransitionTime: - description: RFC 3339 date and time when this condition - last transitioned - format: date-time - type: string - message: - description: Human readable message indicating details - about last transition. - type: string - reason: - description: (brief) reason for the condition's last transition, - and is usually a machine and human readable constant - type: string - status: - description: Status is the status of the condition. Can - be True, False, Unknown. - type: string - type: - description: Type is the type of the condition. Currently - only Admitted or UnservableInFutureVersions. - type: string - required: - - status - - type - type: object - type: array - host: - description: Host is the host string under which the route is - exposed; this value is required - type: string - routerCanonicalHostname: - description: CanonicalHostname is the external host name for - the router that can be used as a CNAME for the host requested - for this route. This value is optional and may not be set - in all cases. - type: string - routerName: - description: Name is a name chosen by the router to identify - itself; this value is required - type: string - wildcardPolicy: - description: Wildcard policy is the wildcard policy that was - allowed where this route is exposed. - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} diff --git a/vendor/github.com/openshift/api/route/v1/route-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/route/v1/route-TechPreviewNoUpgrade.crd.yaml deleted file mode 100644 index 48ff2c5e8..000000000 --- a/vendor/github.com/openshift/api/route/v1/route-TechPreviewNoUpgrade.crd.yaml +++ /dev/null @@ -1,618 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/1228 - release.openshift.io/feature-set: TechPreviewNoUpgrade - name: routes.route.openshift.io -spec: - group: route.openshift.io - names: - kind: Route - plural: routes - singular: route - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.ingress[0].host - name: Host - type: string - - jsonPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status - name: Admitted - type: string - - jsonPath: .spec.to.name - name: Service - type: string - - jsonPath: .spec.tls.type - name: TLS - type: string - name: v1 - schema: - openAPIV3Schema: - description: "A route allows developers to expose services through an HTTP(S) - aware load balancing and proxy layer via a public DNS entry. The route may - further specify TLS options and a certificate, or specify a public CNAME - that the router should also accept for HTTP and HTTPS traffic. An administrator - typically configures their router to be visible outside the cluster firewall, - and may also add additional security, caching, or traffic controls on the - service content. Routers usually talk directly to the service endpoints. - \n Once a route is created, the `host` field may not be changed. Generally, - routers use the oldest route with a given host when resolving conflicts. - \n Routers are subject to additional customization and may support additional - controls via the annotations field. \n Because administrators may configure - multiple routers, the route status field is used to return information to - clients about the names and states of the route under each router. If a - client chooses a duplicate name, for instance, the route status conditions - are used to indicate the route cannot be chosen. \n To enable HTTP/2 ALPN - on a route it requires a custom (non-wildcard) certificate. This prevents - connection coalescing by clients, notably web browsers. We do not support - HTTP/2 ALPN on routes that use the default certificate because of the risk - of connection re-use/coalescing. Routes that do not have their own custom - certificate will not be HTTP/2 ALPN-enabled on either the frontend or the - backend. \n Compatibility level 1: Stable within a major release for a minimum - of 12 months or 3 minor releases (whichever is longer)." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: spec is the desired state of the route - 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: - default: Service - description: The kind of target that the route is referring - to. Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default - 100, that specifies the target's relative weight against other - target reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - httpHeaders: - description: httpHeaders defines policy for HTTP headers. - properties: - actions: - description: 'actions specifies options for modifying headers - and their values. Note that this option only applies to cleartext - HTTP connections and to secure HTTP connections for which the - ingress controller terminates encryption (that is, edge-terminated - or reencrypt connections). Headers cannot be modified for TLS - passthrough connections. Setting the HSTS (`Strict-Transport-Security`) - header is not supported via actions. `Strict-Transport-Security` - may only be configured using the "haproxy.router.openshift.io/hsts_header" - route annotation, and only in accordance with the policy specified - in Ingress.Spec.RequiredHSTSPolicies. In case of HTTP request - headers, the actions specified in spec.httpHeaders.actions on - the Route will be executed after the actions specified in the - IngressController''s spec.httpHeaders.actions field. In case - of HTTP response headers, the actions specified in spec.httpHeaders.actions - on the IngressController will be executed after the actions - specified in the Route''s spec.httpHeaders.actions field. The - headers set via this API will not appear in access logs. Any - actions defined here are applied after any actions related to - the following other fields: cache-control, spec.clientTLS, spec.httpHeaders.forwardedHeaderPolicy, - spec.httpHeaders.uniqueId, and spec.httpHeaders.headerNameCaseAdjustments. - The following header names are reserved and may not be modified - via this API: Strict-Transport-Security, Proxy, Cookie, Set-Cookie. - Note that the total size of all net added headers *after* interpolating - dynamic values must not exceed the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. Please refer to the documentation - for that API field for more details.' - properties: - request: - description: 'request is a list of HTTP request headers to - modify. Currently, actions may define to either `Set` or - `Delete` headers values. Actions defined here will modify - the request headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Currently, - actions may define to either `Set` or `Delete` headers values. - Route actions will be executed after IngressController actions - for request headers. Actions are applied in sequence as - defined in this list. A maximum of 20 request header actions - may be configured. You can use this field to specify HTTP - request headers that should be set or deleted when forwarding - connections from the client to your application. Sample - fetchers allowed are "req.hdr" and "ssl_c_der". Converters - allowed are "lower" and "base64". Example header values: - "%[req.hdr(X-target),lower]", "%{+Q}[ssl_c_der,base64]". - Any request header configuration applied directly via a - Route resource using this API will override header configuration - for a header of the same name applied via spec.httpHeaders.actions - on the IngressController or route annotation. Note: This - field cannot be used if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are req.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:req\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - response: - description: 'response is a list of HTTP response headers - to modify. Currently, actions may define to either `Set` - or `Delete` headers values. Actions defined here will modify - the response headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Route actions - will be executed before IngressController actions for response - headers. Actions are applied in sequence as defined in this - list. A maximum of 20 response header actions may be configured. - You can use this field to specify HTTP response headers - that should be set or deleted when forwarding responses - from your application to the client. Sample fetchers allowed - are "res.hdr" and "ssl_c_der". Converters allowed are "lower" - and "base64". Example header values: "%[res.hdr(X-target),lower]", - "%{+Q}[ssl_c_der,base64]". Note: This field cannot be used - if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are res.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:res\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - type: object - type: object - 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. This should - be a single serving certificate, not a certificate chain. Do - not include a CA certificate. - 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 - externalCertificate: - description: externalCertificate provides certificate contents - as a secret reference. This should be a single serving certificate, - not a certificate chain. Do not include a CA certificate. The - secret referenced should be present in the same namespace as - that of the Route. Forbidden when `certificate` is set. - properties: - name: - description: 'name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - type: object - x-kubernetes-map-type: atomic - 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 (edge/reencrypt terminations only) (default). - * None - no traffic is allowed on the insecure port. * Redirect - - clients are redirected to the secure port." - enum: - - Allow - - None - - Redirect - - "" - type: string - key: - description: key provides key file contents - type: string - termination: - description: "termination indicates termination type. \n * edge - - TLS termination is done by the router and http is used to - communicate with the backend (default) * passthrough - Traffic - is sent straight to the destination without the router providing - TLS termination * reencrypt - TLS termination is done by the - router and https is used to communicate with the backend \n - Note: passthrough termination is incompatible with httpHeader - actions" - enum: - - edge - - reencrypt - - passthrough - type: string - required: - - termination - type: object - x-kubernetes-validations: - - message: cannot have both spec.tls.certificate and spec.tls.externalCertificate - rule: '!(has(self.certificate) && has(self.externalCertificate))' - - message: 'cannot have both spec.tls.termination: passthrough and - spec.tls.insecureEdgeTerminationPolicy: Allow' - rule: 'has(self.termination) && has(self.insecureEdgeTerminationPolicy) - ? !((self.termination==''passthrough'') && (self.insecureEdgeTerminationPolicy==''Allow'')) - : true' - 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: - default: Service - description: The kind of target that the route is referring to. - Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default 100, - that specifies the target's relative weight against other target - reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - required: - - to - type: object - x-kubernetes-validations: - - message: header actions are not permitted when tls termination is passthrough. - rule: '!has(self.tls) || self.tls.termination != ''passthrough'' || - !has(self.httpHeaders)' - status: - description: status is the current state of the route - properties: - ingress: - description: ingress describes the places where the route may be exposed. - The list of ingress points may contain duplicate Host or RouterName - values. Routes are considered live once they are `Ready` - items: - description: RouteIngress holds information about the places where - a route is exposed. - properties: - conditions: - description: Conditions is the state of the route, may be empty. - items: - description: RouteIngressCondition contains details for the - current condition of this route on a particular router. - properties: - lastTransitionTime: - description: RFC 3339 date and time when this condition - last transitioned - format: date-time - type: string - message: - description: Human readable message indicating details - about last transition. - type: string - reason: - description: (brief) reason for the condition's last transition, - and is usually a machine and human readable constant - type: string - status: - description: Status is the status of the condition. Can - be True, False, Unknown. - type: string - type: - description: Type is the type of the condition. Currently - only Admitted or UnservableInFutureVersions. - type: string - required: - - status - - type - type: object - type: array - host: - description: Host is the host string under which the route is - exposed; this value is required - type: string - routerCanonicalHostname: - description: CanonicalHostname is the external host name for - the router that can be used as a CNAME for the host requested - for this route. This value is optional and may not be set - in all cases. - type: string - routerName: - description: Name is a name chosen by the router to identify - itself; this value is required - type: string - wildcardPolicy: - description: Wildcard policy is the wildcard policy that was - allowed where this route is exposed. - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} diff --git a/vendor/github.com/openshift/api/route/v1/route.crd.yaml b/vendor/github.com/openshift/api/route/v1/route.crd.yaml deleted file mode 100644 index 0ec81826e..000000000 --- a/vendor/github.com/openshift/api/route/v1/route.crd.yaml +++ /dev/null @@ -1,655 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/1228 - name: routes.route.openshift.io -spec: - group: route.openshift.io - names: - kind: Route - plural: routes - singular: route - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.ingress[0].host - name: Host - type: string - - jsonPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status - name: Admitted - type: string - - jsonPath: .spec.to.name - name: Service - type: string - - jsonPath: .spec.tls.type - name: TLS - type: string - name: v1 - schema: - openAPIV3Schema: - description: "A route allows developers to expose services through an HTTP(S) - aware load balancing and proxy layer via a public DNS entry. The route may - further specify TLS options and a certificate, or specify a public CNAME - that the router should also accept for HTTP and HTTPS traffic. An administrator - typically configures their router to be visible outside the cluster firewall, - and may also add additional security, caching, or traffic controls on the - service content. Routers usually talk directly to the service endpoints. - \n Once a route is created, the `host` field may not be changed. Generally, - routers use the oldest route with a given host when resolving conflicts. - \n Routers are subject to additional customization and may support additional - controls via the annotations field. \n Because administrators may configure - multiple routers, the route status field is used to return information to - clients about the names and states of the route under each router. If a - client chooses a duplicate name, for instance, the route status conditions - are used to indicate the route cannot be chosen. \n To enable HTTP/2 ALPN - on a route it requires a custom (non-wildcard) certificate. This prevents - connection coalescing by clients, notably web browsers. We do not support - HTTP/2 ALPN on routes that use the default certificate because of the risk - of connection re-use/coalescing. Routes that do not have their own custom - certificate will not be HTTP/2 ALPN-enabled on either the frontend or the - backend. \n Compatibility level 1: Stable within a major release for a minimum - of 12 months or 3 minor releases (whichever is longer)." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - allOf: - - anyOf: - - properties: - path: - maxLength: 0 - - properties: - tls: - enum: - - null - - not: - properties: - tls: - properties: - termination: - enum: - - passthrough - - anyOf: - - not: - properties: - host: - maxLength: 0 - - not: - properties: - wildcardPolicy: - enum: - - Subdomain - description: spec is the desired state of the route - 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: - default: Service - description: The kind of target that the route is referring - to. Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default - 100, that specifies the target's relative weight against other - target reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - httpHeaders: - description: httpHeaders defines policy for HTTP headers. - properties: - actions: - description: 'actions specifies options for modifying headers - and their values. Note that this option only applies to cleartext - HTTP connections and to secure HTTP connections for which the - ingress controller terminates encryption (that is, edge-terminated - or reencrypt connections). Headers cannot be modified for TLS - passthrough connections. Setting the HSTS (`Strict-Transport-Security`) - header is not supported via actions. `Strict-Transport-Security` - may only be configured using the "haproxy.router.openshift.io/hsts_header" - route annotation, and only in accordance with the policy specified - in Ingress.Spec.RequiredHSTSPolicies. In case of HTTP request - headers, the actions specified in spec.httpHeaders.actions on - the Route will be executed after the actions specified in the - IngressController''s spec.httpHeaders.actions field. In case - of HTTP response headers, the actions specified in spec.httpHeaders.actions - on the IngressController will be executed after the actions - specified in the Route''s spec.httpHeaders.actions field. The - headers set via this API will not appear in access logs. Any - actions defined here are applied after any actions related to - the following other fields: cache-control, spec.clientTLS, spec.httpHeaders.forwardedHeaderPolicy, - spec.httpHeaders.uniqueId, and spec.httpHeaders.headerNameCaseAdjustments. - The following header names are reserved and may not be modified - via this API: Strict-Transport-Security, Proxy, Cookie, Set-Cookie. - Note that the total size of all net added headers *after* interpolating - dynamic values must not exceed the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. Please refer to the documentation - for that API field for more details.' - properties: - request: - description: 'request is a list of HTTP request headers to - modify. Currently, actions may define to either `Set` or - `Delete` headers values. Actions defined here will modify - the request headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Currently, - actions may define to either `Set` or `Delete` headers values. - Route actions will be executed after IngressController actions - for request headers. Actions are applied in sequence as - defined in this list. A maximum of 20 request header actions - may be configured. You can use this field to specify HTTP - request headers that should be set or deleted when forwarding - connections from the client to your application. Sample - fetchers allowed are "req.hdr" and "ssl_c_der". Converters - allowed are "lower" and "base64". Example header values: - "%[req.hdr(X-target),lower]", "%{+Q}[ssl_c_der,base64]". - Any request header configuration applied directly via a - Route resource using this API will override header configuration - for a header of the same name applied via spec.httpHeaders.actions - on the IngressController or route annotation. Note: This - field cannot be used if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are req.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:req\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - response: - description: 'response is a list of HTTP response headers - to modify. Currently, actions may define to either `Set` - or `Delete` headers values. Actions defined here will modify - the response headers of all requests made through a route. - These actions are applied to a specific Route defined within - a cluster i.e. connections made through a route. Route actions - will be executed before IngressController actions for response - headers. Actions are applied in sequence as defined in this - list. A maximum of 20 response header actions may be configured. - You can use this field to specify HTTP response headers - that should be set or deleted when forwarding responses - from your application to the client. Sample fetchers allowed - are "res.hdr" and "ssl_c_der". Converters allowed are "lower" - and "base64". Example header values: "%[res.hdr(X-target),lower]", - "%{+Q}[ssl_c_der,base64]". Note: This field cannot be used - if your route uses TLS passthrough.' - items: - description: RouteHTTPHeader specifies configuration for - setting or deleting an HTTP header. - properties: - action: - description: action specifies actions to perform on - headers, such as setting or deleting headers. - properties: - set: - description: 'set defines the HTTP header that should - be set: added if it doesn''t exist or replaced - if it does. This field is required when type is - Set and forbidden otherwise.' - properties: - value: - description: value specifies a header value. - Dynamic values can be added. The value will - be interpreted as an HAProxy format string - as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise - must be a valid HTTP header value as defined - in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - The value of this field must be no more than - 16384 characters in length. Note that the - total size of all net added headers *after* - interpolating dynamic values must not exceed - the value of spec.tuningOptions.headerBufferMaxRewriteBytes - on the IngressController. - maxLength: 16384 - minLength: 1 - type: string - required: - - value - type: object - type: - description: type defines the type of the action - to be applied on the header. Possible values are - Set or Delete. Set allows you to set HTTP request - and response headers. Delete allows you to delete - HTTP request and response headers. - enum: - - Set - - Delete - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: set is required when type is Set, and forbidden - otherwise - rule: 'has(self.type) && self.type == ''Set'' ? has(self.set) - : !has(self.set)' - name: - description: 'name specifies the name of a header on - which to perform an action. Its value must be a valid - HTTP header name as defined in RFC 2616 section 4.2. - The name must consist only of alphanumeric and the - following special characters, "-!#$%&''*+.^_`". The - following header names are reserved and may not be - modified via this API: Strict-Transport-Security, - Proxy, Cookie, Set-Cookie. It must be no more than - 255 characters in length. Header name must be unique.' - maxLength: 255 - minLength: 1 - pattern: ^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$ - type: string - x-kubernetes-validations: - - message: strict-transport-security header may not - be modified via header actions - rule: self.lowerAscii() != 'strict-transport-security' - - message: proxy header may not be modified via header - actions - rule: self.lowerAscii() != 'proxy' - - message: cookie header may not be modified via header - actions - rule: self.lowerAscii() != 'cookie' - - message: set-cookie header may not be modified via - header actions - rule: self.lowerAscii() != 'set-cookie' - required: - - action - - name - type: object - maxItems: 20 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - x-kubernetes-validations: - - message: Either the header value provided is not in correct - format or the sample fetcher/converter specified is not - allowed. The dynamic header value will be interpreted - as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 - and may use HAProxy's %[] syntax and otherwise must be - a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. - Sample fetchers allowed are res.hdr, ssl_c_der. Converters - allowed are lower, base64. - rule: self.all(key, key.action.type == "Delete" || (has(key.action.set) - && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:res\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$'))) - type: object - type: object - 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: - allOf: - - not: - enum: - - 0 - - not: - enum: - - "" - 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: - allOf: - - anyOf: - - properties: - caCertificate: - maxLength: 0 - certificate: - maxLength: 0 - destinationCACertificate: - maxLength: 0 - key: - maxLength: 0 - - not: - properties: - termination: - enum: - - passthrough - - anyOf: - - properties: - destinationCACertificate: - maxLength: 0 - - not: - properties: - termination: - enum: - - edge - 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. This should - be a single serving certificate, not a certificate chain. Do - not include a CA certificate. - 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 (edge/reencrypt terminations only) (default). - * None - no traffic is allowed on the insecure port. * Redirect - - clients are redirected to the secure port." - enum: - - Allow - - None - - Redirect - - "" - type: string - key: - description: key provides key file contents - type: string - termination: - description: "termination indicates termination type. \n * edge - - TLS termination is done by the router and http is used to - communicate with the backend (default) * passthrough - Traffic - is sent straight to the destination without the router providing - TLS termination * reencrypt - TLS termination is done by the - router and https is used to communicate with the backend \n - Note: passthrough termination is incompatible with httpHeader - actions" - enum: - - edge - - reencrypt - - passthrough - type: string - required: - - termination - type: object - x-kubernetes-validations: - - message: 'cannot have both spec.tls.termination: passthrough and - spec.tls.insecureEdgeTerminationPolicy: Allow' - rule: 'has(self.termination) && has(self.insecureEdgeTerminationPolicy) - ? !((self.termination==''passthrough'') && (self.insecureEdgeTerminationPolicy==''Allow'')) - : true' - 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: - default: Service - description: The kind of target that the route is referring to. - Currently, only 'Service' is allowed - enum: - - Service - - "" - type: string - name: - description: name of the service/target that is being referred - to. e.g. name of the service - minLength: 1 - type: string - weight: - default: 100 - description: weight as an integer between 0 and 256, default 100, - that specifies the target's relative weight against other target - reference objects. 0 suppresses requests to this backend. - format: int32 - maximum: 256 - minimum: 0 - type: integer - required: - - kind - - name - 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 - required: - - to - type: object - x-kubernetes-validations: - - message: header actions are not permitted when tls termination is passthrough. - rule: '!has(self.tls) || self.tls.termination != ''passthrough'' || - !has(self.httpHeaders)' - status: - description: status is the current state of the route - properties: - ingress: - description: ingress describes the places where the route may be exposed. - The list of ingress points may contain duplicate Host or RouterName - values. Routes are considered live once they are `Ready` - items: - description: RouteIngress holds information about the places where - a route is exposed. - properties: - conditions: - description: Conditions is the state of the route, may be empty. - items: - description: RouteIngressCondition contains details for the - current condition of this route on a particular router. - properties: - lastTransitionTime: - description: RFC 3339 date and time when this condition - last transitioned - format: date-time - type: string - message: - description: Human readable message indicating details - about last transition. - type: string - reason: - description: (brief) reason for the condition's last transition, - and is usually a machine and human readable constant - type: string - status: - description: Status is the status of the condition. Can - be True, False, Unknown. - type: string - type: - description: Type is the type of the condition. Currently - only Admitted or UnservableInFutureVersions. - type: string - required: - - status - - type - type: object - type: array - host: - description: Host is the host string under which the route is - exposed; this value is required - type: string - routerCanonicalHostname: - description: CanonicalHostname is the external host name for - the router that can be used as a CNAME for the host requested - for this route. This value is optional and may not be set - in all cases. - type: string - routerName: - description: Name is a name chosen by the router to identify - itself; this value is required - type: string - wildcardPolicy: - description: Wildcard policy is the wildcard policy that was - allowed where this route is exposed. - type: string - type: object - type: array - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} diff --git a/vendor/github.com/openshift/api/route/v1/route.crd.yaml-patch b/vendor/github.com/openshift/api/route/v1/route.crd.yaml-patch deleted file mode 100644 index 7f09302f3..000000000 --- a/vendor/github.com/openshift/api/route/v1/route.crd.yaml-patch +++ /dev/null @@ -1,67 +0,0 @@ -- op: add - path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/allOf - value: - # spec.path must be empty when using passthrough TLS. - - anyOf: - - properties: - path: - maxLength: 0 - - properties: - tls: - enum: [null] - - not: - properties: - tls: - properties: - termination: - enum: ["passthrough"] - # spec.host must be nonempty for a wildcard route. - - anyOf: - - not: - properties: - host: - maxLength: 0 - - not: - properties: - wildcardPolicy: - enum: ["Subdomain"] -- op: add - path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/port/properties/targetPort - value: - # spec.port.targetPort cannot be the integer 0 or the empty string. (Note - # that negative integer values are allowed, as is the string "0".) - allOf: - - not: - enum: [0] - - not: - enum: [""] - x-kubernetes-int-or-string: true -- op: add - path: /spec/versions/name=v1/schema/openAPIV3Schema/properties/spec/properties/tls/allOf - value: - # spec.tls.certificate, spec.tls.key, spec.tls.caCertificate, and - # spec.tls.destinationCACertificate must omitted when using passthrough TLS. - - anyOf: - - properties: - certificate: - maxLength: 0 - key: - maxLength: 0 - caCertificate: - maxLength: 0 - destinationCACertificate: - maxLength: 0 - - not: - properties: - termination: - enum: ["passthrough"] - # spec.tls.destinationCACertificate must be omitted when using edge-terminated - # TLS. - - anyOf: - - properties: - destinationCACertificate: - maxLength: 0 - - not: - properties: - termination: - enum: ["edge"] diff --git a/vendor/github.com/openshift/api/route/v1/stable.route.testsuite.yaml b/vendor/github.com/openshift/api/route/v1/stable.route.testsuite.yaml deleted file mode 100644 index d1e476673..000000000 --- a/vendor/github.com/openshift/api/route/v1/stable.route.testsuite.yaml +++ /dev/null @@ -1,675 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this -name: "[Stable] Route" -crd: route.crd.yaml -tests: - onCreate: - - name: Should be able to create a minimal Route - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - weight: 100 - wildcardPolicy: None - - name: "cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow" - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Allow - expectedError: "cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow" - - name: "spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: Redirect" - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - wildcardPolicy: None - - name: "spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: None" - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - wildcardPolicy: None - - name: Should be able to create a Route with valid actions - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-actions - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - type: Set - set: - value: DENY - - name: X-Cache-Info - action: - type: Set - set: - value: "not cacheable; meta data too large" - - name: X-XSS-Protection - action: - type: Delete - - name: X-Source - action: - type: Set - set: - value: "%[res.hdr(X-Value),lower]" - request: - - name: Content-Location - action: - type: Set - set: - value: /my-first-blog-post - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: "%{+Q}[ssl_c_der,base64]" - - name: Content-Language - action: - type: Delete - - name: X-Target - action: - type: Set - set: - value: "%[req.hdr(host),lower]" - - name: X-Conditional - action: - type: Set - set: - value: "%[req.hdr(Host)] if foo" - - name: X-Condition - action: - type: Set - set: - value: "%[req.hdr(Host)]\ if\ foo" - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-actions - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - weight: 100 - wildcardPolicy: None - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - type: Set - set: - value: DENY - - name: X-Cache-Info - action: - type: Set - set: - value: "not cacheable; meta data too large" - - name: X-XSS-Protection - action: - type: Delete - - name: X-Source - action: - type: Set - set: - value: "%[res.hdr(X-Value),lower]" - request: - - name: Content-Location - action: - type: Set - set: - value: /my-first-blog-post - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: "%{+Q}[ssl_c_der,base64]" - - name: Content-Language - action: - type: Delete - - name: X-Target - action: - type: Set - set: - value: "%[req.hdr(host),lower]" - - name: X-Conditional - action: - type: Set - set: - value: "%[req.hdr(Host)] if foo" - - name: X-Condition - action: - type: Set - set: - value: "%[req.hdr(Host)]\ if\ foo" - - name: "Should not allow response header actions if tls termination is set to passthrough" - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-passthrough - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: passthrough - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - type: Set - set: - value: DENY - - name: X-XSS-Protection - action: - type: Delete - expectedError: "header actions are not permitted when tls termination is passthrough." - - name: "Should not allow request header actions if tls termination is set to passthrough" - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-passthrough - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: passthrough - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: Content-Location - action: - type: Set - set: - value: /my-first-blog-post - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: "%{+Q}[ssl_c_der,base64]" - - name: Content-Language - action: - type: Delete - - name: X-Target - action: - type: Set - set: - value: "%[req.hdr(host),lower]" - expectedError: "header actions are not permitted when tls termination is passthrough." - - name: Should not allow to set/delete HSTS header. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-hsts - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - type: Set - set: - value: DENY - - name: Strict-Transport-Security - action: - type: Delete - request: - - name: Content-Location - action: - type: Set - set: - value: /my-first-blog-post - - name: Content-Language - action: - type: Delete - expectedError: "strict-transport-security header may not be modified via header actions" - - name: Should not allow to set proxy request header. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - name: hello-openshift-edge-proxy - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: Proxy - action: - type: Set - set: - value: example.xyz - expectedError: "proxy header may not be modified via header actions" - - name: Should not allow to set cookie header. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - name: hello-openshift-edge-proxy - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: Cookie - action: - type: Set - set: - value: "PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1" - expectedError: "cookie header may not be modified via header actions" - - name: Should not allow to set set-cookie header. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - name: hello-openshift-edge-proxy - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: Set-Cookie - action: - type: Set - set: - value: "sessionId=e8bb43229de9; Domain=foo.example.com" - expectedError: "set-cookie header may not be modified via header actions" - - name: Should not allow to set/delete dynamic headers with unclosed braces. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-unclosed-braces - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: Content-Location - action: - type: Set - set: - value: /my-first-blog-post - - name: Content-Language - action: - type: Delete - - name: expires - action: - type: Set - set: - value: "%[req.hdr(host),lower" - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are req.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set dynamic response header values with not allowed sample fetchers. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Target - action: - type: Set - set: - value: "%{+Q}[ssl_c_der1,base64]" - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are res.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set/delete dynamic response header values with not allowed converters. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Target - action: - type: Set - set: - value: "%{+Q}[ssl_c_der,bogus]" - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are res.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set/delete dynamic response header values containing req.hdr fetcher. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Target - action: - type: Set - set: - value: "%[req.hdr(host),lower]" - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are res.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set/delete dynamic response header values containing req.hdr fetcher. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: X-Source - action: - type: Set - set: - value: "%[res.hdr(X-Value),lower]" - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are req.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set/delete dynamic request header values with not allowed converters. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: "%{+Q}[ssl_c_der,bogus]" - - name: Content-Language - action: - type: Delete - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are req.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow to set dynamic request header values with not allowed sample fetchers. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: "%{+Q}[ssl_c_der1122,base64]" - - name: Content-Language - action: - type: Delete - expectedError: "Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are req.hdr, ssl_c_der. Converters allowed are lower, base64." - - name: Should not allow empty value in request - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - request: - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: - expectedError: 'Route.route.openshift.io "hello-openshift-edge-not-allowed-values" is invalid: [spec.httpHeaders.actions.request[0].action.set.value: Required value, : Invalid value: "null": some validation rules were not checked because the object was invalid; correct the existing errors to complete validation]' - - name: Should not allow empty value in response - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-edge-not-allowed-values - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-SSL-Client-Cert - action: - type: Set - set: - value: - expectedError: 'Route.route.openshift.io "hello-openshift-edge-not-allowed-values" is invalid: [spec.httpHeaders.actions.response[0].action.set.value: Required value, : Invalid value: "null": some validation rules were not checked because the object was invalid; correct the existing errors to complete validation]' - - name: Should be required to specify the set field when the discriminant type is Set. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-actions - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - type: Set - expectedError: "set is required when type is Set, and forbidden otherwise" - - name: Should be required to specify the set field when the discriminant type is Set. - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - metadata: - labels: - type: sharded - name: hello-openshift-actions - namespace: hello-openshift - spec: - subdomain: hello-openshift - tls: - termination: edge - to: - kind: Service - name: hello-openshift - httpHeaders: - actions: - response: - - name: X-Frame-Options - action: - set: - value: DENY - expectedError: 'Route.route.openshift.io "hello-openshift-actions" is invalid: [spec.httpHeaders.actions.response[0].action.type: Required value, : Invalid value: "null": some validation rules were not checked because the object was invalid; correct the existing errors to complete validation]' diff --git a/vendor/github.com/openshift/api/route/v1/techpreview.route.testsuite.yaml b/vendor/github.com/openshift/api/route/v1/techpreview.route.testsuite.yaml deleted file mode 100644 index 0f0cdd11b..000000000 --- a/vendor/github.com/openshift/api/route/v1/techpreview.route.testsuite.yaml +++ /dev/null @@ -1,103 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this -name: '[TechPreview] Route' -crd: route-TechPreviewNoUpgrade.crd.yaml -tests: - onCreate: - - name: Should be able to create a minimal Route - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - weight: 100 - wildcardPolicy: None - - name: 'cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Allow - expectedError: 'cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow' - - name: 'spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: Redirect' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: Redirect - wildcardPolicy: None - - name: 'spec.tls.termination: passthrough is compatible with spec.tls.insecureEdgeTerminationPolicy: None' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - expected: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - host: test.foo - to: - kind: Service - name: foo - weight: 100 - tls: - termination: passthrough - insecureEdgeTerminationPolicy: None - wildcardPolicy: None - - name: 'cannot have both spec.tls.certificate and spec.tls.externalCertificate' - initial: | - apiVersion: route.openshift.io/v1 - kind: Route - spec: - to: - kind: Service - name: foo - tls: - termination: edge - key: |- - -----BEGIN RSA PRIVATE KEY----- - -----END RSA PRIVATE KEY----- - certificate: |- - -----BEGIN CERTIFICATE----- - -----END CERTIFICATE----- - externalCertificate: - name: "my-local-secret" - expectedError: 'Invalid value: "object": cannot have both spec.tls.certificate and spec.tls.externalCertificate' diff --git a/vendor/github.com/openshift/api/route/v1/types.go b/vendor/github.com/openshift/api/route/v1/types.go index b5a567d6a..cd5e5eced 100644 --- a/vendor/github.com/openshift/api/route/v1/types.go +++ b/vendor/github.com/openshift/api/route/v1/types.go @@ -10,6 +10,12 @@ import ( // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +kubebuilder:resource:path=routes,scope=Namespaced +// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/1228 +// +kubebuilder:printcolumn:name=Host,JSONPath=.status.ingress[0].host,type=string +// +kubebuilder:printcolumn:name=Admitted,JSONPath=.status.ingress[0].conditions[?(@.type=="Admitted")].status,type=string +// +kubebuilder:printcolumn:name=Service,JSONPath=.spec.to.name,type=string +// +kubebuilder:printcolumn:name=TLS,JSONPath=.spec.tls.type,type=string // A route allows developers to expose services through an HTTP(S) aware load balancing and proxy // layer via a public DNS entry. The route may further specify TLS options and a certificate, or @@ -409,7 +415,7 @@ type RouterShard struct { // TLSConfig defines config used to secure a route and provide termination // // +kubebuilder:validation:XValidation:rule="has(self.termination) && has(self.insecureEdgeTerminationPolicy) ? !((self.termination=='passthrough') && (self.insecureEdgeTerminationPolicy=='Allow')) : true", message="cannot have both spec.tls.termination: passthrough and spec.tls.insecureEdgeTerminationPolicy: Allow" -// +openshift:validation:FeatureSetAwareXValidation:featureSet=TechPreviewNoUpgrade;CustomNoUpgrade,rule="!(has(self.certificate) && has(self.externalCertificate))", message="cannot have both spec.tls.certificate and spec.tls.externalCertificate" +// +openshift:validation:FeatureGateAwareXValidation:featureGate=ExternalRouteCertificate,rule="!(has(self.certificate) && has(self.externalCertificate))", message="cannot have both spec.tls.certificate and spec.tls.externalCertificate" type TLSConfig struct { // termination indicates termination type. // @@ -454,7 +460,7 @@ type TLSConfig struct { // be present in the same namespace as that of the Route. // Forbidden when `certificate` is set. // - // +openshift:enable:FeatureSets=CustomNoUpgrade;TechPreviewNoUpgrade + // +openshift:enable:FeatureGate=ExternalRouteCertificate // +optional ExternalCertificate *LocalObjectReference `json:"externalCertificate,omitempty" protobuf:"bytes,7,opt,name=externalCertificate"` } diff --git a/vendor/github.com/openshift/api/route/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/route/v1/zz_generated.featuregated-crd-manifests.yaml new file mode 100644 index 000000000..aced0855f --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/zz_generated.featuregated-crd-manifests.yaml @@ -0,0 +1,34 @@ +routes.route.openshift.io: + Annotations: {} + ApprovedPRNumber: https://github.com/openshift/api/pull/1228 + CRDName: routes.route.openshift.io + Capability: "" + Category: "" + FeatureGates: + - ExternalRouteCertificate + FilenameOperatorName: "" + FilenameOperatorOrdering: "" + FilenameRunLevel: "" + GroupName: route.openshift.io + HasStatus: true + KindName: Route + Labels: {} + PluralName: routes + PrinterColumns: + - jsonPath: .status.ingress[0].host + name: Host + type: string + - jsonPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status + name: Admitted + type: string + - jsonPath: .spec.to.name + name: Service + type: string + - jsonPath: .spec.tls.type + name: TLS + type: string + Scope: Namespaced + ShortNames: null + TopLevelFeatureGates: [] + Version: v1 + diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/clientset.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/clientset.go index 7ca945a3f..3489558fd 100644 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/clientset.go +++ b/vendor/github.com/openshift/client-go/project/clientset/versioned/clientset.go @@ -17,8 +17,7 @@ type Interface interface { ProjectV1() projectv1.ProjectV1Interface } -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. +// Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient projectV1 *projectv1.ProjectV1Client diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/doc.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/doc.go deleted file mode 100644 index 0e0c2a890..000000000 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/fake/register.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/fake/register.go index 55d568189..64269eabc 100644 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/fake/register.go +++ b/vendor/github.com/openshift/client-go/project/clientset/versioned/fake/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/scheme/register.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/scheme/register.go index 5706a6c0c..062621ee1 100644 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/scheme/register.go +++ b/vendor/github.com/openshift/client-go/project/clientset/versioned/scheme/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_project.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_project.go index 5840a63fc..88d3195d8 100644 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_project.go +++ b/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_project.go @@ -7,11 +7,10 @@ import ( json "encoding/json" "fmt" - projectv1 "github.com/openshift/api/project/v1" - applyconfigurationsprojectv1 "github.com/openshift/client-go/project/applyconfigurations/project/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "github.com/openshift/api/project/v1" + projectv1 "github.com/openshift/client-go/project/applyconfigurations/project/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" @@ -22,24 +21,24 @@ type FakeProjects struct { Fake *FakeProjectV1 } -var projectsResource = schema.GroupVersionResource{Group: "project.openshift.io", Version: "v1", Resource: "projects"} +var projectsResource = v1.SchemeGroupVersion.WithResource("projects") -var projectsKind = schema.GroupVersionKind{Group: "project.openshift.io", Version: "v1", Kind: "Project"} +var projectsKind = v1.SchemeGroupVersion.WithKind("Project") // Get takes name of the project, and returns the corresponding project object, and an error if there is any. -func (c *FakeProjects) Get(ctx context.Context, name string, options v1.GetOptions) (result *projectv1.Project, err error) { +func (c *FakeProjects) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Project, err error) { obj, err := c.Fake. - Invokes(testing.NewRootGetAction(projectsResource, name), &projectv1.Project{}) + Invokes(testing.NewRootGetAction(projectsResource, name), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // List takes label and field selectors, and returns the list of Projects that match those selectors. -func (c *FakeProjects) List(ctx context.Context, opts v1.ListOptions) (result *projectv1.ProjectList, err error) { +func (c *FakeProjects) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ProjectList, err error) { obj, err := c.Fake. - Invokes(testing.NewRootListAction(projectsResource, projectsKind, opts), &projectv1.ProjectList{}) + Invokes(testing.NewRootListAction(projectsResource, projectsKind, opts), &v1.ProjectList{}) if obj == nil { return nil, err } @@ -48,8 +47,8 @@ func (c *FakeProjects) List(ctx context.Context, opts v1.ListOptions) (result *p if label == nil { label = labels.Everything() } - list := &projectv1.ProjectList{ListMeta: obj.(*projectv1.ProjectList).ListMeta} - for _, item := range obj.(*projectv1.ProjectList).Items { + list := &v1.ProjectList{ListMeta: obj.(*v1.ProjectList).ListMeta} + for _, item := range obj.(*v1.ProjectList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } @@ -58,69 +57,69 @@ func (c *FakeProjects) List(ctx context.Context, opts v1.ListOptions) (result *p } // Watch returns a watch.Interface that watches the requested projects. -func (c *FakeProjects) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { +func (c *FakeProjects) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { return c.Fake. InvokesWatch(testing.NewRootWatchAction(projectsResource, opts)) } // Create takes the representation of a project and creates it. Returns the server's representation of the project, and an error, if there is any. -func (c *FakeProjects) Create(ctx context.Context, project *projectv1.Project, opts v1.CreateOptions) (result *projectv1.Project, err error) { +func (c *FakeProjects) Create(ctx context.Context, project *v1.Project, opts metav1.CreateOptions) (result *v1.Project, err error) { obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(projectsResource, project), &projectv1.Project{}) + Invokes(testing.NewRootCreateAction(projectsResource, project), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // Update takes the representation of a project and updates it. Returns the server's representation of the project, and an error, if there is any. -func (c *FakeProjects) Update(ctx context.Context, project *projectv1.Project, opts v1.UpdateOptions) (result *projectv1.Project, err error) { +func (c *FakeProjects) Update(ctx context.Context, project *v1.Project, opts metav1.UpdateOptions) (result *v1.Project, err error) { obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(projectsResource, project), &projectv1.Project{}) + Invokes(testing.NewRootUpdateAction(projectsResource, project), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeProjects) UpdateStatus(ctx context.Context, project *projectv1.Project, opts v1.UpdateOptions) (*projectv1.Project, error) { +func (c *FakeProjects) UpdateStatus(ctx context.Context, project *v1.Project, opts metav1.UpdateOptions) (*v1.Project, error) { obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(projectsResource, "status", project), &projectv1.Project{}) + Invokes(testing.NewRootUpdateSubresourceAction(projectsResource, "status", project), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // Delete takes name of the project and deletes it. Returns an error if one occurs. -func (c *FakeProjects) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { +func (c *FakeProjects) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteActionWithOptions(projectsResource, name, opts), &projectv1.Project{}) + Invokes(testing.NewRootDeleteActionWithOptions(projectsResource, name, opts), &v1.Project{}) return err } // DeleteCollection deletes a collection of objects. -func (c *FakeProjects) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { +func (c *FakeProjects) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { action := testing.NewRootDeleteCollectionAction(projectsResource, listOpts) - _, err := c.Fake.Invokes(action, &projectv1.ProjectList{}) + _, err := c.Fake.Invokes(action, &v1.ProjectList{}) return err } // Patch applies the patch and returns the patched project. -func (c *FakeProjects) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *projectv1.Project, err error) { +func (c *FakeProjects) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Project, err error) { obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(projectsResource, name, pt, data, subresources...), &projectv1.Project{}) + Invokes(testing.NewRootPatchSubresourceAction(projectsResource, name, pt, data, subresources...), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // Apply takes the given apply declarative configuration, applies it and returns the applied project. -func (c *FakeProjects) Apply(ctx context.Context, project *applyconfigurationsprojectv1.ProjectApplyConfiguration, opts v1.ApplyOptions) (result *projectv1.Project, err error) { +func (c *FakeProjects) Apply(ctx context.Context, project *projectv1.ProjectApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Project, err error) { if project == nil { return nil, fmt.Errorf("project provided to Apply must not be nil") } @@ -133,16 +132,16 @@ func (c *FakeProjects) Apply(ctx context.Context, project *applyconfigurationspr return nil, fmt.Errorf("project.Name must be provided to Apply") } obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(projectsResource, *name, types.ApplyPatchType, data), &projectv1.Project{}) + Invokes(testing.NewRootPatchSubresourceAction(projectsResource, *name, types.ApplyPatchType, data), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } // ApplyStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *FakeProjects) ApplyStatus(ctx context.Context, project *applyconfigurationsprojectv1.ProjectApplyConfiguration, opts v1.ApplyOptions) (result *projectv1.Project, err error) { +func (c *FakeProjects) ApplyStatus(ctx context.Context, project *projectv1.ProjectApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Project, err error) { if project == nil { return nil, fmt.Errorf("project provided to Apply must not be nil") } @@ -155,9 +154,9 @@ func (c *FakeProjects) ApplyStatus(ctx context.Context, project *applyconfigurat return nil, fmt.Errorf("project.Name must be provided to Apply") } obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(projectsResource, *name, types.ApplyPatchType, data, "status"), &projectv1.Project{}) + Invokes(testing.NewRootPatchSubresourceAction(projectsResource, *name, types.ApplyPatchType, data, "status"), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } diff --git a/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_projectrequest.go b/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_projectrequest.go index 86aea37b4..579ba0fa4 100644 --- a/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_projectrequest.go +++ b/vendor/github.com/openshift/client-go/project/clientset/versioned/typed/project/v1/fake/fake_projectrequest.go @@ -7,10 +7,9 @@ import ( json "encoding/json" "fmt" - projectv1 "github.com/openshift/api/project/v1" - v1 "github.com/openshift/client-go/project/applyconfigurations/project/v1" + v1 "github.com/openshift/api/project/v1" + projectv1 "github.com/openshift/client-go/project/applyconfigurations/project/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - schema "k8s.io/apimachinery/pkg/runtime/schema" types "k8s.io/apimachinery/pkg/types" testing "k8s.io/client-go/testing" ) @@ -20,12 +19,12 @@ type FakeProjectRequests struct { Fake *FakeProjectV1 } -var projectrequestsResource = schema.GroupVersionResource{Group: "project.openshift.io", Version: "v1", Resource: "projectrequests"} +var projectrequestsResource = v1.SchemeGroupVersion.WithResource("projectrequests") -var projectrequestsKind = schema.GroupVersionKind{Group: "project.openshift.io", Version: "v1", Kind: "ProjectRequest"} +var projectrequestsKind = v1.SchemeGroupVersion.WithKind("ProjectRequest") // Apply takes the given apply declarative configuration, applies it and returns the applied projectRequest. -func (c *FakeProjectRequests) Apply(ctx context.Context, projectRequest *v1.ProjectRequestApplyConfiguration, opts metav1.ApplyOptions) (result *projectv1.ProjectRequest, err error) { +func (c *FakeProjectRequests) Apply(ctx context.Context, projectRequest *projectv1.ProjectRequestApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ProjectRequest, err error) { if projectRequest == nil { return nil, fmt.Errorf("projectRequest provided to Apply must not be nil") } @@ -38,19 +37,19 @@ func (c *FakeProjectRequests) Apply(ctx context.Context, projectRequest *v1.Proj return nil, fmt.Errorf("projectRequest.Name must be provided to Apply") } obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(projectrequestsResource, *name, types.ApplyPatchType, data), &projectv1.ProjectRequest{}) + Invokes(testing.NewRootPatchSubresourceAction(projectrequestsResource, *name, types.ApplyPatchType, data), &v1.ProjectRequest{}) if obj == nil { return nil, err } - return obj.(*projectv1.ProjectRequest), err + return obj.(*v1.ProjectRequest), err } // Create takes the representation of a projectRequest and creates it. Returns the server's representation of the project, and an error, if there is any. -func (c *FakeProjectRequests) Create(ctx context.Context, projectRequest *projectv1.ProjectRequest, opts metav1.CreateOptions) (result *projectv1.Project, err error) { +func (c *FakeProjectRequests) Create(ctx context.Context, projectRequest *v1.ProjectRequest, opts metav1.CreateOptions) (result *v1.Project, err error) { obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(projectrequestsResource, projectRequest), &projectv1.Project{}) + Invokes(testing.NewRootCreateAction(projectrequestsResource, projectRequest), &v1.Project{}) if obj == nil { return nil, err } - return obj.(*projectv1.Project), err + return obj.(*v1.Project), err } diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go index cc97c71ff..38acf6dc7 100644 --- a/vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go @@ -23,6 +23,13 @@ func Parser() *typed.Parser { var parserOnce sync.Once var parser *typed.Parser var schemaYAML = typed.YAMLObject(`types: +- name: com.github.openshift.api.route.v1.LocalObjectReference + map: + fields: + - name: name + type: + scalar: string + elementRelationship: atomic - name: com.github.openshift.api.route.v1.Route map: fields: @@ -44,6 +51,58 @@ var schemaYAML = typed.YAMLObject(`types: type: namedType: com.github.openshift.api.route.v1.RouteStatus default: {} +- name: com.github.openshift.api.route.v1.RouteHTTPHeader + map: + fields: + - name: action + type: + namedType: com.github.openshift.api.route.v1.RouteHTTPHeaderActionUnion + default: {} + - name: name + type: + scalar: string + default: "" +- name: com.github.openshift.api.route.v1.RouteHTTPHeaderActionUnion + map: + fields: + - name: set + type: + namedType: com.github.openshift.api.route.v1.RouteSetHTTPHeader + - name: type + type: + scalar: string + default: "" + unions: + - discriminator: type + fields: + - fieldName: set + discriminatorValue: Set +- name: com.github.openshift.api.route.v1.RouteHTTPHeaderActions + map: + fields: + - name: request + type: + list: + elementType: + namedType: com.github.openshift.api.route.v1.RouteHTTPHeader + elementRelationship: associative + keys: + - name + - name: response + type: + list: + elementType: + namedType: com.github.openshift.api.route.v1.RouteHTTPHeader + elementRelationship: associative + keys: + - name +- name: com.github.openshift.api.route.v1.RouteHTTPHeaders + map: + fields: + - name: actions + type: + namedType: com.github.openshift.api.route.v1.RouteHTTPHeaderActions + default: {} - name: com.github.openshift.api.route.v1.RouteIngress map: fields: @@ -92,6 +151,13 @@ var schemaYAML = typed.YAMLObject(`types: type: namedType: io.k8s.apimachinery.pkg.util.intstr.IntOrString default: {} +- name: com.github.openshift.api.route.v1.RouteSetHTTPHeader + map: + fields: + - name: value + type: + scalar: string + default: "" - name: com.github.openshift.api.route.v1.RouteSpec map: fields: @@ -104,6 +170,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: host type: scalar: string + - name: httpHeaders + type: + namedType: com.github.openshift.api.route.v1.RouteHTTPHeaders - name: path type: scalar: string @@ -158,6 +227,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: destinationCACertificate type: scalar: string + - name: externalCertificate + type: + namedType: com.github.openshift.api.route.v1.LocalObjectReference - name: insecureEdgeTerminationPolicy type: scalar: string diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go new file mode 100644 index 000000000..da17405b0 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go @@ -0,0 +1,23 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// LocalObjectReferenceApplyConfiguration represents an declarative configuration of the LocalObjectReference type for use +// with apply. +type LocalObjectReferenceApplyConfiguration struct { + Name *string `json:"name,omitempty"` +} + +// LocalObjectReferenceApplyConfiguration constructs an declarative configuration of the LocalObjectReference type for use with +// apply. +func LocalObjectReference() *LocalObjectReferenceApplyConfiguration { + return &LocalObjectReferenceApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *LocalObjectReferenceApplyConfiguration) WithName(value string) *LocalObjectReferenceApplyConfiguration { + b.Name = &value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go new file mode 100644 index 000000000..f06203cab --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go @@ -0,0 +1,32 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// RouteHTTPHeaderApplyConfiguration represents an declarative configuration of the RouteHTTPHeader type for use +// with apply. +type RouteHTTPHeaderApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Action *RouteHTTPHeaderActionUnionApplyConfiguration `json:"action,omitempty"` +} + +// RouteHTTPHeaderApplyConfiguration constructs an declarative configuration of the RouteHTTPHeader type for use with +// apply. +func RouteHTTPHeader() *RouteHTTPHeaderApplyConfiguration { + return &RouteHTTPHeaderApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RouteHTTPHeaderApplyConfiguration) WithName(value string) *RouteHTTPHeaderApplyConfiguration { + b.Name = &value + return b +} + +// WithAction sets the Action field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Action field is set to the value of the last call. +func (b *RouteHTTPHeaderApplyConfiguration) WithAction(value *RouteHTTPHeaderActionUnionApplyConfiguration) *RouteHTTPHeaderApplyConfiguration { + b.Action = value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go new file mode 100644 index 000000000..ef7fa5812 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go @@ -0,0 +1,42 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// RouteHTTPHeaderActionsApplyConfiguration represents an declarative configuration of the RouteHTTPHeaderActions type for use +// with apply. +type RouteHTTPHeaderActionsApplyConfiguration struct { + Response []RouteHTTPHeaderApplyConfiguration `json:"response,omitempty"` + Request []RouteHTTPHeaderApplyConfiguration `json:"request,omitempty"` +} + +// RouteHTTPHeaderActionsApplyConfiguration constructs an declarative configuration of the RouteHTTPHeaderActions type for use with +// apply. +func RouteHTTPHeaderActions() *RouteHTTPHeaderActionsApplyConfiguration { + return &RouteHTTPHeaderActionsApplyConfiguration{} +} + +// WithResponse adds the given value to the Response field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Response field. +func (b *RouteHTTPHeaderActionsApplyConfiguration) WithResponse(values ...*RouteHTTPHeaderApplyConfiguration) *RouteHTTPHeaderActionsApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithResponse") + } + b.Response = append(b.Response, *values[i]) + } + return b +} + +// WithRequest adds the given value to the Request field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Request field. +func (b *RouteHTTPHeaderActionsApplyConfiguration) WithRequest(values ...*RouteHTTPHeaderApplyConfiguration) *RouteHTTPHeaderActionsApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithRequest") + } + b.Request = append(b.Request, *values[i]) + } + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go new file mode 100644 index 000000000..b786c07dc --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go @@ -0,0 +1,36 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openshift/api/route/v1" +) + +// RouteHTTPHeaderActionUnionApplyConfiguration represents an declarative configuration of the RouteHTTPHeaderActionUnion type for use +// with apply. +type RouteHTTPHeaderActionUnionApplyConfiguration struct { + Type *v1.RouteHTTPHeaderActionType `json:"type,omitempty"` + Set *RouteSetHTTPHeaderApplyConfiguration `json:"set,omitempty"` +} + +// RouteHTTPHeaderActionUnionApplyConfiguration constructs an declarative configuration of the RouteHTTPHeaderActionUnion type for use with +// apply. +func RouteHTTPHeaderActionUnion() *RouteHTTPHeaderActionUnionApplyConfiguration { + return &RouteHTTPHeaderActionUnionApplyConfiguration{} +} + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *RouteHTTPHeaderActionUnionApplyConfiguration) WithType(value v1.RouteHTTPHeaderActionType) *RouteHTTPHeaderActionUnionApplyConfiguration { + b.Type = &value + return b +} + +// WithSet sets the Set field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Set field is set to the value of the last call. +func (b *RouteHTTPHeaderActionUnionApplyConfiguration) WithSet(value *RouteSetHTTPHeaderApplyConfiguration) *RouteHTTPHeaderActionUnionApplyConfiguration { + b.Set = value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go new file mode 100644 index 000000000..e112230c8 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go @@ -0,0 +1,23 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// RouteHTTPHeadersApplyConfiguration represents an declarative configuration of the RouteHTTPHeaders type for use +// with apply. +type RouteHTTPHeadersApplyConfiguration struct { + Actions *RouteHTTPHeaderActionsApplyConfiguration `json:"actions,omitempty"` +} + +// RouteHTTPHeadersApplyConfiguration constructs an declarative configuration of the RouteHTTPHeaders type for use with +// apply. +func RouteHTTPHeaders() *RouteHTTPHeadersApplyConfiguration { + return &RouteHTTPHeadersApplyConfiguration{} +} + +// WithActions sets the Actions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Actions field is set to the value of the last call. +func (b *RouteHTTPHeadersApplyConfiguration) WithActions(value *RouteHTTPHeaderActionsApplyConfiguration) *RouteHTTPHeadersApplyConfiguration { + b.Actions = value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go new file mode 100644 index 000000000..4c0952c79 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go @@ -0,0 +1,23 @@ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// RouteSetHTTPHeaderApplyConfiguration represents an declarative configuration of the RouteSetHTTPHeader type for use +// with apply. +type RouteSetHTTPHeaderApplyConfiguration struct { + Value *string `json:"value,omitempty"` +} + +// RouteSetHTTPHeaderApplyConfiguration constructs an declarative configuration of the RouteSetHTTPHeader type for use with +// apply. +func RouteSetHTTPHeader() *RouteSetHTTPHeaderApplyConfiguration { + return &RouteSetHTTPHeaderApplyConfiguration{} +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *RouteSetHTTPHeaderApplyConfiguration) WithValue(value string) *RouteSetHTTPHeaderApplyConfiguration { + b.Value = &value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go index 8034bace0..c6dcacfb2 100644 --- a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go @@ -17,6 +17,7 @@ type RouteSpecApplyConfiguration struct { Port *RoutePortApplyConfiguration `json:"port,omitempty"` TLS *TLSConfigApplyConfiguration `json:"tls,omitempty"` WildcardPolicy *routev1.WildcardPolicyType `json:"wildcardPolicy,omitempty"` + HTTPHeaders *RouteHTTPHeadersApplyConfiguration `json:"httpHeaders,omitempty"` } // RouteSpecApplyConfiguration constructs an declarative configuration of the RouteSpec type for use with @@ -93,3 +94,11 @@ func (b *RouteSpecApplyConfiguration) WithWildcardPolicy(value routev1.WildcardP b.WildcardPolicy = &value return b } + +// WithHTTPHeaders sets the HTTPHeaders field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HTTPHeaders field is set to the value of the last call. +func (b *RouteSpecApplyConfiguration) WithHTTPHeaders(value *RouteHTTPHeadersApplyConfiguration) *RouteSpecApplyConfiguration { + b.HTTPHeaders = value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go index 5188a3921..9f5f4449c 100644 --- a/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go +++ b/vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go @@ -9,12 +9,13 @@ import ( // TLSConfigApplyConfiguration represents an declarative configuration of the TLSConfig type for use // with apply. type TLSConfigApplyConfiguration struct { - Termination *v1.TLSTerminationType `json:"termination,omitempty"` - Certificate *string `json:"certificate,omitempty"` - Key *string `json:"key,omitempty"` - CACertificate *string `json:"caCertificate,omitempty"` - DestinationCACertificate *string `json:"destinationCACertificate,omitempty"` - InsecureEdgeTerminationPolicy *v1.InsecureEdgeTerminationPolicyType `json:"insecureEdgeTerminationPolicy,omitempty"` + Termination *v1.TLSTerminationType `json:"termination,omitempty"` + Certificate *string `json:"certificate,omitempty"` + Key *string `json:"key,omitempty"` + CACertificate *string `json:"caCertificate,omitempty"` + DestinationCACertificate *string `json:"destinationCACertificate,omitempty"` + InsecureEdgeTerminationPolicy *v1.InsecureEdgeTerminationPolicyType `json:"insecureEdgeTerminationPolicy,omitempty"` + ExternalCertificate *LocalObjectReferenceApplyConfiguration `json:"externalCertificate,omitempty"` } // TLSConfigApplyConfiguration constructs an declarative configuration of the TLSConfig type for use with @@ -70,3 +71,11 @@ func (b *TLSConfigApplyConfiguration) WithInsecureEdgeTerminationPolicy(value v1 b.InsecureEdgeTerminationPolicy = &value return b } + +// WithExternalCertificate sets the ExternalCertificate field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExternalCertificate field is set to the value of the last call. +func (b *TLSConfigApplyConfiguration) WithExternalCertificate(value *LocalObjectReferenceApplyConfiguration) *TLSConfigApplyConfiguration { + b.ExternalCertificate = value + return b +} diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/clientset.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/clientset.go index 2dfd30b81..23c80b601 100644 --- a/vendor/github.com/openshift/client-go/route/clientset/versioned/clientset.go +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/clientset.go @@ -17,8 +17,7 @@ type Interface interface { RouteV1() routev1.RouteV1Interface } -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. +// Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient routeV1 *routev1.RouteV1Client diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/doc.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/doc.go deleted file mode 100644 index 0e0c2a890..000000000 --- a/vendor/github.com/openshift/client-go/route/clientset/versioned/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/fake/register.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/fake/register.go index 279f25d9d..21e116a50 100644 --- a/vendor/github.com/openshift/client-go/route/clientset/versioned/fake/register.go +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/fake/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go index 0604e5613..53ac82ff5 100644 --- a/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/fake/fake_route.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/fake/fake_route.go index 6f41ab132..734c8b712 100644 --- a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/fake/fake_route.go +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/fake/fake_route.go @@ -7,11 +7,10 @@ import ( json "encoding/json" "fmt" - routev1 "github.com/openshift/api/route/v1" - applyconfigurationsroutev1 "github.com/openshift/client-go/route/applyconfigurations/route/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "github.com/openshift/api/route/v1" + routev1 "github.com/openshift/client-go/route/applyconfigurations/route/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" @@ -23,25 +22,25 @@ type FakeRoutes struct { ns string } -var routesResource = schema.GroupVersionResource{Group: "route.openshift.io", Version: "v1", Resource: "routes"} +var routesResource = v1.SchemeGroupVersion.WithResource("routes") -var routesKind = schema.GroupVersionKind{Group: "route.openshift.io", Version: "v1", Kind: "Route"} +var routesKind = v1.SchemeGroupVersion.WithKind("Route") // Get takes name of the route, and returns the corresponding route object, and an error if there is any. -func (c *FakeRoutes) Get(ctx context.Context, name string, options v1.GetOptions) (result *routev1.Route, err error) { +func (c *FakeRoutes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Route, err error) { obj, err := c.Fake. - Invokes(testing.NewGetAction(routesResource, c.ns, name), &routev1.Route{}) + Invokes(testing.NewGetAction(routesResource, c.ns, name), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // List takes label and field selectors, and returns the list of Routes that match those selectors. -func (c *FakeRoutes) List(ctx context.Context, opts v1.ListOptions) (result *routev1.RouteList, err error) { +func (c *FakeRoutes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.RouteList, err error) { obj, err := c.Fake. - Invokes(testing.NewListAction(routesResource, routesKind, c.ns, opts), &routev1.RouteList{}) + Invokes(testing.NewListAction(routesResource, routesKind, c.ns, opts), &v1.RouteList{}) if obj == nil { return nil, err @@ -51,8 +50,8 @@ func (c *FakeRoutes) List(ctx context.Context, opts v1.ListOptions) (result *rou if label == nil { label = labels.Everything() } - list := &routev1.RouteList{ListMeta: obj.(*routev1.RouteList).ListMeta} - for _, item := range obj.(*routev1.RouteList).Items { + list := &v1.RouteList{ListMeta: obj.(*v1.RouteList).ListMeta} + for _, item := range obj.(*v1.RouteList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } @@ -61,75 +60,75 @@ func (c *FakeRoutes) List(ctx context.Context, opts v1.ListOptions) (result *rou } // Watch returns a watch.Interface that watches the requested routes. -func (c *FakeRoutes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { +func (c *FakeRoutes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { return c.Fake. InvokesWatch(testing.NewWatchAction(routesResource, c.ns, opts)) } // Create takes the representation of a route and creates it. Returns the server's representation of the route, and an error, if there is any. -func (c *FakeRoutes) Create(ctx context.Context, route *routev1.Route, opts v1.CreateOptions) (result *routev1.Route, err error) { +func (c *FakeRoutes) Create(ctx context.Context, route *v1.Route, opts metav1.CreateOptions) (result *v1.Route, err error) { obj, err := c.Fake. - Invokes(testing.NewCreateAction(routesResource, c.ns, route), &routev1.Route{}) + Invokes(testing.NewCreateAction(routesResource, c.ns, route), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // Update takes the representation of a route and updates it. Returns the server's representation of the route, and an error, if there is any. -func (c *FakeRoutes) Update(ctx context.Context, route *routev1.Route, opts v1.UpdateOptions) (result *routev1.Route, err error) { +func (c *FakeRoutes) Update(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (result *v1.Route, err error) { obj, err := c.Fake. - Invokes(testing.NewUpdateAction(routesResource, c.ns, route), &routev1.Route{}) + Invokes(testing.NewUpdateAction(routesResource, c.ns, route), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeRoutes) UpdateStatus(ctx context.Context, route *routev1.Route, opts v1.UpdateOptions) (*routev1.Route, error) { +func (c *FakeRoutes) UpdateStatus(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (*v1.Route, error) { obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(routesResource, "status", c.ns, route), &routev1.Route{}) + Invokes(testing.NewUpdateSubresourceAction(routesResource, "status", c.ns, route), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // Delete takes name of the route and deletes it. Returns an error if one occurs. -func (c *FakeRoutes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { +func (c *FakeRoutes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(routesResource, c.ns, name, opts), &routev1.Route{}) + Invokes(testing.NewDeleteActionWithOptions(routesResource, c.ns, name, opts), &v1.Route{}) return err } // DeleteCollection deletes a collection of objects. -func (c *FakeRoutes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { +func (c *FakeRoutes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { action := testing.NewDeleteCollectionAction(routesResource, c.ns, listOpts) - _, err := c.Fake.Invokes(action, &routev1.RouteList{}) + _, err := c.Fake.Invokes(action, &v1.RouteList{}) return err } // Patch applies the patch and returns the patched route. -func (c *FakeRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *routev1.Route, err error) { +func (c *FakeRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Route, err error) { obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, name, pt, data, subresources...), &routev1.Route{}) + Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, name, pt, data, subresources...), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // Apply takes the given apply declarative configuration, applies it and returns the applied route. -func (c *FakeRoutes) Apply(ctx context.Context, route *applyconfigurationsroutev1.RouteApplyConfiguration, opts v1.ApplyOptions) (result *routev1.Route, err error) { +func (c *FakeRoutes) Apply(ctx context.Context, route *routev1.RouteApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Route, err error) { if route == nil { return nil, fmt.Errorf("route provided to Apply must not be nil") } @@ -142,17 +141,17 @@ func (c *FakeRoutes) Apply(ctx context.Context, route *applyconfigurationsroutev return nil, fmt.Errorf("route.Name must be provided to Apply") } obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, *name, types.ApplyPatchType, data), &routev1.Route{}) + Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, *name, types.ApplyPatchType, data), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } // ApplyStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *FakeRoutes) ApplyStatus(ctx context.Context, route *applyconfigurationsroutev1.RouteApplyConfiguration, opts v1.ApplyOptions) (result *routev1.Route, err error) { +func (c *FakeRoutes) ApplyStatus(ctx context.Context, route *routev1.RouteApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Route, err error) { if route == nil { return nil, fmt.Errorf("route provided to Apply must not be nil") } @@ -165,10 +164,10 @@ func (c *FakeRoutes) ApplyStatus(ctx context.Context, route *applyconfigurations return nil, fmt.Errorf("route.Name must be provided to Apply") } obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &routev1.Route{}) + Invokes(testing.NewPatchSubresourceAction(routesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1.Route{}) if obj == nil { return nil, err } - return obj.(*routev1.Route), err + return obj.(*v1.Route), err } diff --git a/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go b/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go new file mode 100644 index 000000000..74c179e68 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/subject.go @@ -0,0 +1,56 @@ +package authorizationutil + +import ( + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apiserver/pkg/authentication/serviceaccount" +) + +func BuildRBACSubjects(users, groups []string) []rbacv1.Subject { + subjects := []rbacv1.Subject{} + + for _, user := range users { + saNamespace, saName, err := serviceaccount.SplitUsername(user) + if err == nil { + subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Namespace: saNamespace, Name: saName}) + } else { + subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: user}) + } + } + + for _, group := range groups { + subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: group}) + } + + return subjects +} + +func RBACSubjectsToUsersAndGroups(subjects []rbacv1.Subject, defaultNamespace string) (users []string, groups []string) { + for _, subject := range subjects { + + switch { + case subject.APIGroup == rbacv1.GroupName && subject.Kind == rbacv1.GroupKind: + groups = append(groups, subject.Name) + case subject.APIGroup == rbacv1.GroupName && subject.Kind == rbacv1.UserKind: + users = append(users, subject.Name) + case subject.APIGroup == "" && subject.Kind == rbacv1.ServiceAccountKind: + // default the namespace to namespace we're working in if + // it's available. This allows rolebindings that reference + // SAs in the local namespace to avoid having to qualify + // them. + ns := defaultNamespace + if len(subject.Namespace) > 0 { + ns = subject.Namespace + } + if len(ns) > 0 { + name := serviceaccount.MakeUsername(ns, subject.Name) + users = append(users, name) + } else { + // maybe error? this fails safe at any rate + } + default: + // maybe error? This fails safe at any rate + } + } + + return users, groups +} diff --git a/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go b/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go new file mode 100644 index 000000000..040d0f643 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/authorization/authorizationutil/util.go @@ -0,0 +1,50 @@ +package authorizationutil + +import ( + "context" + "errors" + + authorizationv1 "k8s.io/api/authorization/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/authentication/user" + authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" +) + +// AddUserToSAR adds the requisite user information to a SubjectAccessReview. +// It returns the modified SubjectAccessReview. +func AddUserToSAR(user user.Info, sar *authorizationv1.SubjectAccessReview) *authorizationv1.SubjectAccessReview { + sar.Spec.User = user.GetName() + // reminiscent of the bad old days of C. Copies copy the min number of elements of both source and dest + sar.Spec.Groups = make([]string, len(user.GetGroups())) + copy(sar.Spec.Groups, user.GetGroups()) + sar.Spec.Extra = map[string]authorizationv1.ExtraValue{} + + for k, v := range user.GetExtra() { + sar.Spec.Extra[k] = authorizationv1.ExtraValue(v) + } + + return sar +} + +// Authorize verifies that a given user is permitted to carry out a given +// action. If this cannot be determined, or if the user is not permitted, an +// error is returned. +func Authorize(sarClient authorizationclient.SubjectAccessReviewInterface, user user.Info, resourceAttributes *authorizationv1.ResourceAttributes) error { + sar := AddUserToSAR(user, &authorizationv1.SubjectAccessReview{ + Spec: authorizationv1.SubjectAccessReviewSpec{ + ResourceAttributes: resourceAttributes, + }, + }) + + resp, err := sarClient.Create(context.TODO(), sar, metav1.CreateOptions{}) + if err == nil && resp != nil && resp.Status.Allowed { + return nil + } + + if err == nil { + err = errors.New(resp.Status.Reason) + } + return kerrors.NewForbidden(schema.GroupResource{Group: resourceAttributes.Group, Resource: resourceAttributes.Resource}, resourceAttributes.Name, err) +} diff --git a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go b/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go index 554112c49..63184d2eb 100644 --- a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go +++ b/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go @@ -371,7 +371,7 @@ func (c *TLSCertificateConfig) GetPEMBytes() ([]byte, []byte, error) { if err != nil { return nil, nil, err } - keyBytes, err := encodeKey(c.Key) + keyBytes, err := EncodeKey(c.Key) if err != nil { return nil, nil, err } @@ -644,15 +644,20 @@ func MakeSelfSignedCAConfigForSubject(subject pkix.Name, expireDays int) (*TLSCe } caLifetime := time.Duration(caLifetimeInDays) * 24 * time.Hour - return makeSelfSignedCAConfigForSubjectAndDuration(subject, caLifetime) + return makeSelfSignedCAConfigForSubjectAndDuration(subject, time.Now, caLifetime) } func MakeSelfSignedCAConfigForDuration(name string, caLifetime time.Duration) (*TLSCertificateConfig, error) { subject := pkix.Name{CommonName: name} - return makeSelfSignedCAConfigForSubjectAndDuration(subject, caLifetime) + return makeSelfSignedCAConfigForSubjectAndDuration(subject, time.Now, caLifetime) } -func makeSelfSignedCAConfigForSubjectAndDuration(subject pkix.Name, caLifetime time.Duration) (*TLSCertificateConfig, error) { +func UnsafeMakeSelfSignedCAConfigForDurationAtTime(name string, currentTime func() time.Time, caLifetime time.Duration) (*TLSCertificateConfig, error) { + subject := pkix.Name{CommonName: name} + return makeSelfSignedCAConfigForSubjectAndDuration(subject, currentTime, caLifetime) +} + +func makeSelfSignedCAConfigForSubjectAndDuration(subject pkix.Name, currentTime func() time.Time, caLifetime time.Duration) (*TLSCertificateConfig, error) { // Create CA cert rootcaPublicKey, rootcaPrivateKey, publicKeyHash, err := newKeyPairWithHash() if err != nil { @@ -661,7 +666,7 @@ func makeSelfSignedCAConfigForSubjectAndDuration(subject pkix.Name, caLifetime t // AuthorityKeyId and SubjectKeyId should match for a self-signed CA authorityKeyId := publicKeyHash subjectKeyId := publicKeyHash - rootcaTemplate := newSigningCertificateTemplateForDuration(subject, caLifetime, time.Now, authorityKeyId, subjectKeyId) + rootcaTemplate := newSigningCertificateTemplateForDuration(subject, caLifetime, currentTime, authorityKeyId, subjectKeyId) rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey) if err != nil { return nil, err @@ -682,7 +687,7 @@ func MakeCAConfigForDuration(name string, caLifetime time.Duration, issuer *CA) authorityKeyId := issuer.Config.Certs[0].SubjectKeyId subjectKeyId := publicKeyHash signerTemplate := newSigningCertificateTemplateForDuration(pkix.Name{CommonName: name}, caLifetime, time.Now, authorityKeyId, subjectKeyId) - signerCert, err := issuer.signCertificate(signerTemplate, signerPublicKey) + signerCert, err := issuer.SignCertificate(signerTemplate, signerPublicKey) if err != nil { return nil, err } @@ -741,7 +746,7 @@ func (ca *CA) MakeAndWriteSubCA(certFile, keyFile, serialFile, name string, expi }, nil } -func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.String, expireDays int) (*TLSCertificateConfig, bool, error) { +func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.Set[string], expireDays int) (*TLSCertificateConfig, bool, error) { certConfig, err := GetServerCert(certFile, keyFile, hostnames) if err != nil { certConfig, err = ca.MakeAndWriteServerCert(certFile, keyFile, hostnames, expireDays) @@ -751,25 +756,27 @@ func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.String, return certConfig, false, nil } -func GetServerCert(certFile, keyFile string, hostnames sets.String) (*TLSCertificateConfig, error) { +func GetServerCert(certFile, keyFile string, hostnames sets.Set[string]) (*TLSCertificateConfig, error) { server, err := GetTLSCertificateConfig(certFile, keyFile) if err != nil { return nil, err } cert := server.Certs[0] - ips, dns := IPAddressesDNSNames(hostnames.List()) - missingIps := ipsNotInSlice(ips, cert.IPAddresses) - missingDns := stringsNotInSlice(dns, cert.DNSNames) - if len(missingIps) == 0 && len(missingDns) == 0 { + certNames := sets.New[string]() + for _, ip := range cert.IPAddresses { + certNames.Insert(ip.String()) + } + certNames.Insert(cert.DNSNames...) + if hostnames.Equal(certNames) { klog.V(4).Infof("Found existing server certificate in %s", certFile) return server, nil } - return nil, fmt.Errorf("Existing server certificate in %s was missing some hostnames (%v) or IP addresses (%v).", certFile, missingDns, missingIps) + return nil, fmt.Errorf("Existing server certificate in %s does not match required hostnames.", certFile) } -func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.String, expireDays int) (*TLSCertificateConfig, error) { +func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.Set[string], expireDays int) (*TLSCertificateConfig, error) { klog.V(4).Infof("Generating server certificate in %s, key in %s", certFile, keyFile) server, err := ca.MakeServerCert(hostnames, expireDays) @@ -786,17 +793,17 @@ func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.St // if the extension attempt failed. type CertificateExtensionFunc func(*x509.Certificate) error -func (ca *CA) MakeServerCert(hostnames sets.String, expireDays int, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { +func (ca *CA) MakeServerCert(hostnames sets.Set[string], expireDays int, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() authorityKeyId := ca.Config.Certs[0].SubjectKeyId subjectKeyId := publicKeyHash - serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), expireDays, time.Now, authorityKeyId, subjectKeyId) + serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: sets.List(hostnames)[0]}, sets.List(hostnames), expireDays, time.Now, authorityKeyId, subjectKeyId) for _, fn := range fns { if err := fn(serverTemplate); err != nil { return nil, err } } - serverCrt, err := ca.signCertificate(serverTemplate, serverPublicKey) + serverCrt, err := ca.SignCertificate(serverTemplate, serverPublicKey) if err != nil { return nil, err } @@ -807,17 +814,17 @@ func (ca *CA) MakeServerCert(hostnames sets.String, expireDays int, fns ...Certi return server, nil } -func (ca *CA) MakeServerCertForDuration(hostnames sets.String, lifetime time.Duration, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { +func (ca *CA) MakeServerCertForDuration(hostnames sets.Set[string], lifetime time.Duration, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() authorityKeyId := ca.Config.Certs[0].SubjectKeyId subjectKeyId := publicKeyHash - serverTemplate := newServerCertificateTemplateForDuration(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), lifetime, time.Now, authorityKeyId, subjectKeyId) + serverTemplate := newServerCertificateTemplateForDuration(pkix.Name{CommonName: sets.List(hostnames)[0]}, sets.List(hostnames), lifetime, time.Now, authorityKeyId, subjectKeyId) for _, fn := range fns { if err := fn(serverTemplate); err != nil { return nil, err } } - serverCrt, err := ca.signCertificate(serverTemplate, serverPublicKey) + serverCrt, err := ca.SignCertificate(serverTemplate, serverPublicKey) if err != nil { return nil, err } @@ -843,7 +850,7 @@ func GetClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificat return nil, err } - if subject := certConfig.Certs[0].Subject; subjectChanged(subject, userToSubject(u)) { + if subject := certConfig.Certs[0].Subject; subjectChanged(subject, UserToSubject(u)) { return nil, fmt.Errorf("existing client certificate in %s was issued for a different Subject (%s)", certFile, subject) } @@ -871,8 +878,8 @@ func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info, expir } clientPublicKey, clientPrivateKey, _ := NewKeyPair() - clientTemplate := newClientCertificateTemplate(userToSubject(u), expireDays, time.Now) - clientCrt, err := ca.signCertificate(clientTemplate, clientPublicKey) + clientTemplate := NewClientCertificateTemplate(UserToSubject(u), expireDays, time.Now) + clientCrt, err := ca.SignCertificate(clientTemplate, clientPublicKey) if err != nil { return nil, err } @@ -881,7 +888,7 @@ func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info, expir if err != nil { return nil, err } - keyData, err := encodeKey(clientPrivateKey) + keyData, err := EncodeKey(clientPrivateKey) if err != nil { return nil, err } @@ -898,8 +905,8 @@ func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info, expir func (ca *CA) MakeClientCertificateForDuration(u user.Info, lifetime time.Duration) (*TLSCertificateConfig, error) { clientPublicKey, clientPrivateKey, _ := NewKeyPair() - clientTemplate := newClientCertificateTemplateForDuration(userToSubject(u), lifetime, time.Now) - clientCrt, err := ca.signCertificate(clientTemplate, clientPublicKey) + clientTemplate := NewClientCertificateTemplateForDuration(UserToSubject(u), lifetime, time.Now) + clientCrt, err := ca.SignCertificate(clientTemplate, clientPublicKey) if err != nil { return nil, err } @@ -908,7 +915,7 @@ func (ca *CA) MakeClientCertificateForDuration(u user.Info, lifetime time.Durati if err != nil { return nil, err } - keyData, err := encodeKey(clientPrivateKey) + keyData, err := EncodeKey(clientPrivateKey) if err != nil { return nil, err } @@ -933,7 +940,7 @@ func (s sortedForDER) Less(i, j int) bool { return l1 < l2 } -func userToSubject(u user.Info) pkix.Name { +func UserToSubject(u user.Info) pkix.Name { // Ok we are going to order groups in a peculiar way here to workaround a // 2 bugs, 1 in golang (https://github.com/golang/go/issues/24254) which // incorrectly encodes Multivalued RDNs and another in GNUTLS clients @@ -959,7 +966,7 @@ func userToSubject(u user.Info) pkix.Name { } } -func (ca *CA) signCertificate(template *x509.Certificate, requestKey crypto.PublicKey) (*x509.Certificate, error) { +func (ca *CA) SignCertificate(template *x509.Certificate, requestKey crypto.PublicKey) (*x509.Certificate, error) { // Increment and persist serial serial, err := ca.SerialGenerator.Next(template) if err != nil { @@ -1106,7 +1113,7 @@ func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) { } // Can be used as a certificate in http.Transport TLSClientConfig -func newClientCertificateTemplate(subject pkix.Name, expireDays int, currentTime func() time.Time) *x509.Certificate { +func NewClientCertificateTemplate(subject pkix.Name, expireDays int, currentTime func() time.Time) *x509.Certificate { var lifetimeInDays = DefaultCertificateLifetimeInDays if expireDays > 0 { lifetimeInDays = expireDays @@ -1118,11 +1125,11 @@ func newClientCertificateTemplate(subject pkix.Name, expireDays int, currentTime lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour - return newClientCertificateTemplateForDuration(subject, lifetime, currentTime) + return NewClientCertificateTemplateForDuration(subject, lifetime, currentTime) } // Can be used as a certificate in http.Transport TLSClientConfig -func newClientCertificateTemplateForDuration(subject pkix.Name, lifetime time.Duration, currentTime func() time.Time) *x509.Certificate { +func NewClientCertificateTemplateForDuration(subject pkix.Name, lifetime time.Duration, currentTime func() time.Time) *x509.Certificate { return &x509.Certificate{ Subject: subject, @@ -1168,7 +1175,7 @@ func EncodeCertificates(certs ...*x509.Certificate) ([]byte, error) { } return b.Bytes(), nil } -func encodeKey(key crypto.PrivateKey) ([]byte, error) { +func EncodeKey(key crypto.PrivateKey) ([]byte, error) { b := bytes.Buffer{} switch key := key.(type) { case *ecdsa.PrivateKey: @@ -1202,7 +1209,7 @@ func writeCertificates(f io.Writer, certs ...*x509.Certificate) error { return nil } func writeKeyFile(f io.Writer, key crypto.PrivateKey) error { - bytes, err := encodeKey(key) + bytes, err := EncodeKey(key) if err != nil { return err } @@ -1212,41 +1219,3 @@ func writeKeyFile(f io.Writer, key crypto.PrivateKey) error { return nil } - -func stringsNotInSlice(needles []string, haystack []string) []string { - missing := []string{} - for _, needle := range needles { - if !stringInSlice(needle, haystack) { - missing = append(missing, needle) - } - } - return missing -} - -func stringInSlice(needle string, haystack []string) bool { - for _, straw := range haystack { - if needle == straw { - return true - } - } - return false -} - -func ipsNotInSlice(needles []net.IP, haystack []net.IP) []net.IP { - missing := []net.IP{} - for _, needle := range needles { - if !ipInSlice(needle, haystack) { - missing = append(missing, needle) - } - } - return missing -} - -func ipInSlice(needle net.IP, haystack []net.IP) bool { - for _, straw := range haystack { - if needle.Equal(straw) { - return true - } - } - return false -} diff --git a/vendor/github.com/openshift/library-go/pkg/proc/proc_linux.go b/vendor/github.com/openshift/library-go/pkg/proc/proc_linux.go index d8ecd6349..fb8c7745d 100644 --- a/vendor/github.com/openshift/library-go/pkg/proc/proc_linux.go +++ b/vendor/github.com/openshift/library-go/pkg/proc/proc_linux.go @@ -2,7 +2,6 @@ package proc import ( "bufio" - "io/ioutil" "os" "path/filepath" "strconv" @@ -16,7 +15,7 @@ import ( // parseProcForZombies parses the current procfs mounted at /proc // to find processes in the zombie state. func parseProcForZombies() ([]int, error) { - files, err := ioutil.ReadDir("/proc") + files, err := os.ReadDir("/proc") if err != nil { return nil, err } diff --git a/vendor/github.com/openshift/library-go/pkg/route/secretmanager/fake/fake_manager.go b/vendor/github.com/openshift/library-go/pkg/route/secretmanager/fake/fake_manager.go new file mode 100644 index 000000000..2e1fca2de --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/route/secretmanager/fake/fake_manager.go @@ -0,0 +1,33 @@ +package fake + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" +) + +type SecretManager struct { + Err error + Secret *corev1.Secret + IsRegistered bool +} + +func (m *SecretManager) RegisterRoute(ctx context.Context, namespace string, routeName string, secretName string, handler cache.ResourceEventHandlerFuncs) error { + return m.Err +} +func (m *SecretManager) UnregisterRoute(namespace string, routeName string) error { + return m.Err +} + +func (m *SecretManager) GetSecret(ctx context.Context, namespace string, routeName string) (*corev1.Secret, error) { + return m.Secret, m.Err +} +func (m *SecretManager) IsRouteRegistered(namespace string, routeName string) bool { + return m.IsRegistered +} + +func (m *SecretManager) Queue() workqueue.RateLimitingInterface { + return nil +} diff --git a/vendor/github.com/openshift/library-go/pkg/route/secretmanager/manager.go b/vendor/github.com/openshift/library-go/pkg/route/secretmanager/manager.go new file mode 100644 index 000000000..7a3974748 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/route/secretmanager/manager.go @@ -0,0 +1,147 @@ +package secretmanager + +import ( + "context" + "fmt" + "sync" + + "github.com/openshift/library-go/pkg/secret" + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" +) + +type SecretManager interface { + RegisterRoute(ctx context.Context, namespace string, routeName string, secretName string, handler cache.ResourceEventHandlerFuncs) error + UnregisterRoute(namespace string, routeName string) error + GetSecret(ctx context.Context, namespace string, routeName string) (*v1.Secret, error) + IsRouteRegistered(namespace string, routeName string) bool + Queue() workqueue.RateLimitingInterface +} + +// Manager is responsible for managing secrets associated with routes. It implements SecretManager. +type manager struct { + // monitor for managing and watching "single" secret dynamically. + monitor secret.SecretMonitor + + // Map of registered handlers for each route. + // Populated inside RegisterRoute() and used in UnregisterRoute(), GetSecret. + // generateKey() will create the map key. + registeredHandlers map[string]secret.SecretEventHandlerRegistration + + // Lock to protect access to registeredHandlers map. + handlersLock sync.RWMutex + + // Work queue to be used by the consumer of this Manager, mostly to add secret change events. + queue workqueue.RateLimitingInterface +} + +func NewManager(kubeClient kubernetes.Interface, queue workqueue.RateLimitingInterface) SecretManager { + return &manager{ + monitor: secret.NewSecretMonitor(kubeClient), + handlersLock: sync.RWMutex{}, + queue: queue, + registeredHandlers: make(map[string]secret.SecretEventHandlerRegistration), + } +} + +// Queue returns the work queue for the manager. +func (m *manager) Queue() workqueue.RateLimitingInterface { + return m.queue +} + +// RegisterRoute registers a route with a secret, enabling the manager to watch for the secret changes and associate them with the handler functions. +// Returns an error if the route is already registered with a secret or if adding the secret event handler fails. +func (m *manager) RegisterRoute(ctx context.Context, namespace, routeName, secretName string, handler cache.ResourceEventHandlerFuncs) error { + m.handlersLock.Lock() + defer m.handlersLock.Unlock() + + // Generate a unique key for the provided namespace and routeName. + key := generateKey(namespace, routeName) + + // Check if the route is already registered with the given key. + // Each route (namespace/routeName) should be registered only once with any secret. + // Note: inside a namespace multiple different routes can be registered(watch) with a common secret. + if _, exists := m.registeredHandlers[key]; exists { + return fmt.Errorf("route already registered with key %s", key) + } + + // Add a secret event handler for the specified namespace and secret, with the handler functions. + klog.V(5).Infof("trying to add handler for key %s with secret %s", key, secretName) + handlerRegistration, err := m.monitor.AddSecretEventHandler(ctx, namespace, secretName, handler) + if err != nil { + return err + } + + // Store the registration in the manager's map. Used during UnregisterRoute() and GetSecret(). + m.registeredHandlers[key] = handlerRegistration + klog.Infof("secret manager registered route for key %s with secret %s", key, secretName) + + return nil +} + +// UnregisterRoute removes the registration of a route from the manager. +// It removes the secret event handler from secret monitor and deletes its associated handler from manager's map. +func (m *manager) UnregisterRoute(namespace, routeName string) error { + m.handlersLock.Lock() + defer m.handlersLock.Unlock() + + key := generateKey(namespace, routeName) + + // Get the registered handler. + handlerRegistration, exists := m.registeredHandlers[key] + if !exists { + return fmt.Errorf("no handler registered with key %s", key) + } + + // Remove the corresponding secret event handler from the secret monitor. + klog.V(5).Info("trying to remove handler with key", key) + err := m.monitor.RemoveSecretEventHandler(handlerRegistration) + if err != nil { + return err + } + + // delete the registered handler from manager's map of handlers. + delete(m.registeredHandlers, key) + klog.Infof("secret manager unregistered route for key %s", key) + + return nil +} + +// GetSecret retrieves the secret object registered with a route. +func (m *manager) GetSecret(ctx context.Context, namespace, routeName string) (*v1.Secret, error) { + m.handlersLock.RLock() + defer m.handlersLock.RUnlock() + + key := generateKey(namespace, routeName) + + handlerRegistration, exists := m.registeredHandlers[key] + if !exists { + return nil, fmt.Errorf("no handler registered with key %s", key) + } + + // Get the secret from the secret monitor's cache using the registered handler. + obj, err := m.monitor.GetSecret(ctx, handlerRegistration) + if err != nil { + return nil, err + } + + return obj, nil +} + +// IsRouteRegistered returns true if route is registered, false otherwise +func (m *manager) IsRouteRegistered(namespace, routeName string) bool { + m.handlersLock.RLock() + defer m.handlersLock.RUnlock() + + key := generateKey(namespace, routeName) + _, exists := m.registeredHandlers[key] + return exists +} + +// generateKey creates a unique identifier for a route +func generateKey(namespace, route string) string { + return fmt.Sprintf("%s/%s", namespace, route) +} diff --git a/vendor/github.com/openshift/library-go/pkg/secret/OWNERS b/vendor/github.com/openshift/library-go/pkg/secret/OWNERS new file mode 100644 index 000000000..a13f72be3 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/secret/OWNERS @@ -0,0 +1,9 @@ +reviewers: + - deads2k + - soltysh + - Miciah + - chiragkyal +approvers: + - deads2k + - soltysh + - Miciah diff --git a/vendor/github.com/openshift/library-go/pkg/secret/monitor.go b/vendor/github.com/openshift/library-go/pkg/secret/monitor.go new file mode 100644 index 000000000..c8505acce --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/secret/monitor.go @@ -0,0 +1,139 @@ +package secret + +import ( + "context" + "fmt" + "sync" + + "k8s.io/client-go/tools/cache" + "k8s.io/klog/v2" +) + +// ObjectKey represents the unique identifier for a resource, used to access it in the cache. +type ObjectKey struct { + // Namespace is the namespace in which the resource is located. + Namespace string + // Name denotes metadata.name of a resource being monitored by informer + Name string +} + +// singleItemMonitor monitors a single resource using a SharedInformer. +type singleItemMonitor struct { + key ObjectKey + informer cache.SharedInformer + lock sync.Mutex + stopped bool + stopCh chan struct{} +} + +// NewObjectKey creates a new ObjectKey for the given namespace and name. +func NewObjectKey(namespace, name string) ObjectKey { + return ObjectKey{ + Namespace: namespace, + Name: name, + } +} + +// newSingleItemMonitor creates a new singleItemMonitor for the given key and informer. +func newSingleItemMonitor(key ObjectKey, informer cache.SharedInformer) *singleItemMonitor { + return &singleItemMonitor{ + key: key, + informer: informer, + stopped: true, + stopCh: make(chan struct{}), + } +} + +// HasSynced returns true if the informer's cache has been successfully synced. +func (i *singleItemMonitor) HasSynced() bool { + return i.informer.HasSynced() +} + +// StartInformer starts and runs the informer until the provided context is canceled, +// or StopInformer() is called. +func (i *singleItemMonitor) StartInformer(ctx context.Context) { + i.lock.Lock() + defer i.lock.Unlock() + + if !i.stopped { + klog.Warning("informer is already running") + return + } + + go func() { + select { + case <-ctx.Done(): + klog.V(5).Info("stopping informer due to context cancellation") + if !i.StopInformer() { + klog.Error("failed to stop informer") + } + // this case is required to exit from the goroutine + // after normal StopInformer() call i.e when stopCh is closed. + case <-i.stopCh: + } + }() + + klog.Info("starting informer") + i.stopped = false + + go i.informer.Run(i.stopCh) +} + +// StopInformer stops the informer. +// Retuns false if called twice, or before StartInformer(); true otherwise. +func (i *singleItemMonitor) StopInformer() bool { + i.lock.Lock() + defer i.lock.Unlock() + + if i.stopped { + return false + } + i.stopped = true + close(i.stopCh) // Signal the informer to stop + klog.Info("informer stopped") + return true +} + +// AddEventHandler adds an event handler to the informer and returns +// secretEventHandlerRegistration after populating objectKey and registration. +func (i *singleItemMonitor) AddEventHandler(handler cache.ResourceEventHandler) (SecretEventHandlerRegistration, error) { + i.lock.Lock() + defer i.lock.Unlock() + + if i.stopped { + return nil, fmt.Errorf("cannot add handler %v to already stopped informer", handler) + } + + registration, err := i.informer.AddEventHandler(handler) + if err != nil { + return nil, err + } + + return &secretEventHandlerRegistration{ + ResourceEventHandlerRegistration: registration, + objectKey: i.key, + }, nil +} + +// RemoveEventHandler removes an event handler from the informer. +func (i *singleItemMonitor) RemoveEventHandler(handle SecretEventHandlerRegistration) error { + i.lock.Lock() + defer i.lock.Unlock() + + if handle == nil { + return fmt.Errorf("nil handler registration is provided") + } + + if i.stopped { + return fmt.Errorf("can not remove handler %v from stopped informer", handle.GetHandler()) + } + + return i.informer.RemoveEventHandler(handle.GetHandler()) +} + +// GetItem returns the accumulator being monitored +// by informer, using keyFunc (namespace/name). +func (i *singleItemMonitor) GetItem() (item interface{}, exists bool, err error) { + keyFunc := i.key.Namespace + "/" + i.key.Name + return i.informer.GetStore().GetByKey(keyFunc) +} diff --git a/vendor/github.com/openshift/library-go/pkg/secret/secret_monitor.go b/vendor/github.com/openshift/library-go/pkg/secret/secret_monitor.go new file mode 100644 index 000000000..ddccb0484 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/secret/secret_monitor.go @@ -0,0 +1,217 @@ +package secret + +import ( + "context" + "fmt" + "sync" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + "k8s.io/klog/v2" +) + +// SecretEventHandlerRegistration is for registering and unregistering event handlers for secret monitoring. +type SecretEventHandlerRegistration interface { + cache.ResourceEventHandlerRegistration + + GetKey() ObjectKey + GetHandler() cache.ResourceEventHandlerRegistration +} + +// SecretMonitor helps in monitoring and handling a specific secret using singleItemMonitor. +type SecretMonitor interface { + // AddSecretEventHandler adds a secret event handler to the monitor for a specific secret in the given namespace. + // The handler will be notified of events related to the "specified" secret only. + // The returned SecretEventHandlerRegistration can be used to later remove the handler. + AddSecretEventHandler(ctx context.Context, namespace, secretName string, handler cache.ResourceEventHandler) (SecretEventHandlerRegistration, error) + + // RemoveSecretEventHandler removes a previously added secret event handler using the provided registration. + // If the handler is not found or if there is an issue removing it, an error is returned. + RemoveSecretEventHandler(handlerRegistration SecretEventHandlerRegistration) error + + // GetSecret retrieves the secret object from the informer's cache using the provided SecretEventHandlerRegistration. + // This allows accessing the latest state of the secret without making an API call. + GetSecret(ctx context.Context, handlerRegistration SecretEventHandlerRegistration) (*corev1.Secret, error) +} + +// secretEventHandlerRegistration is an implementation of the SecretEventHandlerRegistration. +type secretEventHandlerRegistration struct { + cache.ResourceEventHandlerRegistration + + // objectKey represents the unique identifier for the secret associated with this event handler registration. + // It will be populated during AddEventHandler, and will be used during RemoveEventHandler, GetSecret. + objectKey ObjectKey +} + +func (r *secretEventHandlerRegistration) GetKey() ObjectKey { + return r.objectKey +} + +func (r *secretEventHandlerRegistration) GetHandler() cache.ResourceEventHandlerRegistration { + return r.ResourceEventHandlerRegistration +} + +type monitoredItem struct { + itemMonitor *singleItemMonitor + numHandlers int +} + +// secretMonitor is an implementation of the SecretMonitor +type secretMonitor struct { + kubeClient kubernetes.Interface + lock sync.RWMutex + monitors map[ObjectKey]*monitoredItem +} + +func NewSecretMonitor(kubeClient kubernetes.Interface) SecretMonitor { + return &secretMonitor{ + kubeClient: kubeClient, + monitors: map[ObjectKey]*monitoredItem{}, + } +} + +// AddSecretEventHandler adds a secret event handler to the monitor. +func (s *secretMonitor) AddSecretEventHandler(ctx context.Context, namespace, secretName string, handler cache.ResourceEventHandler) (SecretEventHandlerRegistration, error) { + return s.addSecretEventHandler(ctx, namespace, secretName, handler, s.createSecretInformer(namespace, secretName)) +} + +// createSecretInformer creates a SharedInformer for monitoring a specific secret. +func (s *secretMonitor) createSecretInformer(namespace, name string) cache.SharedInformer { + return cache.NewSharedInformer( + cache.NewListWatchFromClient( + s.kubeClient.CoreV1().RESTClient(), + "secrets", + namespace, + fields.OneTermEqualSelector("metadata.name", name), + ), + &corev1.Secret{}, + 0, + ) +} + +// addSecretEventHandler adds a secret event handler and starts the informer if not already running. +func (s *secretMonitor) addSecretEventHandler(ctx context.Context, namespace, secretName string, handler cache.ResourceEventHandler, secretInformer cache.SharedInformer) (SecretEventHandlerRegistration, error) { + s.lock.Lock() + defer s.lock.Unlock() + + if handler == nil { + return nil, fmt.Errorf("nil handler is provided") + } + + // secret identifier (namespace/secret) + key := NewObjectKey(namespace, secretName) + + // Start secret informer if monitor does not exist. + m, exists := s.monitors[key] + if !exists { + m = &monitoredItem{} + m.itemMonitor = newSingleItemMonitor(key, secretInformer) + m.itemMonitor.StartInformer(ctx) + + // wait for first sync + if !cache.WaitForCacheSync(ctx.Done(), m.itemMonitor.HasSynced) { + return nil, fmt.Errorf("failed waiting for cache sync") + } + + // add item key to monitors map + s.monitors[key] = m + + klog.Info("secret informer started", " item key ", key) + } + + // add the event handler + registration, err := m.itemMonitor.AddEventHandler(handler) + if err != nil { + return nil, err + } + + // Increment numHandlers + m.numHandlers += 1 + + // TODO: this can be too noisy, later we need to use higher verbosity + klog.Info("secret handler added", " item key ", key) + + return registration, nil +} + +// RemoveSecretEventHandler removes a secret event handler and stops the informer if no handlers are left. +// If the handler is not found or if there is an issue removing it, an error is returned. +func (s *secretMonitor) RemoveSecretEventHandler(handlerRegistration SecretEventHandlerRegistration) error { + s.lock.Lock() + defer s.lock.Unlock() + + if handlerRegistration == nil { + return fmt.Errorf("nil secret handler registration is provided") + } + + // Extract the key from the registration to identify the associated monitor. + // populated in AddEventHandler() + key := handlerRegistration.GetKey() + + // check if secret informer already exists for the secret(key) + m, exists := s.monitors[key] + if !exists { + return fmt.Errorf("secret monitor already removed for item key %v", key) + } + + if err := m.itemMonitor.RemoveEventHandler(handlerRegistration); err != nil { + return err + } + // Decrement numHandlers + m.numHandlers -= 1 + klog.Info("secret handler removed", " item key", key) + + // stop informer if there is no handler + if m.numHandlers <= 0 { + if !m.itemMonitor.StopInformer() { + return fmt.Errorf("secret informer already stopped for item key %v", key) + } + // remove the key from map + delete(s.monitors, key) + klog.Info("secret informer stopped", " item key ", key) + } + + return nil +} + +// GetSecret retrieves the secret object from the informer's cache. Error if the secret is not found in the cache. +func (s *secretMonitor) GetSecret(ctx context.Context, handlerRegistration SecretEventHandlerRegistration) (*corev1.Secret, error) { + s.lock.RLock() + defer s.lock.RUnlock() + + if handlerRegistration == nil { + return nil, fmt.Errorf("nil secret handler registration is provided") + } + key := handlerRegistration.GetKey() + secretName := key.Name + + // check if secret informer exists + m, exists := s.monitors[key] + if !exists { + return nil, fmt.Errorf("secret monitor doesn't exist for key %v", key) + } + + // wait for informer store sync, to load secrets + if !cache.WaitForCacheSync(ctx.Done(), handlerRegistration.HasSynced) { + return nil, fmt.Errorf("failed waiting for cache sync") + } + + uncast, exists, err := m.itemMonitor.GetItem() + + if err != nil { + return nil, err + } + if !exists { + return nil, apierrors.NewNotFound(corev1.Resource("secrets"), secretName) + } + + secret, ok := uncast.(*corev1.Secret) + if !ok { + return nil, fmt.Errorf("unexpected type: %T", uncast) + } + + return secret, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4186d1ab7..582bd07a8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -201,13 +201,13 @@ github.com/modern-go/reflect2 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg -# github.com/openshift/api v0.0.0-20240202140003-8b34b9854c7f +# github.com/openshift/api v0.0.0-20240424142232-29a704bf5aa2 ## explicit; go 1.21 github.com/openshift/api/project/v1 github.com/openshift/api/route github.com/openshift/api/route/v1 -# github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 -## explicit; go 1.19 +# github.com/openshift/client-go v0.0.0-20240405120947-c67c8325cdd8 +## explicit; go 1.21 github.com/openshift/client-go/project/applyconfigurations/internal github.com/openshift/client-go/project/applyconfigurations/project/v1 github.com/openshift/client-go/project/clientset/versioned @@ -223,10 +223,14 @@ github.com/openshift/client-go/route/clientset/versioned/scheme github.com/openshift/client-go/route/clientset/versioned/typed/route/v1 github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/fake github.com/openshift/client-go/route/listers/route/v1 -# github.com/openshift/library-go v0.0.0-20230120202744-256994f916c4 -## explicit; go 1.19 +# github.com/openshift/library-go v0.0.0-20240426144148-0690e4a4602d +## explicit; go 1.21 +github.com/openshift/library-go/pkg/authorization/authorizationutil github.com/openshift/library-go/pkg/crypto github.com/openshift/library-go/pkg/proc +github.com/openshift/library-go/pkg/route/secretmanager +github.com/openshift/library-go/pkg/route/secretmanager/fake +github.com/openshift/library-go/pkg/secret github.com/openshift/library-go/pkg/serviceability # github.com/pkg/errors v0.9.1 ## explicit From 2f06f7c1fe26ce09301a031f77bbdfd095e877d1 Mon Sep 17 00:00:00 2001 From: chiragkyal Date: Tue, 14 May 2024 16:11:39 +0530 Subject: [PATCH 2/2] CFE-1020: feature:route external certificate reference Introduces new RouteSecretManager plugin for the management and validation of routes with externalCertificate. Integration with secretManager to register, unregister, and read referenced secret. Handling of the routes when referenced secret is updated or deleted. ValidateTLSExternalCertificate function to test preconditions for using externalCertificate. Everything is behind AllowExternalCertificates flag which is true when cluster-ingress-operator sets it, if RouteExternalCertificate feature-gate is enabled. Signed-off-by: chiragkyal --- pkg/cmd/infra/router/router.go | 5 + pkg/cmd/infra/router/template.go | 13 + pkg/router/controller/route_secret_manager.go | 223 ++++ .../controller/route_secret_manager_test.go | 1151 +++++++++++++++++ pkg/router/routeapihelpers/validation.go | 73 +- pkg/router/router_test.go | 2 + pkg/router/template/fake.go | 5 + pkg/router/template/plugin.go | 3 + pkg/router/template/router.go | 12 + pkg/router/template/router_test.go | 2 + 10 files changed, 1488 insertions(+), 1 deletion(-) create mode 100644 pkg/router/controller/route_secret_manager.go create mode 100644 pkg/router/controller/route_secret_manager_test.go diff --git a/pkg/cmd/infra/router/router.go b/pkg/cmd/infra/router/router.go index c758cd217..4bc9503fc 100644 --- a/pkg/cmd/infra/router/router.go +++ b/pkg/cmd/infra/router/router.go @@ -78,6 +78,10 @@ type RouterSelection struct { // WatchEndpoints when true will watch Endpoints instead of // EndpointSlices. WatchEndpoints bool + + // AllowExternalCertificates when true enables RouteSecretManager plugin and the external certificate validation. + // The cluster-ingress-operator sets it if RouteExternalCertificate feature-gate is enabled. + AllowExternalCertificates bool } // Bind sets the appropriate labels @@ -107,6 +111,7 @@ func (o *RouterSelection) Bind(flag *pflag.FlagSet) { flag.MarkDeprecated("enable-ingress", "Ingress resources are now synchronized to routes automatically.") flag.StringVar(&o.ListenAddr, "listen-addr", env("ROUTER_LISTEN_ADDR", ""), "The name of an interface to listen on to expose metrics and health checking. If not specified, will not listen. Overrides stats port.") flag.BoolVar(&o.WatchEndpoints, "watch-endpoints", isTrue(env("ROUTER_WATCH_ENDPOINTS", "")), "Watch Endpoints instead of the EndpointSlice resource.") + flag.BoolVar(&o.AllowExternalCertificates, "allow-external-certificates", isTrue(env("ROUTER_ENABLE_EXTERNAL_CERTIFICATE", "")), "Enable RouteSecretManager plugin and validation of external certificates.") } // RouteUpdate updates the route before it is seen by the cache. diff --git a/pkg/cmd/infra/router/template.go b/pkg/cmd/infra/router/template.go index d92ae7060..14e5b2056 100644 --- a/pkg/cmd/infra/router/template.go +++ b/pkg/cmd/infra/router/template.go @@ -36,6 +36,7 @@ import ( routelisters "github.com/openshift/client-go/route/listers/route/v1" "github.com/openshift/library-go/pkg/crypto" "github.com/openshift/library-go/pkg/proc" + "github.com/openshift/library-go/pkg/route/secretmanager" "github.com/openshift/router/pkg/router" "github.com/openshift/router/pkg/router/controller" @@ -718,6 +719,10 @@ func (o *TemplateRouterOptions) Run(stopCh <-chan struct{}) error { if err != nil { return err } + authorizationClient, err := authorizationclient.NewForConfig(config) + if err != nil { + return err + } var cfgManager templateplugin.ConfigManager var blueprintPlugin router.Plugin @@ -746,6 +751,8 @@ func (o *TemplateRouterOptions) Run(stopCh <-chan struct{}) error { return err } + secretManager := secretmanager.NewManager(kc, nil) + pluginCfg := templateplugin.TemplatePluginConfig{ WorkingDir: o.WorkingDir, TemplatePath: o.TemplateFile, @@ -773,6 +780,9 @@ func (o *TemplateRouterOptions) Run(stopCh <-chan struct{}) error { HTTPResponseHeaders: o.HTTPResponseHeaders, HTTPRequestHeaders: o.HTTPRequestHeaders, } + if o.AllowExternalCertificates { + pluginCfg.SecretManager = secretManager + } svcFetcher := templateplugin.NewListWatchServiceLookup(kc.CoreV1(), o.ResyncInterval, o.Namespace) templatePlugin, err := templateplugin.NewTemplatePlugin(pluginCfg, svcFetcher) @@ -804,6 +814,9 @@ func (o *TemplateRouterOptions) Run(stopCh <-chan struct{}) error { if o.ExtendedValidation { plugin = controller.NewExtendedValidator(plugin, recorder) } + if o.AllowExternalCertificates { + plugin = controller.NewRouteSecretManager(plugin, recorder, secretManager, kc.CoreV1(), authorizationClient.SubjectAccessReviews()) + } plugin = controller.NewUniqueHost(plugin, o.RouterSelection.DisableNamespaceOwnershipCheck, recorder) plugin = controller.NewHostAdmitter(plugin, o.RouteAdmissionFunc(), o.AllowWildcardRoutes, o.RouterSelection.DisableNamespaceOwnershipCheck, recorder) diff --git a/pkg/router/controller/route_secret_manager.go b/pkg/router/controller/route_secret_manager.go new file mode 100644 index 000000000..bbb7ff262 --- /dev/null +++ b/pkg/router/controller/route_secret_manager.go @@ -0,0 +1,223 @@ +package controller + +import ( + "context" + "fmt" + + routev1 "github.com/openshift/api/route/v1" + "github.com/openshift/library-go/pkg/route/secretmanager" + "github.com/openshift/router/pkg/router" + "github.com/openshift/router/pkg/router/routeapihelpers" + kapi "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apimachinery/pkg/watch" + authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" +) + +// RouteSecretManager implements the router.Plugin interface to register +// or unregister route with secretManger if externalCertificate is used. +// It also reads the referenced secret to update in-memory tls.Certificate and tls.Key +type RouteSecretManager struct { + // plugin is the next plugin in the chain. + plugin router.Plugin + // recorder is an interface for indicating route status. + recorder RouteStatusRecorder + + secretManager secretmanager.SecretManager + secretsGetter corev1client.SecretsGetter + sarClient authorizationclient.SubjectAccessReviewInterface +} + +// NewRouteSecretManager creates a new instance of RouteSecretManager. +// It wraps the provided plugin and adds secret management capabilities. +func NewRouteSecretManager(plugin router.Plugin, recorder RouteStatusRecorder, secretManager secretmanager.SecretManager, secretsGetter corev1client.SecretsGetter, sarClient authorizationclient.SubjectAccessReviewInterface) *RouteSecretManager { + return &RouteSecretManager{ + plugin: plugin, + recorder: recorder, + secretManager: secretManager, + secretsGetter: secretsGetter, + sarClient: sarClient, + } +} + +func (p *RouteSecretManager) HandleNode(eventType watch.EventType, node *kapi.Node) error { + return p.plugin.HandleNode(eventType, node) +} + +func (p *RouteSecretManager) HandleEndpoints(eventType watch.EventType, endpoints *kapi.Endpoints) error { + return p.plugin.HandleEndpoints(eventType, endpoints) +} + +func (p *RouteSecretManager) HandleNamespaces(namespaces sets.String) error { + return p.plugin.HandleNamespaces(namespaces) +} + +func (p *RouteSecretManager) Commit() error { + return p.plugin.Commit() +} + +// HandleRoute manages the registration, unregistration, and validation of routes with external certificates. +// For Added events, it validates the route's external certificate configuration and registers it with the secret manager. +// For Modified events, it first unregisters the route if it's already registered and then revalidates and registers it again. +// For Deleted events, it unregisters the route if it's registered. +// Additionally, it delegates the handling of the event to the next plugin in the chain after performing the necessary actions. +func (p *RouteSecretManager) HandleRoute(eventType watch.EventType, route *routev1.Route) error { + log.V(10).Info("HandleRoute: RouteSecretManager", "eventType", eventType) + + switch eventType { + case watch.Added: + // register with secret monitor + if hasExternalCertificate(route) { + if err := p.validateAndRegister(route); err != nil { + return err + } + } + + // For Modified events always unregister and reregister the route even if the TLS configuration did not change. + // Since the `HandleRoute()` method does not carry the old route spec, + // and there's no definite way to compare old and new TLS configurations, + // assume that the TLS configuration is always updated, necessitating re-registration. + // Additionally, always creating a new `secretHandler` ensures that there are no stale route specs + // in the next plugin chain, especially when the referenced secret is updated or deleted. + // This prevents sending outdated routes to subsequent plugins, preserving expected functionality. + // TODO: Refer https://github.com/openshift/router/pull/565#discussion_r1596441128 for possible ways to improve the logic. + case watch.Modified: + // unregister associated secret monitor, if registered + if p.secretManager.IsRouteRegistered(route.Namespace, route.Name) { + if err := p.secretManager.UnregisterRoute(route.Namespace, route.Name); err != nil { + log.Error(err, "failed to unregister route") + return err + } + } + // register with secret monitor + if hasExternalCertificate(route) { + if err := p.validateAndRegister(route); err != nil { + return err + } + } + + case watch.Deleted: + // unregister associated secret monitor, if registered + if p.secretManager.IsRouteRegistered(route.Namespace, route.Name) { + if err := p.secretManager.UnregisterRoute(route.Namespace, route.Name); err != nil { + log.Error(err, "failed to unregister route") + return err + } + } + default: + return fmt.Errorf("invalid eventType %v", eventType) + } + + // call next plugin + return p.plugin.HandleRoute(eventType, route) +} + +// validateAndRegister validates the route's externalCertificate configuration and registers it with the secret manager. +// It also updates the in-memory TLS certificate and key after reading from secret informer's cache. +func (p *RouteSecretManager) validateAndRegister(route *routev1.Route) error { + fldPath := field.NewPath("spec").Child("tls").Child("externalCertificate") + // validate + if err := routeapihelpers.ValidateTLSExternalCertificate(route, fldPath, p.sarClient, p.secretsGetter).ToAggregate(); err != nil { + log.Error(err, "skipping route due to invalid externalCertificate configuration", "namespace", route.Namespace, "route", route.Name) + p.recorder.RecordRouteRejection(route, "ExternalCertificateValidationFailed", err.Error()) + p.plugin.HandleRoute(watch.Deleted, route) + return err + } + + // register route with secretManager + handler := p.generateSecretHandler(route) + if err := p.secretManager.RegisterRoute(context.TODO(), route.Namespace, route.Name, route.Spec.TLS.ExternalCertificate.Name, handler); err != nil { + log.Error(err, "failed to register route") + return err + } + // read referenced secret + secret, err := p.secretManager.GetSecret(context.TODO(), route.Namespace, route.Name) + if err != nil { + log.Error(err, "failed to get referenced secret") + return err + } + + // Update the tls.Certificate and tls.Key fields of the route with the data from the referenced secret. + // Since externalCertificate does not contain the CACertificate, tls.CACertificate will not be updated. + // NOTE that this update is only performed in-memory and will not reflect in the actual route resource stored in etcd, because + // the router does not make kube-client calls to directly update route resources. + route.Spec.TLS.Certificate = string(secret.Data["tls.crt"]) + route.Spec.TLS.Key = string(secret.Data["tls.key"]) + + return nil +} + +// generateSecretHandler creates ResourceEventHandlerFuncs to handle Add, Update, and Delete events on secrets. +// AddFunc: Invoked when a new secret is added. It logs the addition of the secret. +// UpdateFunc: Invoked when an existing secret is updated. It performs validation of the route's external certificate configuration. +// If the validation fails, it records the route rejection, and triggers the deletion of the route by calling the HandleRoute method with a watch.Deleted event. +// If the validation succeeds, it updates the route's TLS certificate and key with the new secret data and calls the next plugin's HandleRoute method with a watch.Modified event, and then the next plugin's Commit() method. +// DeleteFunc: Invoked when the secret is deleted. It unregisters the associated route, records the route rejection, and triggers the deletion of the route by calling the HandleRoute method with a watch.Deleted event. +func (p *RouteSecretManager) generateSecretHandler(route *routev1.Route) cache.ResourceEventHandlerFuncs { + // secret handler + return cache.ResourceEventHandlerFuncs{ + + // AddFunc is intentionally left empty (only logs the event) because this handler is generated only after ensuring the existence of the secret. + // By leaving this empty, we prevent unnecessary triggering for the addition of the secret again. Additionally, GetSecret() method is called + // immediately after registering with the secretManager, to read the secret from the cache. + AddFunc: func(obj interface{}) { + secret := obj.(*kapi.Secret) + log.V(4).Info("secret added for route", "namespace", route.Namespace, "secret", secret.Name, "route", route.Name) + }, + + UpdateFunc: func(old interface{}, new interface{}) { + secretOld := old.(*kapi.Secret) + secretNew := new.(*kapi.Secret) + log.V(4).Info("secret updated for route", "namespace", route.Namespace, "secret", secretNew.Name, "old-version", secretOld.ResourceVersion, "new-version", secretNew.ResourceVersion, "route", route.Name) + + // re-validate + fldPath := field.NewPath("spec").Child("tls").Child("externalCertificate") + if err := routeapihelpers.ValidateTLSExternalCertificate(route, fldPath, p.sarClient, p.secretsGetter).ToAggregate(); err != nil { + log.Error(err, "skipping route due to invalid externalCertificate configuration", "namespace", route.Namespace, "route", route.Name) + p.recorder.RecordRouteRejection(route, "ExternalCertificateValidationFailed", err.Error()) + p.plugin.HandleRoute(watch.Deleted, route) + return + } + + // read referenced secret (updated data) + secret, err := p.secretManager.GetSecret(context.TODO(), route.Namespace, route.Name) + if err != nil { + log.Error(err, "failed to get referenced secret") + p.recorder.RecordRouteRejection(route, "ExternalCertificateGetFailed", err.Error()) + p.plugin.HandleRoute(watch.Deleted, route) + return + } + + // update tls.Certificate and tls.Key + route.Spec.TLS.Certificate = string(secret.Data["tls.crt"]) + route.Spec.TLS.Key = string(secret.Data["tls.key"]) + + // call the next plugin with watch.Modified + p.plugin.HandleRoute(watch.Modified, route) + // commit the changes + p.plugin.Commit() + }, + + DeleteFunc: func(obj interface{}) { + secret := obj.(*kapi.Secret) + msg := fmt.Sprintf("secret %s deleted for route %s/%s", secret.Name, route.Namespace, route.Name) + log.V(4).Info(msg) + + // unregister associated secret monitor + if err := p.secretManager.UnregisterRoute(route.Namespace, route.Name); err != nil { + log.Error(err, "failed to unregister route") + } + + p.recorder.RecordRouteRejection(route, "ExternalCertificateSecretDeleted", msg) + p.plugin.HandleRoute(watch.Deleted, route) + }, + } +} + +func hasExternalCertificate(route *routev1.Route) bool { + tls := route.Spec.TLS + return tls != nil && tls.ExternalCertificate != nil && len(tls.ExternalCertificate.Name) > 0 +} diff --git a/pkg/router/controller/route_secret_manager_test.go b/pkg/router/controller/route_secret_manager_test.go new file mode 100644 index 000000000..bd0b99693 --- /dev/null +++ b/pkg/router/controller/route_secret_manager_test.go @@ -0,0 +1,1151 @@ +package controller + +import ( + "context" + "fmt" + "reflect" + "testing" + + "github.com/openshift/library-go/pkg/route/secretmanager/fake" + "github.com/openshift/router/pkg/router" + + routev1 "github.com/openshift/api/route/v1" + authorizationv1 "k8s.io/api/authorization/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/watch" + testclient "k8s.io/client-go/kubernetes/fake" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" +) + +type testSARCreator struct { + allow bool + err error + sar *authorizationv1.SubjectAccessReview +} + +func (t *testSARCreator) Create(_ context.Context, subjectAccessReview *authorizationv1.SubjectAccessReview, _ metav1.CreateOptions) (*authorizationv1.SubjectAccessReview, error) { + t.sar = subjectAccessReview + return &authorizationv1.SubjectAccessReview{ + Status: authorizationv1.SubjectAccessReviewStatus{ + Allowed: t.allow, + }, + }, t.err +} + +type testSecretGetter struct { + namespace string + secret *corev1.Secret +} + +func (t *testSecretGetter) Secrets(_ string) corev1client.SecretInterface { + return testclient.NewSimpleClientset(t.secret).CoreV1().Secrets(t.namespace) +} + +// fakeSecretInformer will list/watch only one secret inside a namespace +func fakeSecretInformer(fakeKubeClient *testclient.Clientset, namespace, name string) cache.SharedInformer { + fieldSelector := fields.OneTermEqualSelector("metadata.name", name).String() + return cache.NewSharedInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + options.FieldSelector = fieldSelector + return fakeKubeClient.CoreV1().Secrets(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + options.FieldSelector = fieldSelector + return fakeKubeClient.CoreV1().Secrets(namespace).Watch(context.TODO(), options) + }, + }, + &corev1.Secret{}, + 0, + ) +} + +func fakeSecret(namespace, name string, secretType corev1.SecretType, data map[string][]byte) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: data, + Type: secretType, + } +} + +type fakePluginDone struct { + eventType watch.EventType + route *routev1.Route + err error + doneCh chan struct{} +} + +func (p *fakePluginDone) HandleRoute(eventType watch.EventType, route *routev1.Route) error { + defer close(p.doneCh) + p.eventType, p.route = eventType, route + return p.err +} +func (p *fakePluginDone) HandleNode(t watch.EventType, node *corev1.Node) error { + return fmt.Errorf("not expected") +} +func (p *fakePluginDone) HandleEndpoints(watch.EventType, *corev1.Endpoints) error { + return fmt.Errorf("not expected") +} +func (p *fakePluginDone) HandleNamespaces(namespaces sets.String) error { + return fmt.Errorf("not expected") +} +func (p *fakePluginDone) Commit() error { + return p.err +} + +var _ router.Plugin = &fakePluginDone{} + +func TestRouteSecretManager(t *testing.T) { + + scenarios := []struct { + name string + route *routev1.Route + secretManager fake.SecretManager + eventType watch.EventType + allow bool + expectedRoute *routev1.Route + expectedEventType watch.EventType + expectedRejections map[string]string + expectedError bool + }{ + // scenarios when route is added + { + name: "route added with externalCertificate denied", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{}), + }, + eventType: watch.Added, + allow: false, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route added with externalCertificate allowed but secret not found", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("other-sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{}), + }, + eventType: watch.Added, + allow: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route added with externalCertificate allowed but secret of incorrect type", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeBasicAuth, map[string][]byte{}), + }, + eventType: watch.Added, + allow: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route added with externalCertificate allowed and correct secret but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + Err: fmt.Errorf("something"), + }, + eventType: watch.Added, + allow: true, + expectedError: true, + }, + { + name: "route added with externalCertificate allowed and correct secret", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + }, + eventType: watch.Added, + allow: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + Certificate: "my-crt", + Key: "my-key", + }, + }, + }, + expectedEventType: watch.Added, + }, + { + name: "route added without externalCertificate", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + eventType: watch.Added, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + expectedEventType: watch.Added, + }, + + // scenarios when route is updated (old route without externalCertificate, new route with externalCertificate) + { + name: "route updated: old route without externalCertificate, new route with externalCertificate denied", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: false, + }, + allow: false, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route without externalCertificate, new route with externalCertificate allowed but secret not found", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("other-sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: false, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route without externalCertificate, new route with externalCertificate allowed but secret of incorrect type", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeBasicAuth, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: false, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route without externalCertificate, new route with externalCertificate allowed and correct secret but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: false, + Err: fmt.Errorf("something"), + }, + allow: true, + eventType: watch.Modified, + expectedError: true, + }, + { + name: "route updated: old route without externalCertificate, new route with externalCertificate allowed and correct secret", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: false, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + Certificate: "my-crt", + Key: "my-key", + }, + }, + }, + expectedEventType: watch.Modified, + }, + + // scenarios when route is updated (old route with externalCertificate, new route with externalCertificate) + { + name: "route updated: old route with externalCertificate, new route with externalCertificate denied", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: true, + }, + allow: false, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route with externalCertificate, new route with externalCertificate allowed but secret not found", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("other-sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: true, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route with externalCertificate, new route with externalCertificate allowed but secret of incorrect type", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeBasicAuth, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: true, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + expectedError: true, + }, + { + name: "route updated: old route with externalCertificate, new route with externalCertificate allowed and correct secret but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: true, + Err: fmt.Errorf("something"), + }, + allow: true, + eventType: watch.Modified, + expectedError: true, + }, + { + name: "route updated: old route with externalCertificate, new route with externalCertificate allowed and correct secret", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + IsRegistered: true, + }, + allow: true, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + Certificate: "my-crt", + Key: "my-key", + }, + }, + }, + expectedEventType: watch.Modified, + }, + + // scenarios when route is updated (old route with externalCertificate, new route without externalCertificate) + { + name: "route updated: old route with externalCertificate, new route without externalCertificate but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + secretManager: fake.SecretManager{ + IsRegistered: true, + Err: fmt.Errorf("something"), + }, + eventType: watch.Modified, + expectedError: true, + }, + { + name: "route updated: old route with externalCertificate, new route without externalCertificate: works", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + secretManager: fake.SecretManager{ + IsRegistered: true, + }, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + expectedEventType: watch.Modified, + }, + + // scenario when route is updated (old route without externalCertificate, new route without externalCertificate) + { + name: "route updated: old route without externalCertificate, new route without externalCertificate", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + secretManager: fake.SecretManager{ + IsRegistered: false, + }, + eventType: watch.Modified, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + expectedEventType: watch.Modified, + }, + + // scenarios when route is deleted + { + name: "route deleted without externalCertificate registered", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + secretManager: fake.SecretManager{IsRegistered: false}, + eventType: watch.Deleted, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{}, + }, + expectedEventType: watch.Deleted, + }, + { + name: "route deleted with externalCertificate registered", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{IsRegistered: true}, + eventType: watch.Deleted, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + }, + { + name: "route deleted with externalCertificate registered, but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{IsRegistered: true, Err: fmt.Errorf("something")}, + eventType: watch.Deleted, + expectedError: true, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + p := &fakePlugin{} + recorder := routeStatusRecorder{rejections: make(map[string]string)} + + // assign default value to expectedRejections + if s.expectedRejections == nil { + s.expectedRejections = map[string]string{} + } + rsm := NewRouteSecretManager(p, recorder, &s.secretManager, &testSecretGetter{namespace: s.route.Namespace, secret: s.secretManager.Secret}, &testSARCreator{allow: s.allow}) + + gotErr := rsm.HandleRoute(s.eventType, s.route) + if (gotErr != nil) != s.expectedError { + t.Fatalf("expected error to be %t, but got %t", s.expectedError, gotErr != nil) + } + if !reflect.DeepEqual(s.expectedRoute, p.route) { + t.Fatalf("expected route for next plugin %v, but got %v", s.expectedRoute, p.route) + } + if s.expectedEventType != p.t { + t.Fatalf("expected %s event for next plugin, but got %s", s.expectedEventType, p.t) + } + if !reflect.DeepEqual(s.expectedRejections, recorder.rejections) { + t.Fatalf("expected rejections %v, but got %v", s.expectedRejections, recorder.rejections) + } + }) + } +} + +func TestSecretUpdateAndDelete(t *testing.T) { + + scenarios := []struct { + name string + route *routev1.Route + secretManager fake.SecretManager + allow bool + deleteSecret bool + expectedRoute *routev1.Route + expectedEventType watch.EventType + expectedRejections map[string]string + }{ + { + name: "secret updated but permission revoked", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + }, + allow: false, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateValidationFailed", + }, + }, + { + name: "secret updated with permission but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + Err: fmt.Errorf("something"), + }, + allow: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateGetFailed", + }, + }, + { + name: "secret updated with permission correctly", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + }, + allow: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + Certificate: "my-crt", + Key: "my-key", + }, + }, + }, + expectedEventType: watch.Modified, + expectedRejections: map[string]string{}, + }, + { + name: "secret deleted but got error from secretManager", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + Err: fmt.Errorf("something"), + }, + deleteSecret: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateSecretDeleted", + }, + }, + { + name: "secret deleted and route successfully unregistered", + route: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + secretManager: fake.SecretManager{ + Secret: fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{ + "tls.crt": []byte("my-crt"), + "tls.key": []byte("my-key"), + }), + }, + deleteSecret: true, + expectedRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "route-test", + Namespace: "sandbox", + }, + Spec: routev1.RouteSpec{ + TLS: &routev1.TLSConfig{ + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-secret", + }, + }, + }, + }, + expectedEventType: watch.Deleted, + expectedRejections: map[string]string{ + "sandbox-route-test": "ExternalCertificateSecretDeleted", + }, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + oldSecret := fakeSecret("sandbox", "tls-secret", corev1.SecretTypeTLS, map[string][]byte{}) + kubeClient := testclient.NewSimpleClientset(oldSecret) + informer := fakeSecretInformer(kubeClient, "sandbox", "tls-secret") + go informer.Run(context.TODO().Done()) + + // wait for informer to start + if !cache.WaitForCacheSync(context.TODO().Done(), informer.HasSynced) { + t.Fatal("cache not synced yet") + } + + p := &fakePluginDone{ + doneCh: make(chan struct{}), + } + recorder := routeStatusRecorder{rejections: make(map[string]string)} + rsm := NewRouteSecretManager(p, recorder, &s.secretManager, &testSecretGetter{namespace: s.route.Namespace, secret: oldSecret}, &testSARCreator{allow: s.allow}) + + if _, err := informer.AddEventHandler(rsm.generateSecretHandler(s.route)); err != nil { + t.Fatalf("failed to add handler: %v", err) + } + + if s.deleteSecret { + // delete the secret + if err := kubeClient.CoreV1().Secrets(s.route.Namespace).Delete(context.TODO(), s.secretManager.Secret.Name, metav1.DeleteOptions{}); err != nil { + t.Fatalf("failed to delete secret: %v", err) + } + + } else { + // update the secret + if _, err := kubeClient.CoreV1().Secrets(s.route.Namespace).Update(context.TODO(), s.secretManager.Secret, metav1.UpdateOptions{}); err != nil { + t.Fatalf("failed to update secret: %v", err) + } + } + // wait until p.plugin.HandleRoute() completes (required to handle race condition) + <-p.doneCh + + if !reflect.DeepEqual(s.expectedRoute, p.route) { + t.Fatalf("expected route for next plugin %v, but got %v", s.expectedRoute, p.route) + } + if s.expectedEventType != p.eventType { + t.Fatalf("expected %s event for next plugin, but got %s", s.expectedEventType, p.eventType) + } + if !reflect.DeepEqual(s.expectedRejections, recorder.rejections) { + t.Fatalf("expected rejections %v, but got %v", s.expectedRejections, recorder.rejections) + } + }) + } +} diff --git a/pkg/router/routeapihelpers/validation.go b/pkg/router/routeapihelpers/validation.go index 863054b88..2f105d3e8 100644 --- a/pkg/router/routeapihelpers/validation.go +++ b/pkg/router/routeapihelpers/validation.go @@ -2,6 +2,7 @@ package routeapihelpers import ( "bytes" + "context" "crypto/ecdsa" "crypto/rsa" "crypto/tls" @@ -9,10 +10,25 @@ import ( "encoding/pem" "fmt" - "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/authentication/user" "k8s.io/client-go/util/cert" routev1 "github.com/openshift/api/route/v1" + "github.com/openshift/library-go/pkg/authorization/authorizationutil" + + authorizationv1 "k8s.io/api/authorization/v1" + kapi "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" +) + +const ( + // routerServiceAccount is used to validate RBAC permissions for externalCertificate + // TODO: avoid hard coding the serviceaccount name, and instead use environment variable, may be through cluster-ingress-operator. + routerServiceAccount = "system:serviceaccount:openshift-ingress:router" ) type blockVerifierFunc func(block *pem.Block) (*pem.Block, error) @@ -390,3 +406,58 @@ func UpgradeRouteValidation(route *routev1.Route) field.ErrorList { // are getting rejected now). return nil } + +// ValidateTLSExternalCertificate tests different pre-conditions required for +// using externalCertificate. +func ValidateTLSExternalCertificate(route *routev1.Route, fldPath *field.Path, sarc authorizationclient.SubjectAccessReviewInterface, secretsGetter corev1client.SecretsGetter) field.ErrorList { + tls := route.Spec.TLS + + errs := field.ErrorList{} + // The router serviceaccount must have permission to get/list/watch the referenced secret. + // The role and rolebinding to provide this access must be provided by the user. + if err := authorizationutil.Authorize(sarc, &user.DefaultInfo{Name: routerServiceAccount}, + &authorizationv1.ResourceAttributes{ + Namespace: route.Namespace, + Verb: "get", + Resource: "secrets", + Name: tls.ExternalCertificate.Name, + }); err != nil { + errs = append(errs, field.Forbidden(fldPath, "router serviceaccount does not have permission to get this secret")) + } + + if err := authorizationutil.Authorize(sarc, &user.DefaultInfo{Name: routerServiceAccount}, + &authorizationv1.ResourceAttributes{ + Namespace: route.Namespace, + Verb: "watch", + Resource: "secrets", + Name: tls.ExternalCertificate.Name, + }); err != nil { + errs = append(errs, field.Forbidden(fldPath, "router serviceaccount does not have permission to watch this secret")) + } + + if err := authorizationutil.Authorize(sarc, &user.DefaultInfo{Name: routerServiceAccount}, + &authorizationv1.ResourceAttributes{ + Namespace: route.Namespace, + Verb: "list", + Resource: "secrets", + Name: tls.ExternalCertificate.Name, + }); err != nil { + errs = append(errs, field.Forbidden(fldPath, "router serviceaccount does not have permission to list this secret")) + } + + // The secret should be in the same namespace as that of the route. + secret, err := secretsGetter.Secrets(route.Namespace).Get(context.TODO(), tls.ExternalCertificate.Name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return append(errs, field.NotFound(fldPath, err.Error())) + } + return append(errs, field.InternalError(fldPath, err)) + } + + // The secret should be of type kubernetes.io/tls + if secret.Type != kapi.SecretTypeTLS { + errs = append(errs, field.Invalid(fldPath, tls.ExternalCertificate.Name, fmt.Sprintf("secret of type %q required", kapi.SecretTypeTLS))) + } + + return errs +} diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go index ae033a367..c9313e99d 100644 --- a/pkg/router/router_test.go +++ b/pkg/router/router_test.go @@ -14,6 +14,7 @@ import ( "time" routev1 "github.com/openshift/api/route/v1" + fakesm "github.com/openshift/library-go/pkg/route/secretmanager/fake" projectfake "github.com/openshift/client-go/project/clientset/versioned/fake" routeclient "github.com/openshift/client-go/route/clientset/versioned" @@ -124,6 +125,7 @@ func TestMain(m *testing.M) { Value: `'"shouldn'\''t break"'`, Action: "Set", }}, + SecretManager: &fakesm.SecretManager{}, } plugin, err = templateplugin.NewTemplatePlugin(pluginCfg, svcFetcher) if err != nil { diff --git a/pkg/router/template/fake.go b/pkg/router/template/fake.go index 614db31a7..2f4560772 100644 --- a/pkg/router/template/fake.go +++ b/pkg/router/template/fake.go @@ -1,5 +1,9 @@ package templaterouter +import ( + fakesm "github.com/openshift/library-go/pkg/route/secretmanager/fake" +) + // NewFakeTemplateRouter provides an empty template router with a simple certificate manager // backed by a fake cert writer for testing func NewFakeTemplateRouter() *templateRouter { @@ -9,6 +13,7 @@ func NewFakeTemplateRouter() *templateRouter { serviceUnits: make(map[ServiceUnitKey]ServiceUnit), certManager: fakeCertManager, rateLimitedCommitFunction: nil, + secretManager: &fakesm.SecretManager{}, } } diff --git a/pkg/router/template/plugin.go b/pkg/router/template/plugin.go index 0d536a697..1db78354c 100644 --- a/pkg/router/template/plugin.go +++ b/pkg/router/template/plugin.go @@ -17,6 +17,7 @@ import ( routev1 "github.com/openshift/api/route/v1" + "github.com/openshift/library-go/pkg/route/secretmanager" unidlingapi "github.com/openshift/router/pkg/router/unidling" ) @@ -68,6 +69,7 @@ type TemplatePluginConfig struct { HTTPHeaderNameCaseAdjustments []HTTPHeaderNameCaseAdjustment HTTPResponseHeaders []HTTPHeader HTTPRequestHeaders []HTTPHeader + SecretManager secretmanager.SecretManager } // RouterInterface controls the interaction of the plugin with the underlying router implementation @@ -164,6 +166,7 @@ func NewTemplatePlugin(cfg TemplatePluginConfig, lookupSvc ServiceLookup) (*Temp httpHeaderNameCaseAdjustments: cfg.HTTPHeaderNameCaseAdjustments, httpResponseHeaders: cfg.HTTPResponseHeaders, httpRequestHeaders: cfg.HTTPRequestHeaders, + secretManager: cfg.SecretManager, } router, err := newTemplateRouter(templateRouterCfg) return newDefaultTemplatePlugin(router, cfg.IncludeUDP, lookupSvc), err diff --git a/pkg/router/template/router.go b/pkg/router/template/router.go index aafad83f5..1983d7e9b 100644 --- a/pkg/router/template/router.go +++ b/pkg/router/template/router.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" routev1 "github.com/openshift/api/route/v1" + "github.com/openshift/library-go/pkg/route/secretmanager" logf "github.com/openshift/router/log" "github.com/openshift/router/pkg/router/crl" @@ -64,6 +65,7 @@ type templateRouter struct { state map[ServiceAliasConfigKey]ServiceAliasConfig serviceUnits map[ServiceUnitKey]ServiceUnit certManager certificateManager + secretManager secretmanager.SecretManager // defaultCertificate is a concatenated certificate(s), their keys, and their CAs that should be used by the underlying // implementation as the default certificate if no certificate is resolved by the normal matching mechanisms. This is // usually a wildcard certificate for a cloud domain such as *.mypaas.com to allow applications to create app.mypaas.com @@ -155,6 +157,7 @@ type templateRouterCfg struct { httpHeaderNameCaseAdjustments []HTTPHeaderNameCaseAdjustment httpResponseHeaders []HTTPHeader httpRequestHeaders []HTTPHeader + secretManager secretmanager.SecretManager } // templateConfig is a subset of the templateRouter information that should be passed to the template for generating @@ -249,6 +252,7 @@ func newTemplateRouter(cfg templateRouterCfg) (*templateRouter, error) { state: make(map[ServiceAliasConfigKey]ServiceAliasConfig), serviceUnits: make(map[ServiceUnitKey]ServiceUnit), certManager: certManager, + secretManager: cfg.secretManager, defaultCertificate: cfg.defaultCertificate, defaultCertificatePath: cfg.defaultCertificatePath, defaultCertificateDir: cfg.defaultCertificateDir, @@ -1114,6 +1118,14 @@ func (r *templateRouter) RemoveRoute(route *routev1.Route) { defer r.lock.Unlock() r.removeRouteInternal(route) + + if r.secretManager != nil { // TODO: remove this nil check while dropping AllowExternalCertificates flag. + if r.secretManager.IsRouteRegistered(route.Namespace, route.Name) { + if err := r.secretManager.UnregisterRoute(route.Namespace, route.Name); err != nil { + log.Error(err, "failed to unregister route") + } + } + } } // removeRouteInternal removes the given route - internal diff --git a/pkg/router/template/router_test.go b/pkg/router/template/router_test.go index 9c4610d11..7266957bb 100644 --- a/pkg/router/template/router_test.go +++ b/pkg/router/template/router_test.go @@ -12,6 +12,7 @@ import ( "github.com/google/go-cmp/cmp" routev1 "github.com/openshift/api/route/v1" + fakesm "github.com/openshift/library-go/pkg/route/secretmanager/fake" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" @@ -627,6 +628,7 @@ func findCert(cert string, certs map[string]Certificate, isPrivateKey bool, t *t // TestRemoveRoute tests removing a ServiceAliasConfig from a ServiceUnit func TestRemoveRoute(t *testing.T) { router := NewFakeTemplateRouter() + router.secretManager = &fakesm.SecretManager{IsRegistered: true} route := &routev1.Route{ ObjectMeta: metav1.ObjectMeta{ Namespace: "foo",