From 5001210e41597adc4036415f97034eb8ac85858b Mon Sep 17 00:00:00 2001 From: jspdown Date: Thu, 12 Mar 2026 15:15:32 +0000 Subject: [PATCH 1/2] feat(CRDs): update Traefik Hub to v1.29.0 --- .../hub/hub.traefik.io_contentitems.yaml | 169 ++++++++++++++++++ .../hub/hub.traefik.io_uplinks.yaml | 89 +++++++++ traefik-crds/tests/crds_test.yaml | 4 +- traefik/crds/hub.traefik.io_contentitems.yaml | 169 ++++++++++++++++++ traefik/crds/hub.traefik.io_uplinks.yaml | 89 +++++++++ 5 files changed, 518 insertions(+), 2 deletions(-) create mode 100644 traefik-crds/crds-files/hub/hub.traefik.io_contentitems.yaml create mode 100644 traefik/crds/hub.traefik.io_contentitems.yaml diff --git a/traefik-crds/crds-files/hub/hub.traefik.io_contentitems.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_contentitems.yaml new file mode 100644 index 000000000..d00d61361 --- /dev/null +++ b/traefik-crds/crds-files/hub/hub.traefik.io_contentitems.yaml @@ -0,0 +1,169 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.1 + name: contentitems.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: ContentItem + listKind: ContentItemList + plural: contentitems + singular: contentitem + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ContentItem defines additional documentation for given resource. + 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: Defines the documentation to attach to the referenced resource. + properties: + content: + description: Content is the valid markdown content. + maxLength: 1500000 + type: string + link: + description: Link is the link to the content. + properties: + href: + description: Href is the public URL of the content. + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + required: + - href + type: object + order: + description: Order defines the order of the content in the UI. + format: int32 + minimum: 0 + type: integer + parentRef: + description: ParentRef is the reference to the resource that this + content belongs to. + properties: + kind: + description: Kind is the kind of the resource that this content + belongs to. + enum: + - APIPortal + - API + - APIBundle + type: string + name: + description: Name is the name of the resource that this content + belongs to. + maxLength: 253 + type: string + required: + - kind + - name + type: object + title: + description: Title is the public-facing name of the ContentItem. + maxLength: 253 + minLength: 1 + type: string + required: + - order + - parentRef + - title + type: object + x-kubernetes-validations: + - message: exactly one of content or link must be specified + rule: '[has(self.content), has(self.link)].filter(x, x).size() == 1' + status: + description: The current status of this ContentItem. + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + hash: + description: Hash is a hash representing the ContentItem. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/traefik-crds/crds-files/hub/hub.traefik.io_uplinks.yaml b/traefik-crds/crds-files/hub/hub.traefik.io_uplinks.yaml index be6743307..7ec4e196b 100644 --- a/traefik-crds/crds-files/hub/hub.traefik.io_uplinks.yaml +++ b/traefik-crds/crds-files/hub/hub.traefik.io_uplinks.yaml @@ -52,6 +52,95 @@ spec: ExposeName is the name of the service to expose. By default it uses -. type: string + healthCheck: + description: HealthCheck configures the active health check on the + parent cluster for this uplink's load balancer. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent to the + health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname in the Host + header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls for healthy targets. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the health check + endpoint. + type: string + port: + description: Port defines the server URL port for the health check + endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for the health + check endpoint. + type: string + status: + description: Status defines the expected HTTP status code of the + response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + unhealthyInterval: + anyOf: + - type: integer + - type: string + description: |- + UnhealthyInterval defines the frequency of the health check calls for unhealthy targets. + When UnhealthyInterval is not defined, it defaults to the Interval value. + Default: 30s + x-kubernetes-int-or-string: true + type: object + passiveHealthCheck: + description: PassiveHealthCheck configures the passive health check + on the parent cluster for this uplink's load balancer. + properties: + failureWindow: + anyOf: + - type: integer + - type: string + description: FailureWindow defines the time window during which + the failed attempts must occur for the server to be marked as + unhealthy. It also defines for how long the server will be considered + unhealthy. + x-kubernetes-int-or-string: true + maxFailedAttempts: + description: MaxFailedAttempts is the number of consecutive failed + attempts allowed within the failure window before marking the + server as unhealthy. + type: integer + type: object weight: description: Weight for WRR on the parent. type: integer diff --git a/traefik-crds/tests/crds_test.yaml b/traefik-crds/tests/crds_test.yaml index 88c9617d1..0bcf1fd37 100644 --- a/traefik-crds/tests/crds_test.yaml +++ b/traefik-crds/tests/crds_test.yaml @@ -26,7 +26,7 @@ tests: hub: true asserts: - hasDocuments: - count: 14 + count: 15 - isKind: of: CustomResourceDefinition - equal: @@ -34,7 +34,7 @@ tests: value: hub.traefik.io - matchRegex: path: spec.names.kind - pattern: ^(AccessControlPolicy|AIService|APIBundle|APICatalogItem|APIPlan|APIPortal|APIRateLimit|API|APIVersion|ManagedSubscription|ManagedApplication|APIAuth|APIPortalAuth|Uplink)$ + pattern: ^(AccessControlPolicy|AIService|APIBundle|APICatalogItem|APIPlan|APIPortal|APIRateLimit|API|APIVersion|ManagedSubscription|ManagedApplication|APIAuth|APIPortalAuth|Uplink|ContentItem)$ - equal: path: metadata.annotations["helm.sh/resource-policy"] value: keep diff --git a/traefik/crds/hub.traefik.io_contentitems.yaml b/traefik/crds/hub.traefik.io_contentitems.yaml new file mode 100644 index 000000000..d00d61361 --- /dev/null +++ b/traefik/crds/hub.traefik.io_contentitems.yaml @@ -0,0 +1,169 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.17.1 + name: contentitems.hub.traefik.io +spec: + group: hub.traefik.io + names: + kind: ContentItem + listKind: ContentItemList + plural: contentitems + singular: contentitem + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ContentItem defines additional documentation for given resource. + 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: Defines the documentation to attach to the referenced resource. + properties: + content: + description: Content is the valid markdown content. + maxLength: 1500000 + type: string + link: + description: Link is the link to the content. + properties: + href: + description: Href is the public URL of the content. + type: string + x-kubernetes-validations: + - message: must be a valid URL + rule: isURL(self) + required: + - href + type: object + order: + description: Order defines the order of the content in the UI. + format: int32 + minimum: 0 + type: integer + parentRef: + description: ParentRef is the reference to the resource that this + content belongs to. + properties: + kind: + description: Kind is the kind of the resource that this content + belongs to. + enum: + - APIPortal + - API + - APIBundle + type: string + name: + description: Name is the name of the resource that this content + belongs to. + maxLength: 253 + type: string + required: + - kind + - name + type: object + title: + description: Title is the public-facing name of the ContentItem. + maxLength: 253 + minLength: 1 + type: string + required: + - order + - parentRef + - title + type: object + x-kubernetes-validations: + - message: exactly one of content or link must be specified + rule: '[has(self.content), has(self.link)].filter(x, x).size() == 1' + status: + description: The current status of this ContentItem. + properties: + conditions: + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + hash: + description: Hash is a hash representing the ContentItem. + type: string + syncedAt: + format: date-time + type: string + version: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/traefik/crds/hub.traefik.io_uplinks.yaml b/traefik/crds/hub.traefik.io_uplinks.yaml index be6743307..7ec4e196b 100644 --- a/traefik/crds/hub.traefik.io_uplinks.yaml +++ b/traefik/crds/hub.traefik.io_uplinks.yaml @@ -52,6 +52,95 @@ spec: ExposeName is the name of the service to expose. By default it uses -. type: string + healthCheck: + description: HealthCheck configures the active health check on the + parent cluster for this uplink's load balancer. + properties: + followRedirects: + description: |- + FollowRedirects defines whether redirects should be followed during the health check calls. + Default: true + type: boolean + headers: + additionalProperties: + type: string + description: Headers defines custom headers to be sent to the + health check endpoint. + type: object + hostname: + description: Hostname defines the value of hostname in the Host + header of the health check request. + type: string + interval: + anyOf: + - type: integer + - type: string + description: |- + Interval defines the frequency of the health check calls for healthy targets. + Default: 30s + x-kubernetes-int-or-string: true + method: + description: Method defines the healthcheck method. + type: string + mode: + description: |- + Mode defines the health check mode. + If defined to grpc, will use the gRPC health check protocol to probe the server. + Default: http + type: string + path: + description: Path defines the server URL path for the health check + endpoint. + type: string + port: + description: Port defines the server URL port for the health check + endpoint. + type: integer + scheme: + description: Scheme replaces the server URL scheme for the health + check endpoint. + type: string + status: + description: Status defines the expected HTTP status code of the + response to the health check request. + type: integer + timeout: + anyOf: + - type: integer + - type: string + description: |- + Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. + Default: 5s + x-kubernetes-int-or-string: true + unhealthyInterval: + anyOf: + - type: integer + - type: string + description: |- + UnhealthyInterval defines the frequency of the health check calls for unhealthy targets. + When UnhealthyInterval is not defined, it defaults to the Interval value. + Default: 30s + x-kubernetes-int-or-string: true + type: object + passiveHealthCheck: + description: PassiveHealthCheck configures the passive health check + on the parent cluster for this uplink's load balancer. + properties: + failureWindow: + anyOf: + - type: integer + - type: string + description: FailureWindow defines the time window during which + the failed attempts must occur for the server to be marked as + unhealthy. It also defines for how long the server will be considered + unhealthy. + x-kubernetes-int-or-string: true + maxFailedAttempts: + description: MaxFailedAttempts is the number of consecutive failed + attempts allowed within the failure window before marking the + server as unhealthy. + type: integer + type: object weight: description: Weight for WRR on the parent. type: integer From 7e12461b69c79a4e6a96353725dd5129922237f8 Mon Sep 17 00:00:00 2001 From: jspdown Date: Wed, 4 Mar 2026 10:08:34 +0100 Subject: [PATCH 2/2] feat: add Traefik Hub ContentItem CRD --- traefik-crds/kustomization.yaml | 1 + traefik/crds/kustomization.yaml | 1 + traefik/templates/hub-admission-controller.yaml | 1 + traefik/templates/rbac/clusterrole.yaml | 2 ++ traefik/templates/rbac/role.yaml | 2 ++ traefik/tests/rbac-config_test.yaml | 2 ++ 6 files changed, 9 insertions(+) diff --git a/traefik-crds/kustomization.yaml b/traefik-crds/kustomization.yaml index f9c6e6482..a1aafbca2 100644 --- a/traefik-crds/kustomization.yaml +++ b/traefik-crds/kustomization.yaml @@ -16,6 +16,7 @@ resources: - crds-files/hub/hub.traefik.io_apiratelimits.yaml - crds-files/hub/hub.traefik.io_apis.yaml - crds-files/hub/hub.traefik.io_apiversions.yaml + - crds-files/hub/hub.traefik.io_contentitems.yaml - crds-files/hub/hub.traefik.io_managedapplications.yaml - crds-files/hub/hub.traefik.io_managedsubscriptions.yaml - crds-files/traefik/traefik.io_ingressroutes.yaml diff --git a/traefik/crds/kustomization.yaml b/traefik/crds/kustomization.yaml index 9f0416422..132c8b2c4 100644 --- a/traefik/crds/kustomization.yaml +++ b/traefik/crds/kustomization.yaml @@ -15,6 +15,7 @@ resources: - hub.traefik.io_apiratelimits.yaml - hub.traefik.io_apis.yaml - hub.traefik.io_apiversions.yaml + - hub.traefik.io_contentitems.yaml - hub.traefik.io_managedapplications.yaml - hub.traefik.io_managedsubscriptions.yaml - traefik.io_ingressroutes.yaml diff --git a/traefik/templates/hub-admission-controller.yaml b/traefik/templates/hub-admission-controller.yaml index 324f48cd0..7ad1701f4 100644 --- a/traefik/templates/hub-admission-controller.yaml +++ b/traefik/templates/hub-admission-controller.yaml @@ -71,6 +71,7 @@ webhooks: (dict "name" "hub-agent.traefik.plan" "endpoint" "/api-plan" "resource" "apiplans") (dict "name" "hub-agent.traefik.portal" "endpoint" "/api-portal" "resource" "apiportals") (dict "name" "hub-agent.traefik.version" "endpoint" "/api-version" "resource" "apiversions") + (dict "name" "hub-agent.traefik.version" "endpoint" "/content-item" "resource" "contentitems") }} {{- range $resources }} - name: hub-agent.traefik.{{ .name }} diff --git a/traefik/templates/rbac/clusterrole.yaml b/traefik/templates/rbac/clusterrole.yaml index 91b67f5ca..4aed4fbe2 100644 --- a/traefik/templates/rbac/clusterrole.yaml +++ b/traefik/templates/rbac/clusterrole.yaml @@ -216,6 +216,7 @@ rules: - apibundles - apiplans - apicatalogitems + - contentitems - managedsubscriptions - managedapplications verbs: @@ -239,6 +240,7 @@ rules: - apibundles/status - apiplans/status - apicatalogitems/status + - contentitems/status - managedsubscriptions/status - managedapplications/status verbs: diff --git a/traefik/templates/rbac/role.yaml b/traefik/templates/rbac/role.yaml index bf72e92a1..40116d209 100644 --- a/traefik/templates/rbac/role.yaml +++ b/traefik/templates/rbac/role.yaml @@ -175,6 +175,7 @@ rules: - apiplans - apicatalogitems - apiaccesses + - contentitems - managedsubscriptions - managedapplications verbs: @@ -198,6 +199,7 @@ rules: - apibundles/status - apiplans/status - apicatalogitems/status + - contentitems/status - managedsubscriptions/status - managedapplications/status verbs: diff --git a/traefik/tests/rbac-config_test.yaml b/traefik/tests/rbac-config_test.yaml index 2aa7ce8d1..39d1fc325 100644 --- a/traefik/tests/rbac-config_test.yaml +++ b/traefik/tests/rbac-config_test.yaml @@ -832,6 +832,7 @@ tests: - apibundles/status - apiplans/status - apicatalogitems/status + - contentitems/status - managedsubscriptions/status - managedapplications/status verbs: @@ -863,6 +864,7 @@ tests: - apibundles/status - apiplans/status - apicatalogitems/status + - contentitems/status - managedsubscriptions/status - managedapplications/status verbs: