diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 15251b657..9eefbcab5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "istio build-tools", - "image": "gcr.io/istio-testing/build-tools:master-4759bf88d40172234fc6a0b9e11a4c5f1ea58a90", + "image": "gcr.io/istio-testing/build-tools:master-12939d7be6baee95d63b1a9d7c4e194f1b241257", "privileged": true, "remoteEnv": { "USE_GKE_GCLOUD_AUTH_PLUGIN": "True", diff --git a/.github/workflows/update-deps.yaml b/.github/workflows/update-deps.yaml index 335c3f7a9..ff4e1c883 100644 --- a/.github/workflows/update-deps.yaml +++ b/.github/workflows/update-deps.yaml @@ -23,7 +23,7 @@ jobs: update-deps: runs-on: ubuntu-latest container: - image: gcr.io/istio-testing/build-tools:master-4759bf88d40172234fc6a0b9e11a4c5f1ea58a90 + image: gcr.io/istio-testing/build-tools:master-12939d7be6baee95d63b1a9d7c4e194f1b241257 options: --entrypoint '' steps: diff --git a/Makefile.core.mk b/Makefile.core.mk index 24cc1bd1b..fc5e3922d 100644 --- a/Makefile.core.mk +++ b/Makefile.core.mk @@ -468,12 +468,12 @@ OPM ?= $(LOCALBIN)/opm ISTIOCTL ?= $(LOCALBIN)/istioctl ## Tool Versions -OPERATOR_SDK_VERSION ?= v1.37.0 -HELM_VERSION ?= v3.16.2 -CONTROLLER_TOOLS_VERSION ?= v0.16.4 -OPM_VERSION ?= v1.47.0 -OLM_VERSION ?= 0.28.0 -GITLEAKS_VERSION ?= v8.21.1 +OPERATOR_SDK_VERSION ?= v1.38.0 +HELM_VERSION ?= v3.16.3 +CONTROLLER_TOOLS_VERSION ?= v0.16.5 +OPM_VERSION ?= v1.48.0 +OLM_VERSION ?= v0.30.0 +GITLEAKS_VERSION ?= v8.21.2 ISTIOCTL_VERSION ?= 1.23.0 # GENERATE_RELATED_IMAGES defines whether `spec.relatedImages` is going to be generated or not diff --git a/PROJECT b/PROJECT index 4a9317002..a1996da46 100644 --- a/PROJECT +++ b/PROJECT @@ -19,14 +19,6 @@ resources: kind: Istio path: github.com/istio-ecosystem/sail-operator/api/v1alpha1 version: v1alpha1 -- api: - crdVersion: v1 - namespaced: false - controller: true - domain: sailoperator.io - kind: RemoteIstio - path: github.com/istio-ecosystem/sail-operator/api/v1alpha1 - version: v1alpha1 - api: crdVersion: v1 namespaced: false diff --git a/api/v1alpha1/istio_types.go b/api/v1alpha1/istio_types.go index 0b9715a5f..f20e027a7 100644 --- a/api/v1alpha1/istio_types.go +++ b/api/v1alpha1/istio_types.go @@ -51,10 +51,10 @@ type IstioSpec struct { // +sail:profile // The built-in installation configuration profile to use. // The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - // Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + // Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. // +++PROFILES-DROPDOWN-HIDDEN-UNTIL-WE-FULLY-IMPLEMENT-THEM+++operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:external", "urn:alm:descriptor:com.tectonic.ui:select:minimal", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote"} // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} - // +kubebuilder:validation:Enum=ambient;default;demo;empty;openshift-ambient;openshift;preview;stable + // +kubebuilder:validation:Enum=ambient;default;demo;empty;openshift-ambient;openshift;preview;remote;stable Profile string `json:"profile,omitempty"` // Namespace to which the Istio components should be installed. Note that this field is immutable. @@ -227,6 +227,9 @@ const ( // IstioReasonIstiodNotReady indicates that the control plane is fully reconciled, but istiod is not ready. IstioReasonIstiodNotReady IstioConditionReason = "IstiodNotReady" + // IstioReasonRemoteIstiodNotReady indicates that the control plane is fully reconciled, but the remote istiod is not ready. + IstioReasonRemoteIstiodNotReady IstioConditionReason = "RemoteIstiodNotReady" + // IstioReasonReadinessCheckFailed indicates that readiness could not be ascertained. IstioReasonReadinessCheckFailed IstioConditionReason = "ReadinessCheckFailed" ) diff --git a/api/v1alpha1/istiocni_types.go b/api/v1alpha1/istiocni_types.go index aa56044a1..5a9c5d754 100644 --- a/api/v1alpha1/istiocni_types.go +++ b/api/v1alpha1/istiocni_types.go @@ -37,10 +37,10 @@ type IstioCNISpec struct { // +sail:profile // The built-in installation configuration profile to use. // The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - // Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + // Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. // +++PROFILES-DROPDOWN-HIDDEN-UNTIL-WE-FULLY-IMPLEMENT-THEM+++operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:external", "urn:alm:descriptor:com.tectonic.ui:select:minimal", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote"} // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} - // +kubebuilder:validation:Enum=ambient;default;demo;empty;openshift-ambient;openshift;preview;stable + // +kubebuilder:validation:Enum=ambient;default;demo;empty;openshift-ambient;openshift;preview;remote;stable Profile string `json:"profile,omitempty"` // Namespace to which the Istio CNI component should be installed. diff --git a/api/v1alpha1/istiorevision_types.go b/api/v1alpha1/istiorevision_types.go index 675af9450..b3b103dfe 100644 --- a/api/v1alpha1/istiorevision_types.go +++ b/api/v1alpha1/istiorevision_types.go @@ -28,11 +28,6 @@ const ( // IstioRevisionSpec defines the desired state of IstioRevision // +kubebuilder:validation:XValidation:rule="self.values.global.istioNamespace == self.__namespace__",message="spec.values.global.istioNamespace must match spec.namespace" type IstioRevisionSpec struct { - // Type indicates whether this revision represents a local or a remote control plane installation. - // +kubebuilder:default=Local - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable" - Type IstioRevisionType `json:"type"` - // +sail:version // Defines the version of Istio to install. // Must be one of: v1.23.2. @@ -178,16 +173,6 @@ const ( IstioRevisionReasonHealthy IstioRevisionConditionReason = "Healthy" ) -type IstioRevisionType string - -const ( - // IstioRevisionTypeLocal indicates that the revision represents a local control plane installation. - IstioRevisionTypeLocal IstioRevisionType = "Local" - - // IstioRevisionTypeRemote indicates that the revision represents a remote control plane installation. - IstioRevisionTypeRemote IstioRevisionType = "Remote" -) - // +kubebuilder:object:root=true // +kubebuilder:resource:scope=Cluster,shortName=istiorev,categories=istio-io // +kubebuilder:subresource:status diff --git a/api/v1alpha1/values_types.gen.go b/api/v1alpha1/values_types.gen.go index c2eea6744..ccd7b5006 100644 --- a/api/v1alpha1/values_types.gen.go +++ b/api/v1alpha1/values_types.gen.go @@ -1671,6 +1671,7 @@ type MeshConfigExtensionProvider struct { // Configures a Datadog tracing provider. Datadog *MeshConfigExtensionProviderDatadogTracingProvider `json:"datadog,omitempty"` + // +hidefromdoc // Configures a Stackdriver provider. Stackdriver *MeshConfigExtensionProviderStackdriverProvider `json:"stackdriver,omitempty"` @@ -1811,6 +1812,10 @@ type MeshConfigExtensionProviderEnvoyExternalAuthorizationHttpProvider struct { // or if the authorization service has returned a HTTP 5xx error. // Default is false and the request will be rejected with "Forbidden" response. FailOpen *bool `json:"failOpen,omitempty"` + // If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + // If true, recalculate routes with the new ExtAuthZ added/removed headers. + // Default is false + ClearRouteCache *bool `json:"clearRouteCache,omitempty"` // Sets the HTTP status that is returned to the client when there is a network error to the authorization service. // The default status is "403" (HTTP Forbidden). StatusOnError *string `json:"statusOnError,omitempty"` @@ -1899,6 +1904,10 @@ type MeshConfigExtensionProviderEnvoyExternalAuthorizationGrpcProvider struct { // or if the authorization service has returned a HTTP 5xx error. // Default is false. For HTTP request, it will be rejected with 403 (HTTP Forbidden). For TCP connection, it will be closed immediately. FailOpen *bool `json:"failOpen,omitempty"` + // If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + // If true, recalculate routes with the new ExtAuthZ added/removed headers. + // Default is false + ClearRouteCache *bool `json:"clearRouteCache,omitempty"` // Sets the HTTP status that is returned to the client when there is a network error to the authorization service. // The default status is "403" (HTTP Forbidden). StatusOnError *string `json:"statusOnError,omitempty"` @@ -2334,7 +2343,7 @@ type MeshConfigExtensionProviderGrpcService struct { // Optional. Specifies the timeout for the GRPC request. Timeout *metav1.Duration `json:"timeout,omitempty"` // Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - // scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + // scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to // be injected. InitialMetadata []*MeshConfigExtensionProviderHttpHeader `json:"initialMetadata,omitempty"` } @@ -2686,15 +2695,18 @@ type Tracing struct { // Use a Lightstep tracer. // NOTE: For Istio 1.15+, this configuration option will result // in using OpenTelemetry-based Lightstep integration. + // +hidefromdoc Lightstep *TracingLightstep `json:"lightstep,omitempty"` // Use a Datadog tracer. Datadog *TracingDatadog `json:"datadog,omitempty"` // Use a Stackdriver tracer. + // +hidefromdoc Stackdriver *TracingStackdriver `json:"stackdriver,omitempty"` // Use an OpenCensus tracer exporting to an OpenCensus agent. + // +hidefromdoc OpenCensusAgent *TracingOpenCensusAgent `json:"openCensusAgent,omitempty"` // Configures the custom tags to be added to active span by all proxies (i.e. sidecars // and gateways). // The key represents the name of the tag. @@ -2722,6 +2734,9 @@ type Tracing struct { // uses Istio mutual TLS and shares the root CA with Pilot, specify the TLS // mode as `ISTIO_MUTUAL`. TlsSettings *ClientTLSSettings `json:"tlsSettings,omitempty"` + // Determines whether or not trace spans generated by Envoy will include Istio specific tags. + // By default Istio specific tags are included in the trace spans. + EnableIstioTags *bool `json:"enableIstioTags,omitempty"` } // SDS defines secret discovery service(SDS) configuration to be used by the proxy. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6587fcd95..2ec699d97 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1935,6 +1935,11 @@ func (in *MeshConfigExtensionProviderEnvoyExternalAuthorizationGrpcProvider) Dee *out = new(bool) **out = **in } + if in.ClearRouteCache != nil { + in, out := &in.ClearRouteCache, &out.ClearRouteCache + *out = new(bool) + **out = **in + } if in.StatusOnError != nil { in, out := &in.StatusOnError, &out.StatusOnError *out = new(string) @@ -1985,6 +1990,11 @@ func (in *MeshConfigExtensionProviderEnvoyExternalAuthorizationHttpProvider) Dee *out = new(bool) **out = **in } + if in.ClearRouteCache != nil { + in, out := &in.ClearRouteCache, &out.ClearRouteCache + *out = new(bool) + **out = **in + } if in.StatusOnError != nil { in, out := &in.StatusOnError, &out.StatusOnError *out = new(string) @@ -4831,6 +4841,11 @@ func (in *Tracing) DeepCopyInto(out *Tracing) { *out = new(ClientTLSSettings) (*in).DeepCopyInto(*out) } + if in.EnableIstioTags != nil { + in, out := &in.EnableIstioTags, &out.EnableIstioTags + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tracing. diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 88d1b7d50..1b1540d5a 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -6,7 +6,7 @@ LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=servicemeshoperator3 LABEL operators.operatorframework.io.bundle.channels.v1="candidates" -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.37.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.38.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 diff --git a/bundle/manifests/extensions.istio.io_wasmplugins.yaml b/bundle/manifests/extensions.istio.io_wasmplugins.yaml index 22803cb14..98dec3286 100644 --- a/bundle/manifests/extensions.istio.io_wasmplugins.yaml +++ b/bundle/manifests/extensions.istio.io_wasmplugins.yaml @@ -305,6 +305,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -321,8 +327,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_destinationrules.yaml b/bundle/manifests/networking.istio.io_destinationrules.yaml index 998f51d54..92a9d4be0 100644 --- a/bundle/manifests/networking.istio.io_destinationrules.yaml +++ b/bundle/manifests/networking.istio.io_destinationrules.yaml @@ -1884,6 +1884,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1900,8 +1906,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -3801,6 +3805,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -3817,8 +3827,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -5718,6 +5726,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -5734,8 +5748,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_envoyfilters.yaml b/bundle/manifests/networking.istio.io_envoyfilters.yaml index f2181cfc6..af202fd69 100644 --- a/bundle/manifests/networking.istio.io_envoyfilters.yaml +++ b/bundle/manifests/networking.istio.io_envoyfilters.yaml @@ -345,6 +345,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -361,8 +367,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_gateways.yaml b/bundle/manifests/networking.istio.io_gateways.yaml index c6307b2ed..c4d5dbd8a 100644 --- a/bundle/manifests/networking.istio.io_gateways.yaml +++ b/bundle/manifests/networking.istio.io_gateways.yaml @@ -196,6 +196,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -212,8 +218,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -425,6 +429,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -441,8 +451,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -654,6 +662,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -670,8 +684,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_proxyconfigs.yaml b/bundle/manifests/networking.istio.io_proxyconfigs.yaml index a9a4ab728..a5b7a373b 100644 --- a/bundle/manifests/networking.istio.io_proxyconfigs.yaml +++ b/bundle/manifests/networking.istio.io_proxyconfigs.yaml @@ -89,6 +89,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -105,8 +111,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_serviceentries.yaml b/bundle/manifests/networking.istio.io_serviceentries.yaml index dab356fed..2f35395b6 100644 --- a/bundle/manifests/networking.istio.io_serviceentries.yaml +++ b/bundle/manifests/networking.istio.io_serviceentries.yaml @@ -258,6 +258,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -274,8 +280,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -551,6 +555,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -567,8 +577,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -844,6 +852,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -860,8 +874,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_sidecars.yaml b/bundle/manifests/networking.istio.io_sidecars.yaml index dd6b32b37..38a3a21fa 100644 --- a/bundle/manifests/networking.istio.io_sidecars.yaml +++ b/bundle/manifests/networking.istio.io_sidecars.yaml @@ -503,6 +503,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -519,8 +525,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -1041,6 +1045,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1057,8 +1067,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -1579,6 +1587,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1595,8 +1609,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_virtualservices.yaml b/bundle/manifests/networking.istio.io_virtualservices.yaml index b07b71aa1..30590fe26 100644 --- a/bundle/manifests/networking.istio.io_virtualservices.yaml +++ b/bundle/manifests/networking.istio.io_virtualservices.yaml @@ -1003,6 +1003,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1019,8 +1025,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -2039,6 +2043,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -2055,8 +2065,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -3075,6 +3083,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -3091,8 +3105,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_workloadentries.yaml b/bundle/manifests/networking.istio.io_workloadentries.yaml index 8ff93a410..5a42a45b6 100644 --- a/bundle/manifests/networking.istio.io_workloadentries.yaml +++ b/bundle/manifests/networking.istio.io_workloadentries.yaml @@ -121,6 +121,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -137,8 +143,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -277,6 +281,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -293,8 +303,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -433,6 +441,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -449,8 +463,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/networking.istio.io_workloadgroups.yaml b/bundle/manifests/networking.istio.io_workloadgroups.yaml index 486c0e689..44679f157 100644 --- a/bundle/manifests/networking.istio.io_workloadgroups.yaml +++ b/bundle/manifests/networking.istio.io_workloadgroups.yaml @@ -249,6 +249,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -265,8 +271,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -535,6 +539,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -551,8 +561,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -821,6 +829,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -837,8 +851,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/sailoperator.io_istiocnis.yaml b/bundle/manifests/sailoperator.io_istiocnis.yaml index 29623eb00..f0ab6cc4f 100644 --- a/bundle/manifests/sailoperator.io_istiocnis.yaml +++ b/bundle/manifests/sailoperator.io_istiocnis.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 creationTimestamp: null name: istiocnis.sailoperator.io spec: @@ -70,7 +70,7 @@ spec: description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. enum: - ambient - default @@ -79,6 +79,7 @@ spec: - openshift-ambient - openshift - preview + - remote - stable type: string values: diff --git a/bundle/manifests/sailoperator.io_istiorevisions.yaml b/bundle/manifests/sailoperator.io_istiorevisions.yaml index 8e871f2ee..93d1c4377 100644 --- a/bundle/manifests/sailoperator.io_istiorevisions.yaml +++ b/bundle/manifests/sailoperator.io_istiorevisions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 creationTimestamp: null name: istiorevisions.sailoperator.io spec: @@ -78,14 +78,6 @@ spec: x-kubernetes-validations: - message: Value is immutable rule: self == oldSelf - type: - default: Local - description: Type indicates whether this revision represents a local - or a remote control plane installation. - type: string - x-kubernetes-validations: - - message: Value is immutable - rule: self == oldSelf values: description: Defines the values to be passed to the Helm charts when installing Istio. @@ -3792,6 +3784,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4281,6 +4278,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4350,6 +4353,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4919,7 +4928,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: @@ -9386,7 +9395,6 @@ spec: type: string required: - namespace - - type - version type: object x-kubernetes-validations: diff --git a/bundle/manifests/sailoperator.io_istios.yaml b/bundle/manifests/sailoperator.io_istios.yaml index 642746603..6579d3d21 100644 --- a/bundle/manifests/sailoperator.io_istios.yaml +++ b/bundle/manifests/sailoperator.io_istios.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 creationTimestamp: null name: istios.sailoperator.io spec: @@ -95,7 +95,7 @@ spec: description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. enum: - ambient - default @@ -104,6 +104,7 @@ spec: - openshift-ambient - openshift - preview + - remote - stable type: string updateStrategy: @@ -3851,6 +3852,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4340,6 +4346,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4409,6 +4421,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4978,7 +4996,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: diff --git a/bundle/manifests/sailoperator.io_remoteistios.yaml b/bundle/manifests/sailoperator.io_remoteistios.yaml index 7d26470e8..2799e8597 100644 --- a/bundle/manifests/sailoperator.io_remoteistios.yaml +++ b/bundle/manifests/sailoperator.io_remoteistios.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 creationTimestamp: null name: remoteistios.sailoperator.io spec: @@ -3842,6 +3842,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4331,6 +4336,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4400,6 +4411,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4969,7 +4986,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: diff --git a/bundle/manifests/security.istio.io_authorizationpolicies.yaml b/bundle/manifests/security.istio.io_authorizationpolicies.yaml index bebc1b2c6..7f450f367 100644 --- a/bundle/manifests/security.istio.io_authorizationpolicies.yaml +++ b/bundle/manifests/security.istio.io_authorizationpolicies.yaml @@ -321,6 +321,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -337,8 +343,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -674,6 +678,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -690,8 +700,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/security.istio.io_peerauthentications.yaml b/bundle/manifests/security.istio.io_peerauthentications.yaml index 0d9ad5524..e0393c18e 100644 --- a/bundle/manifests/security.istio.io_peerauthentications.yaml +++ b/bundle/manifests/security.istio.io_peerauthentications.yaml @@ -127,6 +127,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -143,8 +149,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -286,6 +290,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -302,8 +312,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/security.istio.io_requestauthentications.yaml b/bundle/manifests/security.istio.io_requestauthentications.yaml index 2d1b0ba00..52135c199 100644 --- a/bundle/manifests/security.istio.io_requestauthentications.yaml +++ b/bundle/manifests/security.istio.io_requestauthentications.yaml @@ -255,6 +255,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -271,8 +277,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -542,6 +546,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -558,8 +568,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/manifests/servicemeshoperator3.clusterserviceversion.yaml b/bundle/manifests/servicemeshoperator3.clusterserviceversion.yaml index 0e7193635..46b4981f4 100644 --- a/bundle/manifests/servicemeshoperator3.clusterserviceversion.yaml +++ b/bundle/manifests/servicemeshoperator3.clusterserviceversion.yaml @@ -34,7 +34,7 @@ metadata: capabilities: Seamless Upgrades categories: OpenShift Optional, Integration & Delivery, Networking, Security containerImage: quay.io/maistra-dev/sail-operator:3.0-latest - createdAt: "2024-10-23T21:09:47Z" + createdAt: "2024-11-25T15:12:07Z" description: The OpenShift Service Mesh Operator enables you to install, configure, and manage an instance of Red Hat OpenShift Service Mesh. OpenShift Service Mesh is based on the open source Istio project. @@ -50,7 +50,7 @@ metadata: features.operators.openshift.io/token-auth-gcp: "false" operators.openshift.io/valid-subscription: '["OpenShift Container Platform", "OpenShift Platform Plus"]' - operators.operatorframework.io/builder: operator-sdk-v1.37.0 + operators.operatorframework.io/builder: operator-sdk-v1.38.0 operators.operatorframework.io/internal-objects: '["wasmplugins.extensions.istio.io","destinationrules.networking.istio.io","envoyfilters.networking.istio.io","gateways.networking.istio.io","proxyconfigs.networking.istio.io","serviceentries.networking.istio.io","sidecars.networking.istio.io","virtualservices.networking.istio.io","workloadentries.networking.istio.io","workloadgroups.networking.istio.io","authorizationpolicies.security.istio.io","peerauthentications.security.istio.io","requestauthentications.security.istio.io","telemetries.telemetry.istio.io"]' operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 repository: https://github.com/istio-ecosystem/sail-operator @@ -133,6 +133,9 @@ spec: - kind: WorkloadGroup name: workloadgroups.networking.istio.io version: v1beta1 + - kind: RemoteIstio + name: remoteistios.sailoperator.io + version: v1alpha1 - kind: AuthorizationPolicy name: authorizationpolicies.security.istio.io version: v1 @@ -178,7 +181,7 @@ spec: - description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. displayName: Profile path: profile x-descriptors: @@ -276,7 +279,7 @@ spec: - description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. displayName: Profile path: profile x-descriptors: @@ -290,75 +293,6 @@ spec: displayName: Helm Values path: values version: v1alpha1 - - description: |- - RemoteIstio represents a remote Istio Service Mesh deployment consisting of one or more - remote control plane instances (represented by one or more IstioRevision objects). - displayName: Remote Istio - kind: RemoteIstio - name: remoteistios.sailoperator.io - specDescriptors: - - description: "Type of strategy to use. Can be \"InPlace\" or \"RevisionBased\". - When the \"InPlace\" strategy\nis used, the existing Istio control plane - is updated in-place. The workloads therefore\ndon't need to be moved from - one control plane instance to another. When the \"RevisionBased\"\nstrategy - is used, a new Istio control plane instance is created for every change - to the\nIstio.spec.version field. The old control plane remains in place - until all workloads have\nbeen moved to the new control plane instance.\n\n\nThe - \"InPlace\" strategy is the default.\tTODO: change default to \"RevisionBased\"" - displayName: Type - path: updateStrategy.type - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:select:InPlace - - urn:alm:descriptor:com.tectonic.ui:select:RevisionBased - - description: |- - Defines the version of Istio to install. - Must be one of: v1.23.2. - displayName: Istio Version - path: version - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:fieldGroup:General - - urn:alm:descriptor:com.tectonic.ui:select:v1.23.2 - - description: |- - Defines how many seconds the operator should wait before removing a non-active revision after all - the workloads have stopped using it. You may want to set this value on the order of minutes. - The minimum is 0 and the default value is 30. - displayName: Inactive Revision Deletion Grace Period (seconds) - path: updateStrategy.inactiveRevisionDeletionGracePeriodSeconds - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:number - - description: |- - Defines whether the workloads should be moved from one control plane instance to another - automatically. If updateWorkloads is true, the operator moves the workloads from the old - control plane instance to the new one after the new control plane is ready. - If updateWorkloads is false, the user must move the workloads manually by updating the - istio.io/rev labels on the namespace and/or the pods. - Defaults to false. - displayName: Update Workloads Automatically - path: updateStrategy.updateWorkloads - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - - description: Namespace to which the Istio components should be installed. - displayName: Namespace - path: namespace - x-descriptors: - - urn:alm:descriptor:io.kubernetes:Namespace - - description: |- - The built-in installation configuration profile to use. - The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. - displayName: Profile - path: profile - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:hidden - - description: Defines the update strategy to use when the version in the RemoteIstio - CR is updated. - displayName: Update Strategy - path: updateStrategy - - description: Defines the values to be passed to the Helm charts when installing - Istio. - displayName: Helm Values - path: values - version: v1alpha1 description: |- Red Hat OpenShift Service Mesh is a platform that provides behavioral insight and operational control over a service mesh, providing a uniform way to connect, secure, and monitor microservice applications. diff --git a/bundle/manifests/telemetry.istio.io_telemetries.yaml b/bundle/manifests/telemetry.istio.io_telemetries.yaml index ec3cf100a..9a897b7b9 100644 --- a/bundle/manifests/telemetry.istio.io_telemetries.yaml +++ b/bundle/manifests/telemetry.istio.io_telemetries.yaml @@ -354,6 +354,11 @@ spec: description: Controls span reporting. nullable: true type: boolean + enableIstioTags: + description: Determines whether or not trace spans generated + by Envoy will include Istio specific tags. + nullable: true + type: boolean match: description: Allows tailoring of behavior to specific conditions. properties: @@ -416,6 +421,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -432,8 +443,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -802,6 +811,11 @@ spec: description: Controls span reporting. nullable: true type: boolean + enableIstioTags: + description: Determines whether or not trace spans generated + by Envoy will include Istio specific tags. + nullable: true + type: boolean match: description: Allows tailoring of behavior to specific conditions. properties: @@ -864,6 +878,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -880,8 +900,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 3bef409f7..3a0ad9018 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -5,7 +5,7 @@ annotations: operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: servicemeshoperator3 operators.operatorframework.io.bundle.channels.v1: "candidates" - operators.operatorframework.io.metrics.builder: operator-sdk-v1.37.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.38.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4 diff --git a/bundle/tests/scorecard/config.yaml b/bundle/tests/scorecard/config.yaml index bd9bf1e03..cf5c4335e 100644 --- a/bundle/tests/scorecard/config.yaml +++ b/bundle/tests/scorecard/config.yaml @@ -8,7 +8,7 @@ stages: - entrypoint: - scorecard-test - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: basic test: basic-check-spec-test @@ -18,7 +18,7 @@ stages: - entrypoint: - scorecard-test - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-bundle-validation-test @@ -28,7 +28,7 @@ stages: - entrypoint: - scorecard-test - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-crds-have-validation-test @@ -38,7 +38,7 @@ stages: - entrypoint: - scorecard-test - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-spec-descriptors-test @@ -48,7 +48,7 @@ stages: - entrypoint: - scorecard-test - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-status-descriptors-test diff --git a/chart/crds/extensions.istio.io_wasmplugins.yaml b/chart/crds/extensions.istio.io_wasmplugins.yaml index 1acec4b67..2067b280d 100644 --- a/chart/crds/extensions.istio.io_wasmplugins.yaml +++ b/chart/crds/extensions.istio.io_wasmplugins.yaml @@ -305,6 +305,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -321,8 +327,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_destinationrules.yaml b/chart/crds/networking.istio.io_destinationrules.yaml index b00eef64e..451f7352d 100644 --- a/chart/crds/networking.istio.io_destinationrules.yaml +++ b/chart/crds/networking.istio.io_destinationrules.yaml @@ -1883,6 +1883,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1899,8 +1905,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -3800,6 +3804,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -3816,8 +3826,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -5717,6 +5725,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -5733,8 +5747,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_envoyfilters.yaml b/chart/crds/networking.istio.io_envoyfilters.yaml index e2be5b942..70ed2f9fb 100644 --- a/chart/crds/networking.istio.io_envoyfilters.yaml +++ b/chart/crds/networking.istio.io_envoyfilters.yaml @@ -344,6 +344,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -360,8 +366,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_gateways.yaml b/chart/crds/networking.istio.io_gateways.yaml index 0d29b562f..ece08a057 100644 --- a/chart/crds/networking.istio.io_gateways.yaml +++ b/chart/crds/networking.istio.io_gateways.yaml @@ -195,6 +195,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -211,8 +217,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -424,6 +428,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -440,8 +450,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -653,6 +661,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -669,8 +683,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_proxyconfigs.yaml b/chart/crds/networking.istio.io_proxyconfigs.yaml index 7432a7498..e7e64d508 100644 --- a/chart/crds/networking.istio.io_proxyconfigs.yaml +++ b/chart/crds/networking.istio.io_proxyconfigs.yaml @@ -88,6 +88,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -104,8 +110,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_serviceentries.yaml b/chart/crds/networking.istio.io_serviceentries.yaml index a87b1c236..de8ff0350 100644 --- a/chart/crds/networking.istio.io_serviceentries.yaml +++ b/chart/crds/networking.istio.io_serviceentries.yaml @@ -257,6 +257,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -273,8 +279,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -550,6 +554,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -566,8 +576,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -843,6 +851,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -859,8 +873,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_sidecars.yaml b/chart/crds/networking.istio.io_sidecars.yaml index 560e8fbb1..3ea0e2665 100644 --- a/chart/crds/networking.istio.io_sidecars.yaml +++ b/chart/crds/networking.istio.io_sidecars.yaml @@ -502,6 +502,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -518,8 +524,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -1040,6 +1044,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1056,8 +1066,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -1578,6 +1586,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1594,8 +1608,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_virtualservices.yaml b/chart/crds/networking.istio.io_virtualservices.yaml index 8a49cfad3..39e31750c 100644 --- a/chart/crds/networking.istio.io_virtualservices.yaml +++ b/chart/crds/networking.istio.io_virtualservices.yaml @@ -1002,6 +1002,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -1018,8 +1024,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -2038,6 +2042,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -2054,8 +2064,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -3074,6 +3082,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -3090,8 +3104,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_workloadentries.yaml b/chart/crds/networking.istio.io_workloadentries.yaml index cf682cd2d..f0053326f 100644 --- a/chart/crds/networking.istio.io_workloadentries.yaml +++ b/chart/crds/networking.istio.io_workloadentries.yaml @@ -120,6 +120,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -136,8 +142,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -276,6 +280,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -292,8 +302,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -432,6 +440,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -448,8 +462,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/networking.istio.io_workloadgroups.yaml b/chart/crds/networking.istio.io_workloadgroups.yaml index 9f06ab833..2758ad3ab 100644 --- a/chart/crds/networking.istio.io_workloadgroups.yaml +++ b/chart/crds/networking.istio.io_workloadgroups.yaml @@ -248,6 +248,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -264,8 +270,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -534,6 +538,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -550,8 +560,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -820,6 +828,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -836,8 +850,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/sailoperator.io_istiocnis.yaml b/chart/crds/sailoperator.io_istiocnis.yaml index 1acbea7bb..9878d656d 100644 --- a/chart/crds/sailoperator.io_istiocnis.yaml +++ b/chart/crds/sailoperator.io_istiocnis.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 name: istiocnis.sailoperator.io spec: group: sailoperator.io @@ -70,7 +70,7 @@ spec: description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. enum: - ambient - default @@ -79,6 +79,7 @@ spec: - openshift-ambient - openshift - preview + - remote - stable type: string values: diff --git a/chart/crds/sailoperator.io_istiorevisions.yaml b/chart/crds/sailoperator.io_istiorevisions.yaml index ee7a4eac0..0fb0ed099 100644 --- a/chart/crds/sailoperator.io_istiorevisions.yaml +++ b/chart/crds/sailoperator.io_istiorevisions.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 name: istiorevisions.sailoperator.io spec: group: sailoperator.io @@ -78,14 +78,6 @@ spec: x-kubernetes-validations: - message: Value is immutable rule: self == oldSelf - type: - default: Local - description: Type indicates whether this revision represents a local - or a remote control plane installation. - type: string - x-kubernetes-validations: - - message: Value is immutable - rule: self == oldSelf values: description: Defines the values to be passed to the Helm charts when installing Istio. @@ -3792,6 +3784,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4281,6 +4278,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4350,6 +4353,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4919,7 +4928,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: @@ -9386,7 +9395,6 @@ spec: type: string required: - namespace - - type - version type: object x-kubernetes-validations: diff --git a/chart/crds/sailoperator.io_istios.yaml b/chart/crds/sailoperator.io_istios.yaml index 2cd9cf0a0..02e7b590f 100644 --- a/chart/crds/sailoperator.io_istios.yaml +++ b/chart/crds/sailoperator.io_istios.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 name: istios.sailoperator.io spec: group: sailoperator.io @@ -95,7 +95,7 @@ spec: description: |- The built-in installation configuration profile to use. The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'. - Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, stable. + Must be one of: ambient, default, demo, empty, openshift-ambient, openshift, preview, remote, stable. enum: - ambient - default @@ -104,6 +104,7 @@ spec: - openshift-ambient - openshift - preview + - remote - stable type: string updateStrategy: @@ -3851,6 +3852,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4340,6 +4346,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4409,6 +4421,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4978,7 +4996,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: diff --git a/chart/crds/sailoperator.io_remoteistios.yaml b/chart/crds/sailoperator.io_remoteistios.yaml index ec9441aed..d36a83222 100644 --- a/chart/crds/sailoperator.io_remoteistios.yaml +++ b/chart/crds/sailoperator.io_remoteistios.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.4 + controller-gen.kubebuilder.io/version: v0.16.5 name: remoteistios.sailoperator.io spec: group: sailoperator.io @@ -3842,6 +3842,11 @@ spec: description: Address of the Datadog Agent. type: string type: object + enableIstioTags: + description: |- + Determines whether or not trace spans generated by Envoy will include Istio specific tags. + By default Istio specific tags are included in the trace spans. + type: boolean lightstep: description: |- Use a Lightstep tracer. @@ -4331,6 +4336,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the gRPC API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed, @@ -4400,6 +4411,12 @@ spec: implements the Envoy ext_authz filter authorization check service using the HTTP API. properties: + clearRouteCache: + description: |- + If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions. + If true, recalculate routes with the new ExtAuthZ added/removed headers. + Default is false + type: boolean failOpen: description: |- If true, the user request will be allowed even if the communication with the authorization service has failed, @@ -4969,7 +4986,7 @@ spec: initialMetadata: description: |- Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for - scenarios in which additional ad hoc authorization headers (e.g. “x-foo-bar: baz-key“) are to + scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to be injected. items: properties: diff --git a/chart/crds/security.istio.io_authorizationpolicies.yaml b/chart/crds/security.istio.io_authorizationpolicies.yaml index 0f72f71e1..a83d6ee0c 100644 --- a/chart/crds/security.istio.io_authorizationpolicies.yaml +++ b/chart/crds/security.istio.io_authorizationpolicies.yaml @@ -320,6 +320,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -336,8 +342,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -673,6 +677,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -689,8 +699,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/security.istio.io_peerauthentications.yaml b/chart/crds/security.istio.io_peerauthentications.yaml index 3d6895db5..329efc01f 100644 --- a/chart/crds/security.istio.io_peerauthentications.yaml +++ b/chart/crds/security.istio.io_peerauthentications.yaml @@ -126,6 +126,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -142,8 +148,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -285,6 +289,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -301,8 +311,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/security.istio.io_requestauthentications.yaml b/chart/crds/security.istio.io_requestauthentications.yaml index 53fe59d32..2d6729688 100644 --- a/chart/crds/security.istio.io_requestauthentications.yaml +++ b/chart/crds/security.istio.io_requestauthentications.yaml @@ -254,6 +254,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -270,8 +276,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -541,6 +545,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -557,8 +567,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/crds/telemetry.istio.io_telemetries.yaml b/chart/crds/telemetry.istio.io_telemetries.yaml index c858b2995..beaa1537b 100644 --- a/chart/crds/telemetry.istio.io_telemetries.yaml +++ b/chart/crds/telemetry.istio.io_telemetries.yaml @@ -353,6 +353,11 @@ spec: description: Controls span reporting. nullable: true type: boolean + enableIstioTags: + description: Determines whether or not trace spans generated + by Envoy will include Istio specific tags. + nullable: true + type: boolean match: description: Allows tailoring of behavior to specific conditions. properties: @@ -415,6 +420,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -431,8 +442,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. @@ -801,6 +810,11 @@ spec: description: Controls span reporting. nullable: true type: boolean + enableIstioTags: + description: Determines whether or not trace spans generated + by Envoy will include Istio specific tags. + nullable: true + type: boolean match: description: Allows tailoring of behavior to specific conditions. properties: @@ -863,6 +877,12 @@ spec: description: Human-readable message indicating details about last transition. type: string + observedGeneration: + anyOf: + - type: integer + - type: string + description: Resource Generation to which the Condition refers. + x-kubernetes-int-or-string: true reason: description: Unique, one-word, CamelCase reason for the condition's last transition. @@ -879,8 +899,6 @@ spec: anyOf: - type: integer - type: string - description: Resource Generation to which the Reconciled Condition - refers. x-kubernetes-int-or-string: true validationMessages: description: Includes any errors or warnings detected by Istio's analyzers. diff --git a/chart/samples/remoteistio-sample.yaml b/chart/samples/remoteistio-sample.yaml deleted file mode 100644 index 66407f939..000000000 --- a/chart/samples/remoteistio-sample.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: sailoperator.io/v1alpha1 -kind: RemoteIstio -metadata: - name: default -spec: - version: latest - namespace: istio-system - updateStrategy: - type: InPlace - inactiveRevisionDeletionGracePeriodSeconds: 30 - values: - istiodRemote: - injectionPath: /inject/cluster/cluster2/net/network1 - global: - remotePilotAddress: 1.2.3.4 \ No newline at end of file diff --git a/chart/templates/olm/scorecard.yaml b/chart/templates/olm/scorecard.yaml index feebc2ada..82c508161 100644 --- a/chart/templates/olm/scorecard.yaml +++ b/chart/templates/olm/scorecard.yaml @@ -9,7 +9,7 @@ stages: - entrypoint: - scorecard-test - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: basic test: basic-check-spec-test @@ -19,7 +19,7 @@ stages: - entrypoint: - scorecard-test - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-bundle-validation-test @@ -29,7 +29,7 @@ stages: - entrypoint: - scorecard-test - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-crds-have-validation-test @@ -39,7 +39,7 @@ stages: - entrypoint: - scorecard-test - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-spec-descriptors-test @@ -49,7 +49,7 @@ stages: - entrypoint: - scorecard-test - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.37.0 + image: quay.io/operator-framework/scorecard-test:v1.38.0 labels: suite: olm test: olm-status-descriptors-test diff --git a/chart/values.yaml b/chart/values.yaml index c4f5ff6a4..27dcc9fa2 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -18,10 +18,13 @@ csv: This version of the operator supports the following Istio versions: + - v1.24.0 + - v1.23.3 - v1.23.2 + - v1.22.6 - v1.22.5 - v1.21.6 - - latest (bb972b54) + - latest (803629b9) [See this page](https://github.com/istio-ecosystem/sail-operator/blob/main/bundle/README.md) for instructions on how to use it. support: Community based diff --git a/cmd/main.go b/cmd/main.go index d713a8131..1d8b4cac2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -23,7 +23,6 @@ import ( "github.com/istio-ecosystem/sail-operator/controllers/istio" "github.com/istio-ecosystem/sail-operator/controllers/istiocni" "github.com/istio-ecosystem/sail-operator/controllers/istiorevision" - "github.com/istio-ecosystem/sail-operator/controllers/remoteistio" "github.com/istio-ecosystem/sail-operator/controllers/webhook" "github.com/istio-ecosystem/sail-operator/pkg/config" "github.com/istio-ecosystem/sail-operator/pkg/enqueuelogger" @@ -144,13 +143,6 @@ func main() { os.Exit(1) } - err = remoteistio.NewReconciler(reconcilerCfg, mgr.GetClient(), mgr.GetScheme()). - SetupWithManager(mgr) - if err != nil { - setupLog.Error(err, "unable to create controller", "controller", "RemoteIstio") - os.Exit(1) - } - err = istiorevision.NewReconciler(reconcilerCfg, mgr.GetClient(), mgr.GetScheme(), chartManager). SetupWithManager(mgr) if err != nil { diff --git a/common/.commonfiles.sha b/common/.commonfiles.sha index aebb24f3e..feef7bcc2 100644 --- a/common/.commonfiles.sha +++ b/common/.commonfiles.sha @@ -1 +1 @@ -82dc68a737b72d394c344d4fd71ff9e9ebf01852 +e955cacd8ba890189a80551485d35a0e228276ec diff --git a/common/config/.golangci.yml b/common/config/.golangci.yml index 2c0565492..b5a0349b9 100644 --- a/common/config/.golangci.yml +++ b/common/config/.golangci.yml @@ -18,7 +18,7 @@ linters: disable-all: true enable: - errcheck - - exportloopref + - copyloopvar - depguard - gocritic - gofumpt diff --git a/common/scripts/setup_env.sh b/common/scripts/setup_env.sh index c63f1fa33..746d900ed 100755 --- a/common/scripts/setup_env.sh +++ b/common/scripts/setup_env.sh @@ -75,7 +75,7 @@ fi TOOLS_REGISTRY_PROVIDER=${TOOLS_REGISTRY_PROVIDER:-gcr.io} PROJECT_ID=${PROJECT_ID:-istio-testing} if [[ "${IMAGE_VERSION:-}" == "" ]]; then - IMAGE_VERSION=master-4759bf88d40172234fc6a0b9e11a4c5f1ea58a90 + IMAGE_VERSION=master-12939d7be6baee95d63b1a9d7c4e194f1b241257 fi if [[ "${IMAGE_NAME:-}" == "" ]]; then IMAGE_NAME=build-tools diff --git a/controllers/istio/istio_controller.go b/controllers/istio/istio_controller.go index 24043a2ec..b013c9bf1 100644 --- a/controllers/istio/istio_controller.go +++ b/controllers/istio/istio_controller.go @@ -115,7 +115,6 @@ func (r *Reconciler) reconcileActiveRevision(ctx context.Context, istio *v1alpha return revision.CreateOrUpdate(ctx, r.Client, getActiveRevisionName(istio), - v1alpha1.IstioRevisionTypeLocal, istio.Spec.Version, istio.Spec.Namespace, values, metav1.OwnerReference{ APIVersion: v1alpha1.GroupVersion.String(), @@ -324,6 +323,8 @@ func convertConditionReason(reason v1alpha1.IstioRevisionConditionReason) v1alph return v1alpha1.IstioReasonReadinessCheckFailed case v1alpha1.IstioRevisionReasonReconcileError: return v1alpha1.IstioReasonReconcileError + case v1alpha1.IstioRevisionReasonRemoteIstiodNotReady: + return v1alpha1.IstioReasonRemoteIstiodNotReady default: panic(fmt.Sprintf("can't convert IstioRevisionConditionReason: %s", reason)) } diff --git a/controllers/istio/istio_controller_test.go b/controllers/istio/istio_controller_test.go index f91a9db54..129acf0ea 100644 --- a/controllers/istio/istio_controller_test.go +++ b/controllers/istio/istio_controller_test.go @@ -527,7 +527,6 @@ func TestDetermineStatus(t *testing.T) { initObjs := []client.Object{istio} for _, rev := range tc.revisions { - rev := rev initObjs = append(initObjs, &rev) } @@ -728,7 +727,6 @@ func TestUpdateStatus(t *testing.T) { initObjs := []client.Object{istio} for _, rev := range tc.revisions { - rev := rev initObjs = append(initObjs, &rev) } diff --git a/controllers/istiocni/istiocni_controller.go b/controllers/istiocni/istiocni_controller.go index d8b031b1f..23f558083 100644 --- a/controllers/istiocni/istiocni_controller.go +++ b/controllers/istiocni/istiocni_controller.go @@ -30,6 +30,7 @@ import ( "github.com/istio-ecosystem/sail-operator/pkg/helm" "github.com/istio-ecosystem/sail-operator/pkg/istiovalues" "github.com/istio-ecosystem/sail-operator/pkg/kube" + "github.com/istio-ecosystem/sail-operator/pkg/predicate" "github.com/istio-ecosystem/sail-operator/pkg/reconciler" "github.com/istio-ecosystem/sail-operator/pkg/validation" appsv1 "k8s.io/api/apps/v1" @@ -40,6 +41,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -225,7 +227,11 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&corev1.ConfigMap{}, ownedResourceHandler). Watches(&appsv1.DaemonSet{}, ownedResourceHandler). Watches(&corev1.ResourceQuota{}, ownedResourceHandler). - Watches(&corev1.ServiceAccount{}, ownedResourceHandler). + + // We use predicate.IgnoreUpdate() so that we skip the reconciliation when a pull secret is added to the ServiceAccount. + // This is necessary so that we don't remove the newly-added secret. + // TODO: this is a temporary hack until we implement the correct solution on the Helm-render side + Watches(&corev1.ServiceAccount{}, ownedResourceHandler, builder.WithPredicates(predicate.IgnoreUpdate())). // TODO: only register NetAttachDef if the CRD is installed (may also need to watch for CRD creation) // Owns(&multusv1.NetworkAttachmentDefinition{}). diff --git a/controllers/istiorevision/istiorevision_controller.go b/controllers/istiorevision/istiorevision_controller.go index 13d162684..f845833ef 100644 --- a/controllers/istiorevision/istiorevision_controller.go +++ b/controllers/istiorevision/istiorevision_controller.go @@ -30,7 +30,9 @@ import ( "github.com/istio-ecosystem/sail-operator/pkg/errlist" "github.com/istio-ecosystem/sail-operator/pkg/helm" "github.com/istio-ecosystem/sail-operator/pkg/kube" + predicate2 "github.com/istio-ecosystem/sail-operator/pkg/predicate" "github.com/istio-ecosystem/sail-operator/pkg/reconciler" + "github.com/istio-ecosystem/sail-operator/pkg/revision" "github.com/istio-ecosystem/sail-operator/pkg/validation" admissionv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" @@ -61,8 +63,7 @@ const ( IstioRevLabel = "istio.io/rev" IstioSidecarInjectLabel = "sidecar.istio.io/inject" - istiodChartName = "istiod" - istiodRemoteChartName = "istiod-remote" + istiodChartName = "istiod" ) // Reconciler reconciles an IstioRevision object @@ -128,9 +129,6 @@ func (r *Reconciler) Finalize(ctx context.Context, rev *v1alpha1.IstioRevision) } func (r *Reconciler) validate(ctx context.Context, rev *v1alpha1.IstioRevision) error { - if rev.Spec.Type == "" { - return reconciler.NewValidationError("spec.type not set") - } if rev.Spec.Version == "" { return reconciler.NewValidationError("spec.version not set") } @@ -172,33 +170,22 @@ func (r *Reconciler) installHelmCharts(ctx context.Context, rev *v1alpha1.IstioR _, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(rev), values, rev.Spec.Namespace, getReleaseName(rev), ownerReference) if err != nil { - return fmt.Errorf("failed to install/update Helm chart %q: %w", getChartName(rev), err) + return fmt.Errorf("failed to install/update Helm chart %q: %w", istiodChartName, err) } return nil } func getReleaseName(rev *v1alpha1.IstioRevision) string { - return fmt.Sprintf("%s-%s", rev.Name, getChartName(rev)) + return fmt.Sprintf("%s-%s", rev.Name, istiodChartName) } func (r *Reconciler) getChartDir(rev *v1alpha1.IstioRevision) string { - return path.Join(r.Config.ResourceDirectory, rev.Spec.Version, "charts", getChartName(rev)) -} - -func getChartName(rev *v1alpha1.IstioRevision) string { - switch rev.Spec.Type { - case v1alpha1.IstioRevisionTypeLocal: - return istiodChartName - case v1alpha1.IstioRevisionTypeRemote: - return istiodRemoteChartName - default: - panic(badIstioRevisionType(rev)) - } + return path.Join(r.Config.ResourceDirectory, rev.Spec.Version, "charts", istiodChartName) } func (r *Reconciler) uninstallHelmCharts(ctx context.Context, rev *v1alpha1.IstioRevision) error { if _, err := r.ChartManager.UninstallChart(ctx, getReleaseName(rev), rev.Spec.Namespace); err != nil { - return fmt.Errorf("failed to uninstall Helm chart %q: %w", getChartName(rev), err) + return fmt.Errorf("failed to uninstall Helm chart %q: %w", istiodChartName, err) } return nil } @@ -246,7 +233,11 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&appsv1.Deployment{}, ownedResourceHandler). // we don't ignore the status here because we use it to calculate the IstioRevision status Watches(&corev1.Endpoints{}, ownedResourceHandler). Watches(&corev1.Service{}, ownedResourceHandler, builder.WithPredicates(ignoreStatusChange())). - Watches(&corev1.ServiceAccount{}, ownedResourceHandler). + + // We use predicate.IgnoreUpdate() so that we skip the reconciliation when a pull secret is added to the ServiceAccount. + // This is necessary so that we don't remove the newly-added secret. + // TODO: this is a temporary hack until we implement the correct solution on the Helm-render side + Watches(&corev1.ServiceAccount{}, ownedResourceHandler, builder.WithPredicates(predicate2.IgnoreUpdate())). Watches(&rbacv1.Role{}, ownedResourceHandler). Watches(&rbacv1.RoleBinding{}, ownedResourceHandler). Watches(&policyv1.PodDisruptionBudget{}, ownedResourceHandler, builder.WithPredicates(ignoreStatusChange())). @@ -332,8 +323,7 @@ func (r *Reconciler) determineReadyCondition(ctx context.Context, rev *v1alpha1. Status: metav1.ConditionFalse, } - switch rev.Spec.Type { - case v1alpha1.IstioRevisionTypeLocal: + if !revision.IsUsingRemoteControlPlane(rev) { istiod := appsv1.Deployment{} if err := r.Client.Get(ctx, istiodDeploymentKey(rev), &istiod); err == nil { if istiod.Status.Replicas == 0 { @@ -354,7 +344,7 @@ func (r *Reconciler) determineReadyCondition(ctx context.Context, rev *v1alpha1. c.Message = fmt.Sprintf("failed to get readiness: %v", err) return c, fmt.Errorf("get failed: %w", err) } - case v1alpha1.IstioRevisionTypeRemote: + } else { webhook := admissionv1.MutatingWebhookConfiguration{} webhookKey := injectionWebhookKey(rev) if err := r.Client.Get(ctx, webhookKey, &webhook); err == nil { @@ -378,8 +368,6 @@ func (r *Reconciler) determineReadyCondition(ctx context.Context, rev *v1alpha1. c.Message = fmt.Sprintf("failed to get readiness: %v", err) return c, fmt.Errorf("get failed: %w", err) } - default: - panic(badIstioRevisionType(rev)) } return c, nil } @@ -610,10 +598,6 @@ func clearIgnoredFields(obj client.Object) { } } -func badIstioRevisionType(rev *v1alpha1.IstioRevision) string { - return fmt.Sprintf("unknown IstioRevisionType: %s", rev.Spec.Type) -} - func wrapEventHandler(logger logr.Logger, handler handler.EventHandler) handler.EventHandler { return enqueuelogger.WrapIfNecessary(v1alpha1.IstioRevisionKind, logger, handler) } diff --git a/controllers/istiorevision/istiorevision_controller_test.go b/controllers/istiorevision/istiorevision_controller_test.go index c27b76129..7c2f21b97 100644 --- a/controllers/istiorevision/istiorevision_controller_test.go +++ b/controllers/istiorevision/istiorevision_controller_test.go @@ -60,7 +60,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", Values: &v1alpha1.Values{ @@ -73,25 +72,6 @@ func TestValidate(t *testing.T) { objects: []client.Object{ns}, expectErr: "", }, - { - name: "no type", - rev: &v1alpha1.IstioRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: v1alpha1.IstioRevisionSpec{ - Version: supportedversion.Default, - Namespace: "istio-system", - Values: &v1alpha1.Values{ - Global: &v1alpha1.GlobalConfig{ - IstioNamespace: ptr.Of("istio-system"), - }, - }, - }, - }, - objects: []client.Object{ns}, - expectErr: `spec.type not set`, - }, { name: "no version", rev: &v1alpha1.IstioRevision{ @@ -99,7 +79,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Namespace: "istio-system", }, }, @@ -113,7 +92,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, }, }, @@ -127,7 +105,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", }, @@ -142,7 +119,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", }, @@ -157,7 +133,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", Values: &v1alpha1.Values{ @@ -177,7 +152,6 @@ func TestValidate(t *testing.T) { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", Values: &v1alpha1.Values{ @@ -198,7 +172,6 @@ func TestValidate(t *testing.T) { Name: "my-revision", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: "istio-system", Values: &v1alpha1.Values{ @@ -293,7 +266,6 @@ func TestDetermineReadyCondition(t *testing.T) { testCases := []struct { name string - revType v1alpha1.IstioRevisionType values *v1alpha1.Values clientObjects []client.Object interceptors interceptor.Funcs @@ -418,9 +390,8 @@ func TestDetermineReadyCondition(t *testing.T) { expectErr: true, }, { - name: "Istiod-remote ready", - revType: v1alpha1.IstioRevisionTypeRemote, - values: nil, + name: "Istiod-remote ready", + values: &v1alpha1.Values{Profile: ptr.Of("remote")}, clientObjects: []client.Object{ &admissionv1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ @@ -437,9 +408,8 @@ func TestDetermineReadyCondition(t *testing.T) { }, }, { - name: "Istiod-remote not ready", - revType: v1alpha1.IstioRevisionTypeRemote, - values: nil, + name: "Istiod-remote not ready", + values: &v1alpha1.Values{Profile: ptr.Of("remote")}, clientObjects: []client.Object{ &admissionv1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ @@ -458,9 +428,8 @@ func TestDetermineReadyCondition(t *testing.T) { }, }, { - name: "Istiod-remote no readiness probe status annotation", - revType: v1alpha1.IstioRevisionTypeRemote, - values: nil, + name: "Istiod-remote no readiness probe status annotation", + values: &v1alpha1.Values{Profile: ptr.Of("remote")}, clientObjects: []client.Object{ &admissionv1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ @@ -478,8 +447,7 @@ func TestDetermineReadyCondition(t *testing.T) { }, { name: "Istiod-remote webhook config not found", - revType: v1alpha1.IstioRevisionTypeRemote, - values: nil, + values: &v1alpha1.Values{Profile: ptr.Of("remote")}, clientObjects: []client.Object{}, expected: v1alpha1.IstioRevisionCondition{ Type: v1alpha1.IstioRevisionConditionReady, @@ -490,7 +458,7 @@ func TestDetermineReadyCondition(t *testing.T) { }, { name: "Istiod-remote client error on get", - revType: v1alpha1.IstioRevisionTypeRemote, + values: &v1alpha1.Values{Profile: ptr.Of("remote")}, clientObjects: []client.Object{}, interceptors: interceptor.Funcs{ Get: func(_ context.Context, _ client.WithWatch, _ client.ObjectKey, obj client.Object, _ ...client.GetOption) error { @@ -515,16 +483,12 @@ func TestDetermineReadyCondition(t *testing.T) { r := NewReconciler(cfg, cl, scheme.Scheme, nil) - if tt.revType == "" { - tt.revType = v1alpha1.IstioRevisionTypeLocal - } rev := &v1alpha1.IstioRevision{ ObjectMeta: metav1.ObjectMeta{ Name: "my-istio", }, Spec: v1alpha1.IstioRevisionSpec{ Namespace: "istio-system", - Type: tt.revType, Values: tt.values, }, } diff --git a/controllers/remoteistio/remoteistio_controller.go b/controllers/remoteistio/remoteistio_controller.go deleted file mode 100644 index fe92ebd00..000000000 --- a/controllers/remoteistio/remoteistio_controller.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright Istio Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remoteistio - -import ( - "context" - "errors" - "fmt" - "reflect" - "strings" - "time" - - "github.com/go-logr/logr" - "github.com/istio-ecosystem/sail-operator/api/v1alpha1" - "github.com/istio-ecosystem/sail-operator/pkg/config" - "github.com/istio-ecosystem/sail-operator/pkg/errlist" - "github.com/istio-ecosystem/sail-operator/pkg/kube" - "github.com/istio-ecosystem/sail-operator/pkg/reconciler" - "github.com/istio-ecosystem/sail-operator/pkg/revision" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "istio.io/istio/pkg/ptr" -) - -// Reconciler reconciles a RemoteIstio object -type Reconciler struct { - Config config.ReconcilerConfig - client.Client - Scheme *runtime.Scheme -} - -func NewReconciler(cfg config.ReconcilerConfig, client client.Client, scheme *runtime.Scheme) *Reconciler { - return &Reconciler{ - Config: cfg, - Client: client, - Scheme: scheme, - } -} - -// +kubebuilder:rbac:groups=sailoperator.io,resources=remoteistios,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=sailoperator.io,resources=remoteistios/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=sailoperator.io,resources=remoteistios/finalizers,verbs=update - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile -func (r *Reconciler) Reconcile(ctx context.Context, istio *v1alpha1.RemoteIstio) (ctrl.Result, error) { - log := logf.FromContext(ctx) - - log.Info("Reconciling") - result, reconcileErr := r.doReconcile(ctx, istio) - - log.Info("Reconciliation done. Updating status.") - statusErr := r.updateStatus(ctx, istio, reconcileErr) - - return result, errors.Join(reconcileErr, statusErr) -} - -// doReconcile is the function that actually reconciles the Istio object. Any error reported by this -// function should get reported in the status of the Istio object by the caller. -func (r *Reconciler) doReconcile(ctx context.Context, istio *v1alpha1.RemoteIstio) (result ctrl.Result, err error) { - if err := validate(istio); err != nil { - return ctrl.Result{}, err - } - - if err = r.reconcileActiveRevision(ctx, istio); err != nil { - return ctrl.Result{}, err - } - - return revision.PruneInactive(ctx, r.Client, istio.UID, getActiveRevisionName(istio), getPruningGracePeriod(istio)) -} - -func validate(istio *v1alpha1.RemoteIstio) error { - if istio.Spec.Version == "" { - return reconciler.NewValidationError("spec.version not set") - } - if istio.Spec.Namespace == "" { - return reconciler.NewValidationError("spec.namespace not set") - } - return nil -} - -func (r *Reconciler) reconcileActiveRevision(ctx context.Context, istio *v1alpha1.RemoteIstio) error { - values, err := revision.ComputeValues( - istio.Spec.Values, istio.Spec.Namespace, istio.Spec.Version, - r.Config.Platform, r.Config.DefaultProfile, istio.Spec.Profile, - r.Config.ResourceDirectory, getActiveRevisionName(istio)) - if err != nil { - return err - } - - return revision.CreateOrUpdate(ctx, r.Client, - getActiveRevisionName(istio), - v1alpha1.IstioRevisionTypeRemote, - istio.Spec.Version, istio.Spec.Namespace, values, - metav1.OwnerReference{ - APIVersion: v1alpha1.GroupVersion.String(), - Kind: v1alpha1.RemoteIstioKind, - Name: istio.Name, - UID: istio.UID, - Controller: ptr.Of(true), - BlockOwnerDeletion: ptr.Of(true), - }) -} - -func getPruningGracePeriod(istio *v1alpha1.RemoteIstio) time.Duration { - strategy := istio.Spec.UpdateStrategy - period := int64(v1alpha1.DefaultRevisionDeletionGracePeriodSeconds) - if strategy != nil && strategy.InactiveRevisionDeletionGracePeriodSeconds != nil { - period = *strategy.InactiveRevisionDeletionGracePeriodSeconds - } - if period < v1alpha1.MinRevisionDeletionGracePeriodSeconds { - period = v1alpha1.MinRevisionDeletionGracePeriodSeconds - } - return time.Duration(period) * time.Second -} - -func (r *Reconciler) getActiveRevision(ctx context.Context, istio *v1alpha1.RemoteIstio) (v1alpha1.IstioRevision, error) { - rev := v1alpha1.IstioRevision{} - err := r.Client.Get(ctx, getActiveRevisionKey(istio), &rev) - if err != nil { - return rev, fmt.Errorf("get failed: %w", err) - } - return rev, nil -} - -func getActiveRevisionKey(istio *v1alpha1.RemoteIstio) types.NamespacedName { - return types.NamespacedName{ - Name: getActiveRevisionName(istio), - } -} - -func getActiveRevisionName(istio *v1alpha1.RemoteIstio) string { - var strategy v1alpha1.UpdateStrategyType - if istio.Spec.UpdateStrategy != nil { - strategy = istio.Spec.UpdateStrategy.Type - } - - switch strategy { - default: - fallthrough - case v1alpha1.UpdateStrategyTypeInPlace: - return istio.Name - case v1alpha1.UpdateStrategyTypeRevisionBased: - return istio.Name + "-" + strings.ReplaceAll(istio.Spec.Version, ".", "-") - } -} - -func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - WithOptions(controller.Options{ - LogConstructor: func(req *reconcile.Request) logr.Logger { - log := mgr.GetLogger().WithName("ctrlr").WithName("remoteistio") - if req != nil { - log = log.WithValues("RemoteIstio", req.Name) - } - return log - }, - }). - For(&v1alpha1.RemoteIstio{}). - Owns(&v1alpha1.IstioRevision{}). - Complete(reconciler.NewStandardReconciler[*v1alpha1.RemoteIstio](r.Client, r.Reconcile)) -} - -func (r *Reconciler) determineStatus(ctx context.Context, istio *v1alpha1.RemoteIstio, reconcileErr error) (v1alpha1.RemoteIstioStatus, error) { - var errs errlist.Builder - status := *istio.Status.DeepCopy() - status.ObservedGeneration = istio.Generation - - // set Reconciled and Ready conditions - if reconcileErr != nil { - status.SetCondition(v1alpha1.RemoteIstioCondition{ - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonReconcileError, - Message: reconcileErr.Error(), - }) - status.SetCondition(v1alpha1.RemoteIstioCondition{ - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionUnknown, - Reason: v1alpha1.RemoteIstioReasonReconcileError, - Message: "cannot determine readiness due to reconciliation error", - }) - status.State = v1alpha1.RemoteIstioReasonReconcileError - } else { - status.ActiveRevisionName = getActiveRevisionName(istio) - rev, err := r.getActiveRevision(ctx, istio) - if apierrors.IsNotFound(err) { - revisionNotFound := func(conditionType v1alpha1.RemoteIstioConditionType) v1alpha1.RemoteIstioCondition { - return v1alpha1.RemoteIstioCondition{ - Type: conditionType, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - } - } - - status.SetCondition(revisionNotFound(v1alpha1.RemoteIstioConditionReconciled)) - status.SetCondition(revisionNotFound(v1alpha1.RemoteIstioConditionReady)) - status.State = v1alpha1.RemoteIstioReasonRevisionNotFound - } else if err == nil { - status.SetCondition(convertCondition(rev.Status.GetCondition(v1alpha1.IstioRevisionConditionReconciled))) - status.SetCondition(convertCondition(rev.Status.GetCondition(v1alpha1.IstioRevisionConditionReady))) - status.State = convertConditionReason(rev.Status.State) - } else { - activeRevisionGetFailed := func(conditionType v1alpha1.RemoteIstioConditionType) v1alpha1.RemoteIstioCondition { - return v1alpha1.RemoteIstioCondition{ - Type: conditionType, - Status: metav1.ConditionUnknown, - Reason: v1alpha1.RemoteIstioReasonFailedToGetActiveRevision, - Message: fmt.Sprintf("failed to get active IstioRevision: %s", err), - } - } - status.SetCondition(activeRevisionGetFailed(v1alpha1.RemoteIstioConditionReconciled)) - status.SetCondition(activeRevisionGetFailed(v1alpha1.RemoteIstioConditionReady)) - status.State = v1alpha1.RemoteIstioReasonFailedToGetActiveRevision - errs.Add(fmt.Errorf("failed to get active IstioRevision: %w", err)) - } - } - - // count the ready, in-use, and total revisions - if revs, err := revision.ListOwned(ctx, r.Client, istio.UID); err == nil { - status.Revisions.Total = int32(len(revs)) - status.Revisions.Ready = 0 - status.Revisions.InUse = 0 - for _, rev := range revs { - if rev.Status.GetCondition(v1alpha1.IstioRevisionConditionReady).Status == metav1.ConditionTrue { - status.Revisions.Ready++ - } - if rev.Status.GetCondition(v1alpha1.IstioRevisionConditionInUse).Status == metav1.ConditionTrue { - status.Revisions.InUse++ - } - } - } else { - status.Revisions.Total = -1 - status.Revisions.Ready = -1 - status.Revisions.InUse = -1 - errs.Add(err) - } - return status, errs.Error() -} - -func (r *Reconciler) updateStatus(ctx context.Context, istio *v1alpha1.RemoteIstio, reconcileErr error) error { - var errs errlist.Builder - status, err := r.determineStatus(ctx, istio, reconcileErr) - if err != nil { - errs.Add(fmt.Errorf("failed to determine status: %w", err)) - } - - if !reflect.DeepEqual(istio.Status, status) { - if err := r.Client.Status().Patch(ctx, istio, kube.NewStatusPatch(status)); err != nil { - errs.Add(fmt.Errorf("failed to patch status: %w", err)) - } - } - return errs.Error() -} - -func convertCondition(condition v1alpha1.IstioRevisionCondition) v1alpha1.RemoteIstioCondition { - return v1alpha1.RemoteIstioCondition{ - Type: convertConditionType(condition), - Status: condition.Status, - Reason: convertConditionReason(condition.Reason), - Message: condition.Message, - } -} - -func convertConditionType(condition v1alpha1.IstioRevisionCondition) v1alpha1.RemoteIstioConditionType { - switch condition.Type { - case v1alpha1.IstioRevisionConditionReconciled: - return v1alpha1.RemoteIstioConditionReconciled - case v1alpha1.IstioRevisionConditionReady: - return v1alpha1.RemoteIstioConditionReady - default: - panic(fmt.Sprintf("can't convert IstioRevisionConditionType: %s", condition.Type)) - } -} - -func convertConditionReason(reason v1alpha1.IstioRevisionConditionReason) v1alpha1.RemoteIstioConditionReason { - switch reason { - case "": - return "" - case v1alpha1.IstioRevisionReasonRemoteIstiodNotReady: - return v1alpha1.RemoteIstioReasonIstiodNotReady - case v1alpha1.IstioRevisionReasonHealthy: - return v1alpha1.RemoteIstioReasonHealthy - case v1alpha1.IstioRevisionReasonReadinessCheckFailed: - return v1alpha1.RemoteIstioReasonReadinessCheckFailed - case v1alpha1.IstioRevisionReasonReconcileError: - return v1alpha1.RemoteIstioReasonReconcileError - default: - panic(fmt.Sprintf("can't convert IstioRevisionConditionReason: %s", reason)) - } -} diff --git a/controllers/remoteistio/remoteistio_controller_test.go b/controllers/remoteistio/remoteistio_controller_test.go deleted file mode 100644 index 8b74879f2..000000000 --- a/controllers/remoteistio/remoteistio_controller_test.go +++ /dev/null @@ -1,927 +0,0 @@ -// Copyright Istio Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remoteistio - -import ( - "context" - "fmt" - "runtime/debug" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/istio-ecosystem/sail-operator/api/v1alpha1" - "github.com/istio-ecosystem/sail-operator/pkg/config" - "github.com/istio-ecosystem/sail-operator/pkg/scheme" - "github.com/istio-ecosystem/sail-operator/pkg/test/testtime" - "github.com/istio-ecosystem/sail-operator/pkg/test/util/supportedversion" - . "github.com/onsi/gomega" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/client/interceptor" - - "istio.io/istio/pkg/ptr" -) - -var ( - ctx = context.Background() - istioNamespace = "my-istio-namespace" - istioName = "my-istio" - istioKey = types.NamespacedName{ - Name: istioName, - } - istioUID = types.UID("my-istio-uid") - objectMeta = metav1.ObjectMeta{ - Name: istioKey.Name, - } -) - -func TestReconcile(t *testing.T) { - cfg := newReconcilerTestConfig(t) - - t.Run("returns error when Istio version not set", func(t *testing.T) { - istio := &v1alpha1.RemoteIstio{ - ObjectMeta: objectMeta, - } - - cl := newFakeClientBuilder(). - WithObjects(istio). - Build() - reconciler := NewReconciler(cfg, cl, scheme.Scheme) - - _, err := reconciler.Reconcile(ctx, istio) - if err == nil { - t.Errorf("Expected an error, but got nil") - } - - Must(t, cl.Get(ctx, istioKey, istio)) - - if istio.Status.State != v1alpha1.RemoteIstioReasonReconcileError { - t.Errorf("Expected status.state to be %q, but got %q", v1alpha1.RemoteIstioReasonReconcileError, istio.Status.State) - } - - reconciledCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReconciled) - if reconciledCond.Status != metav1.ConditionFalse { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionFalse, reconciledCond.Status) - } - - readyCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReady) - if readyCond.Status != metav1.ConditionUnknown { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionUnknown, readyCond.Status) - } - }) - - t.Run("returns error when computeIstioRevisionValues fails", func(t *testing.T) { - istio := &v1alpha1.RemoteIstio{ - ObjectMeta: objectMeta, - Spec: v1alpha1.RemoteIstioSpec{ - Version: "my-version", - }, - } - - cl := newFakeClientBuilder(). - WithStatusSubresource(&v1alpha1.RemoteIstio{}). - WithObjects(istio). - Build() - cfg := newReconcilerTestConfig(t) - cfg.DefaultProfile = "invalid-profile" - reconciler := NewReconciler(cfg, cl, scheme.Scheme) - - _, err := reconciler.Reconcile(ctx, istio) - if err == nil { - t.Errorf("Expected an error, but got nil") - } - - Must(t, cl.Get(ctx, istioKey, istio)) - - if istio.Status.State != v1alpha1.RemoteIstioReasonReconcileError { - t.Errorf("Expected status.state to be %q, but got %q", v1alpha1.RemoteIstioReasonReconcileError, istio.Status.State) - } - - reconciledCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReconciled) - if reconciledCond.Status != metav1.ConditionFalse { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionFalse, reconciledCond.Status) - } - - readyCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReady) - if readyCond.Status != metav1.ConditionUnknown { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionUnknown, readyCond.Status) - } - }) - - t.Run("returns error when reconcileActiveRevision fails", func(t *testing.T) { - istio := &v1alpha1.RemoteIstio{ - ObjectMeta: objectMeta, - Spec: v1alpha1.RemoteIstioSpec{ - Version: "my-version", - }, - } - - cl := newFakeClientBuilder(). - WithObjects(istio). - WithInterceptorFuncs(interceptor.Funcs{ - Create: func(_ context.Context, _ client.WithWatch, _ client.Object, _ ...client.CreateOption) error { - return fmt.Errorf("internal error") - }, - }). - Build() - reconciler := NewReconciler(cfg, cl, scheme.Scheme) - - _, err := reconciler.Reconcile(ctx, istio) - if err == nil { - t.Errorf("Expected an error, but got nil") - } - - Must(t, cl.Get(ctx, istioKey, istio)) - - if istio.Status.State != v1alpha1.RemoteIstioReasonReconcileError { - t.Errorf("Expected status.state to be %q, but got %q", v1alpha1.RemoteIstioReasonReconcileError, istio.Status.State) - } - - reconciledCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReconciled) - if reconciledCond.Status != metav1.ConditionFalse { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionFalse, reconciledCond.Status) - } - - readyCond := istio.Status.GetCondition(v1alpha1.RemoteIstioConditionReady) - if readyCond.Status != metav1.ConditionUnknown { - t.Errorf("Expected Reconciled condition status to be %q, but got %q", metav1.ConditionUnknown, readyCond.Status) - } - }) -} - -func TestValidate(t *testing.T) { - testCases := []struct { - name string - istio *v1alpha1.RemoteIstio - expectErr string - }{ - { - name: "success", - istio: &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: supportedversion.Default, - Namespace: "istio-system", - }, - }, - expectErr: "", - }, - { - name: "no version", - istio: &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: v1alpha1.RemoteIstioSpec{ - Namespace: "istio-system", - }, - }, - expectErr: "spec.version not set", - }, - { - name: "no namespace", - istio: &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: supportedversion.Default, - }, - }, - expectErr: "spec.namespace not set", - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - g := NewWithT(t) - - err := validate(tc.istio) - if tc.expectErr == "" { - g.Expect(err).ToNot(HaveOccurred()) - } else { - g.Expect(err).To(HaveOccurred()) - g.Expect(err.Error()).To(ContainSubstring(tc.expectErr)) - } - }) - } -} - -func TestDetermineStatus(t *testing.T) { - cfg := newReconcilerTestConfig(t) - - generation := int64(100) - - ownedByIstio := metav1.OwnerReference{ - APIVersion: v1alpha1.GroupVersion.String(), - Kind: v1alpha1.RemoteIstioKind, - Name: istioName, - UID: istioUID, - Controller: ptr.Of(true), - BlockOwnerDeletion: ptr.Of(true), - } - - ownedByAnotherIstio := metav1.OwnerReference{ - APIVersion: v1alpha1.GroupVersion.String(), - Kind: v1alpha1.RemoteIstioKind, - Name: "some-other-Istio", - UID: "some-other-uid", - Controller: ptr.Of(true), - BlockOwnerDeletion: ptr.Of(true), - } - - revision := func(name string, ownerRef metav1.OwnerReference, reconciled, ready, inUse bool) v1alpha1.IstioRevision { - return v1alpha1.IstioRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - OwnerReferences: []metav1.OwnerReference{ownerRef}, - }, - Spec: v1alpha1.IstioRevisionSpec{Namespace: istioNamespace}, - Status: v1alpha1.IstioRevisionStatus{ - State: v1alpha1.IstioRevisionReasonHealthy, - Conditions: []v1alpha1.IstioRevisionCondition{ - {Type: v1alpha1.IstioRevisionConditionReconciled, Status: toConditionStatus(reconciled)}, - {Type: v1alpha1.IstioRevisionConditionReady, Status: toConditionStatus(ready)}, - {Type: v1alpha1.IstioRevisionConditionInUse, Status: toConditionStatus(inUse)}, - }, - }, - } - } - - testCases := []struct { - name string - reconciliationErr error - istio *v1alpha1.RemoteIstio - revisions []v1alpha1.IstioRevision - interceptorFuncs *interceptor.Funcs - wantErr bool - expectedStatus v1alpha1.RemoteIstioStatus - }{ - { - name: "reconciliation error", - reconciliationErr: fmt.Errorf("reconciliation error"), - wantErr: false, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonReconcileError, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonReconcileError, - Message: "reconciliation error", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionUnknown, - Reason: v1alpha1.RemoteIstioReasonReconcileError, - Message: "cannot determine readiness due to reconciliation error", - }, - }, - }, - }, - { - name: "mirrors status of active revision", - wantErr: false, - revisions: []v1alpha1.IstioRevision{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name, - OwnerReferences: []metav1.OwnerReference{ownedByIstio}, - }, - Spec: v1alpha1.IstioRevisionSpec{ - Namespace: istioNamespace, - }, - Status: v1alpha1.IstioRevisionStatus{ - State: v1alpha1.IstioRevisionReasonHealthy, - Conditions: []v1alpha1.IstioRevisionCondition{ - { - Type: v1alpha1.IstioRevisionConditionReconciled, - Status: metav1.ConditionTrue, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "reconciled message", - }, - { - Type: v1alpha1.IstioRevisionConditionReady, - Status: metav1.ConditionTrue, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "ready message", - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name + "-not-active", - OwnerReferences: []metav1.OwnerReference{ownedByIstio}, - }, - Spec: v1alpha1.IstioRevisionSpec{ - Namespace: istioNamespace, - }, - Status: v1alpha1.IstioRevisionStatus{ - State: v1alpha1.IstioRevisionReasonHealthy, - Conditions: []v1alpha1.IstioRevisionCondition{ - { - Type: v1alpha1.IstioRevisionConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "shouldn't mirror this revision", - }, - { - Type: v1alpha1.IstioRevisionConditionReady, - Status: metav1.ConditionFalse, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "shouldn't mirror this revision", - }, - }, - }, - }, - }, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonHealthy, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "reconciled message", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "ready message", - }, - }, - ActiveRevisionName: istioKey.Name, - Revisions: v1alpha1.RevisionSummary{ - Total: 2, - Ready: 1, - InUse: 0, - }, - }, - }, - { - name: "shows correct revision counts", - wantErr: false, - revisions: []v1alpha1.IstioRevision{ - // owned by the Istio under test; 3 todal, 2 ready, 1 in use - revision(istioKey.Name, ownedByIstio, true, true, true), - revision(istioKey.Name+"-old1", ownedByIstio, true, true, false), - revision(istioKey.Name+"-old2", ownedByIstio, true, false, false), - // not owned by the Istio being tested; shouldn't affect counts - revision("some-other-istio", ownedByAnotherIstio, true, true, true), - }, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonHealthy, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionTrue, - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionTrue, - }, - }, - ActiveRevisionName: istioKey.Name, - Revisions: v1alpha1.RevisionSummary{ - Total: 3, - Ready: 2, - InUse: 1, - }, - }, - }, - { - name: "active revision not found", - wantErr: false, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonRevisionNotFound, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - }, - ActiveRevisionName: istioKey.Name, - }, - }, - { - name: "get active revision error", - interceptorFuncs: &interceptor.Funcs{ - Get: func(_ context.Context, _ client.WithWatch, _ client.ObjectKey, obj client.Object, _ ...client.GetOption) error { - if _, ok := obj.(*v1alpha1.IstioRevision); ok { - return fmt.Errorf("simulated error") - } - return nil - }, - }, - wantErr: true, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonFailedToGetActiveRevision, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionUnknown, - Reason: v1alpha1.RemoteIstioReasonFailedToGetActiveRevision, - Message: "failed to get active IstioRevision: get failed: simulated error", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionUnknown, - Reason: v1alpha1.RemoteIstioReasonFailedToGetActiveRevision, - Message: "failed to get active IstioRevision: get failed: simulated error", - }, - }, - ActiveRevisionName: istioKey.Name, - Revisions: v1alpha1.RevisionSummary{}, - }, - }, - { - name: "list revisions error", - interceptorFuncs: &interceptor.Funcs{ - List: func(_ context.Context, _ client.WithWatch, list client.ObjectList, _ ...client.ListOption) error { - if _, ok := list.(*v1alpha1.IstioRevisionList); ok { - return fmt.Errorf("simulated error") - } - return nil - }, - }, - wantErr: true, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonRevisionNotFound, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - }, - ActiveRevisionName: istioKey.Name, - Revisions: v1alpha1.RevisionSummary{ - Total: -1, - Ready: -1, - InUse: -1, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - var interceptorFuncs interceptor.Funcs - if tc.interceptorFuncs != nil { - interceptorFuncs = *tc.interceptorFuncs - } - - istio := tc.istio - if istio == nil { - istio = &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name, - UID: istioUID, - Generation: 100, - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: "my-version", - Namespace: istioNamespace, - }, - } - } - - initObjs := []client.Object{istio} - for _, rev := range tc.revisions { - rev := rev - initObjs = append(initObjs, &rev) - } - - cl := newFakeClientBuilder(). - WithObjects(initObjs...). - WithInterceptorFuncs(interceptorFuncs). - Build() - reconciler := NewReconciler(cfg, cl, scheme.Scheme) - - status, err := reconciler.determineStatus(ctx, istio, tc.reconciliationErr) - if (err != nil) != tc.wantErr { - t.Errorf("determineStatus() error = %v, wantErr %v", err, tc.wantErr) - } - - if diff := cmp.Diff(tc.expectedStatus, clearTimestamps(status)); diff != "" { - t.Errorf("returned status wasn't as expected; diff (-expected, +actual):\n%v", diff) - } - }) - } -} - -func TestUpdateStatus(t *testing.T) { - cfg := newReconcilerTestConfig(t) - - generation := int64(100) - oneMinuteAgo := testtime.OneMinuteAgo() - - testCases := []struct { - name string - reconciliationErr error - istio *v1alpha1.RemoteIstio - revisions []v1alpha1.IstioRevision - interceptorFuncs *interceptor.Funcs - disallowWrites bool - wantErr bool - expectedStatus v1alpha1.RemoteIstioStatus - - skipInterceptors bool // used internally by test implementation when it wants to get around the interceptor - }{ - { - name: "updates status even when determineStatus returns error", - interceptorFuncs: &interceptor.Funcs{ - List: func(_ context.Context, _ client.WithWatch, list client.ObjectList, _ ...client.ListOption) error { - if _, ok := list.(*v1alpha1.IstioRevisionList); ok { - return fmt.Errorf("simulated error") - } - return nil - }, - }, - wantErr: true, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonRevisionNotFound, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionFalse, - Reason: v1alpha1.RemoteIstioReasonRevisionNotFound, - Message: "active IstioRevision not found", - }, - }, - ActiveRevisionName: istioKey.Name, - Revisions: v1alpha1.RevisionSummary{ - Total: -1, - Ready: -1, - InUse: -1, - }, - }, - }, - { - name: "skips update when status unchanged", - istio: &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name, - UID: istioUID, - Generation: 100, - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: "my-version", - Namespace: istioNamespace, - }, - Status: v1alpha1.RemoteIstioStatus{ - ObservedGeneration: 100, - State: v1alpha1.RemoteIstioReasonHealthy, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "reconciled message", - LastTransitionTime: *oneMinuteAgo, - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "ready message", - LastTransitionTime: *oneMinuteAgo, - }, - }, - ActiveRevisionName: istioKey.Name, - }, - }, - revisions: []v1alpha1.IstioRevision{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name, - }, - Spec: v1alpha1.IstioRevisionSpec{ - Namespace: istioNamespace, - }, - Status: v1alpha1.IstioRevisionStatus{ - State: v1alpha1.IstioRevisionReasonHealthy, - Conditions: []v1alpha1.IstioRevisionCondition{ - { - Type: v1alpha1.IstioRevisionConditionReconciled, - Status: metav1.ConditionTrue, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "reconciled message", - LastTransitionTime: *oneMinuteAgo, - }, - { - Type: v1alpha1.IstioRevisionConditionReady, - Status: metav1.ConditionTrue, - Reason: v1alpha1.IstioRevisionReasonHealthy, - Message: "ready message", - LastTransitionTime: *oneMinuteAgo, - }, - }, - }, - }, - }, - expectedStatus: v1alpha1.RemoteIstioStatus{ - State: v1alpha1.RemoteIstioReasonHealthy, - ObservedGeneration: generation, - Conditions: []v1alpha1.RemoteIstioCondition{ - { - Type: v1alpha1.RemoteIstioConditionReconciled, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "reconciled message", - }, - { - Type: v1alpha1.RemoteIstioConditionReady, - Status: metav1.ConditionTrue, - Reason: v1alpha1.RemoteIstioReasonHealthy, - Message: "ready message", - }, - }, - ActiveRevisionName: istioKey.Name, - }, - disallowWrites: true, - wantErr: false, - }, - { - name: "returns status update error", - interceptorFuncs: &interceptor.Funcs{ - SubResourcePatch: func(_ context.Context, _ client.Client, _ string, _ client.Object, _ client.Patch, _ ...client.SubResourcePatchOption) error { - return fmt.Errorf("patch status error") - }, - }, - wantErr: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - var interceptorFuncs interceptor.Funcs - if tc.disallowWrites { - if tc.interceptorFuncs != nil { - panic("can't use disallowWrites and interceptorFuncs at the same time") - } - interceptorFuncs = noWrites(t) - } else if tc.interceptorFuncs != nil { - interceptorFuncs = *tc.interceptorFuncs - } - - istio := tc.istio - if istio == nil { - istio = &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: istioKey.Name, - UID: istioUID, - Generation: 100, - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: "my-version", - Namespace: istioNamespace, - }, - } - } - - initObjs := []client.Object{istio} - for _, rev := range tc.revisions { - rev := rev - initObjs = append(initObjs, &rev) - } - - cl := newFakeClientBuilder(). - WithObjects(initObjs...). - WithInterceptorFuncs(interceptorFuncs). - Build() - reconciler := NewReconciler(cfg, cl, scheme.Scheme) - - err := reconciler.updateStatus(ctx, istio, tc.reconciliationErr) - if (err != nil) != tc.wantErr { - t.Errorf("updateStatus() error = %v, wantErr %v", err, tc.wantErr) - } - - Must(t, cl.Get(ctx, istioKey, istio)) - if diff := cmp.Diff(tc.expectedStatus, clearTimestamps(istio.Status)); diff != "" { - t.Errorf("returned status wasn't as expected; diff (-expected, +actual):\n%v", diff) - } - }) - } -} - -func clearTimestamps(status v1alpha1.RemoteIstioStatus) v1alpha1.RemoteIstioStatus { - for i := range status.Conditions { - status.Conditions[i].LastTransitionTime = metav1.Time{} - } - return status -} - -func toConditionStatus(b bool) metav1.ConditionStatus { - if b { - return metav1.ConditionTrue - } - return metav1.ConditionFalse -} - -func TestGetActiveRevisionName(t *testing.T) { - tests := []struct { - name string - version string - updateStrategyType *v1alpha1.UpdateStrategyType - expectedRevisionName string - }{ - { - name: "No update strategy specified", - version: "1.0.0", - updateStrategyType: nil, - expectedRevisionName: "test-istio", - }, - { - name: "InPlace", - version: "1.0.0", - updateStrategyType: ptr.Of(v1alpha1.UpdateStrategyTypeInPlace), - expectedRevisionName: "test-istio", - }, - { - name: "RevisionBased v1.0.0", - version: "1.0.0", - updateStrategyType: ptr.Of(v1alpha1.UpdateStrategyTypeRevisionBased), - expectedRevisionName: "test-istio-1-0-0", - }, - { - name: "RevisionBased v2.0.0", - version: "2.0.0", - updateStrategyType: ptr.Of(v1alpha1.UpdateStrategyTypeRevisionBased), - expectedRevisionName: "test-istio-2-0-0", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - istio := &v1alpha1.RemoteIstio{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-istio", - }, - Spec: v1alpha1.RemoteIstioSpec{ - Version: tt.version, - }, - } - if tt.updateStrategyType != nil { - istio.Spec.UpdateStrategy = &v1alpha1.IstioUpdateStrategy{ - Type: *tt.updateStrategyType, - } - } - actual := getActiveRevisionName(istio) - if actual != tt.expectedRevisionName { - t.Errorf("getActiveRevisionName() = %v, want %v", actual, tt.expectedRevisionName) - } - }) - } -} - -func newFakeClientBuilder() *fake.ClientBuilder { - return fake.NewClientBuilder(). - WithScheme(scheme.Scheme). - WithStatusSubresource(&v1alpha1.RemoteIstio{}) -} - -func TestGetPruningGracePeriod(t *testing.T) { - tests := []struct { - name string - updateStrategy *v1alpha1.IstioUpdateStrategy - expected time.Duration - }{ - { - name: "Nil update strategy", - updateStrategy: nil, - expected: v1alpha1.DefaultRevisionDeletionGracePeriodSeconds * time.Second, - }, - { - name: "Nil grace period", - updateStrategy: &v1alpha1.IstioUpdateStrategy{}, - expected: v1alpha1.DefaultRevisionDeletionGracePeriodSeconds * time.Second, - }, - { - name: "Grace period less than minimum", - updateStrategy: &v1alpha1.IstioUpdateStrategy{ - InactiveRevisionDeletionGracePeriodSeconds: ptr.Of(int64(v1alpha1.MinRevisionDeletionGracePeriodSeconds - 10)), - }, - expected: v1alpha1.MinRevisionDeletionGracePeriodSeconds * time.Second, - }, - { - name: "Grace period more than minimum", - updateStrategy: &v1alpha1.IstioUpdateStrategy{ - InactiveRevisionDeletionGracePeriodSeconds: ptr.Of(int64(v1alpha1.MinRevisionDeletionGracePeriodSeconds + 10)), - }, - expected: (v1alpha1.MinRevisionDeletionGracePeriodSeconds + 10) * time.Second, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - istio := &v1alpha1.RemoteIstio{ - Spec: v1alpha1.RemoteIstioSpec{ - UpdateStrategy: tt.updateStrategy, - }, - } - got := getPruningGracePeriod(istio) - if got != tt.expected { - t.Errorf("getPruningGracePeriod() = %v, want %v", got, tt.expected) - } - }) - } -} - -func Must(t *testing.T, err error) { - t.Helper() - if err != nil { - t.Fatal(err) - } -} - -func noWrites(t *testing.T) interceptor.Funcs { - return interceptor.Funcs{ - Create: func(_ context.Context, _ client.WithWatch, _ client.Object, _ ...client.CreateOption) error { - t.Fatal("unexpected call to Create in", string(debug.Stack())) - return nil - }, - Update: func(_ context.Context, _ client.WithWatch, _ client.Object, _ ...client.UpdateOption) error { - t.Fatal("unexpected call to Update in", string(debug.Stack())) - return nil - }, - Delete: func(_ context.Context, _ client.WithWatch, _ client.Object, _ ...client.DeleteOption) error { - t.Fatal("unexpected call to Delete in", string(debug.Stack())) - return nil - }, - Patch: func(_ context.Context, _ client.WithWatch, _ client.Object, _ client.Patch, _ ...client.PatchOption) error { - t.Fatal("unexpected call to Patch in", string(debug.Stack())) - return nil - }, - DeleteAllOf: func(_ context.Context, _ client.WithWatch, _ client.Object, _ ...client.DeleteAllOfOption) error { - t.Fatal("unexpected call to DeleteAllOf in", string(debug.Stack())) - return nil - }, - SubResourceCreate: func(_ context.Context, _ client.Client, _ string, _ client.Object, _ client.Object, _ ...client.SubResourceCreateOption) error { - t.Fatal("unexpected call to SubResourceCreate in", string(debug.Stack())) - return nil - }, - SubResourceUpdate: func(_ context.Context, _ client.Client, _ string, _ client.Object, _ ...client.SubResourceUpdateOption) error { - t.Fatal("unexpected call to SubResourceUpdate in", string(debug.Stack())) - return nil - }, - SubResourcePatch: func(_ context.Context, _ client.Client, _ string, obj client.Object, _ client.Patch, _ ...client.SubResourcePatchOption) error { - t.Fatalf("unexpected call to SubResourcePatch with the object %+v: %v", obj, string(debug.Stack())) - return nil - }, - } -} - -func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig { - return config.ReconcilerConfig{ - ResourceDirectory: t.TempDir(), - Platform: config.PlatformKubernetes, - DefaultProfile: "", - } -} diff --git a/controllers/webhook/webhook_controller.go b/controllers/webhook/webhook_controller.go index fe6ef714b..142a60b44 100644 --- a/controllers/webhook/webhook_controller.go +++ b/controllers/webhook/webhook_controller.go @@ -30,6 +30,7 @@ import ( "github.com/istio-ecosystem/sail-operator/pkg/constants" "github.com/istio-ecosystem/sail-operator/pkg/enqueuelogger" "github.com/istio-ecosystem/sail-operator/pkg/reconciler" + "github.com/istio-ecosystem/sail-operator/pkg/revision" admissionv1 "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" @@ -74,15 +75,21 @@ func NewReconciler(client client.Client, scheme *runtime.Scheme) *Reconciler { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile func (r *Reconciler) Reconcile(ctx context.Context, webhook *admissionv1.MutatingWebhookConfiguration) (ctrl.Result, error) { + log := logf.FromContext(ctx) + isReady, err := r.probe(ctx, webhook) + reason := "" if err != nil { - isReady = false + log.V(3).Error(err, "Probe failed") + reason = err.Error() } if webhook.Annotations == nil { webhook.Annotations = make(map[string]string) } webhook.Annotations[constants.WebhookReadinessProbeStatusAnnotationKey] = strconv.FormatBool(isReady) + webhook.Annotations[constants.WebhookReadinessProbeStatusReasonAnnotationKey] = reason + err = r.Client.Update(ctx, webhook) if err != nil { return ctrl.Result{}, err @@ -91,7 +98,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, webhook *admissionv1.Mutatin } func doProbe(ctx context.Context, webhook *admissionv1.MutatingWebhookConfiguration) (bool, error) { - log := logf.FromContext(ctx).V(3) + log := logf.FromContext(ctx) if len(webhook.Webhooks) == 0 { return false, errors.New("mutatingwebhookconfiguration contains no webhooks") } @@ -129,13 +136,13 @@ func doProbe(ctx context.Context, webhook *admissionv1.MutatingWebhookConfigurat return false, err } - log.Info("Executing readiness probe on remote control plane", "url", req.URL.String()) + log.V(3).Info("Executing readiness probe on remote control plane", "url", req.URL.String()) resp, err := httpClient.Do(req) if err != nil { - log.Info("Probe failed", "error", err) + log.V(3).Info("Probe failed", "error", err) return false, err } - log.Info("Probe response", "response", resp.StatusCode) + log.V(3).Info("Probe response", "response", resp.StatusCode) return resp.StatusCode == http.StatusOK, nil } @@ -178,36 +185,37 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { // we use the Watches function instead of For(), so that we can wrap the handler so that events that cause the object to be enqueued are logged // +lint-watches:ignore: IstioRevision (not found in charts, but this is the main resource watched by this controller) - Watches(&admissionv1.MutatingWebhookConfiguration{}, objectHandler, builder.WithPredicates(ownedByRemoteIstioPredicate(mgr.GetClient()))). + Watches(&admissionv1.MutatingWebhookConfiguration{}, objectHandler, builder.WithPredicates(ownedByRemoteIstioRevisionPredicate(mgr.GetClient()))). Named("mutatingwebhookconfiguration"). Complete(reconciler.NewStandardReconciler[*admissionv1.MutatingWebhookConfiguration](r.Client, r.Reconcile)) } -func ownedByRemoteIstioPredicate(cl client.Client) predicate.Predicate { +func ownedByRemoteIstioRevisionPredicate(cl client.Client) predicate.Predicate { return predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { - return isOwnedByRemoteIstio(cl, e.Object) + return IsOwnedByRevisionWithRemoteControlPlane(cl, e.Object) }, UpdateFunc: func(e event.UpdateEvent) bool { - return isOwnedByRemoteIstio(cl, e.ObjectNew) + return IsOwnedByRevisionWithRemoteControlPlane(cl, e.ObjectNew) }, DeleteFunc: func(e event.DeleteEvent) bool { - return isOwnedByRemoteIstio(cl, e.Object) + return IsOwnedByRevisionWithRemoteControlPlane(cl, e.Object) }, GenericFunc: func(e event.GenericEvent) bool { - return isOwnedByRemoteIstio(cl, e.Object) + return IsOwnedByRevisionWithRemoteControlPlane(cl, e.Object) }, } } -func isOwnedByRemoteIstio(cl client.Client, obj client.Object) bool { +func IsOwnedByRevisionWithRemoteControlPlane(cl client.Client, obj client.Object) bool { for _, ownerRef := range obj.GetOwnerReferences() { if ownerRef.APIVersion == v1alpha1.GroupVersion.String() && ownerRef.Kind == v1alpha1.IstioRevisionKind { rev := &v1alpha1.IstioRevision{} err := cl.Get(context.Background(), client.ObjectKey{Name: ownerRef.Name}, rev) if err != nil { - // TODO log error - } else if rev.Spec.Type == v1alpha1.IstioRevisionTypeRemote { + return false + } + if revision.IsUsingRemoteControlPlane(rev) { return true } } diff --git a/controllers/webhook/webhook_controller_test.go b/controllers/webhook/webhook_controller_test.go index 2e2b98813..054c316cf 100644 --- a/controllers/webhook/webhook_controller_test.go +++ b/controllers/webhook/webhook_controller_test.go @@ -380,7 +380,7 @@ func TestDoProbe(t *testing.T) { } } -func TestIsOwnedByRemoteIstio(t *testing.T) { +func TestIsOwnedByRevisionWithRemoteControlPlane(t *testing.T) { tests := []struct { name string ownerRefs []metav1.OwnerReference @@ -431,7 +431,7 @@ func TestIsOwnedByRemoteIstio(t *testing.T) { expected: false, }, { - name: "IstioRevision type not remote", + name: "IstioRevision not using remote profile", ownerRefs: []metav1.OwnerReference{ { APIVersion: v1alpha1.GroupVersion.String(), @@ -444,15 +444,13 @@ func TestIsOwnedByRemoteIstio(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "revision1", }, - Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, - }, + Spec: v1alpha1.IstioRevisionSpec{}, }, }, expected: false, }, { - name: "IstioRevision type is remote", + name: "IstioRevision uses remote profile", ownerRefs: []metav1.OwnerReference{ { APIVersion: v1alpha1.GroupVersion.String(), @@ -466,7 +464,9 @@ func TestIsOwnedByRemoteIstio(t *testing.T) { Name: "revision1", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeRemote, + Values: &v1alpha1.Values{ + Profile: ptr.Of("remote"), + }, }, }, }, @@ -489,7 +489,7 @@ func TestIsOwnedByRemoteIstio(t *testing.T) { }, } - result := isOwnedByRemoteIstio(cl, obj) + result := IsOwnedByRevisionWithRemoteControlPlane(cl, obj) g.Expect(result).To(Equal(tt.expected)) }) } diff --git a/docs/README.md b/docs/README.md index 828976cf5..136954d3c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,6 @@ - [Istio resource](#istio-resource) - [IstioRevision resource](#istiorevision-resource) - [IstioCNI resource](#istiocni-resource) - - [RemoteIstio resource](#remoteistio-resource) - [API Reference documentation](#api-reference-documentation) - [Getting Started](#getting-started) - [Installation on OpenShift](#installation-on-openshift) @@ -64,7 +63,7 @@ kind: Istio metadata: name: default spec: - version: v1.22.3 + version: v1.23.2 namespace: istio-system updateStrategy: type: InPlace @@ -98,7 +97,7 @@ kind: IstioCNI metadata: name: default spec: - version: v1.22.3 + version: v1.23.2 namespace: istio-cni values: cni: @@ -107,32 +106,6 @@ spec: - kube-system ``` -### RemoteIstio resource -The `RemoteIstio` resource is used to connect the local cluster to an external Istio control plane. -When you create a `RemoteIstio` resource, the operator deploys the `istiod-remote` Helm chart. -Instead of deploying the entire Istio control plane, this chart deploys only the sidecar injector webhook, allowing you to inject the Istio proxy into your workloads and have this proxy managed by the Istio control plane running outside the cluster (typically in another Kubernetes cluster). - -The `RemoteIstio` resource is very similar to the `Istio` resource, with the most notable difference being the `istiodRemote` field in the `values` section, which allows you to configure the address of the remote Istio control plane: - -```yaml -apiVersion: sailoperator.io/v1alpha1 -kind: RemoteIstio -metadata: - name: default -spec: - version: v1.22.3 - namespace: istio-system - updateStrategy: - type: InPlace - values: - istiodRemote: - injectionPath: /inject/cluster/cluster2/net/network1 - global: - remotePilotAddress: 1.2.3.4 -``` - -For more information on how to use the `RemoteIstio` resource, refer to the [multi-cluster](#multi-cluster) section. - ## API Reference documentation The Sail Operator API reference documentation can be found [here](https://github.com/istio-ecosystem/sail-operator/tree/main/docs/api-reference/sailoperator.io.md). @@ -231,7 +204,7 @@ spec: values: pilot: traceSampling: 0.1 - version: v1.23.0 + version: v1.23.2 ``` Note that the only field that was added is the `spec.version` field. There are a few situations however where the APIs are different and require different approaches to achieve the same outcome. @@ -244,10 +217,6 @@ Sail Operator's Istio resource does not have a `spec.components` field. Instead, The CNI plugin's lifecycle is managed separately from the control plane. You will have to create a [IstioCNI resource](#istiocni-resource) to use CNI. -### istiod-remote - -The functionality of the istiod-remote chart is exposed through the [RemoteIstio resource](#remoteistio-resource). - ## Gateways [Gateways in Istio](https://istio.io/latest/docs/concepts/traffic-management/#gateways) are used to manage inbound and outbound traffic for the mesh. The Sail Operator does not deploy or manage Gateways. You can deploy a gateway either through [gateway-api](https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/) or through [gateway injection](https://istio.io/latest/docs/setup/additional-setup/gateway/#deploying-a-gateway). As you are following the gateway installation instructions, skip the step to install Istio since this is handled by the Sail Operator. @@ -288,7 +257,7 @@ Steps: namespace: istio-system updateStrategy: type: InPlace - version: v1.21.0 + version: v1.22.5 EOF ``` @@ -296,9 +265,10 @@ Steps: ```console $ kubectl get istio -n istio-system - NAME READY STATUS IN USE VERSION AGE - default True Healthy True v1.21.0 2m + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 0 default Healthy v1.22.5 23s ``` + Note: `IN USE` field shows as 0, as `Istio` is yet installed. 4. Create namespace `bookinfo` and deploy bookinfo application. @@ -309,27 +279,36 @@ Steps: ``` Note: if the `Istio` resource name is other than `default`, you need to set the `istio.io/rev` label to the name of the `Istio` resource instead of adding the `istio-injection=enabled` label. -5. Perform the update of the control plane by changing the version in the Istio resource. +5. Review the `Istio` resource after application deployment. + + ```console + $ kubectl get istio -n istio-system + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 1 default Healthy v1.22.5 115s + ``` + Note: `IN USE` field shows as 1, after application being deployed. + +6. Perform the update of the control plane by changing the version in the Istio resource. ```bash - kubectl patch istio default -n istio-system --type='merge' -p '{"spec":{"version":"v1.21.2"}}' + kubectl patch istio default -n istio-system --type='merge' -p '{"spec":{"version":"v1.23.2"}}' ``` -6. Confirm the `Istio` resource version was updated. +7. Confirm the `Istio` resource version was updated. ```console $ kubectl get istio -n istio-system - NAME REVISIONS READY IN USE ACTIVE REVISION VERSION AGE - default 1 1 1 Healthy v1.21.2 12m + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 1 default Healthy v1.23.2 4m50s ``` -7. Delete `bookinfo` pods to trigger sidecar injection with the new version. +8. Delete `bookinfo` pods to trigger sidecar injection with the new version. ```bash kubectl rollout restart deployment -n bookinfo ``` -8. Confirm that the new version is used in the sidecar. +9. Confirm that the new version is used in the sidecar. ```bash istioctl proxy-status @@ -366,7 +345,7 @@ Steps: updateStrategy: type: RevisionBased inactiveRevisionDeletionGracePeriodSeconds: 30 - version: v1.21.0 + version: v1.22.5 EOF ``` @@ -374,16 +353,17 @@ Steps: ```console $ kubectl get istio -n istio-system - NAME READY STATUS IN USE VERSION AGE - default True Healthy True v1.21.0 2m + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 0 default-v1-22-5 Healthy v1.22.5 52s ``` + Note: `IN USE` field shows as 0, as `Istio` is yet installed. 4. Get the `IstioRevision` name. ```console $ kubectl get istiorevision -n istio-system - NAME READY STATUS IN USE VERSION AGE - default-v1-21-0 True Healthy False v1.21.0 114s + NAME TYPE READY STATUS IN USE VERSION AGE + default-v1-22-5 Local True Healthy False v1.22.5 3m4s ``` Note: `IstioRevision` name is in the format `-`. @@ -391,7 +371,7 @@ Steps: ```bash kubectl create namespace bookinfo - kubectl label namespace bookinfo istio.io/rev=default-v1-21-0 + kubectl label namespace bookinfo istio.io/rev=default-v1-22-5 ``` 6. Deploy bookinfo application. @@ -400,78 +380,91 @@ Steps: kubectl apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.22/samples/bookinfo/platform/kube/bookinfo.yaml ``` -7. Confirm that the proxy version matches the control plane version. +7. Review the `Istio` resource after application deployment. + + ```console + $ kubectl get istio -n istio-system + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 1 default-v1-22-5 Healthy v1.22.5 5m13s + ``` + Note: `IN USE` field shows as 1, after application being deployed. + +8. Confirm that the proxy version matches the control plane version. ```bash istioctl proxy-status ``` The column `VERSION` should match the control plane version. -8. Update the control plane to a new version. +9. Update the control plane to a new version. ```bash - kubectl patch istio default -n istio-system --type='merge' -p '{"spec":{"version":"v1.21.2"}}' + kubectl patch istio default -n istio-system --type='merge' -p '{"spec":{"version":"v1.23.2"}}' ``` -9. Verify the `Istio` and `IstioRevision` resources. There will be a new revision created with the new version. +10. Verify the `Istio` and `IstioRevision` resources. There will be a new revision created with the new version. ```console $ kubectl get istio -n istio-system - NAME REVISIONS READY IN USE ACTIVE REVISION VERSION AGE - default 2 2 1 Healthy v1.21.2 23m + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 2 2 1 default-v1-23-2 Healthy v1.23.2 9m23s $ kubectl get istiorevision -n istio-system - NAME READY STATUS IN USE VERSION AGE - default-v1-21-0 True Healthy True v1.21.0 27m - default-v1-21-2 True Healthy False v1.21.2 4m45s + NAME TYPE READY STATUS IN USE VERSION AGE + default-v1-22-5 Local True Healthy True v1.22.5 10m + default-v1-23-2 Local True Healthy False v1.23.2 66s ``` -10. Confirm there are two control plane pods running, one for each revision. +11. Confirm there are two control plane pods running, one for each revision. ```console $ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE - istiod-default-v1-21-0-69d6df7f9c-grm24 1/1 Running 0 28m - istiod-default-v1-21-2-7c4f4674c5-4g7n7 1/1 Running 0 6m9s + istiod-default-v1-22-5-c98fd9675-r7bfw 1/1 Running 0 10m + istiod-default-v1-23-2-7495cdc7bf-v8t4g 1/1 Running 0 113s ``` -11. Confirm the proxy sidecar version remains the same: +12. Confirm the proxy sidecar version remains the same: ```bash istioctl proxy-status ``` The column `VERSION` should still match the old control plane version. -12. Change the label of the `bookinfo` namespace to use the new revision. +13. Change the label of the `bookinfo` namespace to use the new revision. ```bash - kubectl label namespace bookinfo istio.io/rev=default-v1-21-2 --overwrite + kubectl label namespace bookinfo istio.io/rev=default-v1-23-2 --overwrite ``` The existing workload sidecars will continue to run and will remain connected to the old control plane instance. They will not be replaced with a new version until the pods are deleted and recreated. -13. Delete all the pods in the `bookinfo` namespace. +14. Delete all the pods in the `bookinfo` namespace. ```bash kubectl rollout restart deployment -n bookinfo ``` -14. Confirm the new version is used in the sidecars. +15. Confirm the new version is used in the sidecars. ```bash istioctl proxy-status ``` The column `VERSION` should match the updated control plane version. -15. Confirm the old control plane and revision deletion. +16. Confirm the old control plane and revision deletion. ```console $ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE - istiod-default-v1-21-2-7c4f4674c5-4g7n7 1/1 Running 0 94m + istiod-default-v1-23-2-7495cdc7bf-v8t4g 1/1 Running 0 4m40s + + $ kubectl get istio -n istio-system + NAME REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE + default 1 1 1 default-v1-23-2 Healthy v1.23.2 5m $ kubectl get istiorevision -n istio-system - NAME READY STATUS IN USE VERSION AGE - default-v1-21-2 True Healthy True v1.21.2 94m + NAME TYPE READY STATUS IN USE VERSION AGE + default-v1-23-2 Local True Healthy True v1.23.2 5m31s ``` The old `IstioRevision` resource and the old control plane will be deleted when the grace period specified in the `Istio` resource field `spec.updateStrategy.inactiveRevisionDeletionGracePeriodSeconds` expires. @@ -853,17 +846,18 @@ In this setup there is a Primary cluster (`cluster1`) and a Remote cluster (`clu kubectl --context "${CTX_CLUSTER1}" apply -n istio-system -f https://raw.githubusercontent.com/istio-ecosystem/sail-operator/main/docs/multicluster/expose-services.yaml ``` -5. Create `RemoteIstio` resource on `cluster2`. +5. Create an `Istio` on `cluster2` with the `remote` profile. ```sh kubectl apply --context "${CTX_CLUSTER2}" -f - < ingress-gateway.yaml + $ oc apply -f ingress-gateway.yaml ``` 2. Configure the `bookinfo` application with the new gateway: diff --git a/enhancements/SEP2-revision-tags.md b/enhancements/SEP2-revision-tags.md new file mode 100644 index 000000000..3ef946596 --- /dev/null +++ b/enhancements/SEP2-revision-tags.md @@ -0,0 +1,136 @@ +|Status | Authors | Created | +|---------------------------------------------------|--------------|------------| +|Implementation | @dgn | 2024-07-17 | + +# Revision Tag Support + +## Overview +Upstream Istio supports the use of [stable revision tags](https://istio.io/latest/blog/2021/revision-tags/) for multi-revision deployments and canary upgrades of Istio control planes. These tags serve as aliases for revisions and allow users to use stable revision names (e.g. `prod` or `default`), so they don't have to change their namespace and pod labels (in this case `istio.io/rev=prod` or `istio-injection=enabled`) when switching to a new version. Instead, by tagging a new revision with the correct tag and restarting their workloads, they can perform an Istio update without having to change their labels. This is especially useful in situations where the team managing the Istio control plane is separate from the teams managing the workloads. + +Revision tags can have any name, there is only one special case: revisions tagged `default` are treated as if they had an empty revision name, thereby allowing the use of the standard namespace injection label `istio-injection=enabled`. + +Each revision tag only ever points to exactly one Istio revision. Upstream, revision tags are created manually using `istioctl` and- as they only affect injection- are represented in the cluster by a MutatingWebhookConfiguration. + +Here's an example how to create a `default` revision tag that points to the `1-21-1` revision using `istioctl`: + +```bash +istioctl tag set default --revision 1-21-1 +``` + +## Goals +* Provide revision tag support in Sail Operator APIs so users don't have to use istioctl for basic revision tag operations + +## Non-goals +* Compatibility with manual revision tag creation using istioctl. There might be a way to disable the operator functionality to avoid conflicts when creating revision tags manually, but that's it - you either do it yourself or let the operator do it + +## Design + +### User Stories +1. As a user of Sail Operator's RevisionBased update strategy, I want to be able to use the `istio-injection=enabled` label on my namespaces. +1. As a platform engineer, I want my application teams to be able to use a fixed label for proxy injection without having to know which version of Istio is running in the cluster, so that I can perform upgrades in the background without the application teams having to make changes to use the new version. + +### API Changes +We will add a new CRD called `IstioRevisionTag` that consistly most of a `spec.targetRef` field and a `status` subresource. + +#### IstioRevisionTag resource +Here's an example YAML for the new resource: +```yaml +apiGroup: sailoperator.io/v1alpha1 +kind: IstioRevisionTag +metadata: + name: default +spec: + targetRef: + kind: Istio # can also be IstioRevision + name: default +status: + observedGeneration: 1 + conditions: [] + state: Healthy + istiodNamespace: istio-system + istioRevision: default-v1.24.0 +``` + +In the `spec.targetRef` field, users can specify the `IstioRevision` or `Istio` resource that the `IstioRevisionTag` references. In case of referencing a `IstioRevision` resource, the created tag will point to the exact Istio control plane revision that is represented by the `IstioRevision` resource and any update of the tag will have to be made manually by changing the `spec.targetRef` to point to another `IstioRevision`. As long as a `IstioRevisionTag` exists that references a `IstioRevision`, that `IstioRevision` will be considered "in-use" by the Sail Operator, preventing its automatic deletion during a control plane update (see details below under [InUse detection](#inuse-detection)) + +If the `spec.targetRef` is used to reference an `Istio` resource, the Sail Operator will automatically update the revision tag when a new `IstioRevision` is created as part of a version update of the `Istio` resource. In this case, the `IstioRevisionTag` resource behaves like a floating tag, always referencing the active `IstioRevision` of an `Istio` resource. When it comes to InUse detection, the existence of a floating tag will also cause the active `IstioRevision` of the `Istio` resource to be considered InUse. However, it will not prevent automatic deletion, because the reference is updated immediately when the active revision changes during an update. + +#### IstioRevisionTag Status + +The `status.state` field gives a quick hint as to whether a tag has been reconciled and is InUse ("Healthy") or if there are any problems with it. + +The `status.istiodNamespace` and `status.istioRevision` fields are used by the Sail Operator controllers to store information about the Istio control plane that is referenced by this `IstioRevisionTag`. This is especially useful when it is referencing an `Istio` resource, to see which underlying `IstioRevision` is considered referenced by the operator. + +Possible conditions for `status.conditions` are: + +##### Reconciled +`true` when the tag's helm chart has been installed successfully. Possible error reasons are: +__RefNotFound__: the resource referenced by the `spec.targetRef` field was not found +__NameAlreadyExists__: there already is an `IstioRevision` with this name +__ReconcileError__: there was an error installing the chart + +##### InUse +`true` when the `IstioRevisionTag` is referenced by a namespace or pod. Possible reasons when `false` are: +__NotReferencedByAnything__: no namespace or pod is referencing the tag +__UsageCheckFailed__: there was a problem during InUse detection + +#### InUse detection + +An `IstioRevisionTag` is considered InUse when + +* there's a pod or namespace that explicitly references the `IstioRevisionTag` in an `istio.io/rev` label +* the name of the `IstioRevisionTag` name is 'default' and there's a pod or namespace with the `istio-injection: enabled` label + +Note that a pod's `istio.io/rev` annotation will not be considered as that will always have the name of the referenced `IstioRevision` rather than the name of the `IstioRevisionTag`! The labels however are added by users and reflect usage intent, ie the user will use the name of the `IstioRevisionTag`. + +Even if the referenced `IstioRevision` of an `IstioRevisionTag` is considered InUse, that does not suffice to make the `IstioRevisionTag` considered InUse by the operator! It is considered an unused alias for an InUse `IstioRevision`. + +Additionally, the introduction of `IstioRevisionTag` also adds another condition to the InUse detection of `IstioRevision`: being referenced by an `IstioRevisionTag` will now always lead to an `IstioRevision` being considered InUse! For this, it does not matter if the `IstioRevisionTag` is itself considered InUse. + +For completeness' sake, here's an overview of the conditions for an `IstioRevision` to be considered InUse (new condition in bold): + +* there's a pod that explicitly references the `IstioRevision` in an `istio.io/rev` annotation or label +* there's a namespace that explicitly references the `IstioRevision` in an `istio.io/rev` label +* the name of the `IstioRevision` is 'default' and there's a pod or namespace with the `istio-injection: enabled` label +* __there's an `IstioRevisionTag` referencing this `IstioRevision`__ + +#### Changes to existing APIs +We will need to remove the `values.revisionTags` field from our API, which is how the upstream charts expose this feature. + +### Architecture +We will need to update the mechanism to detect revisions that are being used. Today, we only look at the `istio.io/rev` annotation's value to check which revisions are in use. But when revision tags are used, those values will point to the referenced revision instead of the tags, so we have to improve our detection mechanism. The most correct way is probably to look at the revision label on the pods and namespace that is set to configure injection. + +Revision tags and revision names can be used interchangably, so they must never overlap. Therefore, we'll need a `status` on the `IstioRevisionTag` resource that can show the user an error if the name they chose is already taken by a `IstioRevision`. Another case that needs to be covered is when an `IstioRevision` is being reconciled and it would be assigned the same name as an existing tag. In this case, reconciliation of the `IstioRevision` should fail, with an error message that tells the users why this happened, ie "the name is already used by an `IstioRevisionTag`". + +## Alternatives Considered + +### Reuse `IstioRevision`'s type field for revision tags +We could add a `type` of `Tag` to the `IstioRevision` CRD and use that to manage tags. It would have the benefit that the user could list all revisions and tags using `kubectl get istiorevisions` and name-uniqueness would be handled by Kubernetes. The disadvantage though is that revision tags share no other fields with `IstioRevision` and it would be quite confusing for users that 99% of the CRD's fields are not to be used in this case, whereas there would be one new field that is only to be used for `IstioRevisions` with type=Tag. + +Note that the `type` field has since been removed with the removal of `RemoteIstio`. + +### managing tags in Istio resource +In a previous iteration of this SEP, the tags that point to an Istio control plane would have been managed in the `Istio` revision itself, in a `spec.updateStrategy.revisionTags` field. That would have meant that they are always referencing a `Istio` resource while at the same time being copied to every underlying `IstioRevision` resource. + +### values.revisionTags +Istio has a `values.revisionTags` field that we even currently expose in our APIs. The problem is that we copy all values from the `Istio` resource to every `IstioRevision` and that means we would be facing duplicate revision tags when we create additional revisions in the Sail Operator - so, some logic would be required to work around this problem. As it is a similar amount of effort, I prefer the explicit version of adding the field to the `Istio` CRD. + +### Automatic creation of default revision tag +Previously, we had this paragraph in the Architecture section: +> When the very first `IstioRevision` is created in a cluster from a `RevisionBased` Istio resource, the Sail Operator will create a `IstioRevisionTag` with the name `default`, referencing that `IstioRevision`. This way, the standard namespace injection label `istio-injection=enabled` will work out of the box for RevisionBased deployments (see second paragraph of the [Overview](#overview)). + +We have since dropped this from the design as we faced some problems with this approach. Most importantly, it is very hard to detect whether the user is not creating a default IstioRevisionTag or we have simply not seen its creation event yet. We have discussed multiple possible solutions to this, among them usage of a 'virtual' revision tag that is not created on the API server but only exists in-memory, leading to the creation of the respective Kubernetes resources only. This would avoid a race between the operator and the user trying to create tags with the same name simultaneously. + +Due to the complexity of the task we have moved it into a separate ticket: [#439 Create default revision tag automatically](https://github.com/istio-ecosystem/sail-operator/issues/439). + +## Implementation Plan +v1alpha1 +- [ ] Initial implementation & tests (https://github.com/istio-ecosystem/sail-operator/pull/413) +- [ ] Documentation + +v1beta1 +- [ ] [#439 Create default revision tag automatically](https://github.com/istio-ecosystem/sail-operator/issues/439) +- [ ] [#471 Support revision tags in multicluster topologies](https://github.com/istio-ecosystem/sail-operator/issues/471) + +## Test Plan +Functionality will be tested in integration tests. diff --git a/go.mod b/go.mod index 78bb6deca..2be418133 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/istio-ecosystem/sail-operator -go 1.22.0 +go 1.23 + +toolchain go1.23.2 // Client-go does not handle different versions of mergo due to some breaking changes - use the matching version // This replacement is aligned with istio/istio's go.mod @@ -13,24 +15,24 @@ require ( github.com/google/go-cmp v0.6.0 github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 github.com/magiconair/properties v1.8.7 - github.com/onsi/ginkgo/v2 v2.20.1 - github.com/onsi/gomega v1.34.2 - github.com/prometheus/common v0.60.0 + github.com/onsi/ginkgo/v2 v2.20.2 + github.com/onsi/gomega v1.35.1 + github.com/prometheus/common v0.60.1 github.com/stretchr/testify v1.9.0 - golang.org/x/mod v0.20.0 - golang.org/x/text v0.18.0 - golang.org/x/tools v0.24.0 + golang.org/x/mod v0.21.0 + golang.org/x/text v0.20.0 + golang.org/x/tools v0.26.0 gomodules.xyz/jsonpatch/v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.16.1 - istio.io/client-go v1.24.0-alpha.0.0.20241018201953-b3ca3b2a6ef6 - istio.io/istio v0.0.0-20241022213331-bb972b546125 - k8s.io/api v0.31.1 - k8s.io/apiextensions-apiserver v0.31.1 - k8s.io/apimachinery v0.31.1 - k8s.io/cli-runtime v0.31.1 - k8s.io/client-go v0.31.1 - sigs.k8s.io/controller-runtime v0.19.0 + helm.sh/helm/v3 v3.16.3 + istio.io/client-go v1.24.0-alpha.0.0.20241123091016-df47c87e86db + istio.io/istio v0.0.0-20241124151317-803629b94e93 + k8s.io/api v0.31.2 + k8s.io/apiextensions-apiserver v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/cli-runtime v0.31.2 + k8s.io/client-go v0.31.2 + sigs.k8s.io/controller-runtime v0.19.1 ) require ( @@ -44,20 +46,21 @@ require ( github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/containerd v1.7.12 // indirect + github.com/containerd/containerd v1.7.23 // indirect + github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/cyphar/filepath-securejoin v0.3.1 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cyphar/filepath-securejoin v0.3.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/distribution/reference v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v27.3.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v26.0.2+incompatible // indirect + github.com/docker/docker v26.1.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect @@ -65,9 +68,9 @@ require ( github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect @@ -101,7 +104,7 @@ require ( github.com/jmoiron/sqlx v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect @@ -126,7 +129,7 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.4 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.6 // indirect @@ -142,37 +145,37 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.30.0 // indirect - go.opentelemetry.io/otel/metric v1.30.0 // indirect - go.opentelemetry.io/otel/trace v1.30.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.starlark.net v0.0.0-20231121155337-90ade8b19d09 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/time v0.6.0 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/time v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect - google.golang.org/grpc v1.67.1 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect + google.golang.org/grpc v1.68.0 // indirect + google.golang.org/protobuf v1.35.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gotest.tools/v3 v3.5.1 // indirect - istio.io/api v1.24.0-alpha.0.0.20241018201654-7c8ec5b5ab72 // indirect - k8s.io/apiserver v0.31.1 // indirect - k8s.io/component-base v0.31.1 // indirect + istio.io/api v1.24.0-alpha.0.0.20241123090716-918717d1a2a5 // indirect + k8s.io/apiserver v0.31.2 // indirect + k8s.io/component-base v0.31.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 // indirect - k8s.io/kubectl v0.31.1 // indirect - k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 // indirect + k8s.io/kubectl v0.31.2 // indirect + k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/controller-tools v0.15.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/go.sum b/go.sum index 98405b31d..a7be93d39 100644 --- a/go.sum +++ b/go.sum @@ -24,10 +24,10 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= -github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= +github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -56,31 +56,35 @@ github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNS github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= -github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= +github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ= +github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= +github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE= -github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc= +github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8= +github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ= github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE= -github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -101,16 +105,16 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= @@ -215,8 +219,8 @@ github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:V github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -263,6 +267,8 @@ github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8 github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -283,10 +289,10 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= -github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= +github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -306,16 +312,16 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -379,14 +385,14 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.starlark.net v0.0.0-20231121155337-90ade8b19d09 h1:hzy3LFnSN8kuQK8h9tHl4ndF6UruMj47OqwqsS+/Ai4= go.starlark.net v0.0.0-20231121155337-90ade8b19d09/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -401,31 +407,31 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -436,22 +442,22 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -460,14 +466,14 @@ golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUO golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA= -google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU= +google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -487,40 +493,40 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.16.1 h1:cER6tI/8PgUAsaJaQCVBUg3VI9KN4oVaZJgY60RIc0c= -helm.sh/helm/v3 v3.16.1/go.mod h1:r+xBHHP20qJeEqtvBXMf7W35QDJnzY/eiEBzt+TfHps= -istio.io/api v1.24.0-alpha.0.0.20241018201654-7c8ec5b5ab72 h1:AVg/4p5sVhZT6JwBczgvAy9idbVYiCqZFE/QVXNKy/k= -istio.io/api v1.24.0-alpha.0.0.20241018201654-7c8ec5b5ab72/go.mod h1:MQnRok7RZ20/PE56v0LxmoWH0xVxnCQPNuf9O7PAN1I= -istio.io/client-go v1.24.0-alpha.0.0.20241018201953-b3ca3b2a6ef6 h1:qVjgBbqg19vZCpeTMQR0QM8SRfLZTtaSXgWbnWRb0fo= -istio.io/client-go v1.24.0-alpha.0.0.20241018201953-b3ca3b2a6ef6/go.mod h1:usBQZ/vvpGAUA6yGiz6x9ufG50gRC9v0332MesA/lNw= -istio.io/istio v0.0.0-20241022213331-bb972b546125 h1:mliFVPGvuQ9XCZZIG9fSQsI1AVJqz6MUIWQVAlM3MJI= -istio.io/istio v0.0.0-20241022213331-bb972b546125/go.mod h1:27Ub5DbzERxmDSo6hWl+/eaSKOmO3UctQ7c0TPtKUFU= -k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= -k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= -k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= -k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= -k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= -k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c= -k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM= -k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= -k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= -k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= -k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= -k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= -k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= +helm.sh/helm/v3 v3.16.3 h1:kb8bSxMeRJ+knsK/ovvlaVPfdis0X3/ZhYCSFRP+YmY= +helm.sh/helm/v3 v3.16.3/go.mod h1:zeVWGDR4JJgiRbT3AnNsjYaX8OTJlIE9zC+Q7F7iUSU= +istio.io/api v1.24.0-alpha.0.0.20241123090716-918717d1a2a5 h1:YkSovYqcLmX7W1grfnyRfqsRuxenxi1UOFOksQZcq+M= +istio.io/api v1.24.0-alpha.0.0.20241123090716-918717d1a2a5/go.mod h1:MQnRok7RZ20/PE56v0LxmoWH0xVxnCQPNuf9O7PAN1I= +istio.io/client-go v1.24.0-alpha.0.0.20241123091016-df47c87e86db h1:aVs0RM/sBTjEF6aOuiB6Vdu8oBZWf8dX60FyOX2a0ug= +istio.io/client-go v1.24.0-alpha.0.0.20241123091016-df47c87e86db/go.mod h1:Sjf49Th3Q1mo9jtKinGWR05KZMxv1iS20z/ow4DST88= +istio.io/istio v0.0.0-20241124151317-803629b94e93 h1:pCEiKlpgoR8FXUutK69iDPjHmUYBbSTaPMrZtv8QAW0= +istio.io/istio v0.0.0-20241124151317-803629b94e93/go.mod h1:lJKVrMqVspY39QrL9cxHe9qQRVJ+2lN1wlx9AqRJBG4= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= +k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= +k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= +k8s.io/cli-runtime v0.31.2 h1:7FQt4C4Xnqx8V1GJqymInK0FFsoC+fAZtbLqgXYVOLQ= +k8s.io/cli-runtime v0.31.2/go.mod h1:XROyicf+G7rQ6FQJMbeDV9jqxzkWXTYD6Uxd15noe0Q= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= +k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/7iB8a2eSxCyxdVjJp+lLY= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24= -k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM= -k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI= -k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kubectl v0.31.2 h1:gTxbvRkMBwvTSAlobiTVqsH6S8Aa1aGyBcu5xYLsn8M= +k8s.io/kubectl v0.31.2/go.mod h1:EyASYVU6PY+032RrTh5ahtSOMgoDRIux9V1JLKtG5xM= +k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= +k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-tools v0.15.0 h1:4dxdABXGDhIa68Fiwaif0vcu32xfwmgQ+w8p+5CxoAI= sigs.k8s.io/controller-tools v0.15.0/go.mod h1:8zUSS2T8Hx0APCNRhJWbS3CAQEbIxLa07khzh7pZmXM= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/hack/download-charts.sh b/hack/download-charts.sh index 799cc719c..ad01c97bf 100755 --- a/hack/download-charts.sh +++ b/hack/download-charts.sh @@ -96,9 +96,6 @@ function patchIstioCharts() { } function convertIstioProfiles() { - # delete the remote profile, because it isn't needed (we have the RemoteIstio resource instead) - [ -f "${PROFILES_DIR}"/remote.yaml ] && rm "${PROFILES_DIR}"/remote.yaml - # delete the minimal profile, because it ends up being empty after the conversion [ -f "${PROFILES_DIR}"/minimal.yaml ] && rm "${PROFILES_DIR}"/minimal.yaml diff --git a/hack/update-istio.sh b/hack/update-istio.sh index b85508e7e..43d7efb43 100755 --- a/hack/update-istio.sh +++ b/hack/update-istio.sh @@ -26,6 +26,12 @@ VERSIONS_YAML_FILE=${VERSIONS_YAML_FILE:-"versions.yaml"} # The new entry will be placed immediately before the old one function add_stable_version() { echo "Adding new stable version: ${1}" + # we want to add the istiod-remote chart only for 1.23 + istiod_remote_line="" + if [[ ${1} == 1.23.* ]] + then + istiod_remote_line="\"https://istio-release.storage.googleapis.com/charts/istiod-remote-${1}.tgz\"," + fi template=$(cat <<-END { "name": "v${1}", @@ -35,7 +41,7 @@ function add_stable_version() { "charts": [ "https://istio-release.storage.googleapis.com/charts/base-${1}.tgz", "https://istio-release.storage.googleapis.com/charts/istiod-${1}.tgz", - "https://istio-release.storage.googleapis.com/charts/istiod-remote-${1}.tgz", + ${istiod_remote_line} "https://istio-release.storage.googleapis.com/charts/gateway-${1}.tgz", "https://istio-release.storage.googleapis.com/charts/cni-${1}.tgz", "https://istio-release.storage.googleapis.com/charts/ztunnel-${1}.tgz" @@ -43,6 +49,7 @@ function add_stable_version() { } END ) + # Insert the new key above the old one (https://stackoverflow.com/questions/74368503/is-it-possible-to-insert-an-element-into-a-middle-of-array-in-yaml-using-yq) # shellcheck disable=SC2016 yq -i '.versions |= ( diff --git a/hack/update-profiles-list.sh b/hack/update-profiles-list.sh index d2d41a016..b838b1f49 100755 --- a/hack/update-profiles-list.sh +++ b/hack/update-profiles-list.sh @@ -39,4 +39,4 @@ sed -i -E \ -e "/\+sail:profile/,/Profile string/ s/(\/\/ \+operator-sdk:csv:customresourcedefinitions:type=spec,displayName=\"Profile\",xDescriptors=\{.*fieldGroup:General\")[^}]*(})/\1$selectValues}/g" \ -e "/\+sail:profile/,/Profile string/ s/(\/\/ \+kubebuilder:validation:Enum=)(.*)/\1$enumValues/g" \ -e "/\+sail:profile/,/Profile string/ s/(\/\/ Must be one of:)(.*)/\1 ${profiles//,/, }./g" \ - api/v1alpha1/istio_types.go api/v1alpha1/remoteistio_types.go api/v1alpha1/istiocni_types.go + api/v1alpha1/istio_types.go api/v1alpha1/istiocni_types.go diff --git a/hack/update-version-list.sh b/hack/update-version-list.sh index 54ab56e2f..fdf39b3a9 100755 --- a/hack/update-version-list.sh +++ b/hack/update-version-list.sh @@ -31,7 +31,7 @@ function updateVersionsInIstioTypeComment() { -e "/\+sail:version/,/Version string/ s/(\/\/ \+kubebuilder:default=)(.*)/\1$defaultVersion/g" \ -e "/\+sail:version/,/Version string/ s/(\/\/ \Must be one of:)(.*)/\1 $versions./g" \ -e "s/(\+kubebuilder:default=.*version: \")[^\"]*\"/\1$defaultVersion\"/g" \ - api/v1alpha1/istio_types.go api/v1alpha1/remoteistio_types.go api/v1alpha1/istiorevision_types.go api/v1alpha1/istiocni_types.go + api/v1alpha1/istio_types.go api/v1alpha1/istiorevision_types.go api/v1alpha1/istiocni_types.go } function updateVersionsInCSVDescription() { diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 5f88662fa..39ca7fa06 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -65,6 +65,10 @@ const ( // reports whether the remote control plane is ready or not WebhookReadinessProbeStatusAnnotationKey = MetadataNamespace + "/readinessProbe.status" + // WebhookReadinessProbeStatusReasonAnnotationKey is an annotation on the istio-sidecar-injection MutatingWebhookConfiguration that + // reports why the remote control plane is not ready + WebhookReadinessProbeStatusReasonAnnotationKey = MetadataNamespace + "/readinessProbe.reason" + // WebhookReadinessProbePeriodSecondsAnnotationKey is an annotation on the istio-sidecar-injection MutatingWebhookConfiguration that // specifies the period for the readiness probe WebhookReadinessProbePeriodSecondsAnnotationKey = MetadataNamespace + "/readinessProbe.periodSeconds" diff --git a/pkg/predicate/predicate.go b/pkg/predicate/predicate.go new file mode 100644 index 000000000..fc4f7466c --- /dev/null +++ b/pkg/predicate/predicate.go @@ -0,0 +1,27 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package predicate + +import ( + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +// ignoreUpdate returns a predicate that ignores update events. +func IgnoreUpdate() predicate.Funcs { + return predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { return false }, + } +} diff --git a/pkg/revision/reconcile.go b/pkg/revision/reconcile.go index a7fcea3fb..e78d1fd0d 100644 --- a/pkg/revision/reconcile.go +++ b/pkg/revision/reconcile.go @@ -26,7 +26,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" ) -func CreateOrUpdate(ctx context.Context, cl client.Client, revName string, revType v1alpha1.IstioRevisionType, version string, namespace string, +func CreateOrUpdate( + ctx context.Context, cl client.Client, revName string, version string, namespace string, values *v1alpha1.Values, ownerRef metav1.OwnerReference, ) error { log := logf.FromContext(ctx) @@ -53,7 +54,6 @@ func CreateOrUpdate(ctx context.Context, cl client.Client, revName string, revTy OwnerReferences: []metav1.OwnerReference{ownerRef}, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: revType, Version: version, Namespace: namespace, Values: values, diff --git a/pkg/revision/reconcile_test.go b/pkg/revision/reconcile_test.go index 86a350b22..f48f94bb9 100644 --- a/pkg/revision/reconcile_test.go +++ b/pkg/revision/reconcile_test.go @@ -98,8 +98,7 @@ func TestReconcileActiveRevision(t *testing.T) { Controller: ptr.Of(true), BlockOwnerDeletion: ptr.Of(true), } - revType := v1alpha1.IstioRevisionTypeLocal - err := CreateOrUpdate(ctx, cl, "my-revision", revType, version, "istio-system", &tc.istioValues, ownerRef) + err := CreateOrUpdate(ctx, cl, "my-revision", version, "istio-system", &tc.istioValues, ownerRef) if err != nil { t.Errorf("Expected no error, but got: %v", err) } diff --git a/pkg/revision/remote.go b/pkg/revision/remote.go new file mode 100644 index 000000000..068963cc7 --- /dev/null +++ b/pkg/revision/remote.go @@ -0,0 +1,25 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package revision + +import "github.com/istio-ecosystem/sail-operator/api/v1alpha1" + +// IsUsingRemoteControlPlane returns true if the IstioRevision is configured to +// connect to a remote rather than deploy a local control plane. +func IsUsingRemoteControlPlane(rev *v1alpha1.IstioRevision) bool { + // TODO: we should use values.istiodRemote.enabled instead of the profile, but we can't get the final set of values because of new profiles implementation + values := rev.Spec.Values + return values != nil && values.Profile != nil && *values.Profile == "remote" +} diff --git a/pkg/version/semverutils.go b/pkg/version/semverutils.go new file mode 100644 index 000000000..4417ccc6b --- /dev/null +++ b/pkg/version/semverutils.go @@ -0,0 +1,27 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +import "github.com/Masterminds/semver/v3" + +// VersionConstraint returns a semver constraint for the given string or panics +// if the string is not a valid semver constraint. +func Constraint(constraint string) semver.Constraints { + c, err := semver.NewConstraint(constraint) + if err == nil { + return *c + } + panic(err) +} diff --git a/pkg/version/semverutils_test.go b/pkg/version/semverutils_test.go new file mode 100644 index 000000000..846485e6a --- /dev/null +++ b/pkg/version/semverutils_test.go @@ -0,0 +1,34 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +import ( + "testing" +) + +func TestConstraint(t *testing.T) { + t.Run("valid constraint", func(t *testing.T) { + _ = Constraint(">1.0.0") + }) + + t.Run("invalid constraint", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Error("Expected panic for invalid constraint") + } + }() + _ = Constraint("invalid_version") + }) +} diff --git a/resources/v1.23.2/profiles/remote.yaml b/resources/v1.23.2/profiles/remote.yaml new file mode 100644 index 000000000..d72fd66e4 --- /dev/null +++ b/resources/v1.23.2/profiles/remote.yaml @@ -0,0 +1,5 @@ +# The remote profile is used to configure a mesh cluster without a locally deployed control plane. +# Only the injector mutating webhook configuration is installed. +apiVersion: sailoperator.io/v1alpha1 +kind: Istio +spec: {} diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 530e911df..432ea1d7f 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -15,7 +15,8 @@ This end-to-end test suite utilizes Ginkgo, a testing framework known for its ex 1. [Pre-requisites](#Pre-requisites) 1. [How to Run the test](#How-to-Run-the-test) 1. [Running the test locally](#Running-the-test-locally) - 1. [Settings for end-to-end test execution](#Settings-for-end-to-end-test-execution) + 1. [Settings for end-to-end test execution](#Settings-for-end-to-end-test-execution) + 1. [Customizing the test run](#Customizing-the-test-run) 1. [Get test definitions for the end-to-end test](#Get-test-definitions-for-the-end-to-end-test) 1. [Contributing](#contributing) @@ -215,6 +216,23 @@ The following environment variables define the behavior of the test run: * DEPLOYMENT_NAME=sail-operator - The name of the operator deployment. * EXPECTED_REGISTRY=`^docker\.io|^gcr\.io` - Which image registry should the operand images come from. Useful for downstream tests. +### Customizing the test run + +The test run can be customized by setting the following environment variables: + +To change all the sample files used in the test, you can use the following environment variable: +* SAMPLE_YAML_BASE_URL=https://raw.githubusercontent.com/orgName/repoName - The base URL where the sample YAML files are located. This is useful when you want to test the operator with different sample YAML files defined in another repository. Currently the e2e framework use the upstream Istio repository to get the sample YAML files, for example: `https://raw.githubusercontent.com/istio/istio/master/samples/helloworld/helloworld.yaml` for `hello-world` sample yaml file on `master` branch. + +Note: when setting this environment variable, make sure that the sample files are available in the same paths as in the Istio upstream repository. For more information check the [code](https://github.com/istio-ecosystem/sail-operator/blob/74f96ab4a56e3d41e2d31faede290116a68551e9/tests/e2e/util/common/e2e_utils.go#L271). +Alternatively, set the following environment variables to change these file paths: +* TCP_ECHO_DUAL_STACK_YAML_PATH +* TCP_ECHO_IPV4_YAML_PATH +* TCP_ECHO_IPV6_YAML_PATH +* SLEEP_YAML_PATH +* HELLOWORLD_YAML_PATH + +`TCP_ECHO_*` are used in the `dual-stack` test suite, `SLEEP_YAML_PATH` and `HELLOWORLD_YAML_PATH` are used in both `Multicluster` and default test run. + ### Get test definitions for the end-to-end test The end-to-end test suite is defined in the `tests/e2e/operator` directory. If you want to check the test definition without running the test, you can use the following make target: diff --git a/tests/e2e/controlplane/control_plane_suite_test.go b/tests/e2e/controlplane/control_plane_suite_test.go index aca69e1a7..d4c75bdd4 100644 --- a/tests/e2e/controlplane/control_plane_suite_test.go +++ b/tests/e2e/controlplane/control_plane_suite_test.go @@ -40,7 +40,7 @@ var ( istioCniName = env.Get("ISTIOCNI_NAME", "default") skipDeploy = env.GetBool("SKIP_DEPLOY", false) expectedRegistry = env.Get("EXPECTED_REGISTRY", "^docker\\.io|^gcr\\.io") - bookinfoNamespace = env.Get("BOOKINFO_NAMESPACE", "bookinfo") + sampleNamespace = env.Get("SAMPLE_NAMESPACE", "sample") multicluster = env.GetBool("MULTICLUSTER", false) ipFamily = env.Get("IP_FAMILY", "ipv4") diff --git a/tests/e2e/controlplane/control_plane_test.go b/tests/e2e/controlplane/control_plane_test.go index e55967f80..4946e38a7 100644 --- a/tests/e2e/controlplane/control_plane_test.go +++ b/tests/e2e/controlplane/control_plane_test.go @@ -117,9 +117,6 @@ metadata: Describe("given Istio version", func() { for _, version := range supportedversion.List { - // Note: This var version is needed to avoid the closure of the loop - version := version - Context(version.Name, func() { BeforeAll(func() { Expect(k.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Istio namespace failed to be created") @@ -224,31 +221,39 @@ spec: }) }) - When("bookinfo is deployed", func() { + When("sample pod is deployed", func() { BeforeAll(func() { - Expect(k.CreateNamespace(bookinfoNamespace)).To(Succeed(), "Bookinfo namespace failed to be created") - Expect(k.Patch("namespace", bookinfoNamespace, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). - To(Succeed(), "Error patching bookinfo namespace") - Expect(deployBookinfo(version)).To(Succeed(), "Error deploying bookinfo") - Success("Bookinfo deployed") + Expect(k.CreateNamespace(sampleNamespace)).To(Succeed(), "Sample namespace failed to be created") + Expect(k.Patch("namespace", sampleNamespace, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + To(Succeed(), "Error patching sample namespace") + Expect(k.WithNamespace(sampleNamespace). + ApplyWithLabels(common.GetSampleYAML(version, sampleNamespace), "version=v1")). + To(Succeed(), "Error deploying sample") + Success("sample deployed") }) - bookinfoPods := &corev1.PodList{} + samplePods := &corev1.PodList{} It("updates the pods status to Running", func(ctx SpecContext) { - Expect(cl.List(ctx, bookinfoPods, client.InNamespace(bookinfoNamespace))).To(Succeed()) - Expect(bookinfoPods.Items).ToNot(BeEmpty(), "No pods found in bookinfo namespace") + Eventually(func() bool { + // Wait until the sample pod exists. Is wraped inside a function to avoid failure on the first iteration + Expect(cl.List(ctx, samplePods, client.InNamespace(sampleNamespace))).To(Succeed()) + return len(samplePods.Items) > 0 + }).Should(BeTrue(), "No sample pods found") + + Expect(cl.List(ctx, samplePods, client.InNamespace(sampleNamespace))).To(Succeed()) + Expect(samplePods.Items).ToNot(BeEmpty(), "No pods found in sample namespace") - for _, pod := range bookinfoPods.Items { - Eventually(common.GetObject).WithArguments(ctx, cl, kube.Key(pod.Name, bookinfoNamespace), &corev1.Pod{}). + for _, pod := range samplePods.Items { + Eventually(common.GetObject).WithArguments(ctx, cl, kube.Key(pod.Name, sampleNamespace), &corev1.Pod{}). Should(HaveCondition(corev1.PodReady, metav1.ConditionTrue), "Pod is not Ready") } - Success("Bookinfo pods are ready") + Success("sample pods are ready") }) It("has sidecars with the correct istio version", func(ctx SpecContext) { - for _, pod := range bookinfoPods.Items { - sidecarVersion, err := getProxyVersion(pod.Name, bookinfoNamespace) + for _, pod := range samplePods.Items { + sidecarVersion, err := getProxyVersion(pod.Name, sampleNamespace) Expect(err).NotTo(HaveOccurred(), "Error getting sidecar version") Expect(sidecarVersion).To(Equal(version.Version), "Sidecar Istio version does not match the expected version") } @@ -256,9 +261,9 @@ spec: }) AfterAll(func(ctx SpecContext) { - By("Deleting bookinfo") - Expect(k.DeleteNamespace(bookinfoNamespace)).To(Succeed(), "Bookinfo namespace failed to be deleted") - Success("Bookinfo deleted") + By("Deleting sample") + Expect(k.DeleteNamespace(sampleNamespace)).To(Succeed(), "sample namespace failed to be deleted") + Success("sample deleted") }) }) @@ -371,27 +376,6 @@ func forceDeleteIstioResources() error { return nil } -func getBookinfoURL(version supportedversion.VersionInfo) string { - // Bookinfo YAML for the current version can be found from istio/istio repository - // If the version is latest, we need to get the latest version from the master branch - bookinfoURL := fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/samples/bookinfo/platform/kube/bookinfo.yaml", version.Version) - if version.Name == "latest" { - bookinfoURL = "https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/platform/kube/bookinfo.yaml" - } - - return bookinfoURL -} - -func deployBookinfo(version supportedversion.VersionInfo) error { - bookinfoURL := getBookinfoURL(version) - err := k.WithNamespace(bookinfoNamespace).Apply(bookinfoURL) - if err != nil { - return fmt.Errorf("error deploying bookinfo: %w", err) - } - - return nil -} - func getProxyVersion(podName, namespace string) (*semver.Version, error) { output, err := k.WithNamespace(namespace).Exec( podName, diff --git a/tests/e2e/dualstack/dualstack_test.go b/tests/e2e/dualstack/dualstack_test.go index 9a7768438..a754a3268 100644 --- a/tests/e2e/dualstack/dualstack_test.go +++ b/tests/e2e/dualstack/dualstack_test.go @@ -70,9 +70,6 @@ var _ = Describe("DualStack configuration ", Ordered, func() { Describe("for supported versions", func() { for _, version := range supportedversion.List { - // Note: This var version is needed to avoid the closure of the loop - version := version - // The minimum supported version is 1.23 (and above) if version.Version.LessThan(semver.MustParse("1.23.0")) { continue @@ -202,10 +199,10 @@ spec: Expect(k.Patch("namespace", SleepNamespace, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). To(Succeed(), "Error patching sleep namespace") - Expect(k.WithNamespace(DualStackNamespace).Apply(getYAMLPodURL(version, DualStackNamespace))).To(Succeed(), "error deploying tcpDualStack pod") - Expect(k.WithNamespace(IPv4Namespace).Apply(getYAMLPodURL(version, IPv4Namespace))).To(Succeed(), "error deploying ipv4 pod") - Expect(k.WithNamespace(IPv6Namespace).Apply(getYAMLPodURL(version, IPv6Namespace))).To(Succeed(), "error deploying ipv6 pod") - Expect(k.WithNamespace(SleepNamespace).Apply(getYAMLPodURL(version, SleepNamespace))).To(Succeed(), "error deploying sleep pod") + Expect(k.WithNamespace(DualStackNamespace).Apply(common.GetSampleYAML(version, "tcp-echo-dual-stack"))).To(Succeed(), "error deploying tcpDualStack pod") + Expect(k.WithNamespace(IPv4Namespace).Apply(common.GetSampleYAML(version, "tcp-echo-ipv4"))).To(Succeed(), "error deploying ipv4 pod") + Expect(k.WithNamespace(IPv6Namespace).Apply(common.GetSampleYAML(version, "tcp-echo-ipv6"))).To(Succeed(), "error deploying ipv6 pod") + Expect(k.WithNamespace(SleepNamespace).Apply(common.GetSampleYAML(version, "sleep"))).To(Succeed(), "error deploying sleep pod") Success("dualStack validation pods deployed") }) @@ -326,29 +323,6 @@ func getEnvVars(container corev1.Container) []corev1.EnvVar { return container.Env } -func getYAMLPodURL(version supportedversion.VersionInfo, namespace string) string { - var url string - - switch namespace { - case DualStackNamespace: - url = "samples/tcp-echo/tcp-echo-dual-stack.yaml" - case IPv4Namespace: - url = "samples/tcp-echo/tcp-echo-ipv4.yaml" - case IPv6Namespace: - url = "samples/tcp-echo/tcp-echo-ipv6.yaml" - case SleepNamespace: - url = "samples/sleep/sleep.yaml" - default: - return "" - } - - if version.Name == "latest" { - return fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/master/%s", url) - } - - return fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/%s", version.Version, url) -} - func checkPodConnectivity(podName, namespace, echoStr string) { command := fmt.Sprintf(`sh -c 'echo %s | nc tcp-echo.%s 9000'`, echoStr, echoStr) response, err := k.WithNamespace(namespace).Exec(podName, "sleep", command) diff --git a/tests/e2e/multicluster/multicluster_multiprimary_test.go b/tests/e2e/multicluster/multicluster_multiprimary_test.go index 8d647504a..bc34186a3 100644 --- a/tests/e2e/multicluster/multicluster_multiprimary_test.go +++ b/tests/e2e/multicluster/multicluster_multiprimary_test.go @@ -198,8 +198,29 @@ spec: When("sample apps are deployed in both clusters", func() { BeforeAll(func(ctx SpecContext) { + // Create the namespace + Expect(k1.CreateNamespace("sample")).To(Succeed(), "Namespace failed to be created") + Expect(k2.CreateNamespace("sample")).To(Succeed(), "Namespace failed to be created") + + // Label the sample namespace + Expect(k1.Patch("namespace", "sample", "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + To(Succeed(), "Error patching sample namespace") + Expect(k2.Patch("namespace", "sample", "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + To(Succeed(), "Error patching sample namespace") + // Deploy the sample app in both clusters - deploySampleApp("sample", version) + helloWorldURL := common.GetSampleYAML(version, "helloworld") + sleepURL := common.GetSampleYAML(version, "sleep") + + // On Cluster 0, create a service for the helloworld app v1 + Expect(k1.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k1.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "version=v1")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k1.WithNamespace("sample").Apply(sleepURL)).To(Succeed(), "Failed to deploy sleep service") + + // On Cluster 1, create a service for the helloworld app v2 + Expect(k2.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k2.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "version=v2")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k2.WithNamespace("sample").Apply(sleepURL)).To(Succeed(), "Failed to deploy sleep service") Success("Sample app is deployed in both clusters") }) @@ -207,7 +228,7 @@ spec: samplePodsCluster1 := &corev1.PodList{} Expect(clPrimary.List(ctx, samplePodsCluster1, client.InNamespace("sample"))).To(Succeed()) - Expect(samplePodsCluster1.Items).ToNot(BeEmpty(), "No pods found in bookinfo namespace") + Expect(samplePodsCluster1.Items).ToNot(BeEmpty(), "No pods found in sample namespace") for _, pod := range samplePodsCluster1.Items { Eventually(common.GetObject). @@ -217,7 +238,7 @@ spec: samplePodsCluster2 := &corev1.PodList{} Expect(clRemote.List(ctx, samplePodsCluster2, client.InNamespace("sample"))).To(Succeed()) - Expect(samplePodsCluster2.Items).ToNot(BeEmpty(), "No pods found in bookinfo namespace") + Expect(samplePodsCluster2.Items).ToNot(BeEmpty(), "No pods found in sample namespace") for _, pod := range samplePodsCluster2.Items { Eventually(common.GetObject). @@ -290,32 +311,3 @@ spec: Expect(k2.WaitNamespaceDeleted(namespace)).To(Succeed()) }) }) - -// deploySampleApp deploys the sample app in the given cluster -func deploySampleApp(ns string, istioVersion supportedversion.VersionInfo) { - // Create the namespace - Expect(k1.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") - Expect(k2.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") - - // Label the namespace - Expect(k1.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). - To(Succeed(), "Error patching sample namespace") - Expect(k2.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). - To(Succeed(), "Error patching sample namespace") - - version := istioVersion.Version.String() - // Deploy the sample app from upstream URL in both clusters - if istioVersion.Name == "latest" { - version = "master" - } - helloWorldURL := fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/samples/helloworld/helloworld.yaml", version) - Expect(k1.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #1") - Expect(k2.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #2") - - Expect(k1.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v1")).To(Succeed(), "Sample service deploy failed on Cluster #1") - Expect(k2.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v2")).To(Succeed(), "Sample service deploy failed on Cluster #2") - - sleepURL := fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/samples/sleep/sleep.yaml", version) - Expect(k1.WithNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #1") - Expect(k2.WithNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #2") -} diff --git a/tests/e2e/multicluster/multicluster_primaryremote_test.go b/tests/e2e/multicluster/multicluster_primaryremote_test.go index 7ff6db158..55d983041 100644 --- a/tests/e2e/multicluster/multicluster_primaryremote_test.go +++ b/tests/e2e/multicluster/multicluster_primaryremote_test.go @@ -25,6 +25,7 @@ import ( "github.com/istio-ecosystem/sail-operator/pkg/kube" . "github.com/istio-ecosystem/sail-operator/pkg/test/util/ginkgo" "github.com/istio-ecosystem/sail-operator/pkg/test/util/supportedversion" + "github.com/istio-ecosystem/sail-operator/pkg/version" "github.com/istio-ecosystem/sail-operator/tests/e2e/util/certs" "github.com/istio-ecosystem/sail-operator/tests/e2e/util/common" . "github.com/istio-ecosystem/sail-operator/tests/e2e/util/gomega" @@ -68,14 +69,14 @@ var _ = Describe("Multicluster deployment models", Ordered, func() { Describe("Primary-Remote - Multi-Network configuration", func() { // Test the Primary-Remote - Multi-Network configuration for each supported Istio version - for _, version := range supportedversion.List { - // The Primary-Remote - Multi-Network configuration is only supported in Istio 1.23, because that's the only - // version that has the istiod-remote chart. For 1.24, we need to rewrite the support for RemoteIstio. - if !(version.Version.Major() == 1 && version.Version.Minor() == 23) { + for _, v := range supportedversion.List { + // The Primary-Remote - Multi-Network configuration is only supported in Istio 1.24+. + if version.Constraint("<1.24").Check(v.Version) { + Log(fmt.Sprintf("Skipping test, because Istio version %s does not support Primary-Remote Multi-Network configuration", v.Version)) continue } - Context(fmt.Sprintf("Istio version %s", version.Version), func() { + Context(fmt.Sprintf("Istio version %s", v.Version), func() { When("Istio resources are created in both clusters", func() { BeforeAll(func(ctx SpecContext) { Expect(k1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") @@ -115,7 +116,7 @@ spec: multiCluster: clusterName: %s network: %s` - multiclusterPrimaryYAML := fmt.Sprintf(PrimaryYAML, version.Name, controlPlaneNamespace, "mesh1", "cluster1", "network1") + multiclusterPrimaryYAML := fmt.Sprintf(PrimaryYAML, v.Name, controlPlaneNamespace, "mesh1", "cluster1", "network1") Log("Istio CR Primary: ", multiclusterPrimaryYAML) Expect(k1.CreateFromString(multiclusterPrimaryYAML)).To(Succeed(), "Istio Resource creation failed on Primary Cluster") }) @@ -131,7 +132,7 @@ spec: Eventually(common.GetObject). WithArguments(ctx, clPrimary, kube.Key("istiod", controlPlaneNamespace), &appsv1.Deployment{}). Should(HaveCondition(appsv1.DeploymentAvailable, metav1.ConditionTrue), "Istiod is not Available on Primary; unexpected Condition") - Expect(common.GetVersionFromIstiod()).To(Equal(version.Version), "Unexpected istiod version") + Expect(common.GetVersionFromIstiod()).To(Equal(v.Version), "Unexpected istiod version") Success("Istiod is deployed in the namespace and Running on Primary Cluster") }) }) @@ -154,17 +155,18 @@ spec: }) }) - When("RemoteIstio is created in Remote cluster", func() { + When("Istio is created in Remote cluster", func() { BeforeAll(func(ctx SpecContext) { - RemoteYAML := ` + istioYAMLTemplate := ` apiVersion: sailoperator.io/v1alpha1 -kind: RemoteIstio +kind: Istio metadata: name: default spec: version: %s namespace: istio-system values: + profile: remote istiodRemote: injectionPath: /inject/cluster/remote/net/network2 global: @@ -173,10 +175,10 @@ spec: remotePilotAddress, err := common.GetSVCLoadBalancerAddress(ctx, clPrimary, controlPlaneNamespace, "istio-eastwestgateway") Expect(remotePilotAddress).NotTo(BeEmpty(), "Remote Pilot Address is empty") Expect(err).NotTo(HaveOccurred(), "Error getting Remote Pilot Address") - remoteIstioYAML := fmt.Sprintf(RemoteYAML, version.Name, remotePilotAddress) - Log("RemoteIstio CR: ", remoteIstioYAML) - By("Creating RemoteIstio CR on Remote Cluster") - Expect(k2.CreateFromString(remoteIstioYAML)).To(Succeed(), "RemoteIstio Resource creation failed on Remote Cluster") + istioYAML := fmt.Sprintf(istioYAMLTemplate, v.Name, remotePilotAddress) + Log("Istio CR: ", istioYAML) + By("Creating Istio CR on Remote Cluster") + Expect(k2.CreateFromString(istioYAML)).To(Succeed(), "Istio Resource creation failed on Remote Cluster") // Set the controlplane cluster and network for Remote namespace By("Patching the istio-system namespace on Remote Cluster") @@ -196,13 +198,13 @@ spec: To(Succeed(), "Error patching istio-system namespace") // To be able to access the remote cluster from the primary cluster, we need to create a secret in the primary cluster - // RemoteIstio resource will not be Ready until the secret is created + // Remote Istio resource will not be Ready until the secret is created // Get the internal IP of the control plane node in Remote cluster internalIPRemote, err := k2.GetInternalIP("node-role.kubernetes.io/control-plane") Expect(internalIPRemote).NotTo(BeEmpty(), "Internal IP is empty for Remote Cluster") Expect(err).NotTo(HaveOccurred()) - // Wait for the RemoteIstio CR to be created, this can be moved to a condition verification, but the resource it not will be Ready at this point + // Wait for the remote Istio CR to be created, this can be moved to a condition verification, but the resource it not will be Ready at this point time.Sleep(5 * time.Second) // Install a remote secret in Primary cluster that provides access to the Remote cluster API server. @@ -219,11 +221,11 @@ spec: Success("Remote secret is created in Primary cluster") }) - It("updates RemoteIstio CR status to Ready", func(ctx SpecContext) { + It("updates remote Istio CR status to Ready", func(ctx SpecContext) { Eventually(common.GetObject). - WithArguments(ctx, clRemote, kube.Key(istioName), &v1alpha1.RemoteIstio{}). + WithArguments(ctx, clRemote, kube.Key(istioName), &v1alpha1.Istio{}). Should(HaveCondition(v1alpha1.IstioConditionReady, metav1.ConditionTrue), "Istio is not Ready on Remote; unexpected Condition") - Success("RemoteIstio CR is Ready on Remote Cluster") + Success("Istio CR is Ready on Remote Cluster") }) }) @@ -243,8 +245,29 @@ spec: When("sample apps are deployed in both clusters", func() { BeforeAll(func(ctx SpecContext) { + // Create the namespace + Expect(k1.CreateNamespace("sample")).To(Succeed(), "Namespace failed to be created") + Expect(k2.CreateNamespace("sample")).To(Succeed(), "Namespace failed to be created") + + // Label the sample namespace + Expect(k1.Patch("namespace", "sample", "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + To(Succeed(), "Error patching sample namespace") + Expect(k2.Patch("namespace", "sample", "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + To(Succeed(), "Error patching sample namespace") + // Deploy the sample app in both clusters - deploySampleApp("sample", version) + helloWorldURL := common.GetSampleYAML(v, "helloworld") + sleepURL := common.GetSampleYAML(v, "sleep") + + // On Cluster 0, create a service for the helloworld app v1 + Expect(k1.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k1.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "version=v1")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k1.WithNamespace("sample").Apply(sleepURL)).To(Succeed(), "Failed to deploy sleep service") + + // On Cluster 1, create a service for the helloworld app v2 + Expect(k2.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k2.WithNamespace("sample").ApplyWithLabels(helloWorldURL, "version=v2")).To(Succeed(), "Failed to deploy helloworld service") + Expect(k2.WithNamespace("sample").Apply(sleepURL)).To(Succeed(), "Failed to deploy sleep service") Success("Sample app is deployed in both clusters") }) @@ -252,7 +275,7 @@ spec: samplePodsPrimary := &corev1.PodList{} Expect(clPrimary.List(ctx, samplePodsPrimary, client.InNamespace("sample"))).To(Succeed()) - Expect(samplePodsPrimary.Items).ToNot(BeEmpty(), "No pods found in bookinfo namespace") + Expect(samplePodsPrimary.Items).ToNot(BeEmpty(), "No pods found in sample namespace") for _, pod := range samplePodsPrimary.Items { Eventually(common.GetObject). @@ -262,7 +285,7 @@ spec: samplePodsRemote := &corev1.PodList{} Expect(clRemote.List(ctx, samplePodsRemote, client.InNamespace("sample"))).To(Succeed()) - Expect(samplePodsRemote.Items).ToNot(BeEmpty(), "No pods found in bookinfo namespace") + Expect(samplePodsRemote.Items).ToNot(BeEmpty(), "No pods found in sample namespace") for _, pod := range samplePodsRemote.Items { Eventually(common.GetObject). @@ -279,11 +302,11 @@ spec: }) }) - When("Istio CR and RemoteIstio CR are deleted in both clusters", func() { + When("Istio CR is deleted in both clusters", func() { BeforeEach(func() { - Expect(k1.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") - Expect(k2.WithNamespace(controlPlaneNamespace).Delete("remoteistio", istioName)).To(Succeed(), "RemoteIstio CR failed to be deleted") - Success("Istio and RemoteIstio are deleted") + Expect(k1.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "primary Istio CR failed to be deleted") + Expect(k2.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "remote Istio CR failed to be deleted") + Success("Primary and Remote Istio resources are deleted") }) It("removes istiod on Primary", func(ctx SpecContext) { @@ -313,6 +336,12 @@ spec: Expect(k1.WaitNamespaceDeleted("sample")).To(Succeed()) Expect(k2.WaitNamespaceDeleted("sample")).To(Succeed()) Success("Sample app is deleted in both clusters") + + // Delete the resources created by istioctl create-remote-secret + Expect(k2.Delete("ClusterRoleBinding", "istiod-clusterrole-istio-system")).To(Succeed()) + Expect(k2.Delete("ClusterRole", "istiod-clusterrole-istio-system")).To(Succeed()) + Expect(k2.Delete("ClusterRoleBinding", "istiod-gateway-controller-istio-system")).To(Succeed()) + Expect(k2.Delete("ClusterRole", "istiod-gateway-controller-istio-system")).To(Succeed()) }) }) } diff --git a/tests/e2e/util/common/e2e_utils.go b/tests/e2e/util/common/e2e_utils.go index eb1423cc8..0d93c9404 100644 --- a/tests/e2e/util/common/e2e_utils.go +++ b/tests/e2e/util/common/e2e_utils.go @@ -19,6 +19,7 @@ package common import ( "context" "fmt" + "os" "path/filepath" "regexp" "strings" @@ -27,6 +28,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/istio-ecosystem/sail-operator/pkg/kube" "github.com/istio-ecosystem/sail-operator/pkg/test/project" + "github.com/istio-ecosystem/sail-operator/pkg/test/util/supportedversion" "github.com/istio-ecosystem/sail-operator/tests/e2e/util/env" . "github.com/istio-ecosystem/sail-operator/tests/e2e/util/gomega" "github.com/istio-ecosystem/sail-operator/tests/e2e/util/helm" @@ -261,3 +263,60 @@ func InstallOperatorViaHelm(extraArgs ...string) error { func UninstallOperator() error { return helm.Uninstall("sail-operator", "--namespace", OperatorNamespace) } + +// GetSampleYAML returns the URL of the yaml file for the testing app. +// args: +// version: the version of the Istio to get the yaml file from. +// appName: the name of the testing app. Example: helloworld, sleep, tcp-echo. +func GetSampleYAML(version supportedversion.VersionInfo, appName string) string { + // This func will be used to get URLs for the yaml files of the testing apps. Example: helloworld, sleep, tcp-echo. + // Default values points to upstream Istio sample yaml files. Custom paths can be provided using environment variables. + + // Define environment variables for specific apps + envVarMap := map[string]string{ + "tcp-echo-dual-stack": "TCP_ECHO_DUAL_STACK_YAML_PATH", + "tcp-echo-ipv4": "TCP_ECHO_IPV4_YAML_PATH", + "tcp-echo": "TCP_ECHO_IPV4_YAML_PATH", + "tcp-echo-ipv6": "TCP_ECHO_IPV6_YAML_PATH", + "sleep": "SLEEP_YAML_PATH", + "helloworld": "HELLOWORLD_YAML_PATH", + "sample": "HELLOWORLD_YAML_PATH", + } + + // Check if there's a custom path for the given appName + if envVar, exists := envVarMap[appName]; exists { + customPath := os.Getenv(envVar) + if customPath != "" { + return customPath + } + } + + // Default paths if no custom path is provided + var url string + switch appName { + case "tcp-echo-dual-stack": + url = "samples/tcp-echo/tcp-echo-dual-stack.yaml" + case "tcp-echo-ipv4", "tcp-echo": + url = "samples/tcp-echo/tcp-echo-ipv4.yaml" + case "tcp-echo-ipv6": + url = "samples/tcp-echo/tcp-echo-ipv6.yaml" + case "sleep": + url = "samples/sleep/sleep.yaml" + case "helloworld", "sample": + url = "samples/helloworld/helloworld.yaml" + default: + return "" + } + + // Base URL logic + baseURL := os.Getenv("SAMPLE_YAML_BASE_URL") + if baseURL == "" { + baseURL = "https://raw.githubusercontent.com/istio/istio" + } + + if version.Name == "latest" { + return fmt.Sprintf("%s/master/%s", baseURL, url) + } + + return fmt.Sprintf("%s/%s/%s", baseURL, version.Version, url) +} diff --git a/tests/integration/api/istio_test.go b/tests/integration/api/istio_test.go index d939f9cd3..20084d952 100644 --- a/tests/integration/api/istio_test.go +++ b/tests/integration/api/istio_test.go @@ -137,7 +137,6 @@ var _ = Describe("Istio resource", Ordered, func() { }).Should(Succeed()) Expect(rev.Spec).To(Equal(v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: istio.Spec.Version, Namespace: istio.Spec.Namespace, Values: &v1alpha1.Values{ @@ -174,7 +173,6 @@ var _ = Describe("Istio resource", Ordered, func() { Eventually(k8sClient.Get).WithArguments(ctx, revKey, rev).Should(Succeed()) Expect(rev.GetOwnerReferences()).To(ContainElement(NewOwnerReference(istio))) Expect(rev.Spec).To(Equal(v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: istio.Spec.Version, Namespace: istio.Spec.Namespace, Values: &v1alpha1.Values{ @@ -224,8 +222,6 @@ var _ = Describe("Istio resource", Ordered, func() { }) for _, withWorkloads := range []bool{true, false} { - withWorkloads := withWorkloads - Context(generateContextName(withWorkloads), func() { if withWorkloads { BeforeAll(func() { diff --git a/tests/integration/api/istiocni_test.go b/tests/integration/api/istiocni_test.go index f43756ae3..c207d4b11 100644 --- a/tests/integration/api/istiocni_test.go +++ b/tests/integration/api/istiocni_test.go @@ -22,6 +22,7 @@ import ( "time" "github.com/istio-ecosystem/sail-operator/api/v1alpha1" + "github.com/istio-ecosystem/sail-operator/pkg/enqueuelogger" "github.com/istio-ecosystem/sail-operator/pkg/kube" . "github.com/istio-ecosystem/sail-operator/pkg/test/util/ginkgo" "github.com/istio-ecosystem/sail-operator/pkg/test/util/supportedversion" @@ -43,6 +44,8 @@ var _ = Describe("IstioCNI", Ordered, func() { SetDefaultEventuallyPollingInterval(time.Second) SetDefaultEventuallyTimeout(30 * time.Second) + enqueuelogger.LogEnqueueEvents = true + ctx := context.Background() namespace := &corev1.Namespace{ @@ -236,6 +239,32 @@ var _ = Describe("IstioCNI", Ordered, func() { }).Should(Succeed()) }) }) + + It("skips reconcile when a pull secret is added to service account", func() { + waitForInFlightReconcileToFinish() + + sa := &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "istio-cni", + Namespace: cniNamespace, + }, + } + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(sa), sa)).To(Succeed()) + + beforeCount := getIstioCNIReconcileCount(Default) + + By("adding pull secret to ServiceAccount") + sa.ImagePullSecrets = append(sa.ImagePullSecrets, corev1.LocalObjectReference{Name: "other-pull-secret"}) + Expect(k8sClient.Update(ctx, sa)).To(Succeed()) + + Consistently(func(g Gomega) { + afterCount := getIstioCNIReconcileCount(g) + g.Expect(afterCount).To(Equal(beforeCount)) + }, 5*time.Second).Should(Succeed(), "IstioRevision was reconciled when it shouldn't have been") + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(sa), sa)).To(Succeed()) + Expect(sa.ImagePullSecrets).To(ContainElement(corev1.LocalObjectReference{Name: "other-pull-secret"})) + }) }) When("the resource is deleted", func() { diff --git a/tests/integration/api/istiorevision_test.go b/tests/integration/api/istiorevision_test.go index 9b17e63ca..4bfd819a3 100644 --- a/tests/integration/api/istiorevision_test.go +++ b/tests/integration/api/istiorevision_test.go @@ -98,7 +98,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: revName, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -118,7 +117,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: revName, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -138,7 +136,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -158,7 +155,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: "default", }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -182,7 +178,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: revName, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: nsName, Values: &v1alpha1.Values{ @@ -249,7 +244,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: revName, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -321,8 +315,8 @@ var _ = Describe("IstioRevision resource", Ordered, func() { DescribeTable("reconciles owned resource", func(obj client.Object, modify func(obj client.Object), validate func(g Gomega, obj client.Object)) { By("on update", func() { - // ensure all in-flight reconcile operations finish before the test; unfortunately, sleeping seems to be the only option to achieve this - time.Sleep(5 * time.Second) + // ensure all in-flight reconcile operations finish before the test + waitForInFlightReconcileToFinish() Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(obj), obj)).To(Succeed()) @@ -386,20 +380,18 @@ var _ = Describe("IstioRevision resource", Ordered, func() { DescribeTable("skips reconcile when only the status of the owned resource is updated", func(obj client.Object, modify func(obj client.Object)) { - // wait for the in-flight reconcile operations to finish - // unfortunately, I don't see a good way to do this other than by waiting - time.Sleep(5 * time.Second) + waitForInFlightReconcileToFinish() Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(obj), obj)).To(Succeed()) - beforeCount := getReconcileCount(Default) + beforeCount := getIstioRevisionReconcileCount(Default) By("modifying object") modify(obj) Expect(k8sClient.Status().Update(ctx, obj)).To(Succeed()) Consistently(func(g Gomega) { - afterCount := getReconcileCount(g) + afterCount := getIstioRevisionReconcileCount(g) g.Expect(afterCount).To(Equal(beforeCount)) }, 5*time.Second).Should(Succeed()) }, @@ -429,6 +421,34 @@ var _ = Describe("IstioRevision resource", Ordered, func() { ), ) + It("skips reconcile when a pull secret is added to service account", func() { + waitForInFlightReconcileToFinish() + + sa := &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "istiod-" + revName, + Namespace: istioNamespace, + }, + } + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(sa), sa)).To(Succeed()) + + GinkgoWriter.Println("sa:", sa) + + beforeCount := getIstioRevisionReconcileCount(Default) + + By("adding pull secret to ServiceAccount") + sa.ImagePullSecrets = append(sa.ImagePullSecrets, corev1.LocalObjectReference{Name: "other-pull-secret"}) + Expect(k8sClient.Update(ctx, sa)).To(Succeed()) + + Consistently(func(g Gomega) { + afterCount := getIstioRevisionReconcileCount(g) + g.Expect(afterCount).To(Equal(beforeCount)) + }, 5*time.Second).Should(Succeed(), "IstioRevision was reconciled when it shouldn't have been") + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(sa), sa)).To(Succeed()) + Expect(sa.ImagePullSecrets).To(ContainElement(corev1.LocalObjectReference{Name: "other-pull-secret"})) + }) + It("supports concurrent deployment of two control planes", func() { rev2Name := revName + "2" rev2Key := client.ObjectKey{Name: rev2Name} @@ -440,7 +460,6 @@ var _ = Describe("IstioRevision resource", Ordered, func() { Name: rev2Key.Name, }, Spec: v1alpha1.IstioRevisionSpec{ - Type: v1alpha1.IstioRevisionTypeLocal, Version: supportedversion.Default, Namespace: istioNamespace, Values: &v1alpha1.Values{ @@ -473,7 +492,21 @@ var _ = Describe("IstioRevision resource", Ordered, func() { }) }) -func getReconcileCount(g Gomega) float64 { +func waitForInFlightReconcileToFinish() { + // wait for the in-flight reconcile operations to finish + // unfortunately, I don't see a good way to do this other than by waiting + time.Sleep(5 * time.Second) +} + +func getIstioRevisionReconcileCount(g Gomega) float64 { + return getReconcileCount(g, "istiorevision") +} + +func getIstioCNIReconcileCount(g Gomega) float64 { + return getReconcileCount(g, "istiocni") +} + +func getReconcileCount(g Gomega, controllerName string) float64 { resp, err := http.Get("http://localhost:8080/metrics") g.Expect(err).NotTo(HaveOccurred()) defer resp.Body.Close() @@ -487,7 +520,7 @@ func getReconcileCount(g Gomega) float64 { sum := float64(0) for _, metric := range mf.Metric { for _, l := range metric.Label { - if *l.Name == "controller" && *l.Value == "istiorevision" { + if *l.Name == "controller" && *l.Value == controllerName { sum += metric.GetCounter().GetValue() } } diff --git a/tests/integration/api/suite_test.go b/tests/integration/api/suite_test.go index f7cd9e7f4..662b9ea80 100644 --- a/tests/integration/api/suite_test.go +++ b/tests/integration/api/suite_test.go @@ -24,7 +24,6 @@ import ( "github.com/istio-ecosystem/sail-operator/controllers/istio" "github.com/istio-ecosystem/sail-operator/controllers/istiocni" "github.com/istio-ecosystem/sail-operator/controllers/istiorevision" - "github.com/istio-ecosystem/sail-operator/controllers/remoteistio" "github.com/istio-ecosystem/sail-operator/pkg/config" "github.com/istio-ecosystem/sail-operator/pkg/helm" "github.com/istio-ecosystem/sail-operator/pkg/scheme" @@ -83,7 +82,6 @@ var _ = BeforeSuite(func() { cl := mgr.GetClient() scheme := mgr.GetScheme() Expect(istio.NewReconciler(cfg, cl, scheme).SetupWithManager(mgr)).To(Succeed()) - Expect(remoteistio.NewReconciler(cfg, cl, scheme).SetupWithManager(mgr)).To(Succeed()) Expect(istiorevision.NewReconciler(cfg, cl, scheme, chartManager).SetupWithManager(mgr)).To(Succeed()) Expect(istiocni.NewReconciler(cfg, cl, scheme, chartManager).SetupWithManager(mgr)).To(Succeed()) diff --git a/versions.yaml b/versions.yaml index e42e1851a..849f57289 100644 --- a/versions.yaml +++ b/versions.yaml @@ -11,6 +11,27 @@ # go.mod affect the generated API schema for the Sail CRDs (e.g. IstioRevision), # as well as all the Istio CRDs (e.g. VirtualService). versions: + - name: v1.24.0 + version: 1.24.0 + repo: https://github.com/istio/istio + commit: 1.24.0 + charts: + - https://istio-release.storage.googleapis.com/charts/base-1.24.0.tgz + - https://istio-release.storage.googleapis.com/charts/istiod-1.24.0.tgz + - https://istio-release.storage.googleapis.com/charts/gateway-1.24.0.tgz + - https://istio-release.storage.googleapis.com/charts/cni-1.24.0.tgz + - https://istio-release.storage.googleapis.com/charts/ztunnel-1.24.0.tgz + - name: v1.23.3 + version: 1.23.3 + repo: https://github.com/istio/istio + commit: 1.23.3 + charts: + - https://istio-release.storage.googleapis.com/charts/base-1.23.3.tgz + - https://istio-release.storage.googleapis.com/charts/istiod-1.23.3.tgz + - https://istio-release.storage.googleapis.com/charts/istiod-remote-1.23.3.tgz + - https://istio-release.storage.googleapis.com/charts/gateway-1.23.3.tgz + - https://istio-release.storage.googleapis.com/charts/cni-1.23.3.tgz + - https://istio-release.storage.googleapis.com/charts/ztunnel-1.23.3.tgz - name: v1.23.2 version: 1.23.2 repo: https://github.com/istio/istio @@ -22,6 +43,16 @@ versions: - https://istio-release.storage.googleapis.com/charts/gateway-1.23.2.tgz - https://istio-release.storage.googleapis.com/charts/cni-1.23.2.tgz - https://istio-release.storage.googleapis.com/charts/ztunnel-1.23.2.tgz + - name: v1.22.6 + version: 1.22.6 + repo: https://github.com/istio/istio + commit: 1.22.6 + charts: + - https://istio-release.storage.googleapis.com/charts/base-1.22.6.tgz + - https://istio-release.storage.googleapis.com/charts/istiod-1.22.6.tgz + - https://istio-release.storage.googleapis.com/charts/gateway-1.22.6.tgz + - https://istio-release.storage.googleapis.com/charts/cni-1.22.6.tgz + - https://istio-release.storage.googleapis.com/charts/ztunnel-1.22.6.tgz - name: v1.22.5 version: 1.22.5 repo: https://github.com/istio/istio @@ -43,13 +74,13 @@ versions: - https://istio-release.storage.googleapis.com/charts/cni-1.21.6.tgz - https://istio-release.storage.googleapis.com/charts/ztunnel-1.21.6.tgz - name: latest - version: 1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec + version: 1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5 repo: https://github.com/istio/istio branch: master - commit: bb972b546125d3f001cc11114e9fc95486b891ec + commit: 803629b94e938bcd9bace6c158b3b2979a713ea5 charts: - - https://storage.googleapis.com/istio-build/dev/1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec/helm/base-1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec.tgz - - https://storage.googleapis.com/istio-build/dev/1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec/helm/cni-1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec.tgz - - https://storage.googleapis.com/istio-build/dev/1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec/helm/gateway-1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec.tgz - - https://storage.googleapis.com/istio-build/dev/1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec/helm/istiod-1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec.tgz - - https://storage.googleapis.com/istio-build/dev/1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec/helm/ztunnel-1.24-alpha.bb972b546125d3f001cc11114e9fc95486b891ec.tgz + - https://storage.googleapis.com/istio-build/dev/1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5/helm/base-1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5.tgz + - https://storage.googleapis.com/istio-build/dev/1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5/helm/cni-1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5.tgz + - https://storage.googleapis.com/istio-build/dev/1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5/helm/gateway-1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5.tgz + - https://storage.googleapis.com/istio-build/dev/1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5/helm/istiod-1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5.tgz + - https://storage.googleapis.com/istio-build/dev/1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5/helm/ztunnel-1.25-alpha.803629b94e938bcd9bace6c158b3b2979a713ea5.tgz