diff --git a/.gitea/workflows/build-and-publish.yaml b/.gitea/workflows/build-and-publish.yaml new file mode 100644 index 0000000..4fd703a --- /dev/null +++ b/.gitea/workflows/build-and-publish.yaml @@ -0,0 +1,79 @@ +name: Build and Publish +on: + push: + branches: + - main +env: + CHART_NAME: ${{ github.event.repository.name }} + IMAGE_NAME: ${{ github.event.repository.name }} +jobs: + build-release: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - uses: DeterminateSystems/determinate-nix-action@v3 + + - uses: DeterminateSystems/flake-checker-action@main + with: + flake-lock-path: ./build/flake.lock + + - name: Setup Attic cache + uses: ryanccn/attic-action@v0 + with: + endpoint: ${{ secrets.ATTIC_ENDPOINT }} + cache: ${{ secrets.ATTIC_CACHE }} + token: ${{ secrets.ATTIC_TOKEN }} + + - name: Build Docker Image via Nix Flake + run: | + nix build ./build#dockerImage --print-build-logs + docker load < result + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ github.server_url }} + username: ${{ secrets.CI_USER }} + password: ${{ secrets.CI_PASSWORD }} + + - name: Tag and Push Docker Image + run: | + VERSION=${{ github.run_number }} + + # Strip https from server URL + REGISTRY=${GITHUB_SERVER_URL#https://} + + TARGET_IMAGE=$REGISTRY/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} + + # Auto-detect the built image name (better version) + SOURCE_IMAGE=$(docker load < result | awk '{print $3}') + + docker tag $SOURCE_IMAGE $TARGET_IMAGE:$VERSION + docker tag $SOURCE_IMAGE $TARGET_IMAGE:latest + docker push $TARGET_IMAGE:$VERSION + docker push $TARGET_IMAGE:latest + + - name: Setup Helm + uses: azure/setup-helm@v4 + with: + version: v3.14.0 + + - name: Package Helm Chart + run: | + VERSION=${{ github.run_number }} + helm package ops/chart --version $VERSION --app-version $VERSION + + - name: Push Helm Chart to Gitea Registry + run: | + VERSION=${{ github.run_number }} + CHART_FILE=${{ env.CHART_NAME }}-${VERSION}.tgz + + curl -f --user "${{ secrets.CI_USER }}:${{ secrets.CI_PASSWORD }}" \ + -X POST \ + --upload-file ./$CHART_FILE \ + "${{ github.server_url }}/api/packages/${{ github.repository_owner }}/helm/api/charts" diff --git a/src/Dockerfile b/Dockerfile similarity index 100% rename from src/Dockerfile rename to Dockerfile diff --git a/src/Makefile b/Makefile similarity index 99% rename from src/Makefile rename to Makefile index 57455f1..a1bdfcb 100644 --- a/src/Makefile +++ b/Makefile @@ -28,8 +28,8 @@ BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) # This variable is used to construct full image tags for bundle and catalog images. # # For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both -# topmanage.com/src-bundle:$VERSION and topmanage.com/src-catalog:$VERSION. -IMAGE_TAG_BASE ?= topmanage.com/src +# github.com/src-bundle:$VERSION and github.com/src-catalog:$VERSION. +IMAGE_TAG_BASE ?= github.com/src # BUNDLE_IMG defines the image:tag used for the bundle. # You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) diff --git a/PROJECT b/PROJECT new file mode 100644 index 0000000..1d45a41 --- /dev/null +++ b/PROJECT @@ -0,0 +1,32 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html +domain: github.com +layout: +- go.kubebuilder.io/v4 +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} +projectName: src +repo: gitea.corredorconect.com/software-engineering/zitadel-k8s-operator +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: github.com + group: zitadel + kind: Cluster + path: gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: github.com + group: zitadel + kind: Instance + path: gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1 + version: v1alpha1 +version: "3" diff --git a/src/README.md b/README.md similarity index 100% rename from src/README.md rename to README.md diff --git a/src/api/v1alpha1/zitadelcluster_types.go b/api/v1alpha1/cluster_types.go similarity index 52% rename from src/api/v1alpha1/zitadelcluster_types.go rename to api/v1alpha1/cluster_types.go index c9feff1..9565574 100644 --- a/src/api/v1alpha1/zitadelcluster_types.go +++ b/api/v1alpha1/cluster_types.go @@ -22,18 +22,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - +// Image defines the container image name and tag. type Image struct { Name string `json:"name"` Tag string `json:"tag"` } +// Password holds a reference to a Kubernetes Secret key containing a password. type Password struct { SecretKeyRef corev1.SecretKeySelector `json:"secretRef"` } +// SMTPConfig configures an SMTP provider. type SMTPConfig struct { SenderAddress string `json:"senderAddress"` SenderName string `json:"senderName"` @@ -45,6 +45,7 @@ type SMTPConfig struct { ReplyToAddress *string `json:"replyToAddress,omitempty"` } +// DomainSettings configures domain-related behaviour. type DomainSettings struct { // +kubebuilder:default=true UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"` @@ -54,60 +55,65 @@ type DomainSettings struct { SMTPSenderAddressMatchesInstanceDomain bool `json:"smtpSenderAddressMatchesInstanceDomain"` } -// ZitadelClusterSpec defines the desired state of ZitadelCluster -type ZitadelClusterSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +kubebuilder:default="DEFAULT" - FirstOrgName string `json:"firstOrgName"` - DomainSettings DomainSettings `json:"domainSettings"` - SMTPConfig SMTPConfig `json:"smtpConfig"` - Host string `json:"host"` +// ClusterSpec defines the desired state of Cluster. +type ClusterSpec struct { + // Host is the external hostname used to reach Zitadel. + Host string `json:"host"` + + // ExternalPort is the port exposed externally. // +kubebuilder:default=443 ExternalPort int64 `json:"externalPort"` + + // ExternalSecure indicates whether TLS is used on the external endpoint. // +kubebuilder:default=true - ExternalSecure bool `json:"externalSecure"` - Image Image `json:"image"` - Resources corev1.ResourceRequirements `json:"resources"` - PostgreSQLClusterRef PostgreSQLClusterRef `json:"postgresClusterRef"` - // +kubebuilder:validation:Enum=demo;trial;staging;productive;testing - Purpose string `json:"purpose"` - // PodAnnotations to add to the Pods metadata. + ExternalSecure bool `json:"externalSecure"` + + // Image is the Zitadel container image to deploy. + Image Image `json:"image"` + + // Resources defines compute resource requests and limits for the Zitadel pods. + Resources corev1.ResourceRequirements `json:"resources"` + + // PostgreSQLClusterRef references the backing PostgreSQL cluster. + PostgreSQLClusterRef PostgreSQLClusterRef `json:"postgresClusterRef"` + + // Replicas is the desired number of Zitadel pods. + // +kubebuilder:default=3 + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podCount"} + Replicas int32 `json:"replicas,omitempty"` + + // PodAnnotations are extra annotations added to each Zitadel Pod. // +optional // +operator-sdk:csv:customresourcedefinitions:type=spec PodAnnotations map[string]string `json:"podAnnotations,omitempty"` - // ServiceAnnotations to add to the service metadata. + + // ServiceAnnotations are extra annotations added to the Zitadel Service. // +optional // +operator-sdk:csv:customresourcedefinitions:type=spec ServiceAnnotations map[string]string `json:"serviceAnnotations,omitempty"` - // +kubebuilder:default=3 - // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podCount"} - Replicas int32 `json:"replicas,omitempty"` } -// ZitadelClusterStatus defines the observed state of ZitadelCluster -type ZitadelClusterStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file +// ClusterStatus defines the observed state of Cluster. +type ClusterStatus struct { + // Conditions store the status conditions of the Cluster. Conditions []metav1.Condition `json:"conditions,omitempty"` + + // Replicas is the current number of running Zitadel pods. // +kubebuilder:default=3 - // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podCount"} + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podCount"} Replicas int32 `json:"replicas,omitempty"` - // +kubebuilder:default="" - DefaultInstanceId string `json:"defaultInstanceId"` - // +kubebuilder:default="" - SMTPProviderId string `json:"smtpProviderId"` } -// SetCondition sets a status condition -func (s *ZitadelClusterStatus) SetCondition(condition metav1.Condition) { +// SetCondition sets a status condition on the Cluster. +func (s *ClusterStatus) SetCondition(condition metav1.Condition) { if s.Conditions == nil { s.Conditions = make([]metav1.Condition, 0) } meta.SetStatusCondition(&s.Conditions, condition) } -func (s *ZitadelClusterStatus) IsReady() bool { +// IsReady returns true when the cluster has reached the Ready condition. +func (s *ClusterStatus) IsReady() bool { for _, c := range s.Conditions { if c.Type == ConditionTypeReady && c.Status == metav1.ConditionTrue { return true @@ -116,35 +122,40 @@ func (s *ZitadelClusterStatus) IsReady() bool { return false } -func (s *ZitadelClusterStatus) FillWithDefaults(zitadel *ZitadelCluster) { - //(Haim ;^D ): No defaults yet +// FillWithDefaults populates default values on the Cluster status. +func (s *ClusterStatus) FillWithDefaults(_ *Cluster) { + // (Haim ;^D): No defaults yet } //+kubebuilder:object:root=true //+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=`.status.replicas` +//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status` +//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` -// ZitadelCluster is the Schema for the zitadelclusters API -type ZitadelCluster struct { +// Cluster is the Schema for the clusters API. +type Cluster struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec ZitadelClusterSpec `json:"spec,omitempty"` - Status ZitadelClusterStatus `json:"status,omitempty"` + Spec ClusterSpec `json:"spec,omitempty"` + Status ClusterStatus `json:"status,omitempty"` } -func (m *ZitadelCluster) SetDefaults() { - //(Haim ;^D ): No defaults yet +// SetDefaults populates default values on the Cluster spec. +func (m *Cluster) SetDefaults() { + // (Haim ;^D): No defaults yet } //+kubebuilder:object:root=true -// ZitadelClusterList contains a list of ZitadelCluster -type ZitadelClusterList struct { +// ClusterList contains a list of Cluster. +type ClusterList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []ZitadelCluster `json:"items"` + Items []Cluster `json:"items"` } func init() { - SchemeBuilder.Register(&ZitadelCluster{}, &ZitadelClusterList{}) + SchemeBuilder.Register(&Cluster{}, &ClusterList{}) } diff --git a/src/api/v1alpha1/condition_types.go b/api/v1alpha1/condition_types.go similarity index 100% rename from src/api/v1alpha1/condition_types.go rename to api/v1alpha1/condition_types.go diff --git a/src/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go similarity index 89% rename from src/api/v1alpha1/groupversion_info.go rename to api/v1alpha1/groupversion_info.go index a865d67..003c6a1 100644 --- a/src/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -16,7 +16,7 @@ limitations under the License. // Package v1alpha1 contains API Schema definitions for the zitadel v1alpha1 API group // +kubebuilder:object:generate=true -// +groupName=zitadel.topmanage.com +// +groupName=zitadel.github.com package v1alpha1 import ( @@ -26,7 +26,7 @@ import ( var ( // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "zitadel.topmanage.com", Version: "v1alpha1"} + GroupVersion = schema.GroupVersion{Group: "zitadel.github.com", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1alpha1/instance_types.go b/api/v1alpha1/instance_types.go new file mode 100644 index 0000000..82a4cee --- /dev/null +++ b/api/v1alpha1/instance_types.go @@ -0,0 +1,180 @@ +/* +Copyright 2024. + +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 v1alpha1 + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AccessTokenType defines the token format issued to the machine user. +// +kubebuilder:validation:Enum=ACCESS_TOKEN_TYPE_BEARER;ACCESS_TOKEN_TYPE_JWT +type AccessTokenType string + +const ( + AccessTokenTypeBearer AccessTokenType = "ACCESS_TOKEN_TYPE_BEARER" + AccessTokenTypeJWT AccessTokenType = "ACCESS_TOKEN_TYPE_JWT" +) + +// FirstOrg defines the first organisation and its IAM_OWNER machine user. +type FirstOrg struct { + // Name of the first organization. + // +kubebuilder:default="DEFAULT" + Name string `json:"name"` +} + +type LoginUIImage struct { + // +kubebuilder:default="ghcr.io/zitadel/zitadel-login" + Name string `json:"name"` + // if empty it uses the same tag as zitadel cluster + Tag *string `json:"tag,omitempty"` +} + +type LoginUI struct { + Image LoginUIImage `json:"image"` + + Resources corev1.ResourceRequirements `json:"resources"` +} + +// InstanceSpec defines the desired state of Instance. +// Fields map directly to POST /instances/_create (CreateInstance) in the Zitadel System API. +type InstanceSpec struct { + // ClusterRef references the Cluster this instance will be provisioned on. + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec + ClusterRef ClusterRef `json:"clusterRef"` + + // InstanceName is the display name of the Zitadel instance. + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec + InstanceName string `json:"instanceName"` + + // DefaultLanguage is the BCP-47 language tag used as the instance default (e.g. "en"). + // +kubebuilder:default="en" + // +operator-sdk:csv:customresourcedefinitions:type=spec + DefaultLanguage string `json:"defaultLanguage,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + CustomDomain string `json:"customDomain"` + + // Org configures the first organisation and its initial IAM_OWNER machine user. + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec + Org FirstOrg `json:"org"` + + // +kubebuilder:default={image: {name: "ghcr.io/zitadel/zitadel-login"}, resources: {}} + // +operator-sdk:csv:customresourcedefinitions:type=spec + LoginUI LoginUI `json:"loginUI"` +} + +// InstanceStatus defines the observed state of Instance. +type InstanceStatus struct { + // Conditions store the status conditions of the Instance. + // +operator-sdk:csv:customresourcedefinitions:type=status + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // InstanceId is the instance ID returned by Zitadel after successful provisioning. + InstanceId *string `json:"instanceId,omitempty"` +} + +// SetCondition sets a status condition on the Instance. +func (s *InstanceStatus) SetCondition(condition metav1.Condition) { + if s.Conditions == nil { + s.Conditions = make([]metav1.Condition, 0) + } + meta.SetStatusCondition(&s.Conditions, condition) +} + +// IsReady returns true when the instance has reached the Ready condition. +func (s *Instance) IsReady() bool { + return meta.IsStatusConditionTrue(s.Status.Conditions, ConditionTypeReady) +} + +func (d *Instance) IsBeingDeleted() bool { + return !d.DeletionTimestamp.IsZero() +} + +func (s *Instance) ClusterRef(_ context.Context, _ *RefResolver) (*ClusterRef, error) { + return &s.Spec.ClusterRef, nil +} + +// FillWithDefaults populates default values on the Instance status. +func (s *InstanceStatus) FillWithDefaults(_ *Instance) { + // (Haim ;^D): No defaults yet +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Instance",type=string,JSONPath=`.spec.instanceName` +//+kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=`.spec.clusterRef.name` +//+kubebuilder:printcolumn:name="Domain",type=string,JSONPath=`.spec.customDomain` +//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status` +//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` + +// Instance is the Schema for the instances API. +type Instance struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec InstanceSpec `json:"spec,omitempty"` + Status InstanceStatus `json:"status,omitempty"` +} + +// SetDefaults populates default values on the Instance spec. +func (m *Instance) SetDefaults() { + // (Haim ;^D): No defaults yet +} + +func (m *Instance) MachineUserName() string { + return "k8s-operator" +} + +func (m *Instance) MachineName() string { + return "K8S OPERATOR" +} + +func (m *Instance) MachineSecretName() string { + return m.Name + "-owner-machine-secret" +} + +func (m *Instance) LoginMachineUserName() string { + return m.Name + "-login-ui" +} + +func (m *Instance) FirstOrgObjectName() string { + return m.Name + "-" + m.Spec.Org.Name +} + +func (m *Instance) ConnectionObjectName() string { + return m.Name + "-connection" +} + +//+kubebuilder:object:root=true + +// InstanceList contains a list of Instance. +type InstanceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Instance `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Instance{}, &InstanceList{}) +} diff --git a/api/v1alpha1/ref_types.go b/api/v1alpha1/ref_types.go new file mode 100644 index 0000000..652031f --- /dev/null +++ b/api/v1alpha1/ref_types.go @@ -0,0 +1,23 @@ +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" +) + +type PostgreSQLClusterRef struct { + // ObjectReference is a reference to a object. + // +operator-sdk:csv:customresourcedefinitions:type=spec + corev1.ObjectReference `json:",inline"` +} + +type InstanceRef struct { + // ObjectReference is a reference to a object. + // +operator-sdk:csv:customresourcedefinitions:type=spec + corev1.ObjectReference `json:",inline"` +} + +type ClusterRef struct { + // ObjectReference is a reference to a object. + // +operator-sdk:csv:customresourcedefinitions:type=spec + corev1.ObjectReference `json:",inline"` +} diff --git a/src/api/v1alpha1/refresolver.go b/api/v1alpha1/refresolver.go similarity index 52% rename from src/api/v1alpha1/refresolver.go rename to api/v1alpha1/refresolver.go index c13d711..4e53adb 100644 --- a/src/api/v1alpha1/refresolver.go +++ b/api/v1alpha1/refresolver.go @@ -22,9 +22,9 @@ func NewRefResolver(client client.Client) *RefResolver { } } -func (r *RefResolver) ZitadelCluster(ctx context.Context, ref *ZitadelClusterRef, - namespace string) (*ZitadelCluster, error) { - if ref.Kind != "" && ref.Kind != "ZitadelCluster" { +func (r *RefResolver) Instance(ctx context.Context, ref *InstanceRef, + namespace string) (*Instance, error) { + if ref.Kind != "" && ref.Kind != "Instance" { return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) } @@ -36,16 +36,16 @@ func (r *RefResolver) ZitadelCluster(ctx context.Context, ref *ZitadelClusterRef key.Namespace = ref.Namespace } - var zitadel ZitadelCluster + var zitadel Instance if err := r.client.Get(ctx, key, &zitadel); err != nil { return nil, err } return &zitadel, nil } -func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef, - namespace string) (*OIDCApp, error) { - if ref.Kind != "" && ref.Kind != "OIDCApp" { +func (r *RefResolver) Cluster(ctx context.Context, ref *ClusterRef, + namespace string) (*Cluster, error) { + if ref.Kind != "" && ref.Kind != "Cluster" { return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) } @@ -57,70 +57,7 @@ func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef, key.Namespace = ref.Namespace } - var zitadel OIDCApp - if err := r.client.Get(ctx, key, &zitadel); err != nil { - return nil, err - } - return &zitadel, nil -} - -func (r *RefResolver) ActionRef(ctx context.Context, ref *ActionRef, - namespace string) (*Action, error) { - if ref.Kind != "" && ref.Kind != "Action" { - return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) - } - - key := types.NamespacedName{ - Name: ref.Name, - Namespace: namespace, - } - if ref.Namespace != "" { - key.Namespace = ref.Namespace - } - - var zitadel Action - if err := r.client.Get(ctx, key, &zitadel); err != nil { - return nil, err - } - return &zitadel, nil -} - -func (r *RefResolver) ProjectRef(ctx context.Context, ref *ProjectRef, - namespace string) (*Project, error) { - if ref.Kind != "" && ref.Kind != "Project" { - return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) - } - - key := types.NamespacedName{ - Name: ref.Name, - Namespace: namespace, - } - if ref.Namespace != "" { - key.Namespace = ref.Namespace - } - - var zitadel Project - if err := r.client.Get(ctx, key, &zitadel); err != nil { - return nil, err - } - return &zitadel, nil -} - -func (r *RefResolver) OrganizationRef(ctx context.Context, ref *OrganizationRef, - namespace string) (*Organization, error) { - if ref.Kind != "" && ref.Kind != "Organization" { - return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) - } - - key := types.NamespacedName{ - Name: ref.Name, - Namespace: namespace, - } - if ref.Namespace != "" { - key.Namespace = ref.Namespace - } - - var zitadel Organization + var zitadel Cluster if err := r.client.Get(ctx, key, &zitadel); err != nil { return nil, err } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..12cc9cb --- /dev/null +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,419 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2024. + +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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Cluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterList) DeepCopyInto(out *ClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Cluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList. +func (in *ClusterList) DeepCopy() *ClusterList { + if in == nil { + return nil + } + out := new(ClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterRef) DeepCopyInto(out *ClusterRef) { + *out = *in + out.ObjectReference = in.ObjectReference +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRef. +func (in *ClusterRef) DeepCopy() *ClusterRef { + if in == nil { + return nil + } + out := new(ClusterRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { + *out = *in + out.Image = in.Image + in.Resources.DeepCopyInto(&out.Resources) + out.PostgreSQLClusterRef = in.PostgreSQLClusterRef + if in.PodAnnotations != nil { + in, out := &in.PodAnnotations, &out.PodAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ServiceAnnotations != nil { + in, out := &in.ServiceAnnotations, &out.ServiceAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. +func (in *ClusterSpec) DeepCopy() *ClusterSpec { + if in == nil { + return nil + } + out := new(ClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. +func (in *ClusterStatus) DeepCopy() *ClusterStatus { + if in == nil { + return nil + } + out := new(ClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DomainSettings) DeepCopyInto(out *DomainSettings) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainSettings. +func (in *DomainSettings) DeepCopy() *DomainSettings { + if in == nil { + return nil + } + out := new(DomainSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FirstOrg) DeepCopyInto(out *FirstOrg) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirstOrg. +func (in *FirstOrg) DeepCopy() *FirstOrg { + if in == nil { + return nil + } + out := new(FirstOrg) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Image) DeepCopyInto(out *Image) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. +func (in *Image) DeepCopy() *Image { + if in == nil { + return nil + } + out := new(Image) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance) DeepCopyInto(out *Instance) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. +func (in *Instance) DeepCopy() *Instance { + if in == nil { + return nil + } + out := new(Instance) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Instance) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceList) DeepCopyInto(out *InstanceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Instance, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceList. +func (in *InstanceList) DeepCopy() *InstanceList { + if in == nil { + return nil + } + out := new(InstanceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InstanceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceRef) DeepCopyInto(out *InstanceRef) { + *out = *in + out.ObjectReference = in.ObjectReference +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceRef. +func (in *InstanceRef) DeepCopy() *InstanceRef { + if in == nil { + return nil + } + out := new(InstanceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceSpec) DeepCopyInto(out *InstanceSpec) { + *out = *in + out.ClusterRef = in.ClusterRef + out.Org = in.Org + in.LoginUI.DeepCopyInto(&out.LoginUI) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceSpec. +func (in *InstanceSpec) DeepCopy() *InstanceSpec { + if in == nil { + return nil + } + out := new(InstanceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceStatus) DeepCopyInto(out *InstanceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.InstanceId != nil { + in, out := &in.InstanceId, &out.InstanceId + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceStatus. +func (in *InstanceStatus) DeepCopy() *InstanceStatus { + if in == nil { + return nil + } + out := new(InstanceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoginUI) DeepCopyInto(out *LoginUI) { + *out = *in + in.Image.DeepCopyInto(&out.Image) + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginUI. +func (in *LoginUI) DeepCopy() *LoginUI { + if in == nil { + return nil + } + out := new(LoginUI) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoginUIImage) DeepCopyInto(out *LoginUIImage) { + *out = *in + if in.Tag != nil { + in, out := &in.Tag, &out.Tag + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginUIImage. +func (in *LoginUIImage) DeepCopy() *LoginUIImage { + if in == nil { + return nil + } + out := new(LoginUIImage) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Password) DeepCopyInto(out *Password) { + *out = *in + in.SecretKeyRef.DeepCopyInto(&out.SecretKeyRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Password. +func (in *Password) DeepCopy() *Password { + if in == nil { + return nil + } + out := new(Password) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PostgreSQLClusterRef) DeepCopyInto(out *PostgreSQLClusterRef) { + *out = *in + out.ObjectReference = in.ObjectReference +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgreSQLClusterRef. +func (in *PostgreSQLClusterRef) DeepCopy() *PostgreSQLClusterRef { + if in == nil { + return nil + } + out := new(PostgreSQLClusterRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SMTPConfig) DeepCopyInto(out *SMTPConfig) { + *out = *in + if in.User != nil { + in, out := &in.User, &out.User + *out = new(string) + **out = **in + } + if in.Password != nil { + in, out := &in.Password, &out.Password + *out = new(Password) + (*in).DeepCopyInto(*out) + } + if in.ReplyToAddress != nil { + in, out := &in.ReplyToAddress, &out.ReplyToAddress + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SMTPConfig. +func (in *SMTPConfig) DeepCopy() *SMTPConfig { + if in == nil { + return nil + } + out := new(SMTPConfig) + in.DeepCopyInto(out) + return out +} diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml deleted file mode 100644 index 509734b..0000000 --- a/bitbucket-pipelines.yml +++ /dev/null @@ -1,183 +0,0 @@ -definitions: - steps: - - step: &test - name: "Test" - runs-on: - - "linux" - - "self.hosted" - script: - - echo please create tests - - - step: &build - name: "Build" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - script: - - mkdir -p images - - (umask 077 ; echo -n $SSHKEY | base64 -d > ./id_rsa) - - nix build --print-build-logs ./build/#dockerImage - - cp $(readlink ./result) images/ - artifacts: - - images/* - - - step: &package-dev - name: "Package Chart for Dev" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - script: - - mkdir -p charts - - export VERSION="$BITBUCKET_BUILD_NUMBER" - - export REPOSITORY="$K8S_ARES_DEV_DOCKERREGISTRY_URL/$BITBUCKET_REPO_SLUG" - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.tag = env(VERSION)" ./ops/chart/values.yaml' - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.repository = env(REPOSITORY)" ./ops/chart/values.yaml' - - nix-shell -p kubernetes-helm --run 'helm repo add base "$K8S_ARES_DEV_CHARTMUSEUM_ENDPOINT" --username "$K8S_ARES_DEV_CHARTMUSEUM_USERNAME" --password "$K8S_ARES_DEV_CHARTMUSEUM_PASSWORD" --insecure-skip-tls-verify --force-update && helm dependency build ./ops/chart && helm package ./ops/chart -d result --app-version "$VERSION" --version "$VERSION"' - - cp -a ./result/. charts/ - artifacts: - - charts/* - - - step: &package-qa - name: "Package Chart for QA" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - script: - - mkdir -p charts - - export VERSION="$BITBUCKET_BUILD_NUMBER" - - export REPOSITORY="$K8S_ARES_QA_DOCKERREGISTRY_URL/$BITBUCKET_REPO_SLUG" - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.tag = env(VERSION)" ./ops/chart/values.yaml' - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.repository = env(REPOSITORY)" ./ops/chart/values.yaml' - - nix-shell -p kubernetes-helm --run 'helm repo add base "$K8S_ARES_QA_CHARTMUSEUM_ENDPOINT" --username "$K8S_ARES_QA_CHARTMUSEUM_USERNAME" --password "$K8S_ARES_QA_CHARTMUSEUM_PASSWORD" --insecure-skip-tls-verify --force-update && helm dependency build ./ops/chart && helm package ./ops/chart -d result --app-version "$VERSION" --version "$VERSION"' - - cp -a ./result/. charts/ - artifacts: - - charts/* - - - step: &publish-dev - name: "Publish Chart to Dev" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - deployment: dev - script: - - | - nix-shell -p cacert curl --run 'curl -k --fail --data-binary "@charts/$(ls charts | tee /dev/stderr | head -n 1)" -u "$K8S_ARES_DEV_CHARTMUSEUM_USERNAME:$K8S_ARES_DEV_CHARTMUSEUM_PASSWORD" "$K8S_ARES_DEV_CHARTMUSEUM_ENDPOINT/api/charts"' - - - step: &push-dev - name: "Push image to Dev" - image: topmanage/deployment-pipeline-image:28 - runs-on: - - "linux" - - "self.hosted" - # deployment: dev - script: - - | - set -euo pipefail - DOCKERREGISTRY_URL=$K8S_ARES_DEV_DOCKERREGISTRY_URL \ - DOCKERREGISTRY_CACERT=$K8S_ARES_DEV_DOCKERREGISTRY_CACERT \ - DOCKERREGISTRY_CLIENTCERT=$K8S_ARES_DEV_DOCKERREGISTRY_CLIENTCERT \ - DOCKERREGISTRY_CLIENTKEY=$K8S_ARES_DEV_DOCKERREGISTRY_CLIENTKEY \ - DOCKERREGISTRY_PASSWORD=$K8S_ARES_DEV_DOCKERREGISTRY_PASSWORD \ - ./build/push-image.sh - - - step: &publish-qa - name: "Publish Chart to QA" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - deployment: qa - script: - - | - nix-shell -p cacert curl --run 'curl -k --fail --data-binary "@charts/$(ls charts | tee /dev/stderr | head -n 1)" -u "$K8S_ARES_QA_CHARTMUSEUM_USERNAME:$K8S_ARES_QA_CHARTMUSEUM_PASSWORD" "$K8S_ARES_QA_CHARTMUSEUM_ENDPOINT/api/charts"' - - - step: &push-qa - name: "Push image to QA" - image: topmanage/deployment-pipeline-image:28 - runs-on: - - "linux" - - "self.hosted" - # deployment: qa - script: - - | - set -euo pipefail - DOCKERREGISTRY_URL=$K8S_ARES_QA_DOCKERREGISTRY_URL \ - DOCKERREGISTRY_CACERT=$K8S_ARES_QA_DOCKERREGISTRY_CACERT \ - DOCKERREGISTRY_CLIENTCERT=$K8S_ARES_QA_DOCKERREGISTRY_CLIENTCERT \ - DOCKERREGISTRY_CLIENTKEY=$K8S_ARES_QA_DOCKERREGISTRY_CLIENTKEY \ - DOCKERREGISTRY_PASSWORD=$K8S_ARES_QA_DOCKERREGISTRY_PASSWORD \ - ./build/push-image.sh - - - step: &package-prod - name: "Package Chart for Production" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - script: - - mkdir -p charts - - export VERSION="$BITBUCKET_BUILD_NUMBER" - - export REPOSITORY="$K8S_ARES_PROD_DOCKERREGISTRY_URL/$BITBUCKET_REPO_SLUG" - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.tag = env(VERSION)" ./ops/chart/values.yaml' - - nix-shell -p yq-go --run 'yq -i ".controllerManager.manager.image.repository = env(REPOSITORY)" ./ops/chart/values.yaml' - - nix-shell -p kubernetes-helm --run 'helm repo add base "$K8S_ARES_PROD_CHARTMUSEUM_ENDPOINT" --username "$K8S_ARES_PROD_CHARTMUSEUM_USERNAME" --password "$K8S_ARES_PROD_CHARTMUSEUM_PASSWORD" --insecure-skip-tls-verify --force-update && helm dependency build ./ops/chart && helm package ./ops/chart -d result --app-version "$VERSION" --version "$VERSION"' - - cp -a ./result/. charts/ - artifacts: - - charts/* - - - step: &publish-prod - name: "Publish Chart to Production" - runs-on: - - "nixrunner" - - "linux.shell" - - "self.hosted" - deployment: prod - script: - - | - nix-shell -p cacert curl --run 'curl -k --fail --data-binary "@charts/$(ls charts | tee /dev/stderr | head -n 1)" -u "$K8S_ARES_PROD_CHARTMUSEUM_USERNAME:$K8S_ARES_PROD_CHARTMUSEUM_PASSWORD" "$K8S_ARES_PROD_CHARTMUSEUM_ENDPOINT/api/charts"' - - - step: &push-prod - name: "Push image to Production" - image: topmanage/deployment-pipeline-image:28 - runs-on: - - "linux" - - "self.hosted" - # deployment: prod - script: - - | - set -euo pipefail - DOCKERREGISTRY_URL=$K8S_ARES_PROD_DOCKERREGISTRY_URL \ - DOCKERREGISTRY_CACERT=$K8S_ARES_PROD_DOCKERREGISTRY_CACERT \ - DOCKERREGISTRY_CLIENTCERT=$K8S_ARES_PROD_DOCKERREGISTRY_CLIENTCERT \ - DOCKERREGISTRY_CLIENTKEY=$K8S_ARES_PROD_DOCKERREGISTRY_CLIENTKEY \ - DOCKERREGISTRY_PASSWORD=$K8S_ARES_PROD_DOCKERREGISTRY_PASSWORD \ - ./build/push-image.sh - -pipelines: - default: - - parallel: - - step: *build - - step: *test - - step: *package-dev - - step: *push-dev - - step: *publish-dev - branches: - master: - - parallel: - - step: *build - - step: *test - - step: *package-qa - - step: *push-qa - - step: *publish-qa - tags: - release-*: - - parallel: - - step: *build - - step: *test - - step: *package-prod - - step: *push-prod - - step: *publish-prod diff --git a/build/flake.lock b/build/flake.lock index abf6f02..86d6c6e 100644 --- a/build/flake.lock +++ b/build/flake.lock @@ -18,18 +18,6 @@ "type": "github" } }, - "nixpkgs": { - "locked": { - "lastModified": 0, - "narHash": "sha256-7Fu7oazPoYCbDzb9k8D/DdbKrC3aU1zlnc39Y8jy/s8=", - "path": "/nix/store/m4wcdchjxw2fdyzjp8i6irpc613pchkr-source", - "type": "path" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, "nixpkgs-unstable": { "locked": { "lastModified": 1743448293, @@ -48,7 +36,6 @@ "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", "nixpkgs-unstable": "nixpkgs-unstable" } }, diff --git a/build/flake.nix b/build/flake.nix index c43b68b..4f98052 100644 --- a/build/flake.nix +++ b/build/flake.nix @@ -6,17 +6,16 @@ nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; }; - outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils }: + outputs = { self, nixpkgs-unstable, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let - unstable = nixpkgs-unstable.legacyPackages.${system}; - pkgs = nixpkgs.legacyPackages.${system}; - package = unstable.buildGoModule { + pkgs = nixpkgs-unstable.legacyPackages.${system}; + package = pkgs.buildGoModule { pname = "zitadel-k8s-operator"; version = "0.0.0"; - src = ../src; + src = ../.; doCheck = false; - vendorHash = "sha256-HEXIHASdDC7chG9uF56f6pvZPVbxYs/fWFytDz6CAf4="; + vendorHash = "sha256-HEXIHASdDC7chG9uF56frpvZPVbxYs/fWFytDz6CAf4="; installPhase = '' runHook preInstall @@ -45,8 +44,7 @@ in with pkgs; { packages.default = package; packages.dockerImage = dockerPackage; - devShells.default = mkShell { - buildInputs = [ nixfmt unstable.gopls operator-sdk unstable.go ]; - }; + devShells.default = + mkShell { buildInputs = [ nixfmt gopls operator-sdk go ]; }; }); } diff --git a/src/cmd/main.go b/cmd/main.go similarity index 63% rename from src/cmd/main.go rename to cmd/main.go index 0c8550f..adc0f06 100644 --- a/src/cmd/main.go +++ b/cmd/main.go @@ -21,6 +21,8 @@ import ( "os" "time" + // "time" + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. "k8s.io/apimachinery/pkg/runtime" @@ -32,14 +34,17 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" server "sigs.k8s.io/controller-runtime/pkg/metrics/server" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/internal/controller" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - conditions "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/configmap" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/secret" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/service" cloudnativepgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/internal/controller" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder" + conditions "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/configmap" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/secret" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/service" + zitadelresourcesv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-resources-operator/api/v1alpha1" //+kubebuilder:scaffold:imports ) @@ -51,6 +56,7 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(cloudnativepgv1.AddToScheme(scheme)) + utilruntime.Must(zitadelresourcesv1alpha1.AddToScheme(scheme)) utilruntime.Must(zitadelv1alpha1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -77,7 +83,7 @@ func main() { Metrics: server.Options{BindAddress: metricsAddr}, HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, - LeaderElectionID: "88a0b43c.topmanage.com", + LeaderElectionID: "88a0b43c.github.com", // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // when the Manager ends. This requires the binary to immediately end when the // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly @@ -103,7 +109,7 @@ func main() { refResolver := zitadelv1alpha1.NewRefResolver(client) conditionReady := conditions.NewReady() requeueZitadel := 5 * time.Minute - if err = (&controller.ZitadelClusterReconciler{ + if err = (&controller.ClusterReconciler{ Client: client, Scheme: scheme, ConditionReady: conditionReady, @@ -116,35 +122,41 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "ZitadelCluster") os.Exit(1) } - if err = controller.NewOrganizationReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Organization") + + if err = controller.NewInstanceReconciler(client, refResolver, builder, conditionReady, serviceReconciler, requeueZitadel).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Instance") os.Exit(1) } - if err = controller.NewProjectReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Project") - os.Exit(1) - } - if err = controller.NewOIDCAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "OIDCApp") - os.Exit(1) - } - if err = controller.NewMachineUserReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "MachineUser") - os.Exit(1) - } - if err = controller.NewAPIAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "APIApp") - os.Exit(1) - } - if err = controller.NewActionReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Action") - os.Exit(1) - } - if err = controller.NewFlowReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Flow") - os.Exit(1) - } + // if err = controller.NewOrganizationReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "Organization") + // os.Exit(1) + // } + + // if err = controller.NewProjectReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "Project") + // os.Exit(1) + // } + // if err = controller.NewOIDCAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "OIDCApp") + // os.Exit(1) + // } + // if err = controller.NewMachineUserReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "MachineUser") + // os.Exit(1) + // } + // if err = controller.NewAPIAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "APIApp") + // os.Exit(1) + // } + // if err = controller.NewActionReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "Action") + // os.Exit(1) + // } + // if err = controller.NewFlowReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "Flow") + // os.Exit(1) + // } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/src/config/crd/bases/zitadel.topmanage.com_zitadelclusters.yaml b/config/crd/bases/zitadel.github.com_clusters.yaml similarity index 71% rename from src/config/crd/bases/zitadel.topmanage.com_zitadelclusters.yaml rename to config/crd/bases/zitadel.github.com_clusters.yaml index 9804c7a..81b1733 100644 --- a/src/config/crd/bases/zitadel.topmanage.com_zitadelclusters.yaml +++ b/config/crd/bases/zitadel.github.com_clusters.yaml @@ -4,20 +4,30 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.17.3 - name: zitadelclusters.zitadel.topmanage.com + name: clusters.zitadel.github.com spec: - group: zitadel.topmanage.com + group: zitadel.github.com names: - kind: ZitadelCluster - listKind: ZitadelClusterList - plural: zitadelclusters - singular: zitadelcluster + kind: Cluster + listKind: ClusterList + plural: clusters + singular: cluster scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .status.replicas + name: Replicas + type: integer + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 schema: openAPIV3Schema: - description: ZitadelCluster is the Schema for the zitadelclusters API + description: Cluster is the Schema for the clusters API. properties: apiVersion: description: |- @@ -37,40 +47,23 @@ spec: metadata: type: object spec: - description: ZitadelClusterSpec defines the desired state of ZitadelCluster + description: ClusterSpec defines the desired state of Cluster. properties: - domainSettings: - properties: - smtpSenderAddressMatchesInstanceDomain: - default: true - type: boolean - userLoginMustBeDomain: - default: true - type: boolean - validateOrgDomains: - default: true - type: boolean - required: - - smtpSenderAddressMatchesInstanceDomain - - userLoginMustBeDomain - - validateOrgDomains - type: object externalPort: default: 443 + description: ExternalPort is the port exposed externally. format: int64 type: integer externalSecure: default: true + description: ExternalSecure indicates whether TLS is used on the external + endpoint. type: boolean - firstOrgName: - default: DEFAULT - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - type: string host: + description: Host is the external hostname used to reach Zitadel. type: string image: + description: Image is the Zitadel container image to deploy. properties: name: type: string @@ -83,9 +76,12 @@ spec: podAnnotations: additionalProperties: type: string - description: PodAnnotations to add to the Pods metadata. + description: PodAnnotations are extra annotations added to each Zitadel + Pod. type: object postgresClusterRef: + description: PostgreSQLClusterRef references the backing PostgreSQL + cluster. properties: apiVersion: description: API version of the referent. @@ -127,20 +123,14 @@ spec: type: string type: object x-kubernetes-map-type: atomic - purpose: - enum: - - demo - - trial - - staging - - productive - - testing - type: string replicas: default: 3 + description: Replicas is the desired number of Zitadel pods. format: int32 type: integer resources: - description: ResourceRequirements describes the compute resource requirements. + description: Resources defines compute resource requests and limits + for the Zitadel pods. properties: claims: description: |- @@ -201,77 +191,22 @@ spec: serviceAnnotations: additionalProperties: type: string - description: ServiceAnnotations to add to the service metadata. - type: object - smtpConfig: - properties: - host: - type: string - password: - properties: - secretRef: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - secretRef - type: object - replyToAddress: - type: string - senderAddress: - type: string - senderName: - type: string - tls: - default: true - type: boolean - user: - type: string - required: - - host - - senderAddress - - senderName - - tls + description: ServiceAnnotations are extra annotations added to the + Zitadel Service. type: object required: - - domainSettings - externalPort - externalSecure - - firstOrgName - host - image - postgresClusterRef - - purpose - resources - - smtpConfig type: object status: - description: ZitadelClusterStatus defines the observed state of ZitadelCluster + description: ClusterStatus defines the observed state of Cluster. properties: conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file + description: Conditions store the status conditions of the Cluster. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -327,19 +262,11 @@ spec: - type type: object type: array - defaultInstanceId: - default: "" - type: string replicas: default: 3 + description: Replicas is the current number of running Zitadel pods. format: int32 type: integer - smtpProviderId: - default: "" - type: string - required: - - defaultInstanceId - - smtpProviderId type: object type: object served: true diff --git a/src/config/crd/bases/zitadel.topmanage.com_machineusers.yaml b/config/crd/bases/zitadel.github.com_instances.yaml similarity index 52% rename from src/config/crd/bases/zitadel.topmanage.com_machineusers.yaml rename to config/crd/bases/zitadel.github.com_instances.yaml index 409d39a..9197793 100644 --- a/src/config/crd/bases/zitadel.topmanage.com_machineusers.yaml +++ b/config/crd/bases/zitadel.github.com_instances.yaml @@ -4,20 +4,36 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.17.3 - name: machineusers.zitadel.topmanage.com + name: instances.zitadel.github.com spec: - group: zitadel.topmanage.com + group: zitadel.github.com names: - kind: MachineUser - listKind: MachineUserList - plural: machineusers - singular: machineuser + kind: Instance + listKind: InstanceList + plural: instances + singular: instance scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.instanceName + name: Instance + type: string + - jsonPath: .spec.clusterRef.name + name: Cluster + type: string + - jsonPath: .spec.customDomain + name: Domain + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 schema: openAPIV3Schema: - description: MachineUser is the Schema for the machineusers API + description: Instance is the Schema for the instances API. properties: apiVersion: description: |- @@ -37,17 +53,13 @@ spec: metadata: type: object spec: - description: MachineUserSpec defines the desired state of MachineUser + description: |- + InstanceSpec defines the desired state of Instance. + Fields map directly to POST /instances/_create (CreateInstance) in the Zitadel System API. properties: - accessTokenType: - enum: - - ACCESS_TOKEN_TYPE_BEARER - - ACCESS_TOKEN_TYPE_JWT - type: string - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file + clusterRef: + description: ClusterRef references the Cluster this instance will + be provisioned on. properties: apiVersion: description: API version of the referent. @@ -89,70 +101,120 @@ spec: type: string type: object x-kubernetes-map-type: atomic - userGrants: - items: - properties: - projectRef: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - roleKeys: - items: + customDomain: + type: string + defaultLanguage: + default: en + description: DefaultLanguage is the BCP-47 language tag used as the + instance default (e.g. "en"). + type: string + instanceName: + description: InstanceName is the display name of the Zitadel instance. + type: string + loginUI: + default: + image: + name: ghcr.io/zitadel/zitadel-login + resources: {} + properties: + image: + properties: + name: + default: ghcr.io/zitadel/zitadel-login type: string - type: array - required: - - projectRef - type: object - type: array + tag: + description: if empty it uses the same tag as zitadel cluster + type: string + required: + - name + type: object + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + required: + - image + - resources + type: object + org: + description: Org configures the first organisation and its initial + IAM_OWNER machine user. + properties: + name: + default: DEFAULT + description: Name of the first organization. + type: string + required: + - name + type: object required: - - accessTokenType - - organizationRef + - clusterRef + - customDomain + - instanceName + - loginUI + - org type: object status: - description: MachineUserStatus defines the observed state of MachineUser + description: InstanceStatus defines the observed state of Instance. properties: conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file + description: Conditions store the status conditions of the Instance. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -208,19 +270,10 @@ spec: - type type: object type: array - keyId: - default: "" + instanceId: + description: InstanceId is the instance ID returned by Zitadel after + successful provisioning. type: string - patId: - default: "" - type: string - userId: - default: "" - type: string - required: - - keyId - - patId - - userId type: object type: object served: true diff --git a/src/config/crd/kustomization.yaml b/config/crd/kustomization.yaml similarity index 79% rename from src/config/crd/kustomization.yaml rename to config/crd/kustomization.yaml index 278c493..b9ee6c2 100644 --- a/src/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -2,14 +2,8 @@ # since it depends on service name and namespace that are out of this kustomize package. # It should be run by config/default resources: -- bases/zitadel.topmanage.com_zitadelclusters.yaml -- bases/zitadel.topmanage.com_organizations.yaml -- bases/zitadel.topmanage.com_projects.yaml -- bases/zitadel.topmanage.com_oidcapps.yaml -- bases/zitadel.topmanage.com_machineusers.yaml -- bases/zitadel.topmanage.com_apiapps.yaml -- bases/zitadel.topmanage.com_actions.yaml -- bases/zitadel.topmanage.com_flows.yaml +- bases/zitadel.github.com_clusters.yaml +- bases/zitadel.github.com_instances.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -35,6 +29,7 @@ patchesStrategicMerge: #- patches/cainjection_in_apiapps.yaml #- patches/cainjection_in_actions.yaml #- patches/cainjection_in_flows.yaml +#- path: patches/cainjection_in_connections.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/src/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml similarity index 100% rename from src/config/crd/kustomizeconfig.yaml rename to config/crd/kustomizeconfig.yaml diff --git a/src/config/default/kustomization.yaml b/config/default/kustomization.yaml similarity index 100% rename from src/config/default/kustomization.yaml rename to config/default/kustomization.yaml diff --git a/src/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml similarity index 100% rename from src/config/default/manager_auth_proxy_patch.yaml rename to config/default/manager_auth_proxy_patch.yaml diff --git a/src/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml similarity index 100% rename from src/config/default/manager_config_patch.yaml rename to config/default/manager_config_patch.yaml diff --git a/src/config/manager/kustomization.yaml b/config/manager/kustomization.yaml similarity index 100% rename from src/config/manager/kustomization.yaml rename to config/manager/kustomization.yaml diff --git a/src/config/manager/manager.yaml b/config/manager/manager.yaml similarity index 100% rename from src/config/manager/manager.yaml rename to config/manager/manager.yaml diff --git a/src/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml similarity index 100% rename from src/config/rbac/auth_proxy_client_clusterrole.yaml rename to config/rbac/auth_proxy_client_clusterrole.yaml diff --git a/src/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml similarity index 100% rename from src/config/rbac/auth_proxy_role.yaml rename to config/rbac/auth_proxy_role.yaml diff --git a/src/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml similarity index 100% rename from src/config/rbac/auth_proxy_role_binding.yaml rename to config/rbac/auth_proxy_role_binding.yaml diff --git a/src/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml similarity index 100% rename from src/config/rbac/auth_proxy_service.yaml rename to config/rbac/auth_proxy_service.yaml diff --git a/src/config/rbac/zitadelcluster_editor_role.yaml b/config/rbac/cluster_editor_role.yaml similarity index 85% rename from src/config/rbac/zitadelcluster_editor_role.yaml rename to config/rbac/cluster_editor_role.yaml index b8d3287..287dd30 100644 --- a/src/config/rbac/zitadelcluster_editor_role.yaml +++ b/config/rbac/cluster_editor_role.yaml @@ -12,9 +12,9 @@ metadata: name: zitadelcluster-editor-role rules: - apiGroups: - - zitadel.topmanage.com + - zitadel.github.com resources: - - zitadelclusters + - clusters verbs: - create - delete @@ -24,8 +24,8 @@ rules: - update - watch - apiGroups: - - zitadel.topmanage.com + - zitadel.github.com resources: - - zitadelclusters/status + - clusters/status verbs: - get diff --git a/src/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml similarity index 72% rename from src/config/rbac/kustomization.yaml rename to config/rbac/kustomization.yaml index 731832a..32e4e8d 100644 --- a/src/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -16,3 +16,8 @@ resources: - auth_proxy_role.yaml - auth_proxy_role_binding.yaml - auth_proxy_client_clusterrole.yaml +# For each CRD, "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the Project itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. + diff --git a/src/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml similarity index 100% rename from src/config/rbac/leader_election_role.yaml rename to config/rbac/leader_election_role.yaml diff --git a/src/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml similarity index 100% rename from src/config/rbac/leader_election_role_binding.yaml rename to config/rbac/leader_election_role_binding.yaml diff --git a/src/config/rbac/role.yaml b/config/rbac/role.yaml similarity index 79% rename from src/config/rbac/role.yaml rename to config/rbac/role.yaml index 7380230..64197a0 100644 --- a/src/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -127,17 +127,48 @@ rules: - list - patch - watch +- apiGroups: + - zitadel.github.com + resources: + - clusters + - connections + - instances + - machineusers + - organizations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zitadel.github.com + resources: + - clusters/finalizers + - connections/finalizers + - instances/finalizers + - machineusers/finalizers + - organizations/finalizers + verbs: + - update +- apiGroups: + - zitadel.github.com + resources: + - clusters/status + - connections/status + - instances/status + - machineusers/status + - organizations/status + verbs: + - get + - patch + - update - apiGroups: - zitadel.topmanage.com resources: - - actions - - apiapps - - flows - - machineusers - - oidcapps - - organizations - - projects - - zitadelclusters + - instances verbs: - create - delete @@ -149,27 +180,13 @@ rules: - apiGroups: - zitadel.topmanage.com resources: - - actions/finalizers - - apiapps/finalizers - - flows/finalizers - - machineusers/finalizers - - oidcapps/finalizers - - organizations/finalizers - - projects/finalizers - - zitadelclusters/finalizers + - instances/finalizers verbs: - update - apiGroups: - zitadel.topmanage.com resources: - - actions/status - - apiapps/status - - flows/status - - machineusers/status - - oidcapps/status - - organizations/status - - projects/status - - zitadelclusters/status + - instances/status verbs: - get - patch diff --git a/src/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml similarity index 100% rename from src/config/rbac/role_binding.yaml rename to config/rbac/role_binding.yaml diff --git a/src/config/rbac/service_account.yaml b/config/rbac/service_account.yaml similarity index 100% rename from src/config/rbac/service_account.yaml rename to config/rbac/service_account.yaml diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml new file mode 100644 index 0000000..3144480 --- /dev/null +++ b/config/samples/kustomization.yaml @@ -0,0 +1,4 @@ +## Append samples of your project ## +resources: +- zitadel_v1alpha1_connection.yaml +# +kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/zitadel_v1alpha1_connection.yaml b/config/samples/zitadel_v1alpha1_connection.yaml new file mode 100644 index 0000000..4b3dc58 --- /dev/null +++ b/config/samples/zitadel_v1alpha1_connection.yaml @@ -0,0 +1,9 @@ +apiVersion: zitadel.github.com/v1alpha1 +kind: Connection +metadata: + labels: + app.kubernetes.io/name: src + app.kubernetes.io/managed-by: kustomize + name: connection-sample +spec: + # TODO(user): Add fields here diff --git a/src/go.mod b/go.mod similarity index 70% rename from src/go.mod rename to go.mod index ba3394d..ae91a8c 100644 --- a/src/go.mod +++ b/go.mod @@ -1,21 +1,16 @@ -module bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src +module gitea.corredorconect.com/software-engineering/zitadel-k8s-operator -go 1.24.1 +go 1.25.8 require ( + gitea.corredorconect.com/software-engineering/zitadel-resources-operator v0.0.0-20260407173354-d5c3485fd29b github.com/cloudnative-pg/cloudnative-pg v1.25.1 - github.com/gorilla/schema v1.4.1 github.com/hashicorp/go-multierror v1.1.1 github.com/onsi/ginkgo/v2 v2.23.3 github.com/onsi/gomega v1.36.3 github.com/sethvargo/go-password v0.3.1 - github.com/zitadel/oidc v1.13.5 - github.com/zitadel/zitadel-go/v3 v3.5.0 - golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 - golang.org/x/oauth2 v0.28.0 - google.golang.org/grpc v1.71.0 - google.golang.org/protobuf v1.36.6 - gopkg.in/square/go-jose.v2 v2.6.0 + github.com/zitadel/zitadel-go/v3 v3.27.0 + google.golang.org/grpc v1.79.3 k8s.io/api v0.32.3 k8s.io/apimachinery v0.32.3 k8s.io/client-go v0.32.3 @@ -29,12 +24,12 @@ require ( github.com/cloudnative-pg/machinery v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect - github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -51,7 +46,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -71,29 +66,30 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/zitadel/logging v0.6.1 // indirect - github.com/zitadel/oidc/v3 v3.36.1 // indirect - github.com/zitadel/schema v1.3.0 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.34.0 // indirect + github.com/zitadel/logging v0.7.0 // indirect + github.com/zitadel/oidc/v3 v3.45.5 // indirect + github.com/zitadel/schema v1.3.2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.37.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/oauth2 v0.35.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.31.0 // indirect + golang.org/x/tools v0.41.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/src/go.sum b/go.sum similarity index 74% rename from src/go.sum rename to go.sum index f1810c9..f5cf078 100644 --- a/src/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ +gitea.corredorconect.com/software-engineering/zitadel-resources-operator v0.0.0-20260407173354-d5c3485fd29b h1:gtF0fMf8EUdlC+oJ1DX1oPcMA+rz24K8CfZ2jMZ84r0= +gitea.corredorconect.com/software-engineering/zitadel-resources-operator v0.0.0-20260407173354-d5c3485fd29b/go.mod h1:DzcXKjG5j+4FIi0Wi/dye2yVD0XhAh5ukQChYwL1DMI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= -github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= +github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudnative-pg/barman-cloud v0.1.0 h1:e/z52CehMBIh1LjZqNBJnncWJbS+1JYvRMBR8Js6Uiw= @@ -18,8 +20,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= @@ -28,13 +30,13 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 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-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= -github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -65,14 +67,12 @@ github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/Z github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= -github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -133,49 +133,46 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y= -github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= -github.com/zitadel/oidc v1.13.5 h1:7jhh68NGZitLqwLiVU9Dtwa4IraJPFF1vS+4UupO93U= -github.com/zitadel/oidc v1.13.5/go.mod h1:rHs1DhU3Sv3tnI6bQRVlFa3u0lCwtR7S21WHY+yXgPA= -github.com/zitadel/oidc/v3 v3.36.1 h1:1AT1NqKKEqAwx4GmKJZ9fYkWH2WIn/VKMfQ46nBtRf0= -github.com/zitadel/oidc/v3 v3.36.1/go.mod h1:dApGZLvWZTHRuxmcbQlW5d2XVjVYR3vGOdq536igmTs= -github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= -github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= -github.com/zitadel/zitadel-go/v3 v3.5.0 h1:8LnUiOCvwhgZxwBY15tk7Yzhv5vEJF+qiM3qWJGtxCI= -github.com/zitadel/zitadel-go/v3 v3.5.0/go.mod h1:YPfMqfpyOIuKdHNsZwWHAR/BWSIFOSIL41TyMnef/aU= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +github.com/zitadel/logging v0.7.0 h1:eugftwMM95Wgqwftsvj81isL0JK/hoScVqp/7iA2adQ= +github.com/zitadel/logging v0.7.0/go.mod h1:9A6h9feBF/3u0IhA4uffdzSDY7mBaf7RE78H5sFMINQ= +github.com/zitadel/oidc/v3 v3.45.5 h1:CubfcXQiqtysk+FZyIcvj1+1ayvdSV89v5xWu5asrDQ= +github.com/zitadel/oidc/v3 v3.45.5/go.mod h1:MKHUazeiNX/jxRc6HD/Dv9qhL/wNuzrJAadBEGXiBeE= +github.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI= +github.com/zitadel/schema v1.3.2/go.mod h1:IZmdfF9Wu62Zu6tJJTH3UsArevs3Y4smfJIj3L8fzxw= +github.com/zitadel/zitadel-go/v3 v3.27.0 h1:1BumImnIk3D9JYTq+IlVq793vZCXuMZuz1meWzeMQN4= +github.com/zitadel/zitadel-go/v3 v3.27.0/go.mod h1:8UaWIIUR+c9jstT6bjoiknaxttxFZKNc7RYs32v03jw= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -185,59 +182,56 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= 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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 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.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= 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.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.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.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -245,11 +239,8 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= diff --git a/src/hack/boilerplate.go.txt b/hack/boilerplate.go.txt similarity index 100% rename from src/hack/boilerplate.go.txt rename to hack/boilerplate.go.txt diff --git a/internal/controller/cluster_controller.go b/internal/controller/cluster_controller.go new file mode 100644 index 0000000..7d2bce3 --- /dev/null +++ b/internal/controller/cluster_controller.go @@ -0,0 +1,470 @@ +/* +Copyright 2024. + +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 controller + +import ( + "context" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "time" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + builder "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder" + condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/configuration" + configmap "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/configmap" + secret "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/secret" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/service" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/masterkey" + systemapiaccount "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/systemapi" + "github.com/hashicorp/go-multierror" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type reconcilePhase struct { + Name string + Reconcile func(context.Context, *zitadelv1alpha1.Cluster) (ctrl.Result, error) +} + +type patcher func(*zitadelv1alpha1.ClusterStatus) error + +// ClusterReconciler reconciles a Cluster object +type ClusterReconciler struct { + client.Client + Scheme *runtime.Scheme + ConditionReady *condition.Ready + Builder *builder.Builder + SecretReconciler *secret.SecretReconciler + ConfigMapReconciler *configmap.ConfigMapReconciler + ServiceReconciler *service.ServiceReconciler + RefResolver *zitadelv1alpha1.RefResolver +} + +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;patch +// +kubebuilder:rbac:groups="",resources=services,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups="",resources=endpoints,verbs=create;patch;get;list;watch +// +kubebuilder:rbac:groups="",resources=endpoints/restricted,verbs=create;patch;get;list;watch +// +kubebuilder:rbac:groups="",resources=pods,verbs=get;delete +// +kubebuilder:rbac:groups="",resources=events,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings;clusterrolebindings,verbs=list;watch;create;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=clusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=zitadel.github.com,resources=clusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=clusters/finalizers,verbs=update +// +kubebuilder:rbac:groups=zitadel.github.com,resources=instances,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=zitadel.github.com,resources=instances/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=instances/finalizers,verbs=update +// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/finalizers,verbs=update +// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests,verbs=get;list;watch;create;patch;delete +// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests/approval,verbs=update +// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete + +func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("Starting Reconcile") + + var zitadel zitadelv1alpha1.Cluster + + if err := r.Get(ctx, req.NamespacedName, &zitadel); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + phases := []reconcilePhase{ + { + Name: "Spec", + Reconcile: r.setSpecDefaults, + }, + { + Name: "Status", + Reconcile: r.setStatusDefaults, + }, + { + Name: "MasterkeySecret", + Reconcile: r.reconcileMasterKeySecret, + }, + { + Name: "ServiceAccount", + Reconcile: r.reconcileSystemAPIUser, + }, + { + Name: "Configuration", + Reconcile: r.reconcileConfig, + }, + { + Name: "InitJob", + Reconcile: r.reconcileInitJob, + }, + { + Name: "SetupJob", + Reconcile: r.reconcileSetupJob, + }, + { + Name: "Deployment", + Reconcile: r.reconcileDeployment, + }, + { + Name: "Service", + Reconcile: r.reconcileService, + }, + } + + for _, p := range phases { + result, err := p.Reconcile(ctx, &zitadel) + if err != nil { + if errors.IsNotFound(err) { + continue + } + + var errBundle *multierror.Error + errBundle = multierror.Append(errBundle, err) + + msg := fmt.Sprintf("Error reconciling %s: %v", p.Name, err) + patchErr := r.patchStatus(ctx, &zitadel, func(s *zitadelv1alpha1.ClusterStatus) error { + patcher := r.ConditionReady.PatcherFailed(msg) + patcher(s) + return nil + }) + if errors.IsNotFound(patchErr) { + errBundle = multierror.Append(errBundle, patchErr) + } + + if err := errBundle.ErrorOrNil(); err != nil { + return ctrl.Result{}, fmt.Errorf("error reconciling %s: %v", p.Name, err) + } + } + if !result.IsZero() { + return result, err + } + } + + if err := r.patchStatus(ctx, &zitadel, r.patcher(ctx, &zitadel)); err != nil && !errors.IsNotFound(err) { + return ctrl.Result{}, err + } + return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil +} + +func (r *ClusterReconciler) setSpecDefaults(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + return ctrl.Result{}, r.patch(ctx, zitadel, func(zit *zitadelv1alpha1.Cluster) { + zit.SetDefaults() + }) +} + +func (r *ClusterReconciler) setStatusDefaults(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + return ctrl.Result{}, r.patchStatus(ctx, zitadel, func(status *zitadelv1alpha1.ClusterStatus) error { + status.FillWithDefaults(zitadel) + return nil + }) +} + +func (r *ClusterReconciler) reconcileMasterKeySecret(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + secretName := masterkey.MasterKeyName(zitadel) + key := types.NamespacedName{ + Name: secretName, + Namespace: zitadel.Namespace, + } + _, err := r.SecretReconciler.ReconcileRandomPassword(ctx, key, masterkey.Key, zitadel) + + if err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) reconcileSystemAPIUser(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + secretName := systemapiaccount.SystemAPIAccountName(zitadel) + key := types.NamespacedName{ + Name: secretName, + Namespace: zitadel.Namespace, + } + _, err := r.SecretReconciler.ReconcileRandomPrivateRSA(ctx, key, systemapiaccount.Key, zitadel) + + if err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) reconcileConfig(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + postgres, err := r.RefResolver.PostgreSQLClusterRef(ctx, &zitadel.Spec.PostgreSQLClusterRef, zitadel.Namespace) + if err != nil { + return ctrl.Result{}, err + } + configName := configuration.ConfigurationName(zitadel) + key := types.NamespacedName{ + Name: configName, + Namespace: zitadel.Namespace, + } + privateKeyData, err := r.RefResolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: systemapiaccount.SystemAPIAccountName(zitadel)}, Key: systemapiaccount.Key}, zitadel.Namespace) + if err != nil { + return ctrl.Result{}, err + } + pemBlock, _ := pem.Decode([]byte(privateKeyData)) + if pemBlock == nil { + return ctrl.Result{}, fmt.Errorf("failed to decode PEM block") + } + privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) + publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + if err != nil { + return ctrl.Result{}, err + } + publicKeyPem := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: publicKeyBytes, + }, + ) + base64key := base64.StdEncoding.EncodeToString(publicKeyPem) + err = r.ConfigMapReconciler.ReconcileZitadelConfiguration(ctx, key, zitadel, postgres, base64key) + + if err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) reconcileInitJob(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + key := client.ObjectKeyFromObject(zitadel) + key.Name = "init-job-" + key.Name + + // Build the desired job + desiredInitJob, err := r.Builder.BuildInitJob(zitadel, key) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error building InitJob: %v", err) + } + + var existingJob batchv1.Job + err = r.Get(ctx, key, &existingJob) + if err != nil { + if !errors.IsNotFound(err) { + return ctrl.Result{}, fmt.Errorf("error getting InitJob: %v", err) + } + // If job is not found, create the job + if err := r.Create(ctx, desiredInitJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating InitJob: %v", err) + } + return ctrl.Result{}, nil + } + + // Compare the image in the existing job with the desired image + existingImage := existingJob.Spec.Template.Spec.Containers[0].Image + desiredImage := desiredInitJob.Spec.Template.Spec.Containers[0].Image + + // If the images don't match, delete the existing job and wait for deletion + if existingImage != desiredImage { + + if err := r.Delete(ctx, &existingJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error deleting existing InitJob: %v", err) + } + + // Wait for the job to be fully deleted before creating a new one + for { + err := r.Get(ctx, key, &existingJob) + if errors.IsNotFound(err) { + break // Job has been deleted, we can proceed + } + if err != nil { + return ctrl.Result{}, fmt.Errorf("error checking if InitJob is deleted: %v", err) + } + // Sleep for a short interval to avoid tight loop + time.Sleep(1 * time.Second) + } + + // Now create the new job + if err := r.Create(ctx, desiredInitJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating new InitJob: %v", err) + } + } + if err := r.Get(ctx, key, &existingJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error fetching existing InitJob status: %v", err) + } + + if existingJob.Status.Succeeded != 1 { // Replace with actual success condition + return ctrl.Result{}, nil + } + // If the job exists and the image matches, no action is needed + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) reconcileSetupJob(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + key := client.ObjectKeyFromObject(zitadel) + key.Name = "setup-job-" + key.Name + + // Build the desired job + desiredSetupJob, err := r.Builder.BuildSetupJob(zitadel, key) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error building SetupJob: %v", err) + } + + var existingJob batchv1.Job + err = r.Get(ctx, key, &existingJob) + if err != nil { + if !errors.IsNotFound(err) { + return ctrl.Result{}, fmt.Errorf("error getting SetupJob: %v", err) + } + // If job is not found, create the job + if err := r.Create(ctx, desiredSetupJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating SetupJob: %v", err) + } + return ctrl.Result{}, nil + } + + // Compare the image in the existing job with the desired image + existingImage := existingJob.Spec.Template.Spec.Containers[0].Image + desiredImage := desiredSetupJob.Spec.Template.Spec.Containers[0].Image + + // If the images don't match, delete the existing job and wait for deletion + if existingImage != desiredImage { + + if err := r.Delete(ctx, &existingJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error deleting existing SetupJob: %v", err) + } + + // Wait for the job to be fully deleted before creating a new one + for { + err := r.Get(ctx, key, &existingJob) + if errors.IsNotFound(err) { + break // Job has been deleted, we can proceed + } + if err != nil { + return ctrl.Result{}, fmt.Errorf("error checking if SetupJob is deleted: %v", err) + } + // Sleep for a short interval to avoid tight loop + time.Sleep(1 * time.Second) + } + + // Now create the new job + if err := r.Create(ctx, desiredSetupJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating new SetupJob: %v", err) + } + } + if err := r.Get(ctx, key, &existingJob); err != nil { + return ctrl.Result{}, fmt.Errorf("error fetching existing SetupJob status: %v", err) + } + + if existingJob.Status.Succeeded != 1 { // Replace with actual success condition + return ctrl.Result{}, nil + } + // If the job exists and the image matches, no action is needed + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) reconcileDeployment(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + // TODO: Reload on config changed + key := client.ObjectKeyFromObject(zitadel) + desiredSts, err := r.Builder.BuildDeployment(zitadel, key) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error building Deployment: %v", err) + } + var existingDep appsv1.Deployment + if err := r.Get(ctx, key, &existingDep); err != nil { + if !errors.IsNotFound(err) { + return ctrl.Result{}, fmt.Errorf("error getting Deployment: %v", err) + } + if err := r.Create(ctx, desiredSts); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating Deployment: %v", err) + } + return ctrl.Result{}, nil + } + + patch := client.MergeFrom(existingDep.DeepCopy()) + existingDep.Spec.Template = desiredSts.Spec.Template + existingDep.Spec.Replicas = desiredSts.Spec.Replicas + return ctrl.Result{}, r.Patch(ctx, &existingDep, patch) +} + +func (r *ClusterReconciler) reconcileService(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) (ctrl.Result, error) { + return ctrl.Result{}, r.reconcileDefaultService(ctx, zitadel) +} + +func (r *ClusterReconciler) reconcileDefaultService(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) error { + key := client.ObjectKeyFromObject(zitadel) + opts := builder.ServiceOpts{ + Ports: []corev1.ServicePort{ + { + Name: deployment.ZitadelName, + Port: deployment.ZitadelPort, + }, + }, + } + desiredSvc, err := r.Builder.BuildService(zitadel, key, opts) + if err != nil { + return fmt.Errorf("error building Service: %v", err) + } + return r.ServiceReconciler.Reconcile(ctx, desiredSvc) +} + +func (r *ClusterReconciler) patchStatus(ctx context.Context, zitadel *zitadelv1alpha1.Cluster, + patcher patcher) error { + patch := client.MergeFrom(zitadel.DeepCopy()) + if err := patcher(&zitadel.Status); err != nil { + return err + } + return r.Status().Patch(ctx, zitadel, patch) +} + +func (r *ClusterReconciler) patcher(ctx context.Context, zitadel *zitadelv1alpha1.Cluster) patcher { + return func(s *zitadelv1alpha1.ClusterStatus) error { + var sts appsv1.Deployment + if err := r.Get(ctx, client.ObjectKeyFromObject(zitadel), &sts); err != nil { + return err + } + zitadel.Status.Replicas = sts.Status.ReadyReplicas + + condition.SetReadyWithDeployment(&zitadel.Status, &sts) + return nil + } +} + +func (r *ClusterReconciler) patch(ctx context.Context, zitadel *zitadelv1alpha1.Cluster, + patcher func(*zitadelv1alpha1.Cluster)) error { + patch := client.MergeFrom(zitadel.DeepCopy()) + patcher(zitadel) + return r.Patch(ctx, zitadel, patch) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zitadelv1alpha1.Cluster{}). + Owns(&appsv1.Deployment{}). + Owns(&corev1.Service{}). + Owns(&corev1.ConfigMap{}). + Owns(&corev1.Secret{}). + WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). + Complete(r) +} diff --git a/internal/controller/instance_controller.go b/internal/controller/instance_controller.go new file mode 100644 index 0000000..9707e80 --- /dev/null +++ b/internal/controller/instance_controller.go @@ -0,0 +1,402 @@ +/* +Copyright 2024. + +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 controller + +import ( + "context" + "fmt" + "time" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/service" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/system" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + zitadelresourcesv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-resources-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + + systemClient "github.com/zitadel/zitadel-go/v3/pkg/client/system" + authn "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/authn" + pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/system" + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder" +) + +// InstanceReconciler reconciles a Instance object +type InstanceReconciler struct { + client.Client + RefResolver *zitadelv1alpha1.RefResolver + ConditionReady *condition.Ready + RequeueInterval time.Duration + Builder *builder.Builder + ServiceReconciler *service.ServiceReconciler +} + +func NewInstanceReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, + builder *builder.Builder, + conditionReady *condition.Ready, + serviceReconciler *service.ServiceReconciler, + requeueInterval time.Duration) *InstanceReconciler { + return &InstanceReconciler{ + Client: client, + RefResolver: refResolver, + ConditionReady: conditionReady, + RequeueInterval: requeueInterval, + ServiceReconciler: serviceReconciler, + Builder: builder, + } +} + +//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=instances,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=instances/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=instances/finalizers,verbs=update +// +kubebuilder:rbac:groups=zitadel.github.com,resources=machineusers,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=zitadel.github.com,resources=machineusers/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=machineusers/finalizers,verbs=update +// +kubebuilder:rbac:groups=zitadel.github.com,resources=connections,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=zitadel.github.com,resources=connections/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=connections/finalizers,verbs=update +// +kubebuilder:rbac:groups=zitadel.github.com,resources=organizations,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=zitadel.github.com,resources=organizations/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=zitadel.github.com,resources=organizations/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. +func (r *InstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + var instance zitadelv1alpha1.Instance + if err := r.Get(ctx, req.NamespacedName, &instance); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + wr := newWrappedInstanceReconciler(r.Client, r.RefResolver, r.Builder, r.ServiceReconciler, &instance) + wf := newWrappedInstanceFinalizer(r.Client, &instance) + tf := system.NewSystemFinalizer(r.Client, wf) + tr := system.NewSystemReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) + + result, err := tr.Reconcile(ctx, &instance) + if err != nil { + return result, fmt.Errorf("error reconciling in InstanceReconciler: %v", err) + } + return result, nil +} + +type wrappedInstanceReconciler struct { + client.Client + refResolver *zitadelv1alpha1.RefResolver + instance *zitadelv1alpha1.Instance + Builder *builder.Builder + ServiceReconciler *service.ServiceReconciler +} + +func newWrappedInstanceReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, + serviceReconciler *service.ServiceReconciler, + instance *zitadelv1alpha1.Instance) system.WrappedSystemReconciler { + return &wrappedInstanceReconciler{ + Client: client, + refResolver: refResolver, + instance: instance, + Builder: builder, + ServiceReconciler: serviceReconciler, + } +} + +type instanceReconcilePhase struct { + Name string + Reconcile func(context.Context, *systemClient.Client) error +} + +func (wr *wrappedInstanceReconciler) Reconcile(ctx context.Context, ztdClient *systemClient.Client) error { + phases := []instanceReconcilePhase{ + { + Name: "instance", + Reconcile: wr.reconcileInstance, + }, + { + Name: "connection", + Reconcile: wr.reconcileConnection, + }, + { + Name: "organization", + Reconcile: wr.reconcileFirstOrganization, + }, + { + Name: "loginUIMachineUser", + Reconcile: wr.reconcileLoginUIMachineUser, + }, + { + Name: "loginUIDeployment", + Reconcile: wr.reconcileLoginUIDeployment, + }, + { + Name: "loginUIService", + Reconcile: wr.reconcileLoginUIService, + }, + } + for _, p := range phases { + err := p.Reconcile(ctx, ztdClient) + if err != nil { + return err + } + } + return nil +} + +func (wr *wrappedInstanceReconciler) reconcileInstance(ctx context.Context, ztdClient *systemClient.Client) error { + var instanceId *string + if wr.instance.Status.InstanceId != nil { + getInstanceRes, err := ztdClient.GetInstance(ctx, &pb.GetInstanceRequest{InstanceId: *wr.instance.Status.InstanceId}) + if err != nil { + return fmt.Errorf("Error getting Instance: %v", err) + } + if getInstanceRes.Instance != nil { + instanceId = &getInstanceRes.Instance.Id + } + } + if instanceId == nil { + createInstanceRes, err := ztdClient.CreateInstance(ctx, &pb.CreateInstanceRequest{ + InstanceName: wr.instance.Spec.InstanceName, + FirstOrgName: wr.instance.Spec.Org.Name, + CustomDomain: wr.instance.Spec.CustomDomain, + DefaultLanguage: wr.instance.Spec.DefaultLanguage, + Owner: &pb.CreateInstanceRequest_Machine_{ + Machine: &pb.CreateInstanceRequest_Machine{ + UserName: wr.instance.MachineUserName(), + Name: wr.instance.MachineName(), + PersonalAccessToken: &pb.CreateInstanceRequest_PersonalAccessToken{ + ExpirationDate: nil, + }, + MachineKey: &pb.CreateInstanceRequest_MachineKey{ + ExpirationDate: nil, + Type: authn.KeyType_KEY_TYPE_JSON, + }, + }, + }, + }) + if err != nil { + return fmt.Errorf("Error creating Instance: %v", err) + } + + key := types.NamespacedName{ + Name: wr.instance.MachineSecretName(), + Namespace: wr.instance.Namespace, + } + secretData := map[string][]byte{ + "pat": []byte(createInstanceRes.Pat), + "machinekey": createInstanceRes.MachineKey, + } + secret, err := wr.Builder.BuildSecret(builder.SecretOpts{Key: key, Data: secretData}, wr.instance) + if err != nil { + return fmt.Errorf("error building instance machine Secret: %v", err) + } + + if err := wr.Create(ctx, secret); err != nil { + return fmt.Errorf("error creating machinekey Secret: %v", err) + } + instanceId = &createInstanceRes.InstanceId + } + patch := ctrlClient.MergeFrom(wr.instance.DeepCopy()) + wr.instance.Status.InstanceId = instanceId + return wr.Client.Status().Patch(ctx, wr.instance, patch) +} + +func (wr *wrappedInstanceReconciler) reconcileConnection(ctx context.Context, ztdClient *systemClient.Client) error { + key := types.NamespacedName{ + Name: wr.instance.ConnectionObjectName(), + Namespace: wr.instance.Namespace, + } + desiredConnection, err := wr.Builder.BuildConnection(key, wr.instance) + if err != nil { + return fmt.Errorf("error building Initial Connectionanization: %v", err) + } + + var existingConnection zitadelresourcesv1alpha1.Connection + if err := wr.Get(ctx, key, &existingConnection); err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("error getting Initial Connectionanization: %v", err) + } + if err := wr.Create(ctx, desiredConnection); err != nil { + return fmt.Errorf("error creating Initial Connectionanization: %v", err) + } + return nil + } + + patch := client.MergeFrom(existingConnection.DeepCopy()) + existingConnection.Spec.Host = desiredConnection.Spec.Host + existingConnection.Spec.Authentication = desiredConnection.Spec.Authentication + return wr.Patch(ctx, &existingConnection, patch) +} + +func (wr *wrappedInstanceReconciler) reconcileFirstOrganization(ctx context.Context, ztdClient *systemClient.Client) error { + key := types.NamespacedName{ + Name: wr.instance.FirstOrgObjectName(), + Namespace: wr.instance.Namespace, + } + desiredOrg, err := wr.Builder.BuildOrganization(builder.OrganizationOpts{Key: key, Zitadel: wr.instance, OrganizationName: wr.instance.Spec.Org.Name}, wr.instance) + if err != nil { + return fmt.Errorf("error building Initial Organization: %v", err) + } + + var existingOrg zitadelresourcesv1alpha1.Organization + if err := wr.Get(ctx, key, &existingOrg); err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("error getting Initial Organization: %v", err) + } + if err := wr.Create(ctx, desiredOrg); err != nil { + return fmt.Errorf("error creating Initial Organization: %v", err) + } + return nil + } + + patch := client.MergeFrom(existingOrg.DeepCopy()) + existingOrg.Spec.OrganzationName = desiredOrg.Spec.OrganzationName + return wr.Patch(ctx, &existingOrg, patch) +} + +func (wr *wrappedInstanceReconciler) reconcileLoginUIMachineUser(ctx context.Context, ztdClient *systemClient.Client) error { + key := types.NamespacedName{ + Name: wr.instance.LoginMachineUserName(), + Namespace: wr.instance.Namespace, + } + + desiredMachineUser, err := wr.Builder.BuildMachineUser(key, builder.MachineUserOpts{Instance: wr.instance, + InternalPermissions: []zitadelresourcesv1alpha1.InternalPermissions{ + { + + Resource: zitadelresourcesv1alpha1.Resource{ + Instance: &zitadelresourcesv1alpha1.InstanceResource{}, + }, + Roles: []string{ + "IAM_LOGIN_CLIENT", + }, + }, + }, + Username: "login-ui", + }, wr.instance) + if err != nil { + return fmt.Errorf("error building LoginUI MachineUser: %v", err) + } + + var existingMachineUser zitadelresourcesv1alpha1.MachineUser + if err := wr.Get(ctx, key, &existingMachineUser); err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("error getting MachineUser: %v", err) + } + if err := wr.Create(ctx, desiredMachineUser); err != nil { + return fmt.Errorf("error creating MachineUser: %v", err) + } + return nil + } + + patch := client.MergeFrom(existingMachineUser.DeepCopy()) + existingMachineUser.Spec.Authorizations = desiredMachineUser.Spec.Authorizations + existingMachineUser.Spec.InternalPermissions = desiredMachineUser.Spec.InternalPermissions + existingMachineUser.Spec.Metadata = desiredMachineUser.Spec.Metadata + return wr.Patch(ctx, &existingMachineUser, patch) +} + +func (wr *wrappedInstanceReconciler) reconcileLoginUIDeployment(ctx context.Context, ztdClient *systemClient.Client) error { + if wr.instance.Status.InstanceId != nil { + return fmt.Errorf("Instance not ready...") + } + cluster, err := wr.refResolver.Cluster(ctx, &wr.instance.Spec.ClusterRef, wr.instance.Namespace) + if err != nil { + return err + } + key := client.ObjectKeyFromObject(wr.instance) + key.Name = key.Name + "-login-ui" + + instanceRes, err := ztdClient.GetInstance(ctx, &pb.GetInstanceRequest{InstanceId: *wr.instance.Status.InstanceId}) + if err != nil { + return err + } + var customDomain string + for _, d := range instanceRes.Instance.Domains { + if d.Primary { + customDomain = d.Domain + break + } + } + desiredSts, err := wr.Builder.BuildLoginDeployment(cluster, wr.instance, customDomain, key) + if err != nil { + return fmt.Errorf("error building Login UI Deployment: %v", err) + } + var existingDep appsv1.Deployment + if err := wr.Get(ctx, key, &existingDep); err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("error getting Login UI Deployment: %v", err) + } + if err := wr.Create(ctx, desiredSts); err != nil { + return fmt.Errorf("error creating Login UI Deployment: %v", err) + } + return nil + } + + patch := client.MergeFrom(existingDep.DeepCopy()) + existingDep.Spec.Template = desiredSts.Spec.Template + existingDep.Spec.Replicas = desiredSts.Spec.Replicas + return wr.Patch(ctx, &existingDep, patch) +} + +func (wr *wrappedInstanceReconciler) reconcileLoginUIService(ctx context.Context, ztdClient *systemClient.Client) error { + key := client.ObjectKeyFromObject(wr.instance) + key.Name = key.Name + "-login-ui" + opts := builder.ServiceOpts{ + Ports: []corev1.ServicePort{ + { + Name: deployment.LoginName, + Port: deployment.LoginPort, + }, + }, + } + desiredSvc, err := wr.Builder.BuildLoginService(wr.instance, key, opts) + if err != nil { + return fmt.Errorf("error building Service: %v", err) + } + return wr.ServiceReconciler.Reconcile(ctx, desiredSvc) +} + +func (wr *wrappedInstanceReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { + patch := client.MergeFrom(wr.instance.DeepCopy()) + patcher(&wr.instance.Status) + + if err := wr.Client.Status().Patch(ctx, wr.instance, patch); err != nil { + return fmt.Errorf("error patching Instance status: %v", err) + } + return nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *InstanceReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zitadelv1alpha1.Instance{}). + Owns(&corev1.Secret{}). + Owns(&appsv1.Deployment{}). + Owns(&corev1.Service{}). + Owns(&zitadelresourcesv1alpha1.Connection{}). + Owns(&zitadelresourcesv1alpha1.Organization{}). + Owns(&zitadelresourcesv1alpha1.MachineUser{}). + WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). + Complete(r) +} diff --git a/internal/controller/instance_controller_finalizer.go b/internal/controller/instance_controller_finalizer.go new file mode 100644 index 0000000..b48e661 --- /dev/null +++ b/internal/controller/instance_controller_finalizer.go @@ -0,0 +1,74 @@ +package controller + +import ( + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/controller/system" + + "context" + "fmt" + + systemClient "github.com/zitadel/zitadel-go/v3/pkg/client/system" + pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/system" + "sigs.k8s.io/controller-runtime/pkg/client" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const ( + instanceFinalizerName = "instance.zitadel.github.com/instance" +) + +type wrappedInstanceFinalizer struct { + client.Client + instance *zitadelv1alpha1.Instance +} + +func newWrappedInstanceFinalizer(client client.Client, instance *zitadelv1alpha1.Instance) system.WrappedSystemFinalizer { + return &wrappedInstanceFinalizer{ + Client: client, + instance: instance, + } +} + +func (wf *wrappedInstanceFinalizer) AddFinalizer(ctx context.Context) error { + if wf.ContainsFinalizer() { + return nil + } + return wf.patch(ctx, wf.instance, func(instance *zitadelv1alpha1.Instance) { + controllerutil.AddFinalizer(instance, instanceFinalizerName) + }) +} + +func (wf *wrappedInstanceFinalizer) RemoveFinalizer(ctx context.Context) error { + if !wf.ContainsFinalizer() { + return nil + } + return wf.patch(ctx, wf.instance, func(instance *zitadelv1alpha1.Instance) { + controllerutil.RemoveFinalizer(wf.instance, instanceFinalizerName) + }) +} + +func (wr *wrappedInstanceFinalizer) ContainsFinalizer() bool { + return controllerutil.ContainsFinalizer(wr.instance, instanceFinalizerName) +} + +func (wf *wrappedInstanceFinalizer) Reconcile(ctx context.Context, ztdClient *systemClient.Client) error { + if wf.instance.Status.InstanceId != nil { + _, err := ztdClient.RemoveInstance(ctx, &pb.RemoveInstanceRequest{InstanceId: *wf.instance.Status.InstanceId}) + if err != nil { + return fmt.Errorf("error removing Instance: %v", err) + } + } + return nil +} + +func (wr *wrappedInstanceFinalizer) patch(ctx context.Context, instance *zitadelv1alpha1.Instance, + patchFn func(*zitadelv1alpha1.Instance)) error { + patch := ctrlClient.MergeFrom(instance.DeepCopy()) + patchFn(instance) + + if err := wr.Client.Patch(ctx, instance, patch); err != nil { + return fmt.Errorf("error patching Instance finalizer: %v", err) + } + return nil +} diff --git a/src/internal/controller/suite_test.go b/internal/controller/suite_test.go similarity index 95% rename from src/internal/controller/suite_test.go rename to internal/controller/suite_test.go index 74607f5..96f54fb 100644 --- a/src/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -30,7 +30,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" //+kubebuilder:scaffold:imports ) diff --git a/ops/chart/crds/action-crd.yaml b/ops/chart/crds/action-crd.yaml deleted file mode 100644 index 6b7ea1e..0000000 --- a/ops/chart/crds/action-crd.yaml +++ /dev/null @@ -1,173 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: actions.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Action - listKind: ActionList - plural: actions - singular: action - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Action is the Schema for the actions API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: ActionSpec defines the desired state of Action - properties: - allowedToFail: - default: true - type: boolean - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - script: - type: string - timeout: - format: duration - type: string - required: - - allowedToFail - - organizationRef - - script - - timeout - type: object - status: - description: ActionStatus defines the observed state of Action - properties: - actionId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - actionId - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/crds/apiapp-crd.yaml b/ops/chart/crds/apiapp-crd.yaml deleted file mode 100644 index 070fea6..0000000 --- a/ops/chart/crds/apiapp-crd.yaml +++ /dev/null @@ -1,176 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: apiapps.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: APIApp - listKind: APIAppList - plural: apiapps - singular: apiapp - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: APIApp is the Schema for the apiapps API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: APIAppSpec defines the desired state of APIApp - properties: - authMethodType: - enum: - - API_AUTH_METHOD_TYPE_BASIC - - API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - type: string - projectRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - required: - - authMethodType - - projectRef - type: object - status: - description: APIAppStatus defines the observed state of APIApp - properties: - appId: - default: "" - type: string - clientId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - keyId: - default: "" - type: string - required: - - appId - - clientId - - keyId - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/crds/zitadelcluster-crd.yaml b/ops/chart/crds/cluster-crd.yaml similarity index 71% rename from ops/chart/crds/zitadelcluster-crd.yaml rename to ops/chart/crds/cluster-crd.yaml index 8b8c05c..ebf8d18 100644 --- a/ops/chart/crds/zitadelcluster-crd.yaml +++ b/ops/chart/crds/cluster-crd.yaml @@ -3,20 +3,30 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.17.3 - name: zitadelclusters.zitadel.topmanage.com + name: clusters.zitadel.github.com spec: - group: zitadel.topmanage.com + group: zitadel.github.com names: - kind: ZitadelCluster - listKind: ZitadelClusterList - plural: zitadelclusters - singular: zitadelcluster + kind: Cluster + listKind: ClusterList + plural: clusters + singular: cluster scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .status.replicas + name: Replicas + type: integer + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 schema: openAPIV3Schema: - description: ZitadelCluster is the Schema for the zitadelclusters API + description: Cluster is the Schema for the clusters API. properties: apiVersion: description: |- @@ -36,40 +46,23 @@ spec: metadata: type: object spec: - description: ZitadelClusterSpec defines the desired state of ZitadelCluster + description: ClusterSpec defines the desired state of Cluster. properties: - domainSettings: - properties: - smtpSenderAddressMatchesInstanceDomain: - default: true - type: boolean - userLoginMustBeDomain: - default: true - type: boolean - validateOrgDomains: - default: true - type: boolean - required: - - smtpSenderAddressMatchesInstanceDomain - - userLoginMustBeDomain - - validateOrgDomains - type: object externalPort: default: 443 + description: ExternalPort is the port exposed externally. format: int64 type: integer externalSecure: default: true + description: ExternalSecure indicates whether TLS is used on the external + endpoint. type: boolean - firstOrgName: - default: DEFAULT - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - type: string host: + description: Host is the external hostname used to reach Zitadel. type: string image: + description: Image is the Zitadel container image to deploy. properties: name: type: string @@ -82,9 +75,12 @@ spec: podAnnotations: additionalProperties: type: string - description: PodAnnotations to add to the Pods metadata. + description: PodAnnotations are extra annotations added to each Zitadel + Pod. type: object postgresClusterRef: + description: PostgreSQLClusterRef references the backing PostgreSQL + cluster. properties: apiVersion: description: API version of the referent. @@ -126,20 +122,14 @@ spec: type: string type: object x-kubernetes-map-type: atomic - purpose: - enum: - - demo - - trial - - staging - - productive - - testing - type: string replicas: default: 3 + description: Replicas is the desired number of Zitadel pods. format: int32 type: integer resources: - description: ResourceRequirements describes the compute resource requirements. + description: Resources defines compute resource requests and limits + for the Zitadel pods. properties: claims: description: |- @@ -200,77 +190,22 @@ spec: serviceAnnotations: additionalProperties: type: string - description: ServiceAnnotations to add to the service metadata. - type: object - smtpConfig: - properties: - host: - type: string - password: - properties: - secretRef: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - secretRef - type: object - replyToAddress: - type: string - senderAddress: - type: string - senderName: - type: string - tls: - default: true - type: boolean - user: - type: string - required: - - host - - senderAddress - - senderName - - tls + description: ServiceAnnotations are extra annotations added to the + Zitadel Service. type: object required: - - domainSettings - externalPort - externalSecure - - firstOrgName - host - image - postgresClusterRef - - purpose - resources - - smtpConfig type: object status: - description: ZitadelClusterStatus defines the observed state of ZitadelCluster + description: ClusterStatus defines the observed state of Cluster. properties: conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file + description: Conditions store the status conditions of the Cluster. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -326,19 +261,11 @@ spec: - type type: object type: array - defaultInstanceId: - default: "" - type: string replicas: default: 3 + description: Replicas is the current number of running Zitadel pods. format: int32 type: integer - smtpProviderId: - default: "" - type: string - required: - - defaultInstanceId - - smtpProviderId type: object type: object served: true diff --git a/ops/chart/crds/flow-crd.yaml b/ops/chart/crds/flow-crd.yaml deleted file mode 100644 index b135d14..0000000 --- a/ops/chart/crds/flow-crd.yaml +++ /dev/null @@ -1,227 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: flows.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Flow - listKind: FlowList - plural: flows - singular: flow - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Flow is the Schema for the flows API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: FlowSpec defines the desired state of Flow - properties: - actionRefs: - items: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - type: array - flowType: - enum: - - FLOW_TYPE_EXTERNAL_AUTHENTICATION - - "1" - - "2" - - "3" - - "4" - type: string - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - triggerType: - enum: - - TRIGGER_TYPE_POST_AUTHENTICATION - - TRIGGER_TYPE_PRE_CREATION - - TRIGGER_TYPE_POST_CREATION - - TRIGGER_TYPE_POST_AUTHENTICATION - - TRIGGER_TYPE_PRE_CREATION - - TRIGGER_TYPE_POST_CREATION - - "1" - - "2" - - "3" - - "4" - - "5" - - "6" - type: string - required: - - actionRefs - - flowType - - organizationRef - - triggerType - type: object - status: - description: FlowStatus defines the observed state of Flow - properties: - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/crds/machineuser-crd.yaml b/ops/chart/crds/instance-crd.yaml similarity index 52% rename from ops/chart/crds/machineuser-crd.yaml rename to ops/chart/crds/instance-crd.yaml index 02f4ab5..b369f50 100644 --- a/ops/chart/crds/machineuser-crd.yaml +++ b/ops/chart/crds/instance-crd.yaml @@ -3,20 +3,36 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.17.3 - name: machineusers.zitadel.topmanage.com + name: instances.zitadel.github.com spec: - group: zitadel.topmanage.com + group: zitadel.github.com names: - kind: MachineUser - listKind: MachineUserList - plural: machineusers - singular: machineuser + kind: Instance + listKind: InstanceList + plural: instances + singular: instance scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.instanceName + name: Instance + type: string + - jsonPath: .spec.clusterRef.name + name: Cluster + type: string + - jsonPath: .spec.customDomain + name: Domain + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 schema: openAPIV3Schema: - description: MachineUser is the Schema for the machineusers API + description: Instance is the Schema for the instances API. properties: apiVersion: description: |- @@ -36,17 +52,13 @@ spec: metadata: type: object spec: - description: MachineUserSpec defines the desired state of MachineUser + description: |- + InstanceSpec defines the desired state of Instance. + Fields map directly to POST /instances/_create (CreateInstance) in the Zitadel System API. properties: - accessTokenType: - enum: - - ACCESS_TOKEN_TYPE_BEARER - - ACCESS_TOKEN_TYPE_JWT - type: string - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file + clusterRef: + description: ClusterRef references the Cluster this instance will + be provisioned on. properties: apiVersion: description: API version of the referent. @@ -88,70 +100,120 @@ spec: type: string type: object x-kubernetes-map-type: atomic - userGrants: - items: - properties: - projectRef: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - roleKeys: - items: + customDomain: + type: string + defaultLanguage: + default: en + description: DefaultLanguage is the BCP-47 language tag used as the + instance default (e.g. "en"). + type: string + instanceName: + description: InstanceName is the display name of the Zitadel instance. + type: string + loginUI: + default: + image: + name: ghcr.io/zitadel/zitadel-login + resources: {} + properties: + image: + properties: + name: + default: ghcr.io/zitadel/zitadel-login type: string - type: array - required: - - projectRef - type: object - type: array + tag: + description: if empty it uses the same tag as zitadel cluster + type: string + required: + - name + type: object + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + required: + - image + - resources + type: object + org: + description: Org configures the first organisation and its initial + IAM_OWNER machine user. + properties: + name: + default: DEFAULT + description: Name of the first organization. + type: string + required: + - name + type: object required: - - accessTokenType - - organizationRef + - clusterRef + - customDomain + - instanceName + - loginUI + - org type: object status: - description: MachineUserStatus defines the observed state of MachineUser + description: InstanceStatus defines the observed state of Instance. properties: conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file + description: Conditions store the status conditions of the Instance. items: description: Condition contains details for one aspect of the current state of this API Resource. @@ -207,19 +269,10 @@ spec: - type type: object type: array - keyId: - default: "" + instanceId: + description: InstanceId is the instance ID returned by Zitadel after + successful provisioning. type: string - patId: - default: "" - type: string - userId: - default: "" - type: string - required: - - keyId - - patId - - userId type: object type: object served: true diff --git a/ops/chart/crds/oidcapp-crd.yaml b/ops/chart/crds/oidcapp-crd.yaml deleted file mode 100644 index 16bfec9..0000000 --- a/ops/chart/crds/oidcapp-crd.yaml +++ /dev/null @@ -1,240 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: oidcapps.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: OIDCApp - listKind: OIDCAppList - plural: oidcapps - singular: oidcapp - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: OIDCApp is the Schema for the oidcapps API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: OIDCAppSpec defines the desired state of OIDCApp - properties: - accessTokenRoleAssertion: - type: boolean - accessTokenType: - enum: - - OIDC_TOKEN_TYPE_BEARER - - OIDC_TOKEN_TYPE_JWT - type: string - additionalOrigins: - items: - type: string - type: array - appType: - enum: - - OIDC_APP_TYPE_WEB - - OIDC_APP_TYPE_USER_AGENT - - OIDC_APP_TYPE_NATIVE - type: string - authMethodType: - enum: - - OIDC_AUTH_METHOD_TYPE_BASIC - - OIDC_AUTH_METHOD_TYPE_POST - - OIDC_AUTH_METHOD_TYPE_NONE - - OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - type: string - clockSkew: - format: duration - type: string - devMode: - type: boolean - grantTypes: - items: - enum: - - OIDC_GRANT_TYPE_AUTHORIZATION_CODE - - OIDC_GRANT_TYPE_IMPLICIT - - OIDC_GRANT_TYPE_REFRESH_TOKEN - - OIDC_GRANT_TYPE_DEVICE_CODE - - OIDC_GRANT_TYPE_TOKEN_EXCHANGE - type: string - type: array - idTokenRoleAssertion: - type: boolean - idTokenUserinfoAssertion: - type: boolean - postLogoutRedirectUris: - items: - type: string - type: array - projectRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - redirectUris: - items: - type: string - type: array - responseTypes: - items: - enum: - - OIDC_RESPONSE_TYPE_CODE - - OIDC_RESPONSE_TYPE_ID_TOKEN - - OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN - type: string - type: array - skipNativeAppSuccessPage: - type: boolean - required: - - accessTokenRoleAssertion - - accessTokenType - - appType - - authMethodType - - clockSkew - - devMode - - grantTypes - - idTokenRoleAssertion - - idTokenUserinfoAssertion - - postLogoutRedirectUris - - projectRef - - redirectUris - - responseTypes - - skipNativeAppSuccessPage - type: object - status: - description: OIDCAppStatus defines the observed state of OIDCApp - properties: - appId: - default: "" - type: string - clientId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - appId - - clientId - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/crds/organization-crd.yaml b/ops/chart/crds/organization-crd.yaml deleted file mode 100644 index ada940c..0000000 --- a/ops/chart/crds/organization-crd.yaml +++ /dev/null @@ -1,184 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: organizations.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Organization - listKind: OrganizationList - plural: organizations - singular: organization - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Organization is the Schema for the organizations API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: OrganizationSpec defines the desired state of Organization - properties: - organizationAdmin: - properties: - email: - type: string - firstName: - type: string - lastName: - type: string - userName: - type: string - required: - - email - - firstName - - lastName - - userName - type: object - zitadelClusterRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - required: - - organizationAdmin - - zitadelClusterRef - type: object - status: - description: OrganizationStatus defines the observed state of Organization - properties: - adminId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - Conditions for the Database object. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - orgId: - default: "" - type: string - required: - - adminId - - orgId - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/crds/project-crd.yaml b/ops/chart/crds/project-crd.yaml deleted file mode 100644 index a218471..0000000 --- a/ops/chart/crds/project-crd.yaml +++ /dev/null @@ -1,239 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: projects.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Project - listKind: ProjectList - plural: projects - singular: project - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Project is the Schema for the projects API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: ProjectSpec defines the desired state of Project - properties: - grants: - items: - properties: - organizationRef: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - roleKeys: - items: - type: string - type: array - required: - - organizationRef - - roleKeys - type: object - type: array - hasProjectCheck: - type: boolean - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - https://zitadel.com/docs/apis/resources/mgmt/management-service-add-project - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - projectRoleAssertion: - type: boolean - projectRoleCheck: - type: boolean - roles: - items: - properties: - displayName: - type: string - group: - type: string - key: - type: string - required: - - displayName - - group - - key - type: object - type: array - required: - - organizationRef - type: object - status: - description: ProjectStatus defines the observed state of Project - properties: - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - Conditions for the Database object. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - projectId: - default: "" - type: string - required: - - projectId - type: object - type: object - served: true - storage: true - subresources: - status: {} - diff --git a/ops/chart/templates/_helpers.tpl b/ops/chart/templates/_helpers.tpl index 1880b9a..e868725 100644 --- a/ops/chart/templates/_helpers.tpl +++ b/ops/chart/templates/_helpers.tpl @@ -54,9 +54,12 @@ app.kubernetes.io/instance: {{ .Release.Name }} Create the name of the service account to use */}} {{- define "zitadel-k8s-operator.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "zitadel-k8s-operator.fullname" .) .Values.serviceAccount.name }} +{{- $default := (include "zitadel-k8s-operator.fullname" .) }} +{{- with .Values.serviceAccount }} +{{- if .create }} +{{- default $default .name }} {{- else }} -{{- default "default" .Values.serviceAccount.name }} +{{- default "default" .name }} +{{- end }} {{- end }} {{- end }} diff --git a/ops/chart/templates/deployment.yaml b/ops/chart/templates/deployment.yaml index b005ccd..84d3485 100644 --- a/ops/chart/templates/deployment.yaml +++ b/ops/chart/templates/deployment.yaml @@ -79,7 +79,11 @@ spec: }} securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 10 }} - securityContext: - runAsNonRoot: true - serviceAccountName: {{ include "zitadel-k8s-operator.fullname" . }}-controller-manager - terminationGracePeriodSeconds: 10 \ No newline at end of file + nodeSelector: {{- toYaml .Values.controllerManager.nodeSelector | nindent 8 }} + securityContext: {{- toYaml .Values.controllerManager.podSecurityContext | nindent + 8 }} + serviceAccountName: {{ include "zitadel-k8s-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + tolerations: {{- toYaml .Values.controllerManager.tolerations | nindent 8 }} + topologySpreadConstraints: {{- toYaml .Values.controllerManager.topologySpreadConstraints + | nindent 8 }} diff --git a/ops/chart/templates/leader-election-rbac.yaml b/ops/chart/templates/leader-election-rbac.yaml index 341e9e5..eaf55b9 100644 --- a/ops/chart/templates/leader-election-rbac.yaml +++ b/ops/chart/templates/leader-election-rbac.yaml @@ -55,5 +55,5 @@ roleRef: name: '{{ include "zitadel-k8s-operator.fullname" . }}-leader-election-role' subjects: - kind: ServiceAccount - name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' - namespace: '{{ .Release.Namespace }}' \ No newline at end of file + name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}' + namespace: '{{ .Release.Namespace }}' diff --git a/ops/chart/templates/manager-rbac.yaml b/ops/chart/templates/manager-rbac.yaml index ff425d1..2435633 100644 --- a/ops/chart/templates/manager-rbac.yaml +++ b/ops/chart/templates/manager-rbac.yaml @@ -128,17 +128,48 @@ rules: - list - patch - watch +- apiGroups: + - zitadel.github.com + resources: + - clusters + - connections + - instances + - machineusers + - organizations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zitadel.github.com + resources: + - clusters/finalizers + - connections/finalizers + - instances/finalizers + - machineusers/finalizers + - organizations/finalizers + verbs: + - update +- apiGroups: + - zitadel.github.com + resources: + - clusters/status + - connections/status + - instances/status + - machineusers/status + - organizations/status + verbs: + - get + - patch + - update - apiGroups: - zitadel.topmanage.com resources: - - actions - - apiapps - - flows - - machineusers - - oidcapps - - organizations - - projects - - zitadelclusters + - instances verbs: - create - delete @@ -150,27 +181,13 @@ rules: - apiGroups: - zitadel.topmanage.com resources: - - actions/finalizers - - apiapps/finalizers - - flows/finalizers - - machineusers/finalizers - - oidcapps/finalizers - - organizations/finalizers - - projects/finalizers - - zitadelclusters/finalizers + - instances/finalizers verbs: - update - apiGroups: - zitadel.topmanage.com resources: - - actions/status - - apiapps/status - - flows/status - - machineusers/status - - oidcapps/status - - organizations/status - - projects/status - - zitadelclusters/status + - instances/status verbs: - get - patch @@ -191,5 +208,5 @@ roleRef: name: '{{ include "zitadel-k8s-operator.fullname" . }}-manager-role' subjects: - kind: ServiceAccount - name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' + name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}' namespace: '{{ .Release.Namespace }}' diff --git a/ops/chart/templates/metrics-reader-rbac.yaml b/ops/chart/templates/metrics-reader-rbac.yaml index e778633..7509b3c 100644 --- a/ops/chart/templates/metrics-reader-rbac.yaml +++ b/ops/chart/templates/metrics-reader-rbac.yaml @@ -11,4 +11,4 @@ rules: - nonResourceURLs: - /metrics verbs: - - get \ No newline at end of file + - get diff --git a/ops/chart/templates/metrics-service.yaml b/ops/chart/templates/metrics-service.yaml index 537aa91..e4c57cc 100644 --- a/ops/chart/templates/metrics-service.yaml +++ b/ops/chart/templates/metrics-service.yaml @@ -12,6 +12,6 @@ spec: type: {{ .Values.metricsService.type }} selector: control-plane: controller-manager - {{- include "zitadel-k8s-operator.selectorLabels" . | nindent 4 }} + {{- include "zitadel-k8s-operator.selectorLabels" . | nindent 4 }} ports: - {{- .Values.metricsService.ports | toYaml | nindent 2 }} \ No newline at end of file + {{- .Values.metricsService.ports | toYaml | nindent 2 }} diff --git a/ops/chart/templates/proxy-rbac.yaml b/ops/chart/templates/proxy-rbac.yaml index c66bcc4..a332c78 100644 --- a/ops/chart/templates/proxy-rbac.yaml +++ b/ops/chart/templates/proxy-rbac.yaml @@ -36,5 +36,5 @@ roleRef: name: '{{ include "zitadel-k8s-operator.fullname" . }}-proxy-role' subjects: - kind: ServiceAccount - name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' - namespace: '{{ .Release.Namespace }}' \ No newline at end of file + name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}' + namespace: '{{ .Release.Namespace }}' diff --git a/ops/chart/templates/serviceaccount.yaml b/ops/chart/templates/serviceaccount.yaml index 9180f1e..7b94d7e 100644 --- a/ops/chart/templates/serviceaccount.yaml +++ b/ops/chart/templates/serviceaccount.yaml @@ -1,11 +1,13 @@ +{{ if .Values.serviceAccount.create }} apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "zitadel-k8s-operator.fullname" . }}-controller-manager + name: {{ include "zitadel-k8s-operator.serviceAccountName" . }} labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src {{- include "zitadel-k8s-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} annotations: - {{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }} \ No newline at end of file + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/ops/chart/values.yaml b/ops/chart/values.yaml index 5fb6bf1..a66022c 100644 --- a/ops/chart/values.yaml +++ b/ops/chart/values.yaml @@ -1,3 +1,4 @@ + controllerManager: kubeRbacProxy: args: @@ -11,7 +12,7 @@ controllerManager: drop: - ALL image: - repository: gcr.io/kubebuilder/kube-rbac-proxy + repository: registry.k8s.io/kubebuilder/kube-rbac-proxy tag: v0.13.1 resources: limits: @@ -31,8 +32,7 @@ controllerManager: drop: - ALL image: - repository: controller - tag: latest + repository: gitea.corredorconect.com/software-engineering/zitadel-k8s-operator resources: limits: cpu: 500m @@ -40,9 +40,12 @@ controllerManager: requests: cpu: 10m memory: 64Mi + nodeSelector: {} + podSecurityContext: + runAsNonRoot: true replicas: 1 - serviceAccount: - annotations: {} + tolerations: [] + topologySpreadConstraints: [] kubernetesClusterDomain: cluster.local metricsService: ports: @@ -51,3 +54,8 @@ metricsService: protocol: TCP targetPort: https type: ClusterIP +serviceAccount: + annotations: {} + automount: true + create: true + name: "" diff --git a/pkg/admin/admin.go b/pkg/admin/admin.go new file mode 100644 index 0000000..212112e --- /dev/null +++ b/pkg/admin/admin.go @@ -0,0 +1,14 @@ +package admin + +import ( + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" +) + +const ( + AccountName = "admin" + Key = "password" +) + +func AdminPasswordSecretName(zitadel *zitadelv1alpha1.Cluster) string { + return zitadel.Name + "-admin-password-secret" +} diff --git a/src/pkg/builder/builder.go b/pkg/builder/builder.go similarity index 100% rename from src/pkg/builder/builder.go rename to pkg/builder/builder.go diff --git a/src/pkg/builder/configmap_builder.go b/pkg/builder/configmap_builder.go similarity index 79% rename from src/pkg/builder/configmap_builder.go rename to pkg/builder/configmap_builder.go index 793ebde..08c202d 100644 --- a/src/pkg/builder/configmap_builder.go +++ b/pkg/builder/configmap_builder.go @@ -1,9 +1,9 @@ package builder import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" "fmt" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -11,7 +11,7 @@ import ( ) type ConfigMapOpts struct { - Zitadel *zitadelv1alpha1.ZitadelCluster + Zitadel *zitadelv1alpha1.Cluster Key types.NamespacedName Data map[string]string Labels map[string]string diff --git a/pkg/builder/connection_builder.go b/pkg/builder/connection_builder.go new file mode 100644 index 0000000..d038917 --- /dev/null +++ b/pkg/builder/connection_builder.go @@ -0,0 +1,40 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + zitadelresourcesv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-resources-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +func (b *Builder) BuildConnection(key types.NamespacedName, instance *zitadelv1alpha1.Instance) (*zitadelresourcesv1alpha1.Connection, error) { + objMeta := + metadata.NewMetadataBuilder(key). + Build() + + org := &zitadelresourcesv1alpha1.Connection{ + ObjectMeta: objMeta, + Spec: zitadelresourcesv1alpha1.ConnectionSpec{ + Host: instance.Spec.CustomDomain, + Authentication: zitadelresourcesv1alpha1.Authentication{ + PAT: &zitadelresourcesv1alpha1.PAT{ + TokenSecretKey: corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: instance.MachineSecretName(), + }, + Key: "pat", + }, + }, + }, + }, + } + + if err := controllerutil.SetControllerReference(instance, org, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference in Connection manifest: %v", err) + } + return org, nil +} diff --git a/src/pkg/builder/deployment_builder.go b/pkg/builder/deployment_builder.go similarity index 82% rename from src/pkg/builder/deployment_builder.go rename to pkg/builder/deployment_builder.go index 686aefb..1737925 100644 --- a/src/pkg/builder/deployment_builder.go +++ b/pkg/builder/deployment_builder.go @@ -3,12 +3,12 @@ package builder import ( "fmt" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - labels "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/labels" - metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" - configuration "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/configuration" - deployment "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + labels "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/labels" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + configuration "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/configuration" + deployment "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/masterkey" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,7 +18,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) -func (b *Builder) BuildDeployment(zitadel *zitadelv1alpha1.ZitadelCluster, key types.NamespacedName) (*appsv1.Deployment, error) { +func (b *Builder) BuildDeployment(zitadel *zitadelv1alpha1.Cluster, key types.NamespacedName) (*appsv1.Deployment, error) { replicas := zitadel.Spec.Replicas objMeta := metadata.NewMetadataBuilder(key). @@ -51,7 +51,7 @@ func (b *Builder) BuildDeployment(zitadel *zitadelv1alpha1.ZitadelCluster, key t return dep, nil } -func (b *Builder) buildDepPodTemplate(zitadel *zitadelv1alpha1.ZitadelCluster, labels map[string]string) (*corev1.PodTemplateSpec, error) { +func (b *Builder) buildDepPodTemplate(zitadel *zitadelv1alpha1.Cluster, labels map[string]string) (*corev1.PodTemplateSpec, error) { objMeta := metadata.NewMetadataBuilder(client.ObjectKeyFromObject(zitadel)). WithZitadel(zitadel). @@ -80,7 +80,7 @@ func (b *Builder) buildDepPodTemplate(zitadel *zitadelv1alpha1.ZitadelCluster, l nil } -func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.ZitadelCluster) *[]corev1.Container { +func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.Cluster) *[]corev1.Container { readyProbeHandle := corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{HTTPHeaders: []corev1.HTTPHeader{}, Port: intstr.FromInt(deployment.ZitadelPort), @@ -119,7 +119,7 @@ func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.ZitadelCluster) *[ { Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", - ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-app"}, Key: "password"}}, + ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-user"}, Key: "password"}}, }, // { diff --git a/src/pkg/builder/job_builder.go b/pkg/builder/job_builder.go similarity index 90% rename from src/pkg/builder/job_builder.go rename to pkg/builder/job_builder.go index 8223b6a..7b50a2c 100644 --- a/src/pkg/builder/job_builder.go +++ b/pkg/builder/job_builder.go @@ -3,9 +3,9 @@ package builder import ( "fmt" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - configuration "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/configuration" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + configuration "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/configuration" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/masterkey" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) -func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key types.NamespacedName) (*batchv1.Job, error) { +func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.Cluster, key types.NamespacedName) (*batchv1.Job, error) { backOffLimit := int32(5) activeDeadlineSeconds := int64(1800) @@ -52,6 +52,7 @@ func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key type Image: zitadel.Spec.Image.Name + ":" + zitadel.Spec.Image.Tag, Args: []string{ "init", + "zitadel", "--config", "/config/zitadel-config-yaml", }, Env: []corev1.EnvVar{ @@ -86,7 +87,7 @@ func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key type { Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", - ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-app"}, Key: "password"}}, + ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-user"}, Key: "password"}}, }, }, VolumeMounts: []corev1.VolumeMount{ @@ -105,7 +106,7 @@ func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key type return initJob, nil } -func (b *Builder) BuildSetupJob(zitadel *zitadelv1alpha1.ZitadelCluster, key types.NamespacedName) (*batchv1.Job, error) { +func (b *Builder) BuildSetupJob(zitadel *zitadelv1alpha1.Cluster, key types.NamespacedName) (*batchv1.Job, error) { backOffLimit := int32(5) activeDeadlineSeconds := int64(1800) @@ -192,7 +193,7 @@ func (b *Builder) BuildSetupJob(zitadel *zitadelv1alpha1.ZitadelCluster, key typ { Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", - ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-app"}, Key: "password"}}, + ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: zitadel.Spec.PostgreSQLClusterRef.Name + "-user"}, Key: "password"}}, }, }, VolumeMounts: []corev1.VolumeMount{ diff --git a/src/pkg/builder/labels/labels.go b/pkg/builder/labels/labels.go similarity index 63% rename from src/pkg/builder/labels/labels.go rename to pkg/builder/labels/labels.go index cc45e34..beb0dd5 100644 --- a/src/pkg/builder/labels/labels.go +++ b/pkg/builder/labels/labels.go @@ -1,8 +1,8 @@ package builder import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - deployment "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + deployment "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" ) const ( @@ -10,6 +10,7 @@ const ( instanceLabel = "app.kubernetes.io/instance" deploymentPodName = "deployment.kubernetes.io/pod-name" appZitadel = "zitadel" + appLoginUI = "zitadel-login-ui" appExporter = "exporter" ) @@ -33,12 +34,17 @@ func (b *LabelsBuilder) WithInstance(instance string) *LabelsBuilder { return b } -func (b *LabelsBuilder) WithZitadel(zitadel *zitadelv1alpha1.ZitadelCluster) *LabelsBuilder { +func (b *LabelsBuilder) WithZitadel(zitadel *zitadelv1alpha1.Cluster) *LabelsBuilder { return b.WithApp(appZitadel). WithInstance(zitadel.Name) } -func (b *LabelsBuilder) WithDeploymentPod(zitadel *zitadelv1alpha1.ZitadelCluster, podIndex int) *LabelsBuilder { +func (b *LabelsBuilder) WithLoginUI(instance *zitadelv1alpha1.Instance) *LabelsBuilder { + return b.WithApp(appLoginUI). + WithInstance(instance.Name) +} + +func (b *LabelsBuilder) WithDeploymentPod(zitadel *zitadelv1alpha1.Cluster, podIndex int) *LabelsBuilder { b.labels[deploymentPodName] = deployment.PodName(zitadel.ObjectMeta, podIndex) return b } @@ -50,12 +56,17 @@ func (b *LabelsBuilder) WithLabels(labels map[string]string) *LabelsBuilder { return b } -func (b *LabelsBuilder) WithZitadelSelectorLabels(zitadel *zitadelv1alpha1.ZitadelCluster) *LabelsBuilder { +func (b *LabelsBuilder) WithZitadelSelectorLabels(zitadel *zitadelv1alpha1.Cluster) *LabelsBuilder { b = b.WithZitadel(zitadel) return b } -func (b *LabelsBuilder) WithMetricsSelectorLabels(zitadel *zitadelv1alpha1.ZitadelCluster) *LabelsBuilder { +func (b *LabelsBuilder) WithLoginUISelectorLabels(instance *zitadelv1alpha1.Instance) *LabelsBuilder { + b = b.WithLoginUI(instance) + return b +} + +func (b *LabelsBuilder) WithMetricsSelectorLabels(zitadel *zitadelv1alpha1.Cluster) *LabelsBuilder { return b.WithApp(appExporter). WithInstance(zitadel.Name) } diff --git a/pkg/builder/login_deployment_builder.go b/pkg/builder/login_deployment_builder.go new file mode 100644 index 0000000..519a608 --- /dev/null +++ b/pkg/builder/login_deployment_builder.go @@ -0,0 +1,120 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + labels "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/labels" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + deployment "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +func (b *Builder) BuildLoginDeployment(cluster *zitadelv1alpha1.Cluster, instance *zitadelv1alpha1.Instance, customDomain string, key types.NamespacedName) (*appsv1.Deployment, error) { + replicas := int32(1) + tag := cluster.Spec.Image.Tag + if instance.Spec.LoginUI.Image.Tag != nil { + tag = *instance.Spec.LoginUI.Image.Tag + } + objMeta := + metadata.NewMetadataBuilder(key). + WithAnnotations(map[string]string{ + "reloader.stakater.com/auto": "true", + }). + Build() + + selectorLabels := + labels.NewLabelsBuilder(). + WithLoginUISelectorLabels(instance). + Build() + templateObjMeta := + metadata.NewMetadataBuilder(client.ObjectKeyFromObject(instance)). + WithLabels(selectorLabels). + Build() + + dep := &appsv1.Deployment{ + ObjectMeta: objMeta, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: selectorLabels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: templateObjMeta, + Spec: corev1.PodSpec{ + // SecurityContext: &corev1.PodSecurityContext{FSGroup: &group}, + Containers: []corev1.Container{ + corev1.Container{ + + Name: "login-ui", + Image: instance.Spec.LoginUI.Image.Name + ":" + tag, + ImagePullPolicy: corev1.PullIfNotPresent, + Env: []corev1.EnvVar{ + { + Name: "ZITADEL_SERVICE_USER_TOKEN_FILE", + Value: "/login-client/pat", + }, + + { + Name: "ZITADEL_API_URL", + Value: fmt.Sprintf("http://%s:%d", deployment.ServiceFQDN(cluster.ObjectMeta), deployment.ZitadelPort), + }, + + { + Name: "CUSTOM_REQUEST_HEADERS", + Value: fmt.Sprintf("Host:%s,X-Zitadel-Public-Host:%s", customDomain, customDomain), + }, + }, + Ports: []corev1.ContainerPort{ + {Name: deployment.LoginName, ContainerPort: deployment.LoginPort}, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/ui/v2/login/healthy", + Port: intstr.FromString(deployment.LoginName), + Scheme: corev1.URISchemeHTTP, + }, + }, + FailureThreshold: 3, + InitialDelaySeconds: 0, + PeriodSeconds: 5, + }, + ReadinessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/ui/v2/login/security", + Port: intstr.FromString(deployment.LoginName), + Scheme: corev1.URISchemeHTTP, + }, + }, + FailureThreshold: 3, + InitialDelaySeconds: 0, + PeriodSeconds: 5, + }, + + Resources: instance.Spec.LoginUI.Resources, + VolumeMounts: []corev1.VolumeMount{ + {Name: "login-ui-pat", MountPath: "/login-client"}, + }, + }, + }, + Volumes: []corev1.Volume{ + {Name: "login-ui-pat", VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{ + SecretName: instance.LoginMachineUserName() + "-pat-secret", + }}}, + }, + }, + }, + }} + if err := controllerutil.SetControllerReference(instance, dep, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference to Deployment: %v", err) + } + return dep, nil +} diff --git a/pkg/builder/machine_user_builder.go b/pkg/builder/machine_user_builder.go new file mode 100644 index 0000000..e9918a3 --- /dev/null +++ b/pkg/builder/machine_user_builder.go @@ -0,0 +1,51 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + zitadelresourcesv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-resources-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +type MachineUserOpts struct { + Instance *zitadelv1alpha1.Instance + Authorizations []zitadelresourcesv1alpha1.Authorization + InternalPermissions []zitadelresourcesv1alpha1.InternalPermissions + Username string +} + +func (b *Builder) BuildMachineUser( + key types.NamespacedName, + opts MachineUserOpts, owner metav1.Object) (*zitadelresourcesv1alpha1.MachineUser, error) { + objMeta := + metadata.NewMetadataBuilder(key). + Build() + + mu := &zitadelresourcesv1alpha1.MachineUser{ + ObjectMeta: objMeta, + Spec: zitadelresourcesv1alpha1.MachineUserSpec{ + OrganizationRef: zitadelresourcesv1alpha1.OrganizationRef{ + ObjectReference: corev1.ObjectReference{ + Kind: "Organization", + Namespace: opts.Instance.Namespace, + Name: opts.Instance.FirstOrgObjectName(), + }, + }, + AccessTokenType: "ACCESS_TOKEN_TYPE_BEARER", + Authorizations: opts.Authorizations, + InternalPermissions: opts.InternalPermissions, + Metadata: []map[string]string{}, + Username: opts.Username, + }, + } + + if err := controllerutil.SetControllerReference(owner, mu, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference in Machine User manifest: %v", err) + } + return mu, nil +} diff --git a/src/pkg/builder/metadata/metadata.go b/pkg/builder/metadata/metadata.go similarity index 81% rename from src/pkg/builder/metadata/metadata.go rename to pkg/builder/metadata/metadata.go index f13532b..2d1213a 100644 --- a/src/pkg/builder/metadata/metadata.go +++ b/pkg/builder/metadata/metadata.go @@ -1,7 +1,7 @@ package metadata import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -22,7 +22,7 @@ func NewMetadataBuilder(key types.NamespacedName) *MetadataBuilder { } } -func (b *MetadataBuilder) WithZitadel(zitadel *zitadelv1alpha1.ZitadelCluster) *MetadataBuilder { +func (b *MetadataBuilder) WithZitadel(zitadel *zitadelv1alpha1.Cluster) *MetadataBuilder { if zitadel == nil { return b } diff --git a/pkg/builder/organization_builder.go b/pkg/builder/organization_builder.go new file mode 100644 index 0000000..3f39f58 --- /dev/null +++ b/pkg/builder/organization_builder.go @@ -0,0 +1,45 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + zitadelresourcesv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-resources-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +type OrganizationOpts struct { + Key types.NamespacedName + Zitadel *zitadelv1alpha1.Instance + OrganizationName string +} + +func (b *Builder) BuildOrganization(opts OrganizationOpts, owner metav1.Object) (*zitadelresourcesv1alpha1.Organization, error) { + objMeta := + metadata.NewMetadataBuilder(opts.Key). + Build() + + org := &zitadelresourcesv1alpha1.Organization{ + ObjectMeta: objMeta, + Spec: zitadelresourcesv1alpha1.OrganizationSpec{ + ConnectionRef: zitadelresourcesv1alpha1.ConnectionRef{ + ObjectReference: corev1.ObjectReference{ + Kind: "Connection", + Namespace: opts.Zitadel.Namespace, + Name: opts.Zitadel.ConnectionObjectName(), + APIVersion: "v1alpha1", + }, + }, + OrganzationName: opts.OrganizationName, + }, + } + + if err := controllerutil.SetControllerReference(owner, org, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference in Organization manifest: %v", err) + } + return org, nil +} diff --git a/src/pkg/builder/secret_builder.go b/pkg/builder/secret_builder.go similarity index 79% rename from src/pkg/builder/secret_builder.go rename to pkg/builder/secret_builder.go index 73078f7..6f31ac1 100644 --- a/src/pkg/builder/secret_builder.go +++ b/pkg/builder/secret_builder.go @@ -1,9 +1,9 @@ package builder import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" "fmt" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -11,7 +11,7 @@ import ( ) type SecretOpts struct { - Zitadel *zitadelv1alpha1.ZitadelCluster + Zitadel *zitadelv1alpha1.Cluster Key types.NamespacedName Data map[string][]byte Labels map[string]string diff --git a/pkg/builder/service_builder.go b/pkg/builder/service_builder.go new file mode 100644 index 0000000..43836e1 --- /dev/null +++ b/pkg/builder/service_builder.go @@ -0,0 +1,69 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + labels "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/labels" + metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +type ServiceOpts struct { + Ports []corev1.ServicePort +} + +func (b *Builder) BuildService(zitadel *zitadelv1alpha1.Cluster, key types.NamespacedName, + opts ServiceOpts) (*corev1.Service, error) { + objMeta := + metadata.NewMetadataBuilder(key). + WithZitadel(zitadel). + Build() + + svc := &corev1.Service{ + ObjectMeta: objMeta, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Ports: opts.Ports, + Selector: serviceSelectorLabels(opts, zitadel), + }, + } + if err := controllerutil.SetControllerReference(zitadel, svc, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference to Service: %v", err) + } + return svc, nil +} + +func (b *Builder) BuildLoginService(instance *zitadelv1alpha1.Instance, key types.NamespacedName, + opts ServiceOpts) (*corev1.Service, error) { + objMeta := + metadata.NewMetadataBuilder(key). + Build() + + svc := &corev1.Service{ + ObjectMeta: objMeta, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Ports: opts.Ports, + Selector: serviceLoginSelectorLabels(opts, instance), + }, + } + if err := controllerutil.SetControllerReference(instance, svc, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference to Service: %v", err) + } + return svc, nil +} + +func serviceLoginSelectorLabels(opts ServiceOpts, instance *zitadelv1alpha1.Instance) map[string]string { + return labels.NewLabelsBuilder(). + WithLoginUISelectorLabels(instance). + Build() +} + +func serviceSelectorLabels(opts ServiceOpts, cluster *zitadelv1alpha1.Cluster) map[string]string { + return labels.NewLabelsBuilder(). + WithZitadelSelectorLabels(cluster). + Build() +} diff --git a/src/pkg/condition/condition.go b/pkg/condition/condition.go similarity index 100% rename from src/pkg/condition/condition.go rename to pkg/condition/condition.go diff --git a/src/pkg/condition/ready.go b/pkg/condition/ready.go similarity index 91% rename from src/pkg/condition/ready.go rename to pkg/condition/ready.go index 2a72b1f..76fce2d 100644 --- a/src/pkg/condition/ready.go +++ b/pkg/condition/ready.go @@ -4,7 +4,7 @@ import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" ) func SetReadyHealthty(c Conditioner) { @@ -51,8 +51,8 @@ func SetReadyFailed(c Conditioner) { SetReadyFailedWithMessage(c, "Failed") } -func SetReadyWithDeployment(c Conditioner, sts *appsv1.Deployment, instanceId string) { - if sts.Status.Replicas == 0 || sts.Status.ReadyReplicas != sts.Status.Replicas || instanceId == "" { +func SetReadyWithDeployment(c Conditioner, sts *appsv1.Deployment) { + if sts.Status.Replicas == 0 || sts.Status.ReadyReplicas != sts.Status.Replicas { c.SetCondition(metav1.Condition{ Type: zitadelv1alpha1.ConditionTypeReady, Status: metav1.ConditionFalse, diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go new file mode 100644 index 0000000..e19fb5f --- /dev/null +++ b/pkg/configuration/configuration.go @@ -0,0 +1,9 @@ +package configuration + +import ( + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" +) + +func ConfigurationName(zitadel *zitadelv1alpha1.Cluster) string { + return zitadel.Name + "-configuration-configmap" +} diff --git a/src/pkg/controller/configmap/controller.go b/pkg/controller/configmap/controller.go similarity index 78% rename from src/pkg/controller/configmap/controller.go rename to pkg/controller/configmap/controller.go index 794fd5d..ac0ecbe 100644 --- a/src/pkg/controller/configmap/controller.go +++ b/pkg/controller/configmap/controller.go @@ -4,10 +4,10 @@ import ( "context" "fmt" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - builder "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + builder "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + systemapiaccount "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/systemapi" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -27,11 +27,10 @@ func NewConfigMapReconciler(client client.Client, builder *builder.Builder) *Con } } -func (r *ConfigMapReconciler) ReconcileZitadelConfiguration(ctx context.Context, key types.NamespacedName, zitadel *zitadelv1alpha1.ZitadelCluster, postgres *cloudnativepgv1.Cluster, base64key string) error { +func (r *ConfigMapReconciler) ReconcileZitadelConfiguration(ctx context.Context, key types.NamespacedName, zitadel *zitadelv1alpha1.Cluster, postgres *cloudnativepgv1.Cluster, base64key string) error { config := make(map[string]string) config["zitadel-config-yaml"] = - fmt.Sprintf(` -Database: + fmt.Sprintf(`Database: Postgres: Host: %s Port: 5432 @@ -57,6 +56,8 @@ Projections: Customizations: smtp_configs: BulkLimit: 2000 +FirstInstance: + Skip: true SystemAPIUsers: - %s: KeyData: %s @@ -66,7 +67,7 @@ SystemAPIUsers: - "SYSTEM_OWNER" - "IAM_OWNER" - "ORG_OWNER" -`, deployment.ServiceFQDNWithService(postgres.ObjectMeta, postgres.Name+"-rw"), zitadel.Spec.Host, zitadel.Spec.ExternalPort, zitadel.Spec.ExternalSecure, masterkey.OwnerName, base64key) +`, deployment.ServiceFQDNWithService(postgres.ObjectMeta, postgres.Name+"-rw"), zitadel.Spec.Host, zitadel.Spec.ExternalPort, zitadel.Spec.ExternalSecure, systemapiaccount.OwnerName, base64key) opts := builder.ConfigMapOpts{ Zitadel: zitadel, diff --git a/src/pkg/controller/secret/controller.go b/pkg/controller/secret/controller.go similarity index 88% rename from src/pkg/controller/secret/controller.go rename to pkg/controller/secret/controller.go index b0101e3..b419486 100644 --- a/src/pkg/controller/secret/controller.go +++ b/pkg/controller/secret/controller.go @@ -8,8 +8,8 @@ import ( "encoding/pem" "fmt" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - builder "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + builder "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder" "github.com/sethvargo/go-password/password" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -29,7 +29,7 @@ func NewSecretReconciler(client client.Client, builder *builder.Builder) *Secret } func (r *SecretReconciler) ReconcileRandomPassword(ctx context.Context, key types.NamespacedName, secretKey string, - zitadel *zitadelv1alpha1.ZitadelCluster) (string, error) { + zitadel *zitadelv1alpha1.Cluster) (string, error) { var existingSecret corev1.Secret if err := r.Get(ctx, key, &existingSecret); err == nil { return string(existingSecret.Data[secretKey]), nil @@ -58,7 +58,7 @@ func (r *SecretReconciler) ReconcileRandomPassword(ctx context.Context, key type } func (r *SecretReconciler) ReconcileRandomPrivateRSA(ctx context.Context, key types.NamespacedName, secretKey string, - zitadel *zitadelv1alpha1.ZitadelCluster) (string, error) { + zitadel *zitadelv1alpha1.Cluster) (string, error) { var existingSecret corev1.Secret if err := r.Get(ctx, key, &existingSecret); err == nil { return string(existingSecret.Data[secretKey]), nil diff --git a/src/pkg/controller/service/controller.go b/pkg/controller/service/controller.go similarity index 100% rename from src/pkg/controller/service/controller.go rename to pkg/controller/service/controller.go diff --git a/src/pkg/controller/zitadel/controller.go b/pkg/controller/system/controller.go similarity index 58% rename from src/pkg/controller/zitadel/controller.go rename to pkg/controller/system/controller.go index 438e416..459ff9d 100644 --- a/src/pkg/controller/zitadel/controller.go +++ b/pkg/controller/system/controller.go @@ -1,4 +1,4 @@ -package zitadel +package system import ( "context" @@ -6,29 +6,29 @@ import ( "fmt" "time" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - health "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/health" - zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" + health "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/health" + zitadelClient "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/zitadel" "github.com/hashicorp/go-multierror" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" ) -type ZitadelReconciler struct { +type SystemReconciler struct { Client client.Client RefResolver *zitadelv1alpha1.RefResolver ConditionReady *condition.Ready - WrappedReconciler WrappedReconciler + WrappedReconciler WrappedSystemReconciler Finalizer Finalizer RequeueInterval time.Duration } -func NewZitadelReconciler(client client.Client, cr *condition.Ready, wr WrappedReconciler, f Finalizer, +func NewSystemReconciler(client client.Client, cr *condition.Ready, wr WrappedSystemReconciler, f Finalizer, requeueInterval time.Duration) Reconciler { - return &ZitadelReconciler{ + return &SystemReconciler{ Client: client, RefResolver: zitadelv1alpha1.NewRefResolver(client), ConditionReady: cr, @@ -38,44 +38,44 @@ func NewZitadelReconciler(client client.Client, cr *condition.Ready, wr WrappedR } } -func (r *ZitadelReconciler) Reconcile(ctx context.Context, resource Resource) (ctrl.Result, error) { +func (r *SystemReconciler) Reconcile(ctx context.Context, resource Resource) (ctrl.Result, error) { if resource.IsBeingDeleted() { if err := r.Finalizer.Finalize(ctx, resource); err != nil { return ctrl.Result{}, fmt.Errorf("error finalizing %s: %v", resource.GetName(), err) } return ctrl.Result{}, nil } - zitadelRef, err := resource.ZitadelClusterRef(ctx, r.RefResolver) + clusterRef, err := resource.ClusterRef(ctx, r.RefResolver) if err != nil { return ctrl.Result{}, err } - zitadel, err := r.RefResolver.ZitadelCluster(ctx, zitadelRef, resource.GetNamespace()) + cluster, err := r.RefResolver.Cluster(ctx, clusterRef, resource.GetNamespace()) if err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) - err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherRefResolver(err, zitadel)) + err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherRefResolver(err, cluster)) errBundle = multierror.Append(errBundle, err) - return ctrl.Result{}, fmt.Errorf("error getting ZitadelCluster: %v", errBundle) + return ctrl.Result{}, fmt.Errorf("error getting Cluster: %v", errBundle) } - if err := waitForZitadelCluster(ctx, r.Client, resource, zitadel); err != nil { + if err := waitForCluster(ctx, r.Client, resource, cluster); err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) err := r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherWithError(err)) errBundle = multierror.Append(errBundle, err) - return ctrl.Result{}, fmt.Errorf("error waiting for Zitadel: %v", errBundle) + return ctrl.Result{}, fmt.Errorf("error waiting for Cluster: %v", errBundle) } - ztdClient, err := zitadelClient.NewClient(ctx, zitadel, *r.RefResolver) + ztdClient, err := zitadelClient.NewSystemClient(ctx, cluster, *r.RefResolver) if err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) - msg := fmt.Sprintf("Error connecting to Zitadel: %v", err) + msg := fmt.Sprintf("Error connecting to System: %v", err) err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherFailed(msg)) errBundle = multierror.Append(errBundle, err) @@ -107,27 +107,27 @@ func (r *ZitadelReconciler) Reconcile(ctx context.Context, resource Resource) (c return r.requeueResult(ctx, resource) } -func (r *ZitadelReconciler) retryResult(ctx context.Context, resource Resource, err error) (ctrl.Result, error) { +func (r *SystemReconciler) retryResult(ctx context.Context, resource Resource, err error) (ctrl.Result, error) { return ctrl.Result{}, err } -func (r *ZitadelReconciler) requeueResult(ctx context.Context, resource Resource) (ctrl.Result, error) { +func (r *SystemReconciler) requeueResult(ctx context.Context, resource Resource) (ctrl.Result, error) { if r.RequeueInterval > 0 { - log.FromContext(ctx).V(1).Info("Requeuing ZITADEL resource") + log.FromContext(ctx).V(1).Info("Requeuing SYSTEM resource") return ctrl.Result{RequeueAfter: r.RequeueInterval}, nil } return ctrl.Result{}, nil } -func waitForZitadelCluster(ctx context.Context, client client.Client, resource Resource, - zitadel *zitadelv1alpha1.ZitadelCluster) error { - var zitadelErr *multierror.Error - healthy, err := health.IsZitadelClusterHealthy(ctx, client, zitadel) +func waitForCluster(ctx context.Context, client client.Client, resource Resource, + system *zitadelv1alpha1.Cluster) error { + var systemErr *multierror.Error + healthy, err := health.IsClusterHealthy(ctx, client, system) if err != nil { - zitadelErr = multierror.Append(zitadelErr, err) + systemErr = multierror.Append(systemErr, err) } if !healthy { - zitadelErr = multierror.Append(zitadelErr, errors.New("Zitadel not healthy")) + systemErr = multierror.Append(systemErr, errors.New("System not healthy")) } - return zitadelErr.ErrorOrNil() + return systemErr.ErrorOrNil() } diff --git a/src/pkg/controller/zitadel/finalizer.go b/pkg/controller/system/finalizer.go similarity index 53% rename from src/pkg/controller/zitadel/finalizer.go rename to pkg/controller/system/finalizer.go index c125f8f..bca4474 100644 --- a/src/pkg/controller/zitadel/finalizer.go +++ b/pkg/controller/system/finalizer.go @@ -1,31 +1,31 @@ -package zitadel +package system import ( "context" "fmt" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + zitadelClient "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/zitadel" apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" ) -type ZitadelFinalizer struct { +type SystemFinalizer struct { Client client.Client RefResolver *zitadelv1alpha1.RefResolver - WrappedFinalizer WrappedFinalizer + WrappedFinalizer WrappedSystemFinalizer } -func NewZitadelFinalizer(client client.Client, wf WrappedFinalizer) Finalizer { - return &ZitadelFinalizer{ +func NewSystemFinalizer(client client.Client, wf WrappedSystemFinalizer) Finalizer { + return &SystemFinalizer{ Client: client, RefResolver: zitadelv1alpha1.NewRefResolver(client), WrappedFinalizer: wf, } } -func (tf *ZitadelFinalizer) AddFinalizer(ctx context.Context) error { +func (tf *SystemFinalizer) AddFinalizer(ctx context.Context) error { if tf.WrappedFinalizer.ContainsFinalizer() { return nil } @@ -35,16 +35,16 @@ func (tf *ZitadelFinalizer) AddFinalizer(ctx context.Context) error { return nil } -func (tf *ZitadelFinalizer) Finalize(ctx context.Context, resource Resource) error { +func (tf *SystemFinalizer) Finalize(ctx context.Context, resource Resource) error { if !tf.WrappedFinalizer.ContainsFinalizer() { return nil } - zitadelRef, err := resource.ZitadelClusterRef(ctx, tf.RefResolver) + clusterRef, err := resource.ClusterRef(ctx, tf.RefResolver) if err != nil { return err } - zitadel, err := tf.RefResolver.ZitadelCluster(ctx, zitadelRef, resource.GetNamespace()) + system, err := tf.RefResolver.Cluster(ctx, clusterRef, resource.GetNamespace()) if err != nil { if apierrors.IsNotFound(err) { if err := tf.WrappedFinalizer.RemoveFinalizer(ctx); err != nil { @@ -52,16 +52,16 @@ func (tf *ZitadelFinalizer) Finalize(ctx context.Context, resource Resource) err } return nil } - return fmt.Errorf("error getting ZitadelCluster: %v", err) + return fmt.Errorf("error getting System: %v", err) } - if err := waitForZitadelCluster(ctx, tf.Client, resource, zitadel); err != nil { - return fmt.Errorf("error waiting for ZitadelCluster: %v", err) + if err := waitForCluster(ctx, tf.Client, resource, system); err != nil { + return fmt.Errorf("error waiting for System: %v", err) } - ztdClient, err := zitadelClient.NewClient(ctx, zitadel, *tf.RefResolver) + ztdClient, err := zitadelClient.NewSystemClient(ctx, system, *tf.RefResolver) if err != nil { - return fmt.Errorf("error connecting to ZitadelCluster: %v", err) + return fmt.Errorf("error connecting to System: %v", err) } defer ztdClient.Connection.Close() diff --git a/pkg/controller/system/types.go b/pkg/controller/system/types.go new file mode 100644 index 0000000..af6c702 --- /dev/null +++ b/pkg/controller/system/types.go @@ -0,0 +1,39 @@ +package system + +import ( + "context" + + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + "github.com/zitadel/zitadel-go/v3/pkg/client/system" + + condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime" +) + +type Resource interface { + v1.Object + ClusterRef(context.Context, *zitadelv1alpha1.RefResolver) (*zitadelv1alpha1.ClusterRef, error) + IsBeingDeleted() bool +} + +type Reconciler interface { + Reconcile(ctx context.Context, resource Resource) (ctrl.Result, error) +} + +type WrappedSystemReconciler interface { + Reconcile(context.Context, *system.Client) error + PatchStatus(context.Context, condition.Patcher) error +} + +type Finalizer interface { + AddFinalizer(context.Context) error + Finalize(context.Context, Resource) error +} + +type WrappedSystemFinalizer interface { + AddFinalizer(context.Context) error + RemoveFinalizer(context.Context) error + ContainsFinalizer() bool + Reconcile(context.Context, *system.Client) error +} diff --git a/src/pkg/deployment/deployment.go b/pkg/deployment/deployment.go similarity index 95% rename from src/pkg/deployment/deployment.go rename to pkg/deployment/deployment.go index e43f50f..0628ee0 100644 --- a/src/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -12,6 +12,8 @@ import ( const ( ZitadelName = "zitadel" ZitadelPort = 8080 + LoginName = "login-ui" + LoginPort = 3000 SecretMountPath = "/var/secrets/" ) diff --git a/src/pkg/health/health.go b/pkg/health/health.go similarity index 70% rename from src/pkg/health/health.go rename to pkg/health/health.go index a32ec34..f396392 100644 --- a/src/pkg/health/health.go +++ b/pkg/health/health.go @@ -3,9 +3,9 @@ package health import ( "context" - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -13,7 +13,7 @@ import ( type EndpointPolicy string -func IsZitadelClusterHealthy(ctx context.Context, client ctrlclient.Client, zitadel *zitadelv1alpha1.ZitadelCluster) (bool, error) { +func IsClusterHealthy(ctx context.Context, client ctrlclient.Client, zitadel *zitadelv1alpha1.Cluster) (bool, error) { key := ctrlclient.ObjectKeyFromObject(zitadel) var dep appsv1.Deployment if err := client.Get(ctx, key, &dep); err != nil { diff --git a/pkg/masterkey/masterkey.go b/pkg/masterkey/masterkey.go new file mode 100644 index 0000000..7d22929 --- /dev/null +++ b/pkg/masterkey/masterkey.go @@ -0,0 +1,13 @@ +package masterkey + +import ( + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" +) + +const ( + Key = "key" +) + +func MasterKeyName(zitadel *zitadelv1alpha1.Cluster) string { + return zitadel.Name + "-masterkey-secret" +} diff --git a/pkg/systemapi/systemapi_account.go b/pkg/systemapi/systemapi_account.go new file mode 100644 index 0000000..6f93d48 --- /dev/null +++ b/pkg/systemapi/systemapi_account.go @@ -0,0 +1,14 @@ +package systemapiaccount + +import ( + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" +) + +const ( + Key = "private.pem" + OwnerName = "k8s-operator" +) + +func SystemAPIAccountName(zitadel *zitadelv1alpha1.Cluster) string { + return zitadel.Name + "-systemapiaccount-secret" +} diff --git a/pkg/zitadel/zitadel.go b/pkg/zitadel/zitadel.go new file mode 100644 index 0000000..d33ab35 --- /dev/null +++ b/pkg/zitadel/zitadel.go @@ -0,0 +1,76 @@ +package zitadel + +import ( + "context" + "fmt" + zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" + "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment" + systemapiaccount "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/systemapi" + "google.golang.org/grpc" + "strings" + + "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel" + + "github.com/zitadel/zitadel-go/v3/pkg/client/system" + corev1 "k8s.io/api/core/v1" +) + +type MachineKey struct { + Type string `json:"type"` + KeyID string `json:"keyId"` + Key string `json:"key"` + UserID string `json:"userId"` +} + +func WithAuthority(cluster *zitadelv1alpha1.Cluster) func() zitadel.Option { + return func() zitadel.Option { + return zitadel.WithDialOptions(grpc.WithAuthority(GetAuthority(cluster))) + } +} + +func NewSystemClient(ctx context.Context, cluster *zitadelv1alpha1.Cluster, refresolver zitadelv1alpha1.RefResolver) (*system.Client, error) { + privateKeyData, err := refresolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: systemapiaccount.SystemAPIAccountName(cluster)}, Key: systemapiaccount.Key}, cluster.Namespace) + if err != nil { + return nil, err + } + systemClient, err := system.NewClient(ctx, GetIssuer(cluster), GetAPI(cluster), + system.JWTProfileFromKey([]byte(strings.TrimSpace(privateKeyData)), systemapiaccount.OwnerName), + system.WithInsecure(), + ) + if err != nil { + return nil, fmt.Errorf("Error creating system client: %v", err) + } + return systemClient, nil +} + +func GetAuthority(zitadel *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("%s:%d", zitadel.Spec.Host, zitadel.Spec.ExternalPort) +} + +func GetInstanceAuthority(zitadel *zitadelv1alpha1.Instance, cluster *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("%s:%d", zitadel.Spec.CustomDomain, cluster.Spec.ExternalPort) +} + +func GetIssuer(zitadel *zitadelv1alpha1.Cluster) string { + scheme := "http" + if zitadel.Spec.ExternalSecure { + scheme = "https" + } + return fmt.Sprintf("%s://%s", scheme, zitadel.Spec.Host) +} + +func GetAPI(zitadel *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("%s:%d", deployment.ServiceFQDN(zitadel.ObjectMeta), deployment.ZitadelPort) +} + +func GetAPIHost(zitadel *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("%s", deployment.ServiceFQDN(zitadel.ObjectMeta)) +} + +func GetAPIPort(zitadel *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("%d", deployment.ZitadelPort) +} + +func GetAPIUrl(zitadel *zitadelv1alpha1.Cluster) string { + return fmt.Sprintf("http://%s:%d", deployment.ServiceFQDN(zitadel.ObjectMeta), deployment.ZitadelPort) +} diff --git a/src/.dockerignore b/src/.dockerignore deleted file mode 100644 index 0f04682..0000000 --- a/src/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file -# Ignore build and test binaries. -bin/ -testbin/ diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index e917e5c..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ - -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib -bin -testbin/* -Dockerfile.cross - -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Kubernetes Generated files - skip generated files, except for vendored files - -!vendor/**/zz_generated.* - -# editor and IDE paraphernalia -.idea -*.swp -*.swo -*~ diff --git a/src/PROJECT b/src/PROJECT deleted file mode 100644 index da86cb5..0000000 --- a/src/PROJECT +++ /dev/null @@ -1,86 +0,0 @@ -# Code generated by tool. DO NOT EDIT. -# This file is used to track the info used to scaffold your project -# and allow the plugins properly work. -# More info: https://book.kubebuilder.io/reference/project-config.html -domain: topmanage.com -layout: -- go.kubebuilder.io/v4-alpha -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} -projectName: src -repo: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src -resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: ZitadelCluster - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: Organization - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: Project - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: OIDCApp - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: MachineUser - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: APIApp - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: Action - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: topmanage.com - group: zitadel - kind: Flow - path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1 - version: v1alpha1 -version: "3" diff --git a/src/api/v1alpha1/action_types.go b/src/api/v1alpha1/action_types.go deleted file mode 100644 index 033efb1..0000000 --- a/src/api/v1alpha1/action_types.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// ActionSpec defines the desired state of Action -type ActionSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +kubebuilder:validation:Required - // +operator-sdk:csv:customresourcedefinitions:type=spec - OrganizationRef OrganizationRef `json:"organizationRef"` - Script string `json:"script"` - // +kubebuilder:default=true - AllowedToFail bool `json:"allowedToFail"` - // +kubebuilder:validation:Type=string - // +kubebuilder:validation:Format=duration - Timeout *metav1.Duration `json:"timeout"` -} - -// ActionStatus defines the observed state of Action -type ActionStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - ActionId string `json:"actionId"` -} - -func (d *ActionStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// Action is the Schema for the actions API -type Action struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ActionSpec `json:"spec,omitempty"` - Status ActionStatus `json:"status,omitempty"` -} - -func (d *Action) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *Action) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *Action) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} - -//+kubebuilder:object:root=true - -// ActionList contains a list of Action -type ActionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Action `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Action{}, &ActionList{}) -} diff --git a/src/api/v1alpha1/apiapp_types.go b/src/api/v1alpha1/apiapp_types.go deleted file mode 100644 index 7b7641d..0000000 --- a/src/api/v1alpha1/apiapp_types.go +++ /dev/null @@ -1,134 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// APIAppSpec defines the desired state of APIApp -type APIAppSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - ProjectRef ProjectRef `json:"projectRef"` - // +kubebuilder:validation:Enum=API_AUTH_METHOD_TYPE_BASIC;API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - AuthMethodType string `json:"authMethodType"` -} - -// APIAppStatus defines the observed state of APIApp -type APIAppStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - AppId string `json:"appId"` - // +kubebuilder:default="" - KeyId string `json:"keyId"` - // +kubebuilder:default="" - ClientId string `json:"clientId"` -} - -func (d *APIAppStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// APIApp is the Schema for the apiapps API -type APIApp struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec APIAppSpec `json:"spec,omitempty"` - Status APIAppStatus `json:"status,omitempty"` -} - -func (d *APIApp) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *APIApp) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *APIApp) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - if project.Status.ProjectId == "" { - return nil, fmt.Errorf("Project has not been created yet...") - } - org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} -func (d *APIApp) Organization(ctx context.Context, refresolver *RefResolver) (*Organization, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - return org, nil -} - -func (d *APIApp) Project(ctx context.Context, refresolver *RefResolver) (*Project, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - return project, nil -} - -//+kubebuilder:object:root=true - -// APIAppList contains a list of APIApp -type APIAppList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []APIApp `json:"items"` -} - -func init() { - SchemeBuilder.Register(&APIApp{}, &APIAppList{}) -} diff --git a/src/api/v1alpha1/flow_types.go b/src/api/v1alpha1/flow_types.go deleted file mode 100644 index f337de4..0000000 --- a/src/api/v1alpha1/flow_types.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// FlowSpec defines the desired state of Flow -type FlowSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +kubebuilder:validation:Required - // +operator-sdk:csv:customresourcedefinitions:type=spec - OrganizationRef OrganizationRef `json:"organizationRef"` - // +kubebuilder:validation:Enum=FLOW_TYPE_EXTERNAL_AUTHENTICATION;"1";"2";"3";"4" - FlowType string `json:"flowType"` - // +kubebuilder:validation:Enum=TRIGGER_TYPE_POST_AUTHENTICATION;TRIGGER_TYPE_PRE_CREATION;TRIGGER_TYPE_POST_CREATION;TRIGGER_TYPE_POST_AUTHENTICATION;TRIGGER_TYPE_PRE_CREATION;TRIGGER_TYPE_POST_CREATION;"1";"2";"3";"4";"5";"6" - TriggerType string `json:"triggerType"` - ActionRefs []ActionRef `json:"actionRefs"` -} - -// FlowStatus defines the observed state of Flow -type FlowStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -func (d *FlowStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// Flow is the Schema for the flows API -type Flow struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FlowSpec `json:"spec,omitempty"` - Status FlowStatus `json:"status,omitempty"` -} - -func (d *Flow) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *Flow) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *Flow) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} - -//+kubebuilder:object:root=true - -// FlowList contains a list of Flow -type FlowList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Flow `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Flow{}, &FlowList{}) -} diff --git a/src/api/v1alpha1/machineuser_types.go b/src/api/v1alpha1/machineuser_types.go deleted file mode 100644 index a4bc10a..0000000 --- a/src/api/v1alpha1/machineuser_types.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -type UserGrant struct { - ProjectRef ProjectRef `json:"projectRef"` - RoleKeys []string `json:"roleKeys,omitempty"` -} - -// MachineUserSpec defines the desired state of MachineUser -type MachineUserSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +kubebuilder:validation:Required - // +operator-sdk:csv:customresourcedefinitions:type=spec - OrganizationRef OrganizationRef `json:"organizationRef" webhook:"inmutable"` - // +kubebuilder:validation:Enum=ACCESS_TOKEN_TYPE_BEARER;ACCESS_TOKEN_TYPE_JWT - AccessTokenType string `json:"accessTokenType"` - UserGrants []UserGrant `json:"userGrants,omitempty"` -} - -// MachineUserStatus defines the observed state of MachineUser -type MachineUserStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - UserId string `json:"userId"` - // +kubebuilder:default="" - KeyId string `json:"keyId"` - // +kubebuilder:default="" - PATId string `json:"patId"` -} - -func (d *MachineUserStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -func (d *MachineUserStatus) GetConditionStatus(conditionType string) bool { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - return meta.IsStatusConditionTrue(d.Conditions, conditionType) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// MachineUser is the Schema for the machineusers API -type MachineUser struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MachineUserSpec `json:"spec,omitempty"` - Status MachineUserStatus `json:"status,omitempty"` -} - -func (d *MachineUser) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *MachineUser) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *MachineUser) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} - -func (d *MachineUser) PatSecretName() string { - return d.Name + "-pat-secret" -} - -func (d *MachineUser) JWTSecretName() string { - return d.Name + "-machinekey-secret" -} - -//+kubebuilder:object:root=true - -// MachineUserList contains a list of MachineUser -type MachineUserList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MachineUser `json:"items"` -} - -func init() { - SchemeBuilder.Register(&MachineUser{}, &MachineUserList{}) -} diff --git a/src/api/v1alpha1/oidcapp_types.go b/src/api/v1alpha1/oidcapp_types.go deleted file mode 100644 index f5f57fa..0000000 --- a/src/api/v1alpha1/oidcapp_types.go +++ /dev/null @@ -1,161 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// +kubebuilder:validation:Enum=OIDC_RESPONSE_TYPE_CODE;OIDC_RESPONSE_TYPE_ID_TOKEN;OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN -type ResponseType string - -// +kubebuilder:validation:Enum=OIDC_GRANT_TYPE_AUTHORIZATION_CODE;OIDC_GRANT_TYPE_IMPLICIT;OIDC_GRANT_TYPE_REFRESH_TOKEN;OIDC_GRANT_TYPE_DEVICE_CODE;OIDC_GRANT_TYPE_TOKEN_EXCHANGE -type GrantType string - -// OIDCAppSpec defines the desired state of OIDCApp -type OIDCAppSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - ProjectRef ProjectRef `json:"projectRef"` - RedirectUris []string `json:"redirectUris"` - ResponseTypes []ResponseType `json:"responseTypes"` - GrantTypes []GrantType `json:"grantTypes"` - // +kubebuilder:validation:Enum=OIDC_APP_TYPE_WEB;OIDC_APP_TYPE_USER_AGENT;OIDC_APP_TYPE_NATIVE - AppType string `json:"appType"` - // +kubebuilder:validation:Enum=OIDC_AUTH_METHOD_TYPE_BASIC;OIDC_AUTH_METHOD_TYPE_POST;OIDC_AUTH_METHOD_TYPE_NONE;OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - AuthMethodType string `json:"authMethodType"` - PostLogoutRedirectUris []string `json:"postLogoutRedirectUris"` - DevMode bool `json:"devMode"` - // +kubebuilder:validation:Enum=OIDC_TOKEN_TYPE_BEARER;OIDC_TOKEN_TYPE_JWT - AccessTokenType string `json:"accessTokenType"` - AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion"` - IdTokenRoleAssertion bool `json:"idTokenRoleAssertion"` - IdTokenUserinfoAssertion bool `json:"idTokenUserinfoAssertion"` - // +kubebuilder:validation:Type=string - // +kubebuilder:validation:Format=duration - ClockSkew *metav1.Duration `json:"clockSkew"` - // +optional - AdditionalOrigins []string `json:"additionalOrigins"` - SkipNativeAppSuccessPage bool `json:"skipNativeAppSuccessPage"` -} - -// OIDCAppStatus defines the observed state of OIDCApp -type OIDCAppStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - AppId string `json:"appId"` - // +kubebuilder:default="" - ClientId string `json:"clientId"` -} - -func (d *OIDCAppStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// OIDCApp is the Schema for the oidcapps API -type OIDCApp struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec OIDCAppSpec `json:"spec,omitempty"` - Status OIDCAppStatus `json:"status,omitempty"` -} - -func (d *OIDCApp) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *OIDCApp) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *OIDCApp) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - - if project.Status.ProjectId == "" { - return nil, fmt.Errorf("Project has not been created yet...") - } - org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} -func (d *OIDCApp) Organization(ctx context.Context, refresolver *RefResolver) (*Organization, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - org, err := refresolver.OrganizationRef(ctx, &project.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - return org, nil -} - -func (d *OIDCApp) Project(ctx context.Context, refresolver *RefResolver) (*Project, error) { - project, err := refresolver.ProjectRef(ctx, &d.Spec.ProjectRef, d.Namespace) - if err != nil { - return nil, err - } - return project, nil -} - -func (d *OIDCApp) ClientSecretName() string { - return d.Name + "-client-secret" -} - -//+kubebuilder:object:root=true - -// OIDCAppList contains a list of OIDCApp -type OIDCAppList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []OIDCApp `json:"items"` -} - -func init() { - SchemeBuilder.Register(&OIDCApp{}, &OIDCAppList{}) -} diff --git a/src/api/v1alpha1/organization_types.go b/src/api/v1alpha1/organization_types.go deleted file mode 100644 index d3009d3..0000000 --- a/src/api/v1alpha1/organization_types.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -type OrganizationAdmin struct { - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - Email string `json:"email"` - UserName string `json:"userName"` -} - -// OrganizationSpec defines the desired state of Organization -type OrganizationSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // +kubebuilder:validation:Required - // +operator-sdk:csv:customresourcedefinitions:type=spec - ZitadelClusterRef ZitadelClusterRef `json:"zitadelClusterRef" webhook:"inmutable"` - OrganizationAdmin OrganizationAdmin `json:"organizationAdmin"` -} - -// OrganizationStatus defines the observed state of Organization -type OrganizationStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // Conditions for the Database object. - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - OrgId string `json:"orgId"` - // +kubebuilder:default="" - AdminId string `json:"adminId"` -} - -func (d *OrganizationStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// Organization is the Schema for the organizations API -type Organization struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec OrganizationSpec `json:"spec,omitempty"` - Status OrganizationStatus `json:"status,omitempty"` -} - -func (d *Organization) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *Organization) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *Organization) ZitadelClusterRef(_ context.Context, _ *RefResolver) (*ZitadelClusterRef, error) { - return &d.Spec.ZitadelClusterRef, nil -} - -//+kubebuilder:object:root=true - -// OrganizationList contains a list of Organization -type OrganizationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Organization `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Organization{}, &OrganizationList{}) -} diff --git a/src/api/v1alpha1/project_types.go b/src/api/v1alpha1/project_types.go deleted file mode 100644 index a84dd7d..0000000 --- a/src/api/v1alpha1/project_types.go +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2024. - -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 v1alpha1 - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -type Role struct { - Key string `json:"key"` - DisplayName string `json:"displayName"` - Group string `json:"group"` -} -type Grant struct { - OrganizationRef OrganizationRef `json:"organizationRef"` - RoleKeys []string `json:"roleKeys"` -} - -// ProjectSpec defines the desired state of Project -type ProjectSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // https://zitadel.com/docs/apis/resources/mgmt/management-service-add-project - // +kubebuilder:validation:Required - // +operator-sdk:csv:customresourcedefinitions:type=spec - OrganizationRef OrganizationRef `json:"organizationRef"` - // +optional - Roles []Role `json:"roles"` - // +optional - Grants []Grant `json:"grants"` - // +optional - ProjectRoleAssertion bool `json:"projectRoleAssertion,omitempty"` - // +optional - ProjectRoleCheck bool `json:"projectRoleCheck,omitempty"` - // +optional - HasProjectCheck bool `json:"hasProjectCheck,omitempty"` -} - -// ProjectStatus defines the observed state of Project -type ProjectStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - // Conditions for the Database object. - // +optional - // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} - Conditions []metav1.Condition `json:"conditions,omitempty"` - // +kubebuilder:default="" - ProjectId string `json:"projectId"` -} - -func (d *ProjectStatus) SetCondition(condition metav1.Condition) { - if d.Conditions == nil { - d.Conditions = make([]metav1.Condition, 0) - } - meta.SetStatusCondition(&d.Conditions, condition) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// Project is the Schema for the projects API -type Project struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ProjectSpec `json:"spec,omitempty"` - Status ProjectStatus `json:"status,omitempty"` -} - -func (d *Project) IsBeingDeleted() bool { - return !d.DeletionTimestamp.IsZero() -} - -func (d *Project) IsReady() bool { - return meta.IsStatusConditionTrue(d.Status.Conditions, ConditionTypeReady) -} - -func (d *Project) ZitadelClusterRef(ctx context.Context, refresolver *RefResolver) (*ZitadelClusterRef, error) { - org, err := refresolver.OrganizationRef(ctx, &d.Spec.OrganizationRef, d.Namespace) - if err != nil { - return nil, err - } - if org.Status.OrgId == "" { - return nil, fmt.Errorf("Organization has not been created yet...") - } - - ref, err := org.ZitadelClusterRef(ctx, refresolver) - if err != nil { - return nil, err - } - return ref, nil -} - -//+kubebuilder:object:root=true - -// ProjectList contains a list of Project -type ProjectList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Project `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Project{}, &ProjectList{}) -} diff --git a/src/api/v1alpha1/ref_types.go b/src/api/v1alpha1/ref_types.go deleted file mode 100644 index 3ed754d..0000000 --- a/src/api/v1alpha1/ref_types.go +++ /dev/null @@ -1,41 +0,0 @@ -package v1alpha1 - -import ( - corev1 "k8s.io/api/core/v1" -) - -type OIDCAppRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} - -type PostgreSQLClusterRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} - -type ZitadelClusterRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} - -type OrganizationRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} - -type ProjectRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} - -type ActionRef struct { - // ObjectReference is a reference to a object. - // +operator-sdk:csv:customresourcedefinitions:type=spec - corev1.ObjectReference `json:",inline"` -} diff --git a/src/api/v1alpha1/zz_generated.deepcopy.go b/src/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 46e6c5e..0000000 --- a/src/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,1124 +0,0 @@ -//go:build !ignore_autogenerated - -/* -Copyright 2024. - -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. -*/ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *APIApp) DeepCopyInto(out *APIApp) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIApp. -func (in *APIApp) DeepCopy() *APIApp { - if in == nil { - return nil - } - out := new(APIApp) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *APIApp) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *APIAppList) DeepCopyInto(out *APIAppList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]APIApp, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIAppList. -func (in *APIAppList) DeepCopy() *APIAppList { - if in == nil { - return nil - } - out := new(APIAppList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *APIAppList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *APIAppSpec) DeepCopyInto(out *APIAppSpec) { - *out = *in - out.ProjectRef = in.ProjectRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIAppSpec. -func (in *APIAppSpec) DeepCopy() *APIAppSpec { - if in == nil { - return nil - } - out := new(APIAppSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *APIAppStatus) DeepCopyInto(out *APIAppStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIAppStatus. -func (in *APIAppStatus) DeepCopy() *APIAppStatus { - if in == nil { - return nil - } - out := new(APIAppStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Action) DeepCopyInto(out *Action) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Action. -func (in *Action) DeepCopy() *Action { - if in == nil { - return nil - } - out := new(Action) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Action) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ActionList) DeepCopyInto(out *ActionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Action, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionList. -func (in *ActionList) DeepCopy() *ActionList { - if in == nil { - return nil - } - out := new(ActionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ActionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ActionRef) DeepCopyInto(out *ActionRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionRef. -func (in *ActionRef) DeepCopy() *ActionRef { - if in == nil { - return nil - } - out := new(ActionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ActionSpec) DeepCopyInto(out *ActionSpec) { - *out = *in - out.OrganizationRef = in.OrganizationRef - if in.Timeout != nil { - in, out := &in.Timeout, &out.Timeout - *out = new(v1.Duration) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionSpec. -func (in *ActionSpec) DeepCopy() *ActionSpec { - if in == nil { - return nil - } - out := new(ActionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ActionStatus) DeepCopyInto(out *ActionStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionStatus. -func (in *ActionStatus) DeepCopy() *ActionStatus { - if in == nil { - return nil - } - out := new(ActionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainSettings) DeepCopyInto(out *DomainSettings) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainSettings. -func (in *DomainSettings) DeepCopy() *DomainSettings { - if in == nil { - return nil - } - out := new(DomainSettings) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Flow) DeepCopyInto(out *Flow) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Flow. -func (in *Flow) DeepCopy() *Flow { - if in == nil { - return nil - } - out := new(Flow) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Flow) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlowList) DeepCopyInto(out *FlowList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Flow, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowList. -func (in *FlowList) DeepCopy() *FlowList { - if in == nil { - return nil - } - out := new(FlowList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FlowList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlowSpec) DeepCopyInto(out *FlowSpec) { - *out = *in - out.OrganizationRef = in.OrganizationRef - if in.ActionRefs != nil { - in, out := &in.ActionRefs, &out.ActionRefs - *out = make([]ActionRef, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowSpec. -func (in *FlowSpec) DeepCopy() *FlowSpec { - if in == nil { - return nil - } - out := new(FlowSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlowStatus) DeepCopyInto(out *FlowStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowStatus. -func (in *FlowStatus) DeepCopy() *FlowStatus { - if in == nil { - return nil - } - out := new(FlowStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Grant) DeepCopyInto(out *Grant) { - *out = *in - out.OrganizationRef = in.OrganizationRef - if in.RoleKeys != nil { - in, out := &in.RoleKeys, &out.RoleKeys - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Grant. -func (in *Grant) DeepCopy() *Grant { - if in == nil { - return nil - } - out := new(Grant) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Image) DeepCopyInto(out *Image) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. -func (in *Image) DeepCopy() *Image { - if in == nil { - return nil - } - out := new(Image) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineUser) DeepCopyInto(out *MachineUser) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineUser. -func (in *MachineUser) DeepCopy() *MachineUser { - if in == nil { - return nil - } - out := new(MachineUser) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineUser) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineUserList) DeepCopyInto(out *MachineUserList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineUser, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineUserList. -func (in *MachineUserList) DeepCopy() *MachineUserList { - if in == nil { - return nil - } - out := new(MachineUserList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineUserList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineUserSpec) DeepCopyInto(out *MachineUserSpec) { - *out = *in - out.OrganizationRef = in.OrganizationRef - if in.UserGrants != nil { - in, out := &in.UserGrants, &out.UserGrants - *out = make([]UserGrant, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineUserSpec. -func (in *MachineUserSpec) DeepCopy() *MachineUserSpec { - if in == nil { - return nil - } - out := new(MachineUserSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineUserStatus) DeepCopyInto(out *MachineUserStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineUserStatus. -func (in *MachineUserStatus) DeepCopy() *MachineUserStatus { - if in == nil { - return nil - } - out := new(MachineUserStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCApp) DeepCopyInto(out *OIDCApp) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCApp. -func (in *OIDCApp) DeepCopy() *OIDCApp { - if in == nil { - return nil - } - out := new(OIDCApp) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *OIDCApp) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCAppList) DeepCopyInto(out *OIDCAppList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]OIDCApp, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCAppList. -func (in *OIDCAppList) DeepCopy() *OIDCAppList { - if in == nil { - return nil - } - out := new(OIDCAppList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *OIDCAppList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCAppRef) DeepCopyInto(out *OIDCAppRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCAppRef. -func (in *OIDCAppRef) DeepCopy() *OIDCAppRef { - if in == nil { - return nil - } - out := new(OIDCAppRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCAppSpec) DeepCopyInto(out *OIDCAppSpec) { - *out = *in - out.ProjectRef = in.ProjectRef - if in.RedirectUris != nil { - in, out := &in.RedirectUris, &out.RedirectUris - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.ResponseTypes != nil { - in, out := &in.ResponseTypes, &out.ResponseTypes - *out = make([]ResponseType, len(*in)) - copy(*out, *in) - } - if in.GrantTypes != nil { - in, out := &in.GrantTypes, &out.GrantTypes - *out = make([]GrantType, len(*in)) - copy(*out, *in) - } - if in.PostLogoutRedirectUris != nil { - in, out := &in.PostLogoutRedirectUris, &out.PostLogoutRedirectUris - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.ClockSkew != nil { - in, out := &in.ClockSkew, &out.ClockSkew - *out = new(v1.Duration) - **out = **in - } - if in.AdditionalOrigins != nil { - in, out := &in.AdditionalOrigins, &out.AdditionalOrigins - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCAppSpec. -func (in *OIDCAppSpec) DeepCopy() *OIDCAppSpec { - if in == nil { - return nil - } - out := new(OIDCAppSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OIDCAppStatus) DeepCopyInto(out *OIDCAppStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCAppStatus. -func (in *OIDCAppStatus) DeepCopy() *OIDCAppStatus { - if in == nil { - return nil - } - out := new(OIDCAppStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Organization) DeepCopyInto(out *Organization) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Organization. -func (in *Organization) DeepCopy() *Organization { - if in == nil { - return nil - } - out := new(Organization) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Organization) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OrganizationAdmin) DeepCopyInto(out *OrganizationAdmin) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrganizationAdmin. -func (in *OrganizationAdmin) DeepCopy() *OrganizationAdmin { - if in == nil { - return nil - } - out := new(OrganizationAdmin) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OrganizationList) DeepCopyInto(out *OrganizationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Organization, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrganizationList. -func (in *OrganizationList) DeepCopy() *OrganizationList { - if in == nil { - return nil - } - out := new(OrganizationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *OrganizationList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OrganizationRef) DeepCopyInto(out *OrganizationRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrganizationRef. -func (in *OrganizationRef) DeepCopy() *OrganizationRef { - if in == nil { - return nil - } - out := new(OrganizationRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OrganizationSpec) DeepCopyInto(out *OrganizationSpec) { - *out = *in - out.ZitadelClusterRef = in.ZitadelClusterRef - out.OrganizationAdmin = in.OrganizationAdmin -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrganizationSpec. -func (in *OrganizationSpec) DeepCopy() *OrganizationSpec { - if in == nil { - return nil - } - out := new(OrganizationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OrganizationStatus) DeepCopyInto(out *OrganizationStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrganizationStatus. -func (in *OrganizationStatus) DeepCopy() *OrganizationStatus { - if in == nil { - return nil - } - out := new(OrganizationStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Password) DeepCopyInto(out *Password) { - *out = *in - in.SecretKeyRef.DeepCopyInto(&out.SecretKeyRef) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Password. -func (in *Password) DeepCopy() *Password { - if in == nil { - return nil - } - out := new(Password) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PostgreSQLClusterRef) DeepCopyInto(out *PostgreSQLClusterRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgreSQLClusterRef. -func (in *PostgreSQLClusterRef) DeepCopy() *PostgreSQLClusterRef { - if in == nil { - return nil - } - out := new(PostgreSQLClusterRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Project) DeepCopyInto(out *Project) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Project. -func (in *Project) DeepCopy() *Project { - if in == nil { - return nil - } - out := new(Project) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Project) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectList) DeepCopyInto(out *ProjectList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Project, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectList. -func (in *ProjectList) DeepCopy() *ProjectList { - if in == nil { - return nil - } - out := new(ProjectList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProjectList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectRef) DeepCopyInto(out *ProjectRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectRef. -func (in *ProjectRef) DeepCopy() *ProjectRef { - if in == nil { - return nil - } - out := new(ProjectRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectSpec) DeepCopyInto(out *ProjectSpec) { - *out = *in - out.OrganizationRef = in.OrganizationRef - if in.Roles != nil { - in, out := &in.Roles, &out.Roles - *out = make([]Role, len(*in)) - copy(*out, *in) - } - if in.Grants != nil { - in, out := &in.Grants, &out.Grants - *out = make([]Grant, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSpec. -func (in *ProjectSpec) DeepCopy() *ProjectSpec { - if in == nil { - return nil - } - out := new(ProjectSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectStatus) DeepCopyInto(out *ProjectStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectStatus. -func (in *ProjectStatus) DeepCopy() *ProjectStatus { - if in == nil { - return nil - } - out := new(ProjectStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Role) DeepCopyInto(out *Role) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Role. -func (in *Role) DeepCopy() *Role { - if in == nil { - return nil - } - out := new(Role) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SMTPConfig) DeepCopyInto(out *SMTPConfig) { - *out = *in - if in.User != nil { - in, out := &in.User, &out.User - *out = new(string) - **out = **in - } - if in.Password != nil { - in, out := &in.Password, &out.Password - *out = new(Password) - (*in).DeepCopyInto(*out) - } - if in.ReplyToAddress != nil { - in, out := &in.ReplyToAddress, &out.ReplyToAddress - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SMTPConfig. -func (in *SMTPConfig) DeepCopy() *SMTPConfig { - if in == nil { - return nil - } - out := new(SMTPConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UserGrant) DeepCopyInto(out *UserGrant) { - *out = *in - out.ProjectRef = in.ProjectRef - if in.RoleKeys != nil { - in, out := &in.RoleKeys, &out.RoleKeys - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserGrant. -func (in *UserGrant) DeepCopy() *UserGrant { - if in == nil { - return nil - } - out := new(UserGrant) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZitadelCluster) DeepCopyInto(out *ZitadelCluster) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelCluster. -func (in *ZitadelCluster) DeepCopy() *ZitadelCluster { - if in == nil { - return nil - } - out := new(ZitadelCluster) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ZitadelCluster) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZitadelClusterList) DeepCopyInto(out *ZitadelClusterList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]ZitadelCluster, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelClusterList. -func (in *ZitadelClusterList) DeepCopy() *ZitadelClusterList { - if in == nil { - return nil - } - out := new(ZitadelClusterList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ZitadelClusterList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZitadelClusterRef) DeepCopyInto(out *ZitadelClusterRef) { - *out = *in - out.ObjectReference = in.ObjectReference -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelClusterRef. -func (in *ZitadelClusterRef) DeepCopy() *ZitadelClusterRef { - if in == nil { - return nil - } - out := new(ZitadelClusterRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZitadelClusterSpec) DeepCopyInto(out *ZitadelClusterSpec) { - *out = *in - out.DomainSettings = in.DomainSettings - in.SMTPConfig.DeepCopyInto(&out.SMTPConfig) - out.Image = in.Image - in.Resources.DeepCopyInto(&out.Resources) - out.PostgreSQLClusterRef = in.PostgreSQLClusterRef - if in.PodAnnotations != nil { - in, out := &in.PodAnnotations, &out.PodAnnotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.ServiceAnnotations != nil { - in, out := &in.ServiceAnnotations, &out.ServiceAnnotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelClusterSpec. -func (in *ZitadelClusterSpec) DeepCopy() *ZitadelClusterSpec { - if in == nil { - return nil - } - out := new(ZitadelClusterSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ZitadelClusterStatus) DeepCopyInto(out *ZitadelClusterStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelClusterStatus. -func (in *ZitadelClusterStatus) DeepCopy() *ZitadelClusterStatus { - if in == nil { - return nil - } - out := new(ZitadelClusterStatus) - in.DeepCopyInto(out) - return out -} diff --git a/src/config/crd/bases/zitadel.topmanage.com_actions.yaml b/src/config/crd/bases/zitadel.topmanage.com_actions.yaml deleted file mode 100644 index 25ec2ee..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_actions.yaml +++ /dev/null @@ -1,173 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: actions.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Action - listKind: ActionList - plural: actions - singular: action - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Action is the Schema for the actions API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: ActionSpec defines the desired state of Action - properties: - allowedToFail: - default: true - type: boolean - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - script: - type: string - timeout: - format: duration - type: string - required: - - allowedToFail - - organizationRef - - script - - timeout - type: object - status: - description: ActionStatus defines the observed state of Action - properties: - actionId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - actionId - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/bases/zitadel.topmanage.com_apiapps.yaml b/src/config/crd/bases/zitadel.topmanage.com_apiapps.yaml deleted file mode 100644 index 0e100e4..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_apiapps.yaml +++ /dev/null @@ -1,176 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: apiapps.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: APIApp - listKind: APIAppList - plural: apiapps - singular: apiapp - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: APIApp is the Schema for the apiapps API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: APIAppSpec defines the desired state of APIApp - properties: - authMethodType: - enum: - - API_AUTH_METHOD_TYPE_BASIC - - API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - type: string - projectRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - required: - - authMethodType - - projectRef - type: object - status: - description: APIAppStatus defines the observed state of APIApp - properties: - appId: - default: "" - type: string - clientId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - keyId: - default: "" - type: string - required: - - appId - - clientId - - keyId - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/bases/zitadel.topmanage.com_flows.yaml b/src/config/crd/bases/zitadel.topmanage.com_flows.yaml deleted file mode 100644 index 10c13fb..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_flows.yaml +++ /dev/null @@ -1,227 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: flows.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Flow - listKind: FlowList - plural: flows - singular: flow - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Flow is the Schema for the flows API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: FlowSpec defines the desired state of Flow - properties: - actionRefs: - items: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - type: array - flowType: - enum: - - FLOW_TYPE_EXTERNAL_AUTHENTICATION - - "1" - - "2" - - "3" - - "4" - type: string - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - triggerType: - enum: - - TRIGGER_TYPE_POST_AUTHENTICATION - - TRIGGER_TYPE_PRE_CREATION - - TRIGGER_TYPE_POST_CREATION - - TRIGGER_TYPE_POST_AUTHENTICATION - - TRIGGER_TYPE_PRE_CREATION - - TRIGGER_TYPE_POST_CREATION - - "1" - - "2" - - "3" - - "4" - - "5" - - "6" - type: string - required: - - actionRefs - - flowType - - organizationRef - - triggerType - type: object - status: - description: FlowStatus defines the observed state of Flow - properties: - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/bases/zitadel.topmanage.com_oidcapps.yaml b/src/config/crd/bases/zitadel.topmanage.com_oidcapps.yaml deleted file mode 100644 index c38e3d1..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_oidcapps.yaml +++ /dev/null @@ -1,240 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: oidcapps.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: OIDCApp - listKind: OIDCAppList - plural: oidcapps - singular: oidcapp - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: OIDCApp is the Schema for the oidcapps API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: OIDCAppSpec defines the desired state of OIDCApp - properties: - accessTokenRoleAssertion: - type: boolean - accessTokenType: - enum: - - OIDC_TOKEN_TYPE_BEARER - - OIDC_TOKEN_TYPE_JWT - type: string - additionalOrigins: - items: - type: string - type: array - appType: - enum: - - OIDC_APP_TYPE_WEB - - OIDC_APP_TYPE_USER_AGENT - - OIDC_APP_TYPE_NATIVE - type: string - authMethodType: - enum: - - OIDC_AUTH_METHOD_TYPE_BASIC - - OIDC_AUTH_METHOD_TYPE_POST - - OIDC_AUTH_METHOD_TYPE_NONE - - OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT - type: string - clockSkew: - format: duration - type: string - devMode: - type: boolean - grantTypes: - items: - enum: - - OIDC_GRANT_TYPE_AUTHORIZATION_CODE - - OIDC_GRANT_TYPE_IMPLICIT - - OIDC_GRANT_TYPE_REFRESH_TOKEN - - OIDC_GRANT_TYPE_DEVICE_CODE - - OIDC_GRANT_TYPE_TOKEN_EXCHANGE - type: string - type: array - idTokenRoleAssertion: - type: boolean - idTokenUserinfoAssertion: - type: boolean - postLogoutRedirectUris: - items: - type: string - type: array - projectRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - redirectUris: - items: - type: string - type: array - responseTypes: - items: - enum: - - OIDC_RESPONSE_TYPE_CODE - - OIDC_RESPONSE_TYPE_ID_TOKEN - - OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN - type: string - type: array - skipNativeAppSuccessPage: - type: boolean - required: - - accessTokenRoleAssertion - - accessTokenType - - appType - - authMethodType - - clockSkew - - devMode - - grantTypes - - idTokenRoleAssertion - - idTokenUserinfoAssertion - - postLogoutRedirectUris - - projectRef - - redirectUris - - responseTypes - - skipNativeAppSuccessPage - type: object - status: - description: OIDCAppStatus defines the observed state of OIDCApp - properties: - appId: - default: "" - type: string - clientId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - appId - - clientId - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/bases/zitadel.topmanage.com_organizations.yaml b/src/config/crd/bases/zitadel.topmanage.com_organizations.yaml deleted file mode 100644 index 60bdfce..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_organizations.yaml +++ /dev/null @@ -1,184 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: organizations.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Organization - listKind: OrganizationList - plural: organizations - singular: organization - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Organization is the Schema for the organizations API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: OrganizationSpec defines the desired state of Organization - properties: - organizationAdmin: - properties: - email: - type: string - firstName: - type: string - lastName: - type: string - userName: - type: string - required: - - email - - firstName - - lastName - - userName - type: object - zitadelClusterRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - required: - - organizationAdmin - - zitadelClusterRef - type: object - status: - description: OrganizationStatus defines the observed state of Organization - properties: - adminId: - default: "" - type: string - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - Conditions for the Database object. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - orgId: - default: "" - type: string - required: - - adminId - - orgId - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/bases/zitadel.topmanage.com_projects.yaml b/src/config/crd/bases/zitadel.topmanage.com_projects.yaml deleted file mode 100644 index 63e3c89..0000000 --- a/src/config/crd/bases/zitadel.topmanage.com_projects.yaml +++ /dev/null @@ -1,239 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.3 - name: projects.zitadel.topmanage.com -spec: - group: zitadel.topmanage.com - names: - kind: Project - listKind: ProjectList - plural: projects - singular: project - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Project is the Schema for the projects API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: ProjectSpec defines the desired state of Project - properties: - grants: - items: - properties: - organizationRef: - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - roleKeys: - items: - type: string - type: array - required: - - organizationRef - - roleKeys - type: object - type: array - hasProjectCheck: - type: boolean - organizationRef: - description: |- - INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file - https://zitadel.com/docs/apis/resources/mgmt/management-service-add-project - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - projectRoleAssertion: - type: boolean - projectRoleCheck: - type: boolean - roles: - items: - properties: - displayName: - type: string - group: - type: string - key: - type: string - required: - - displayName - - group - - key - type: object - type: array - required: - - organizationRef - type: object - status: - description: ProjectStatus defines the observed state of Project - properties: - conditions: - description: |- - INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - Important: Run "make" to regenerate code after modifying this file - Conditions for the Database object. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - projectId: - default: "" - type: string - required: - - projectId - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/src/config/crd/patches/cainjection_in_actions.yaml b/src/config/crd/patches/cainjection_in_actions.yaml deleted file mode 100644 index 0b731e9..0000000 --- a/src/config/crd/patches/cainjection_in_actions.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: actions.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_apiapps.yaml b/src/config/crd/patches/cainjection_in_apiapps.yaml deleted file mode 100644 index 9332f3d..0000000 --- a/src/config/crd/patches/cainjection_in_apiapps.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: apiapps.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_flows.yaml b/src/config/crd/patches/cainjection_in_flows.yaml deleted file mode 100644 index 57b4d50..0000000 --- a/src/config/crd/patches/cainjection_in_flows.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: flows.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_machineusers.yaml b/src/config/crd/patches/cainjection_in_machineusers.yaml deleted file mode 100644 index 49e3ea2..0000000 --- a/src/config/crd/patches/cainjection_in_machineusers.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: machineusers.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_oidcapps.yaml b/src/config/crd/patches/cainjection_in_oidcapps.yaml deleted file mode 100644 index 044872a..0000000 --- a/src/config/crd/patches/cainjection_in_oidcapps.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: oidcapps.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_organizations.yaml b/src/config/crd/patches/cainjection_in_organizations.yaml deleted file mode 100644 index 96ad346..0000000 --- a/src/config/crd/patches/cainjection_in_organizations.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: organizations.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_projects.yaml b/src/config/crd/patches/cainjection_in_projects.yaml deleted file mode 100644 index 499c34e..0000000 --- a/src/config/crd/patches/cainjection_in_projects.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: projects.zitadel.topmanage.com diff --git a/src/config/crd/patches/cainjection_in_zitadelclusters.yaml b/src/config/crd/patches/cainjection_in_zitadelclusters.yaml deleted file mode 100644 index 97750e2..0000000 --- a/src/config/crd/patches/cainjection_in_zitadelclusters.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME - name: zitadelclusters.zitadel.topmanage.com diff --git a/src/config/crd/patches/webhook_in_actions.yaml b/src/config/crd/patches/webhook_in_actions.yaml deleted file mode 100644 index 3841844..0000000 --- a/src/config/crd/patches/webhook_in_actions.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: actions.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_apiapps.yaml b/src/config/crd/patches/webhook_in_apiapps.yaml deleted file mode 100644 index 04173a6..0000000 --- a/src/config/crd/patches/webhook_in_apiapps.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: apiapps.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_flows.yaml b/src/config/crd/patches/webhook_in_flows.yaml deleted file mode 100644 index 4b0187c..0000000 --- a/src/config/crd/patches/webhook_in_flows.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: flows.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_machineusers.yaml b/src/config/crd/patches/webhook_in_machineusers.yaml deleted file mode 100644 index f4ca8cc..0000000 --- a/src/config/crd/patches/webhook_in_machineusers.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: machineusers.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_oidcapps.yaml b/src/config/crd/patches/webhook_in_oidcapps.yaml deleted file mode 100644 index 1a7bc04..0000000 --- a/src/config/crd/patches/webhook_in_oidcapps.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: oidcapps.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_organizations.yaml b/src/config/crd/patches/webhook_in_organizations.yaml deleted file mode 100644 index e61684e..0000000 --- a/src/config/crd/patches/webhook_in_organizations.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: organizations.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_projects.yaml b/src/config/crd/patches/webhook_in_projects.yaml deleted file mode 100644 index 666f241..0000000 --- a/src/config/crd/patches/webhook_in_projects.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: projects.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/crd/patches/webhook_in_zitadelclusters.yaml b/src/config/crd/patches/webhook_in_zitadelclusters.yaml deleted file mode 100644 index dd696dc..0000000 --- a/src/config/crd/patches/webhook_in_zitadelclusters.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: zitadelclusters.zitadel.topmanage.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/src/config/manifests/kustomization.yaml b/src/config/manifests/kustomization.yaml deleted file mode 100644 index c803400..0000000 --- a/src/config/manifests/kustomization.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# These resources constitute the fully configured set of manifests -# used to generate the 'manifests/' directory in a bundle. -resources: -- bases/src.clusterserviceversion.yaml -- ../default -- ../samples -- ../scorecard - -# [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. -# Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. -# These patches remove the unnecessary "cert" volume and its manager container volumeMount. -#patchesJson6902: -#- target: -# group: apps -# version: v1 -# kind: Deployment -# name: controller-manager -# namespace: system -# patch: |- -# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. -# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. -# - op: remove - -# path: /spec/template/spec/containers/0/volumeMounts/0 -# # Remove the "cert" volume, since OLM will create and mount a set of certs. -# # Update the indices in this path if adding or removing volumes in the manager's Deployment. -# - op: remove -# path: /spec/template/spec/volumes/0 diff --git a/src/config/prometheus/kustomization.yaml b/src/config/prometheus/kustomization.yaml deleted file mode 100644 index ed13716..0000000 --- a/src/config/prometheus/kustomization.yaml +++ /dev/null @@ -1,2 +0,0 @@ -resources: -- monitor.yaml diff --git a/src/config/prometheus/monitor.yaml b/src/config/prometheus/monitor.yaml deleted file mode 100644 index ecad441..0000000 --- a/src/config/prometheus/monitor.yaml +++ /dev/null @@ -1,26 +0,0 @@ - -# Prometheus Monitor Service (Metrics) -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: servicemonitor - app.kubernetes.io/instance: controller-manager-metrics-monitor - app.kubernetes.io/component: metrics - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: controller-manager-metrics-monitor - namespace: system -spec: - endpoints: - - path: /metrics - port: https - scheme: https - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token - tlsConfig: - insecureSkipVerify: true - selector: - matchLabels: - control-plane: controller-manager diff --git a/src/config/rbac/action_editor_role.yaml b/src/config/rbac/action_editor_role.yaml deleted file mode 100644 index 2bb95fc..0000000 --- a/src/config/rbac/action_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit actions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: action-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: action-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - actions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - actions/status - verbs: - - get diff --git a/src/config/rbac/action_viewer_role.yaml b/src/config/rbac/action_viewer_role.yaml deleted file mode 100644 index 5e1b269..0000000 --- a/src/config/rbac/action_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view actions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: action-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: action-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - actions - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - actions/status - verbs: - - get diff --git a/src/config/rbac/apiapp_editor_role.yaml b/src/config/rbac/apiapp_editor_role.yaml deleted file mode 100644 index 3bf43db..0000000 --- a/src/config/rbac/apiapp_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit apiapps. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: apiapp-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: apiapp-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - apiapps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - apiapps/status - verbs: - - get diff --git a/src/config/rbac/apiapp_viewer_role.yaml b/src/config/rbac/apiapp_viewer_role.yaml deleted file mode 100644 index 042b6f3..0000000 --- a/src/config/rbac/apiapp_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view apiapps. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: apiapp-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: apiapp-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - apiapps - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - apiapps/status - verbs: - - get diff --git a/src/config/rbac/flow_editor_role.yaml b/src/config/rbac/flow_editor_role.yaml deleted file mode 100644 index a9f28b7..0000000 --- a/src/config/rbac/flow_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit flows. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: flow-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: flow-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - flows - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - flows/status - verbs: - - get diff --git a/src/config/rbac/flow_viewer_role.yaml b/src/config/rbac/flow_viewer_role.yaml deleted file mode 100644 index da5ef2c..0000000 --- a/src/config/rbac/flow_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view flows. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: flow-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: flow-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - flows - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - flows/status - verbs: - - get diff --git a/src/config/rbac/machineuser_editor_role.yaml b/src/config/rbac/machineuser_editor_role.yaml deleted file mode 100644 index e38d5c7..0000000 --- a/src/config/rbac/machineuser_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit machineusers. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: machineuser-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: machineuser-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - machineusers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - machineusers/status - verbs: - - get diff --git a/src/config/rbac/machineuser_viewer_role.yaml b/src/config/rbac/machineuser_viewer_role.yaml deleted file mode 100644 index 970fdb4..0000000 --- a/src/config/rbac/machineuser_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view machineusers. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: machineuser-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: machineuser-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - machineusers - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - machineusers/status - verbs: - - get diff --git a/src/config/rbac/oidcapp_editor_role.yaml b/src/config/rbac/oidcapp_editor_role.yaml deleted file mode 100644 index 2b8e3fd..0000000 --- a/src/config/rbac/oidcapp_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit oidcapps. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: oidcapp-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: oidcapp-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - oidcapps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - oidcapps/status - verbs: - - get diff --git a/src/config/rbac/oidcapp_viewer_role.yaml b/src/config/rbac/oidcapp_viewer_role.yaml deleted file mode 100644 index 8286752..0000000 --- a/src/config/rbac/oidcapp_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view oidcapps. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: oidcapp-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: oidcapp-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - oidcapps - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - oidcapps/status - verbs: - - get diff --git a/src/config/rbac/organization_editor_role.yaml b/src/config/rbac/organization_editor_role.yaml deleted file mode 100644 index 586654f..0000000 --- a/src/config/rbac/organization_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit organizations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: organization-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: organization-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - organizations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - organizations/status - verbs: - - get diff --git a/src/config/rbac/organization_viewer_role.yaml b/src/config/rbac/organization_viewer_role.yaml deleted file mode 100644 index b27740b..0000000 --- a/src/config/rbac/organization_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view organizations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: organization-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: organization-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - organizations - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - organizations/status - verbs: - - get diff --git a/src/config/rbac/project_editor_role.yaml b/src/config/rbac/project_editor_role.yaml deleted file mode 100644 index c42c5e1..0000000 --- a/src/config/rbac/project_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit projects. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: project-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: project-editor-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - projects - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - projects/status - verbs: - - get diff --git a/src/config/rbac/project_viewer_role.yaml b/src/config/rbac/project_viewer_role.yaml deleted file mode 100644 index 4270f83..0000000 --- a/src/config/rbac/project_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view projects. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: project-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: project-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - projects - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - projects/status - verbs: - - get diff --git a/src/config/rbac/zitadelcluster_viewer_role.yaml b/src/config/rbac/zitadelcluster_viewer_role.yaml deleted file mode 100644 index 5ad726d..0000000 --- a/src/config/rbac/zitadelcluster_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view zitadelclusters. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: zitadelcluster-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: src - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - name: zitadelcluster-viewer-role -rules: -- apiGroups: - - zitadel.topmanage.com - resources: - - zitadelclusters - verbs: - - get - - list - - watch -- apiGroups: - - zitadel.topmanage.com - resources: - - zitadelclusters/status - verbs: - - get diff --git a/src/config/samples/kustomization.yaml b/src/config/samples/kustomization.yaml deleted file mode 100644 index 001b84c..0000000 --- a/src/config/samples/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -## Append samples of your project ## -resources: -- zitadel_v1alpha1_zitadelcluster.yaml -- zitadel_v1alpha1_organization.yaml -- zitadel_v1alpha1_project.yaml -- zitadel_v1alpha1_oidcapp.yaml -- zitadel_v1alpha1_machineuser.yaml -- zitadel_v1alpha1_apiapp.yaml -- zitadel_v1alpha1_action.yaml -- zitadel_v1alpha1_flow.yaml -#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/src/config/samples/zitadel_v1alpha1_action.yaml b/src/config/samples/zitadel_v1alpha1_action.yaml deleted file mode 100644 index c851467..0000000 --- a/src/config/samples/zitadel_v1alpha1_action.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: Action -metadata: - labels: - app.kubernetes.io/name: action - app.kubernetes.io/instance: action-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: action-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_apiapp.yaml b/src/config/samples/zitadel_v1alpha1_apiapp.yaml deleted file mode 100644 index 3aea6ef..0000000 --- a/src/config/samples/zitadel_v1alpha1_apiapp.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: APIApp -metadata: - labels: - app.kubernetes.io/name: apiapp - app.kubernetes.io/instance: apiapp-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: apiapp-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_flow.yaml b/src/config/samples/zitadel_v1alpha1_flow.yaml deleted file mode 100644 index 3f9237d..0000000 --- a/src/config/samples/zitadel_v1alpha1_flow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: Flow -metadata: - labels: - app.kubernetes.io/name: flow - app.kubernetes.io/instance: flow-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: flow-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_machineuser.yaml b/src/config/samples/zitadel_v1alpha1_machineuser.yaml deleted file mode 100644 index 5625cfe..0000000 --- a/src/config/samples/zitadel_v1alpha1_machineuser.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: MachineUser -metadata: - labels: - app.kubernetes.io/name: machineuser - app.kubernetes.io/instance: machineuser-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: machineuser-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_oidcapp.yaml b/src/config/samples/zitadel_v1alpha1_oidcapp.yaml deleted file mode 100644 index f096e2c..0000000 --- a/src/config/samples/zitadel_v1alpha1_oidcapp.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: OIDCApp -metadata: - labels: - app.kubernetes.io/name: oidcapp - app.kubernetes.io/instance: oidcapp-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: oidcapp-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_organization.yaml b/src/config/samples/zitadel_v1alpha1_organization.yaml deleted file mode 100644 index bfeedd7..0000000 --- a/src/config/samples/zitadel_v1alpha1_organization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: Organization -metadata: - labels: - app.kubernetes.io/name: organization - app.kubernetes.io/instance: organization-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: organization-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_project.yaml b/src/config/samples/zitadel_v1alpha1_project.yaml deleted file mode 100644 index 5be9337..0000000 --- a/src/config/samples/zitadel_v1alpha1_project.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: Project -metadata: - labels: - app.kubernetes.io/name: project - app.kubernetes.io/instance: project-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: project-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/samples/zitadel_v1alpha1_zitadelcluster.yaml b/src/config/samples/zitadel_v1alpha1_zitadelcluster.yaml deleted file mode 100644 index f9a06df..0000000 --- a/src/config/samples/zitadel_v1alpha1_zitadelcluster.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: zitadel.topmanage.com/v1alpha1 -kind: ZitadelCluster -metadata: - labels: - app.kubernetes.io/name: zitadelcluster - app.kubernetes.io/instance: zitadelcluster-sample - app.kubernetes.io/part-of: src - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: src - name: zitadelcluster-sample -spec: - # TODO(user): Add fields here diff --git a/src/config/scorecard/bases/config.yaml b/src/config/scorecard/bases/config.yaml deleted file mode 100644 index c770478..0000000 --- a/src/config/scorecard/bases/config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: scorecard.operatorframework.io/v1alpha3 -kind: Configuration -metadata: - name: config -stages: -- parallel: true - tests: [] diff --git a/src/config/scorecard/kustomization.yaml b/src/config/scorecard/kustomization.yaml deleted file mode 100644 index 50cd2d0..0000000 --- a/src/config/scorecard/kustomization.yaml +++ /dev/null @@ -1,16 +0,0 @@ -resources: -- bases/config.yaml -patchesJson6902: -- path: patches/basic.config.yaml - target: - group: scorecard.operatorframework.io - version: v1alpha3 - kind: Configuration - name: config -- path: patches/olm.config.yaml - target: - group: scorecard.operatorframework.io - version: v1alpha3 - kind: Configuration - name: config -#+kubebuilder:scaffold:patchesJson6902 diff --git a/src/config/scorecard/patches/basic.config.yaml b/src/config/scorecard/patches/basic.config.yaml deleted file mode 100644 index 8aa4158..0000000 --- a/src/config/scorecard/patches/basic.config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - basic-check-spec - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: basic - test: basic-check-spec-test diff --git a/src/config/scorecard/patches/olm.config.yaml b/src/config/scorecard/patches/olm.config.yaml deleted file mode 100644 index 47153a8..0000000 --- a/src/config/scorecard/patches/olm.config.yaml +++ /dev/null @@ -1,50 +0,0 @@ -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: olm - test: olm-bundle-validation-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: olm - test: olm-crds-have-validation-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-crds-have-resources - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: olm - test: olm-crds-have-resources-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: olm - test: olm-spec-descriptors-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:unknown - labels: - suite: olm - test: olm-status-descriptors-test diff --git a/src/internal/controller/action_controller.go b/src/internal/controller/action_controller.go deleted file mode 100644 index 44998cb..0000000 --- a/src/internal/controller/action_controller.go +++ /dev/null @@ -1,192 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - durationpb "google.golang.org/protobuf/types/known/durationpb" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// ActionReconciler reconciles a Action object -type ActionReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration - Builder *builder.Builder -} - -func NewActionReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready, - requeueInterval time.Duration) *ActionReconciler { - return &ActionReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - Builder: builder, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions/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. -func (r *ActionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var Action zitadelv1alpha1.Action - if err := r.Get(ctx, req.NamespacedName, &Action); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedActionReconciler(r.Client, r.RefResolver, r.Builder, &Action) - wf := newWrappedActionFinalizer(r.Client, &Action, r.RefResolver) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &Action) - if err != nil { - return result, fmt.Errorf("error reconciling in ActionReconciler: %v", err) - } - return result, nil -} - -type wrappedActionReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - Action *zitadelv1alpha1.Action - Builder *builder.Builder -} - -func newWrappedActionReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, - Action *zitadelv1alpha1.Action) zitadel.WrappedReconciler { - return &wrappedActionReconciler{ - Client: client, - refResolver: refResolver, - Action: Action, - Builder: builder, - } -} - -type actionReoncilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedActionReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []actionReoncilePhase{ - { - Name: "action", - Reconcile: wr.reconcileAction, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedActionReconciler) reconcileAction(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.Action.Spec.OrganizationRef, wr.Action.Namespace) - if err != nil { - return err - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - - if wr.Action.Status.ActionId != "" { - p, err := ztdClient.GetAction(ctx, &pb.GetActionRequest{Id: wr.Action.Status.ActionId}) - if p != nil { - _, err := ztdClient.UpdateAction(ctx, - &pb.UpdateActionRequest{ - Id: p.Action.Id, - Name: wr.Action.Name, - Script: wr.Action.Spec.Script, - Timeout: durationpb.New(wr.Action.Spec.Timeout.Duration), - AllowedToFail: wr.Action.Spec.AllowedToFail, - }, - ) - - if err != nil { - if !strings.Contains(err.Error(), "No changes") { - return fmt.Errorf("Error updating Action: %v", err) - } - } - return nil - } - if err != nil { - if !strings.Contains(err.Error(), "not found") { - return fmt.Errorf("Error getting Action: %v", err) - } - } - } - - resp, err := ztdClient.CreateAction(ctx, - &pb.CreateActionRequest{ - Name: wr.Action.Name, - Script: wr.Action.Spec.Script, - Timeout: durationpb.New(wr.Action.Spec.Timeout.Duration), - AllowedToFail: wr.Action.Spec.AllowedToFail, - }, - ) - - if err != nil { - if strings.Contains(err.Error(), "AlreadyExists") { - return nil - } - return fmt.Errorf("error creating action in Zitadel: %v", err) - } - patch := ctrlClient.MergeFrom(wr.Action.DeepCopy()) - wr.Action.Status.ActionId = resp.Id - return wr.Client.Status().Patch(ctx, wr.Action, patch) -} - -func (wr *wrappedActionReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.Action.DeepCopy()) - patcher(&wr.Action.Status) - - if err := wr.Client.Status().Patch(ctx, wr.Action, patch); err != nil { - return fmt.Errorf("error patching Action status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *ActionReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.Action{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/action_controller_finalizer.go b/src/internal/controller/action_controller_finalizer.go deleted file mode 100644 index 760467d..0000000 --- a/src/internal/controller/action_controller_finalizer.go +++ /dev/null @@ -1,94 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - actionFinalizerName = "action.zitadel.topmanage.com/action" -) - -type wrappedActionFinalizer struct { - client.Client - action *zitadelv1alpha1.Action - refresolver *zitadelv1alpha1.RefResolver -} - -func newWrappedActionFinalizer(client client.Client, action *zitadelv1alpha1.Action, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer { - return &wrappedActionFinalizer{ - Client: client, - action: action, - refresolver: refresolver, - } -} - -func (wf *wrappedActionFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.action, func(action *zitadelv1alpha1.Action) { - controllerutil.AddFinalizer(action, actionFinalizerName) - }) -} - -func (wf *wrappedActionFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.action, func(action *zitadelv1alpha1.Action) { - controllerutil.RemoveFinalizer(wf.action, actionFinalizerName) - }) -} - -func (wr *wrappedActionFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.action, actionFinalizerName) -} - -func (wf *wrappedActionFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.action.Status.ActionId == "" { - return nil - } - org, err := wf.refresolver.OrganizationRef(ctx, &wf.action.Spec.OrganizationRef, wf.action.Namespace) - if err != nil { - return err - } - { - - _, err := ztdClient.GetAction(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetActionRequest{Id: wf.action.Status.ActionId}) - if err != nil { - if strings.Contains(err.Error(), `not found`) { - return nil - } - return err - } - } - _, err = ztdClient.DeleteAction(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.DeleteActionRequest{Id: wf.action.Status.ActionId}) - if err != nil { - return err - } - return nil -} - -func (wr *wrappedActionFinalizer) patch(ctx context.Context, action *zitadelv1alpha1.Action, - patchFn func(*zitadelv1alpha1.Action)) error { - patch := ctrlClient.MergeFrom(action.DeepCopy()) - patchFn(action) - - if err := wr.Client.Patch(ctx, action, patch); err != nil { - return fmt.Errorf("error patching Action finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/apiapp_controller.go b/src/internal/controller/apiapp_controller.go deleted file mode 100644 index 347d069..0000000 --- a/src/internal/controller/apiapp_controller.go +++ /dev/null @@ -1,282 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "encoding/json" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - app "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/app" - "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/authn" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// APIAppReconciler reconciles a APIApp object -type APIAppReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration - Builder *builder.Builder -} - -func NewAPIAppReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready, - requeueInterval time.Duration) *APIAppReconciler { - return &APIAppReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - Builder: builder, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=apiapps,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=apiapps/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=apiapps/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. -func (r *APIAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var APIApp zitadelv1alpha1.APIApp - if err := r.Get(ctx, req.NamespacedName, &APIApp); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedAPIAppReconciler(r.Client, r.RefResolver, r.Builder, &APIApp) - wf := newWrappedAPIAppFinalizer(r.Client, &APIApp, r.RefResolver) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &APIApp) - if err != nil { - return result, fmt.Errorf("error reconciling in APIAppReconciler: %v", err) - } - return result, nil -} - -type wrappedAPIAppReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - APIApp *zitadelv1alpha1.APIApp - Builder *builder.Builder -} - -func newWrappedAPIAppReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, - APIApp *zitadelv1alpha1.APIApp) zitadel.WrappedReconciler { - return &wrappedAPIAppReconciler{ - Client: client, - refResolver: refResolver, - APIApp: APIApp, - Builder: builder, - } -} - -type apiAppReoncilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedAPIAppReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []projectReconcilePhase{ - { - Name: "apiapp", - Reconcile: wr.reconcileApp, - }, - { - Name: "keys", - Reconcile: wr.reconcileKeys, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedAPIAppReconciler) reconcileApp(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.APIApp.Organization(ctx, wr.refResolver) - if err != nil { - return err - } - project, err := wr.APIApp.Project(ctx, wr.refResolver) - if err != nil { - return err - } - if wr.APIApp.Status.AppId != "" { - appResp, err := ztdClient.GetAppByID(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetAppByIDRequest{ - ProjectId: project.Status.ProjectId, - AppId: string(wr.APIApp.Status.AppId), - }) - if err != nil { - return fmt.Errorf("Error getting APIApp: %v", err) - } - if appResp.App != nil { - _, err := ztdClient.UpdateAPIAppConfig(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.UpdateAPIAppConfigRequest{ProjectId: project.Status.ProjectId, AppId: wr.APIApp.Status.AppId, - AuthMethodType: app.APIAuthMethodType(app.APIAuthMethodType_value[wr.APIApp.Spec.AuthMethodType]), - }) - if err != nil { - if !strings.Contains(err.Error(), "No changes") { - return fmt.Errorf("Error updating APIApp: %v", err) - } - } - return nil - } - } - - resp, err := ztdClient.AddAPIApp(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.AddAPIAppRequest{ - Name: wr.APIApp.Name, - ProjectId: project.Status.ProjectId, - AuthMethodType: app.APIAuthMethodType(app.APIAuthMethodType_value[wr.APIApp.Spec.AuthMethodType]), - }, - ) - if err != nil { - if strings.Contains(err.Error(), "AlreadyExists") { - return nil - } - return fmt.Errorf("error creating APIApp in Zitadel: %v", err) - } - key := types.NamespacedName{ - Name: wr.APIApp.Name + "-client-secret", - Namespace: wr.APIApp.Namespace, - } - - secretData := map[string][]byte{"client-secret": []byte(resp.ClientSecret)} - secret, err := wr.Builder.BuildSecret(builder.SecretOpts{Immutable: false, Zitadel: nil, Key: key, Data: secretData}, wr.APIApp) - if err != nil { - return fmt.Errorf("error building Secret: %v", err) - } - if err := wr.Create(ctx, secret); err != nil { - return fmt.Errorf("error creating Client-secret Secret: %v", err) - } - patch := ctrlClient.MergeFrom(wr.APIApp.DeepCopy()) - wr.APIApp.Status.AppId = resp.AppId - wr.APIApp.Status.ClientId = resp.ClientId - return wr.Client.Status().Patch(ctx, wr.APIApp, patch) -} - -type Key struct { - Type string `json:"type"` - KeyID string `json:"keyId"` - Key string `json:"key"` - AppID string `json:"appId"` - ClientID string `json:"clientId"` -} - -func (wr *wrappedAPIAppReconciler) reconcileKeys(ctx context.Context, ztdClient *management.Client) error { - if wr.APIApp.Spec.AuthMethodType == "API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT" { - org, err := wr.APIApp.Organization(ctx, wr.refResolver) - if err != nil { - return err - } - project, err := wr.APIApp.Project(ctx, wr.refResolver) - if err != nil { - return err - } - if wr.APIApp.Status.KeyId != "" { - appKey, err := ztdClient.GetAppKey(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetAppKeyRequest{ - ProjectId: project.Status.ProjectId, - AppId: wr.APIApp.Status.AppId, - KeyId: wr.APIApp.Status.KeyId, - }) - if err != nil { - if !strings.Contains(err.Error(), "not found") { - return fmt.Errorf("Could not get key: %v", err) - } - } - if appKey.Key != nil { - return nil - } - } - resp, err := ztdClient.AddAppKey(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.AddAppKeyRequest{ - ProjectId: project.Status.ProjectId, - AppId: wr.APIApp.Status.AppId, - Type: authn.KeyType_KEY_TYPE_JSON, - ExpirationDate: nil, - }) - - if err != nil { - return fmt.Errorf("Error adding Key to app: %v", err) - } - - key := types.NamespacedName{ - Name: wr.APIApp.Name + "-privatekey-secret", - Namespace: wr.APIApp.Namespace, - } - var jsonKey Key - if err = json.Unmarshal(resp.KeyDetails, &jsonKey); err != nil { - return fmt.Errorf("Could not unmarshal key details: %v", err) - } - secretData := map[string][]byte{ - "clientId": []byte(jsonKey.ClientID), - "type": []byte(jsonKey.Type), - "keyId": []byte(jsonKey.KeyID), - "appId": []byte(jsonKey.AppID), - "key": []byte(jsonKey.Key), - } - secret, err := wr.Builder.BuildSecret(builder.SecretOpts{Immutable: false, Zitadel: nil, Key: key, Data: secretData}, wr.APIApp) - if err != nil { - return fmt.Errorf("error building Secret: %v", err) - } - if err := wr.Create(ctx, secret); err != nil { - return fmt.Errorf("error creating private-key Secret: %v", err) - } - patch := ctrlClient.MergeFrom(wr.APIApp.DeepCopy()) - wr.APIApp.Status.KeyId = resp.Id - return wr.Client.Status().Patch(ctx, wr.APIApp, patch) - } - return nil -} - -func (wr *wrappedAPIAppReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.APIApp.DeepCopy()) - patcher(&wr.APIApp.Status) - - if err := wr.Client.Status().Patch(ctx, wr.APIApp, patch); err != nil { - return fmt.Errorf("error patching APIApp status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *APIAppReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.APIApp{}). - Owns(&corev1.Secret{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/apiapp_controller_finalizer.go b/src/internal/controller/apiapp_controller_finalizer.go deleted file mode 100644 index 5853a40..0000000 --- a/src/internal/controller/apiapp_controller_finalizer.go +++ /dev/null @@ -1,91 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - APIAppFinalizerName = "apiapp.zitadel.topmanage.com/apiapp" -) - -type wrappedAPIAppFinalizer struct { - client.Client - APIApp *zitadelv1alpha1.APIApp - refresolver *zitadelv1alpha1.RefResolver -} - -func newWrappedAPIAppFinalizer(client client.Client, APIApp *zitadelv1alpha1.APIApp, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer { - return &wrappedAPIAppFinalizer{ - Client: client, - APIApp: APIApp, - refresolver: refresolver, - } -} - -func (wf *wrappedAPIAppFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.APIApp, func(APIApp *zitadelv1alpha1.APIApp) { - controllerutil.AddFinalizer(APIApp, APIAppFinalizerName) - }) -} - -func (wf *wrappedAPIAppFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.APIApp, func(APIApp *zitadelv1alpha1.APIApp) { - controllerutil.RemoveFinalizer(wf.APIApp, APIAppFinalizerName) - }) -} - -func (wr *wrappedAPIAppFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.APIApp, APIAppFinalizerName) -} - -func (wf *wrappedAPIAppFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.APIApp.Status.AppId == "" { - return nil - } - org, err := wf.APIApp.Organization(ctx, wf.refresolver) - if err != nil { - return err - } - project, err := wf.APIApp.Project(ctx, wf.refresolver) - if err != nil { - return err - } - _, err = ztdClient.RemoveApp(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.RemoveAppRequest{ProjectId: project.Status.ProjectId, AppId: wf.APIApp.Status.AppId}) - if err != nil { - if strings.Contains(err.Error(), "doesn't exist") { - return nil - } - return err - } - return nil -} - -func (wr *wrappedAPIAppFinalizer) patch(ctx context.Context, APIApp *zitadelv1alpha1.APIApp, - patchFn func(*zitadelv1alpha1.APIApp)) error { - patch := ctrlClient.MergeFrom(APIApp.DeepCopy()) - patchFn(APIApp) - - if err := wr.Client.Patch(ctx, APIApp, patch); err != nil { - return fmt.Errorf("error patching APIApp finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/flow_controller.go b/src/internal/controller/flow_controller.go deleted file mode 100644 index 2452fc3..0000000 --- a/src/internal/controller/flow_controller.go +++ /dev/null @@ -1,168 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// FlowReconciler reconciles a Flow object -type FlowReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration - Builder *builder.Builder -} - -func NewFlowReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready, - requeueInterval time.Duration) *FlowReconciler { - return &FlowReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - Builder: builder, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows/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. -func (r *FlowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var Flow zitadelv1alpha1.Flow - if err := r.Get(ctx, req.NamespacedName, &Flow); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedFlowReconciler(r.Client, r.RefResolver, r.Builder, &Flow) - wf := newWrappedFlowFinalizer(r.Client, &Flow, r.RefResolver) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &Flow) - if err != nil { - return result, fmt.Errorf("error reconciling in FlowReconciler: %v", err) - } - return result, nil -} - -type wrappedFlowReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - Flow *zitadelv1alpha1.Flow - Builder *builder.Builder -} - -func newWrappedFlowReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, - Flow *zitadelv1alpha1.Flow) zitadel.WrappedReconciler { - return &wrappedFlowReconciler{ - Client: client, - refResolver: refResolver, - Flow: Flow, - Builder: builder, - } -} - -type flowReoncilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedFlowReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []flowReoncilePhase{ - { - Name: "flow", - Reconcile: wr.reconcileFlow, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedFlowReconciler) reconcileFlow(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.Flow.Spec.OrganizationRef, wr.Flow.Namespace) - if err != nil { - return err - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - - actionIds := []string{} - for _, actionRef := range wr.Flow.Spec.ActionRefs { - action, err := wr.refResolver.ActionRef(ctx, &actionRef, wr.Flow.Namespace) - if err != nil { - return fmt.Errorf("Error resolving action reference: %v", err) - } - if action.Status.ActionId == "" { - return fmt.Errorf("Action with name: %s not ready for trigger", action.Name) - } - actionIds = append(actionIds, action.Status.ActionId) - } - - _, err = ztdClient.SetTriggerActions(ctx, &pb.SetTriggerActionsRequest{ - FlowType: wr.Flow.Spec.FlowType, - TriggerType: wr.Flow.Spec.TriggerType, - ActionIds: actionIds, - }) - if err != nil { - if !strings.Contains(err.Error(), "No Changes") { - return fmt.Errorf("Error triggering action flow: %v", err) - } - } - return nil -} - -func (wr *wrappedFlowReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.Flow.DeepCopy()) - patcher(&wr.Flow.Status) - - if err := wr.Client.Status().Patch(ctx, wr.Flow, patch); err != nil { - return fmt.Errorf("error patching Flow status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *FlowReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.Flow{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/flow_controller_finalizer.go b/src/internal/controller/flow_controller_finalizer.go deleted file mode 100644 index 60c0249..0000000 --- a/src/internal/controller/flow_controller_finalizer.go +++ /dev/null @@ -1,82 +0,0 @@ -package controller - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - flowFinalizerName = "flow.zitadel.topmanage.com/flow" -) - -type wrappedFlowFinalizer struct { - client.Client - flow *zitadelv1alpha1.Flow - refresolver *zitadelv1alpha1.RefResolver -} - -func newWrappedFlowFinalizer(client client.Client, flow *zitadelv1alpha1.Flow, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer { - return &wrappedFlowFinalizer{ - Client: client, - flow: flow, - refresolver: refresolver, - } -} - -func (wf *wrappedFlowFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.flow, func(flow *zitadelv1alpha1.Flow) { - controllerutil.AddFinalizer(flow, flowFinalizerName) - }) -} - -func (wf *wrappedFlowFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.flow, func(flow *zitadelv1alpha1.Flow) { - controllerutil.RemoveFinalizer(wf.flow, flowFinalizerName) - }) -} - -func (wr *wrappedFlowFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.flow, flowFinalizerName) -} - -func (wf *wrappedFlowFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - org, err := wf.refresolver.OrganizationRef(ctx, &wf.flow.Spec.OrganizationRef, wf.flow.Namespace) - if err != nil { - return err - } - - _, err = ztdClient.ClearFlow(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.ClearFlowRequest{ - Type: wf.flow.Spec.FlowType, - }) - if err != nil { - return err - } - return nil -} - -func (wr *wrappedFlowFinalizer) patch(ctx context.Context, flow *zitadelv1alpha1.Flow, - patchFn func(*zitadelv1alpha1.Flow)) error { - patch := ctrlClient.MergeFrom(flow.DeepCopy()) - patchFn(flow) - - if err := wr.Client.Patch(ctx, flow, patch); err != nil { - return fmt.Errorf("error patching Flow finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/machineuser_controller.go b/src/internal/controller/machineuser_controller.go deleted file mode 100644 index 4caab3e..0000000 --- a/src/internal/controller/machineuser_controller.go +++ /dev/null @@ -1,440 +0,0 @@ -package controller - -import ( - "context" - "encoding/json" - "fmt" - "reflect" - "sort" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/authn" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - object "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/object" - project "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/project" - user "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/user" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - clientpkg "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// MachineUserReconciler reconciles a MachineUser object -type MachineUserReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration - Builder *builder.Builder -} - -func NewMachineUserReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready, - requeueInterval time.Duration) *MachineUserReconciler { - return &MachineUserReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - Builder: builder, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=machineusers,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=machineusers/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=machineusers/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. -func (r *MachineUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var MachineUser zitadelv1alpha1.MachineUser - if err := r.Get(ctx, req.NamespacedName, &MachineUser); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedMachineUserReconciler(r.Client, r.RefResolver, r.Builder, &MachineUser) - wf := newWrappedMachineUserFinalizer(r.Client, &MachineUser) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &MachineUser) - if err != nil { - return result, fmt.Errorf("error reconciling in MachineUserReconciler: %v", err) - } - return result, nil -} - -type wrappedMachineUserReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - MachineUser *zitadelv1alpha1.MachineUser - Builder *builder.Builder -} - -func newWrappedMachineUserReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, - MachineUser *zitadelv1alpha1.MachineUser) zitadel.WrappedReconciler { - return &wrappedMachineUserReconciler{ - Client: client, - refResolver: refResolver, - MachineUser: MachineUser, - Builder: builder, - } -} - -type machineUserReconcilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedMachineUserReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []machineUserReconcilePhase{ - { - Name: "machineUser", - Reconcile: wr.reconcileMachineUser, - }, - { - Name: "usergrants", - Reconcile: wr.reconcileUserGrants, - }, - { - Name: "pat", - Reconcile: wr.reconcilePAT, - }, - { - Name: "jwt", - Reconcile: wr.reconcileJWT, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedMachineUserReconciler) reconcileMachineUser(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.MachineUser.Spec.OrganizationRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - zitadel, err := wr.refResolver.ZitadelCluster(ctx, &org.Spec.ZitadelClusterRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - machineUser, err := ztdClient.GetUserByLoginNameGlobal(ctx, &pb.GetUserByLoginNameGlobalRequest{ - LoginName: strings.ToLower(fmt.Sprintf("%s@%s.%s", wr.MachineUser.Name, org.Name, zitadel.Spec.Host)), - }) - if err != nil { - if !strings.Contains(err.Error(), "could not be found") { - return fmt.Errorf("Error getting machineuser: %v", err) - } - } - - var userid string - if machineUser == nil { - resp, err := ztdClient.AddMachineUser(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.AddMachineUserRequest{ - Name: wr.MachineUser.Name, - UserName: wr.MachineUser.Name, - Description: wr.MachineUser.Name, - AccessTokenType: user.AccessTokenType(user.AccessTokenType_value[wr.MachineUser.Spec.AccessTokenType]), - }, - ) - if err != nil { - return fmt.Errorf("error creating MachineUser in Zitadel: %v", err) - } - userid = resp.UserId - } else { - _, err = ztdClient.UpdateMachine(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.UpdateMachineRequest{ - UserId: machineUser.User.Id, - Name: wr.MachineUser.Name, - Description: wr.MachineUser.Name, - AccessTokenType: user.AccessTokenType(user.AccessTokenType_value[wr.MachineUser.Spec.AccessTokenType]), - }) - if err != nil { - if !strings.Contains(err.Error(), "User.NotChanged ") { - return fmt.Errorf("Error updating MchineUser: %v", err) - } - } - userid = machineUser.User.Id - } - - patch := ctrlClient.MergeFrom(wr.MachineUser.DeepCopy()) - wr.MachineUser.Status.UserId = userid - return wr.Client.Status().Patch(ctx, wr.MachineUser, patch) -} - -func (wr *wrappedMachineUserReconciler) reconcilePAT(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.MachineUser.Spec.OrganizationRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - - token, err := ztdClient.GetPersonalAccessTokenByIDs(ctx, &pb.GetPersonalAccessTokenByIDsRequest{ - UserId: wr.MachineUser.Status.UserId, - TokenId: wr.MachineUser.Status.PATId, - }) - if err != nil { - if !(strings.Contains(err.Error(), "NotFound") || strings.Contains(err.Error(), "length must be between 1 and 200 runes")) { - return fmt.Errorf("Error getting PAT: %v", err) - } - } - - if token == nil || !wr.MachineUser.Status.GetConditionStatus(zitadelv1alpha1.ConditionTypePATUpToDate) { - if token != nil { - if _, err = ztdClient.RemovePersonalAccessToken(ctx, &pb.RemovePersonalAccessTokenRequest{ - UserId: wr.MachineUser.Status.UserId, - TokenId: wr.MachineUser.Status.PATId, - }); err != nil { - return fmt.Errorf("Error removing PAT: %v", err) - } - } - resp, err := ztdClient.AddPersonalAccessToken(ctx, &pb.AddPersonalAccessTokenRequest{ - UserId: wr.MachineUser.Status.UserId, - }) - if err != nil { - return fmt.Errorf("Error adding PAT: %v", err) - } - key := types.NamespacedName{ - Name: wr.MachineUser.PatSecretName(), - Namespace: wr.MachineUser.Namespace, - } - desiredPatSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{ - Key: key, - Immutable: false, - Data: map[string][]byte{ - "pat": []byte(resp.Token), - }, - }, wr.MachineUser) - - if err != nil { - return fmt.Errorf("error building PAT Secret: %v", err) - } - - { - var existingPatSecret corev1.Secret - if err := wr.Get(ctx, key, &existingPatSecret); err != nil { - if !errors.IsNotFound(err) { - return fmt.Errorf("error getting PAT Secret: %v", err) - } - if err := wr.Create(ctx, desiredPatSecret); err != nil { - return fmt.Errorf("error creating PAT Secret: %v", err) - } - } - - patch := clientpkg.MergeFrom(existingPatSecret.DeepCopy()) - existingPatSecret.Data = desiredPatSecret.Data - if err = wr.Patch(ctx, &existingPatSecret, patch); err != nil { - return err - } - - } - - if err = wr.PatchStatus(ctx, condition.SetPatUpToDate); err != nil { - return err - } - - patch := ctrlClient.MergeFrom(wr.MachineUser.DeepCopy()) - wr.MachineUser.Status.PATId = resp.TokenId - return wr.Client.Status().Patch(ctx, wr.MachineUser, patch) - } - return nil -} - -func (wr *wrappedMachineUserReconciler) reconcileJWT(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.MachineUser.Spec.OrganizationRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - - token, err := ztdClient.GetMachineKeyByIDs(ctx, &pb.GetMachineKeyByIDsRequest{ - UserId: wr.MachineUser.Status.UserId, - KeyId: wr.MachineUser.Status.KeyId, - }) - if err != nil { - if !(strings.Contains(err.Error(), "NotFound") || strings.Contains(err.Error(), "length must be between 1 and 200 runes")) { - return fmt.Errorf("Error getting JWT: %v", err) - } - } - - if token == nil { - resp, err := ztdClient.AddMachineKey(ctx, &pb.AddMachineKeyRequest{ - UserId: wr.MachineUser.Status.UserId, - Type: authn.KeyType_KEY_TYPE_JSON, - }) - if err != nil { - return fmt.Errorf("Error adding JWT: %v", err) - } - key := types.NamespacedName{ - Name: wr.MachineUser.JWTSecretName(), - Namespace: wr.MachineUser.Namespace, - } - - var jsonKey Key - if err = json.Unmarshal(resp.KeyDetails, &jsonKey); err != nil { - return fmt.Errorf("Could not unmarshal key details: %v", err) - } - - secretData := map[string][]byte{ - "clientId": []byte(jsonKey.ClientID), - "type": []byte(jsonKey.Type), - "keyId": []byte(jsonKey.KeyID), - "appId": []byte(jsonKey.AppID), - "key": []byte(jsonKey.Key), - } - jwtSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{ - Key: key, - Immutable: false, - Data: secretData, - }, wr.MachineUser) - - if err != nil { - return fmt.Errorf("error building machine key Secret: %v", err) - } - if err := wr.Create(ctx, jwtSecret); err != nil { - return fmt.Errorf("error creating machine key Secret: %v", err) - } - patch := ctrlClient.MergeFrom(wr.MachineUser.DeepCopy()) - wr.MachineUser.Status.KeyId = resp.KeyId - return wr.Client.Status().Patch(ctx, wr.MachineUser, patch) - } - return nil -} - -func (wr *wrappedMachineUserReconciler) reconcileUserGrants(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.MachineUser.Spec.OrganizationRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - existingUserGrants, err := ztdClient.ListUserGrants(ctx, &pb.ListUserGrantRequest{ - Queries: []*user.UserGrantQuery{ - { - Query: &user.UserGrantQuery_UserIdQuery{ - UserIdQuery: &user.UserGrantUserIDQuery{ - UserId: wr.MachineUser.Status.UserId, - }, - }, - }, - { - Query: &user.UserGrantQuery_WithGrantedQuery{ - WithGrantedQuery: &user.UserGrantWithGrantedQuery{ - WithGranted: true, - }, - }, - }, - }, - }) - if err != nil { - return fmt.Errorf("Error listing MachineUser grants: %v", err) - } - for _, userGrant := range wr.MachineUser.DeepCopy().Spec.UserGrants { - userGrantedProject, err := wr.refResolver.ProjectRef(ctx, &userGrant.ProjectRef, wr.MachineUser.Namespace) - if err != nil { - return err - } - var existingUserGrant *user.UserGrant - for _, eGrant := range existingUserGrants.Result { - if eGrant.ProjectId == userGrantedProject.Status.ProjectId && eGrant.UserId == wr.MachineUser.Status.UserId { - existingUserGrant = eGrant - break - } - } - if existingUserGrant == nil { - grantedProjects, err := ztdClient.ListGrantedProjects(ctx, &pb.ListGrantedProjectsRequest{ - Queries: []*project.ProjectQuery{ - { - Query: &project.ProjectQuery_NameQuery{ - NameQuery: &project.ProjectNameQuery{ - Name: userGrantedProject.Name, - Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS, - }, - }, - }, - }, - }) - if err != nil { - return fmt.Errorf("Error listing granted projects: %v", err) - } - - var existingProjectGrant *project.GrantedProject - for _, existingGrantedProject := range grantedProjects.Result { - if existingGrantedProject.ProjectId == userGrantedProject.Status.ProjectId { - existingProjectGrant = existingGrantedProject - break - } - } - if existingProjectGrant == nil { - return fmt.Errorf("Error no project granted to user organization") - } - - if err = wr.PatchStatus(ctx, condition.SetPatOutOfDate); err != nil { - return err - } - - _, err = ztdClient.AddUserGrant(ctx, &pb.AddUserGrantRequest{ - UserId: wr.MachineUser.Status.UserId, - RoleKeys: userGrant.RoleKeys, - ProjectId: existingProjectGrant.ProjectId, - ProjectGrantId: existingProjectGrant.GrantId, - }) - if err != nil { - return fmt.Errorf("Error Adding MachineUser grant: %v", err) - } - } else { - sort.Strings(existingUserGrant.RoleKeys) - sort.Strings(userGrant.RoleKeys) - if !reflect.DeepEqual(existingUserGrant.RoleKeys, userGrant.RoleKeys) { - - if err = wr.PatchStatus(ctx, condition.SetPatOutOfDate); err != nil { - return err - } - - _, err := ztdClient.UpdateUserGrant(ctx, &pb.UpdateUserGrantRequest{ - UserId: wr.MachineUser.Status.UserId, - GrantId: existingUserGrant.Id, - RoleKeys: userGrant.RoleKeys, - }) - if err != nil { - return fmt.Errorf("Error Updating MachineUser grant: %v", err) - } - } - } - } - return nil -} - -func (wr *wrappedMachineUserReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.MachineUser.DeepCopy()) - patcher(&wr.MachineUser.Status) - - if err := wr.Client.Status().Patch(ctx, wr.MachineUser, patch); err != nil { - return fmt.Errorf("error patching MachineUser status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *MachineUserReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.MachineUser{}). - Owns(&corev1.Secret{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/machineuser_controller_finalizer.go b/src/internal/controller/machineuser_controller_finalizer.go deleted file mode 100644 index 87630df..0000000 --- a/src/internal/controller/machineuser_controller_finalizer.go +++ /dev/null @@ -1,92 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - machineuserFinalizerName = "machineuser.zitadel.topmanage.com/machineuser" -) - -type wrappedMachineUserFinalizer struct { - client.Client - machineuser *zitadelv1alpha1.MachineUser -} - -func newWrappedMachineUserFinalizer(client client.Client, machineuser *zitadelv1alpha1.MachineUser) zitadel.WrappedFinalizer { - return &wrappedMachineUserFinalizer{ - Client: client, - machineuser: machineuser, - } -} - -func (wf *wrappedMachineUserFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.machineuser, func(machineuser *zitadelv1alpha1.MachineUser) { - controllerutil.AddFinalizer(machineuser, machineuserFinalizerName) - }) -} - -func (wf *wrappedMachineUserFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.machineuser, func(machineuser *zitadelv1alpha1.MachineUser) { - controllerutil.RemoveFinalizer(wf.machineuser, machineuserFinalizerName) - }) -} - -func (wr *wrappedMachineUserFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.machineuser, machineuserFinalizerName) -} - -func (wf *wrappedMachineUserFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.machineuser.Status.UserId == "" { - return nil - } - { - _, err := ztdClient.GetUserByID(ctx, &pb.GetUserByIDRequest{ - Id: wf.machineuser.Status.UserId, - }) - if err != nil { - if strings.Contains(err.Error(), `not be found`) { - return nil - } - return err - } - } - _, err := ztdClient.RemoveUser(ctx, &pb.RemoveUserRequest{ - Id: wf.machineuser.Status.UserId, - }) - if err != nil { - if !strings.Contains(err.Error(), "not be found") { - return err - } - } - return nil -} - -func (wr *wrappedMachineUserFinalizer) patch(ctx context.Context, machineuser *zitadelv1alpha1.MachineUser, - patchFn func(*zitadelv1alpha1.MachineUser)) error { - patch := ctrlClient.MergeFrom(machineuser.DeepCopy()) - patchFn(machineuser) - - if err := wr.Client.Patch(ctx, machineuser, patch); err != nil { - return fmt.Errorf("error patching MachineUser finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/oidcapp_controller.go b/src/internal/controller/oidcapp_controller.go deleted file mode 100644 index 9bf33e8..0000000 --- a/src/internal/controller/oidcapp_controller.go +++ /dev/null @@ -1,221 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - app "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/app" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - durationpb "google.golang.org/protobuf/types/known/durationpb" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// OIDCAppReconciler reconciles a OIDCApp object -type OIDCAppReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration - Builder *builder.Builder -} - -func NewOIDCAppReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready, - requeueInterval time.Duration) *OIDCAppReconciler { - return &OIDCAppReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - Builder: builder, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=oidcapps,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=oidcapps/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=oidcapps/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. -func (r *OIDCAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var OIDCApp zitadelv1alpha1.OIDCApp - if err := r.Get(ctx, req.NamespacedName, &OIDCApp); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedOIDCAppReconciler(r.Client, r.RefResolver, r.Builder, &OIDCApp) - wf := newWrappedOIDCAppFinalizer(r.Client, &OIDCApp, r.RefResolver) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &OIDCApp) - if err != nil { - return result, fmt.Errorf("error reconciling in OIDCAppReconciler: %v", err) - } - return result, nil -} - -type wrappedOIDCAppReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - OIDCApp *zitadelv1alpha1.OIDCApp - Builder *builder.Builder -} - -func newWrappedOIDCAppReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, - OIDCApp *zitadelv1alpha1.OIDCApp) zitadel.WrappedReconciler { - return &wrappedOIDCAppReconciler{ - Client: client, - refResolver: refResolver, - OIDCApp: OIDCApp, - Builder: builder, - } -} - -func (wr *wrappedOIDCAppReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.OIDCApp.Organization(ctx, wr.refResolver) - if err != nil { - return err - } - project, err := wr.OIDCApp.Project(ctx, wr.refResolver) - if err != nil { - return err - } - responseTypes := []app.OIDCResponseType{} - for _, r := range wr.OIDCApp.Spec.ResponseTypes { - responseTypes = append(responseTypes, app.OIDCResponseType(app.OIDCResponseType_value[string(r)])) - } - grantTypes := []app.OIDCGrantType{} - for _, r := range wr.OIDCApp.Spec.GrantTypes { - grantTypes = append(grantTypes, app.OIDCGrantType(app.OIDCGrantType_value[string(r)])) - } - - if wr.OIDCApp.Status.AppId != "" { - appResp, err := ztdClient.GetAppByID(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetAppByIDRequest{ - ProjectId: project.Status.ProjectId, - AppId: string(wr.OIDCApp.Status.AppId), - }) - // TODO: fix flow - if err != nil { - return fmt.Errorf("Error getting OIDCApp: %v", err) - } - if appResp.App != nil { - _, err := ztdClient.UpdateOIDCAppConfig(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.UpdateOIDCAppConfigRequest{ProjectId: project.Status.ProjectId, AppId: wr.OIDCApp.Status.AppId, - RedirectUris: wr.OIDCApp.Spec.RedirectUris, - ResponseTypes: responseTypes, - GrantTypes: grantTypes, - AppType: app.OIDCAppType(app.OIDCAppType_value[wr.OIDCApp.Spec.AppType]), - AuthMethodType: app.OIDCAuthMethodType(app.OIDCAuthMethodType_value[wr.OIDCApp.Spec.AuthMethodType]), - PostLogoutRedirectUris: wr.OIDCApp.Spec.PostLogoutRedirectUris, - DevMode: wr.OIDCApp.Spec.DevMode, - AccessTokenType: app.OIDCTokenType(app.OIDCTokenType_value[wr.OIDCApp.Spec.AccessTokenType]), - AccessTokenRoleAssertion: wr.OIDCApp.Spec.AccessTokenRoleAssertion, - IdTokenRoleAssertion: wr.OIDCApp.Spec.IdTokenRoleAssertion, - IdTokenUserinfoAssertion: wr.OIDCApp.Spec.IdTokenUserinfoAssertion, - ClockSkew: durationpb.New(wr.OIDCApp.Spec.ClockSkew.Duration), - AdditionalOrigins: wr.OIDCApp.Spec.AdditionalOrigins, - SkipNativeAppSuccessPage: wr.OIDCApp.Spec.SkipNativeAppSuccessPage, - }) - if err != nil { - if !strings.Contains(err.Error(), "No changes") { - return fmt.Errorf("Error updating OIDCApp: %v", err) - } - } - return nil - } - } - - resp, err := ztdClient.AddOIDCApp(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.AddOIDCAppRequest{ - Name: wr.OIDCApp.Name, - ProjectId: project.Status.ProjectId, - RedirectUris: wr.OIDCApp.Spec.RedirectUris, - ResponseTypes: responseTypes, - GrantTypes: grantTypes, - AppType: app.OIDCAppType(app.OIDCAppType_value[wr.OIDCApp.Spec.AppType]), - AuthMethodType: app.OIDCAuthMethodType(app.OIDCAuthMethodType_value[wr.OIDCApp.Spec.AuthMethodType]), - PostLogoutRedirectUris: wr.OIDCApp.Spec.PostLogoutRedirectUris, - Version: app.OIDCVersion_OIDC_VERSION_1_0, - DevMode: wr.OIDCApp.Spec.DevMode, - AccessTokenType: app.OIDCTokenType(app.OIDCTokenType_value[wr.OIDCApp.Spec.AccessTokenType]), - AccessTokenRoleAssertion: wr.OIDCApp.Spec.AccessTokenRoleAssertion, - IdTokenRoleAssertion: wr.OIDCApp.Spec.IdTokenRoleAssertion, - IdTokenUserinfoAssertion: wr.OIDCApp.Spec.IdTokenUserinfoAssertion, - ClockSkew: durationpb.New(wr.OIDCApp.Spec.ClockSkew.Duration), - AdditionalOrigins: wr.OIDCApp.Spec.AdditionalOrigins, - SkipNativeAppSuccessPage: wr.OIDCApp.Spec.SkipNativeAppSuccessPage, - }, - ) - if err != nil { - if strings.Contains(err.Error(), "AlreadyExists") { - return nil - } - return fmt.Errorf("error creating OIDCApp in Zitadel: %v", err) - } - key := types.NamespacedName{ - Name: wr.OIDCApp.ClientSecretName(), - Namespace: wr.OIDCApp.Namespace, - } - - // client-secret for backwards compatability - secretData := map[string][]byte{"client-secret": []byte(resp.ClientSecret), "clientSecret": []byte(resp.ClientSecret), "appId": []byte(resp.AppId), "clientId": []byte(resp.ClientId)} - secret, err := wr.Builder.BuildSecret(builder.SecretOpts{Immutable: false, Zitadel: nil, Key: key, Data: secretData}, wr.OIDCApp) - if err != nil { - return fmt.Errorf("error building Secret: %v", err) - } - if err := wr.Create(ctx, secret); err != nil { - return fmt.Errorf("error creating Client-secret Secret: %v", err) - } - patch := ctrlClient.MergeFrom(wr.OIDCApp.DeepCopy()) - wr.OIDCApp.Status.AppId = resp.AppId - wr.OIDCApp.Status.ClientId = resp.ClientId - return wr.Client.Status().Patch(ctx, wr.OIDCApp, patch) -} - -func (wr *wrappedOIDCAppReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.OIDCApp.DeepCopy()) - patcher(&wr.OIDCApp.Status) - - if err := wr.Client.Status().Patch(ctx, wr.OIDCApp, patch); err != nil { - return fmt.Errorf("error patching OIDCApp status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *OIDCAppReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.OIDCApp{}). - Owns(&corev1.Secret{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/oidcapp_controller_finalizer.go b/src/internal/controller/oidcapp_controller_finalizer.go deleted file mode 100644 index 8e310e1..0000000 --- a/src/internal/controller/oidcapp_controller_finalizer.go +++ /dev/null @@ -1,91 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - OIDCAppFinalizerName = "oidcapp.zitadel.topmanage.com/oidcapp" -) - -type wrappedOIDCAppFinalizer struct { - client.Client - OIDCApp *zitadelv1alpha1.OIDCApp - refresolver *zitadelv1alpha1.RefResolver -} - -func newWrappedOIDCAppFinalizer(client client.Client, OIDCApp *zitadelv1alpha1.OIDCApp, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer { - return &wrappedOIDCAppFinalizer{ - Client: client, - OIDCApp: OIDCApp, - refresolver: refresolver, - } -} - -func (wf *wrappedOIDCAppFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.OIDCApp, func(OIDCApp *zitadelv1alpha1.OIDCApp) { - controllerutil.AddFinalizer(OIDCApp, OIDCAppFinalizerName) - }) -} - -func (wf *wrappedOIDCAppFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.OIDCApp, func(OIDCApp *zitadelv1alpha1.OIDCApp) { - controllerutil.RemoveFinalizer(wf.OIDCApp, OIDCAppFinalizerName) - }) -} - -func (wr *wrappedOIDCAppFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.OIDCApp, OIDCAppFinalizerName) -} - -func (wf *wrappedOIDCAppFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.OIDCApp.Status.AppId == "" { - return nil - } - org, err := wf.OIDCApp.Organization(ctx, wf.refresolver) - if err != nil { - return err - } - project, err := wf.OIDCApp.Project(ctx, wf.refresolver) - if err != nil { - return err - } - _, err = ztdClient.RemoveApp(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.RemoveAppRequest{ProjectId: project.Status.ProjectId, AppId: wf.OIDCApp.Status.AppId}) - if err != nil { - if strings.Contains(err.Error(), "doesn't exist") { - return nil - } - return err - } - return nil -} - -func (wr *wrappedOIDCAppFinalizer) patch(ctx context.Context, OIDCApp *zitadelv1alpha1.OIDCApp, - patchFn func(*zitadelv1alpha1.OIDCApp)) error { - patch := ctrlClient.MergeFrom(OIDCApp.DeepCopy()) - patchFn(OIDCApp) - - if err := wr.Client.Patch(ctx, OIDCApp, patch); err != nil { - return fmt.Errorf("error patching OIDCApp finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/organization_controller.go b/src/internal/controller/organization_controller.go deleted file mode 100644 index 771f937..0000000 --- a/src/internal/controller/organization_controller.go +++ /dev/null @@ -1,264 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - adm "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/admin" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// OrganizationReconciler reconciles a Organization object -type OrganizationReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration -} - -func NewOrganizationReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, conditionReady *condition.Ready, - requeueInterval time.Duration) *OrganizationReconciler { - return &OrganizationReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=organizations,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=organizations/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=organizations/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. -func (r *OrganizationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var organization zitadelv1alpha1.Organization - if err := r.Get(ctx, req.NamespacedName, &organization); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedOrganizationReconciler(r.Client, r.RefResolver, &organization) - wf := newWrappedOrganizationFinalizer(r.Client, &organization) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &organization) - if err != nil { - return result, fmt.Errorf("error reconciling in OrganizationReconciler: %v", err) - } - return result, nil -} - -type wrappedOrganizationReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - organization *zitadelv1alpha1.Organization -} - -func newWrappedOrganizationReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, - organization *zitadelv1alpha1.Organization) zitadel.WrappedReconciler { - return &wrappedOrganizationReconciler{ - Client: client, - refResolver: refResolver, - organization: organization, - } -} - -type orgReconcilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedOrganizationReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []orgReconcilePhase{ - { - Name: "organization", - Reconcile: wr.reconcileOrg, - }, - { - Name: "admin", - Reconcile: wr.reconcileInitialAdmin, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedOrganizationReconciler) reconcileOrg(ctx context.Context, ztdClient *management.Client) error { - zitadelCluster, err := wr.refResolver.ZitadelCluster(ctx, &wr.organization.Spec.ZitadelClusterRef, wr.organization.Namespace) - if err != nil { - return err - } - orgRes, err := ztdClient.GetOrgByDomainGlobal(ctx, &pb.GetOrgByDomainGlobalRequest{ - Domain: strings.ToLower(fmt.Sprintf("%s.%s", wr.organization.Name, zitadelCluster.Spec.Host)), - }) - if err != nil { - if !strings.Contains(err.Error(), "not found") { - return fmt.Errorf("Error getting org: %v", err) - } - } - if orgRes == nil { - resp, err := ztdClient.AddOrg(ctx, &pb.AddOrgRequest{ - Name: strings.ToLower(wr.organization.Name), - }) - if err != nil { - return fmt.Errorf("error creating organization in Zitadel: %v", err) - } - patch := ctrlClient.MergeFrom(wr.organization.DeepCopy()) - wr.organization.Status.OrgId = resp.Id - return wr.Client.Status().Patch(ctx, wr.organization, patch) - } - patch := ctrlClient.MergeFrom(wr.organization.DeepCopy()) - wr.organization.Status.OrgId = orgRes.Org.Id - return wr.Client.Status().Patch(ctx, wr.organization, patch) -} - -func (wr *wrappedOrganizationReconciler) reconcileInitialAdmin(ctx context.Context, ztdClient *management.Client) error { - zitadelCluster, err := wr.refResolver.ZitadelCluster(ctx, &wr.organization.Spec.ZitadelClusterRef, wr.organization.Namespace) - if err != nil { - return err - } - - adminUser, err := ztdClient.GetUserByLoginNameGlobal(ctx, &pb.GetUserByLoginNameGlobalRequest{ - LoginName: strings.ToLower(fmt.Sprintf("%s@%s.%s", wr.organization.Spec.OrganizationAdmin.UserName, wr.organization.Name, zitadelCluster.Spec.Host)), - }) - if err != nil { - if !strings.Contains(err.Error(), "could not be found") { - return fmt.Errorf("Error getting admin user: %v", err) - } - } - ctx = middleware.SetOrgID(ctx, wr.organization.Status.OrgId) - var userid string - if adminUser == nil { - resp, err := ztdClient.AddHumanUser(ctx, &pb.AddHumanUserRequest{ - UserName: wr.organization.Spec.OrganizationAdmin.UserName, - Profile: &pb.AddHumanUserRequest_Profile{ - FirstName: wr.organization.Spec.OrganizationAdmin.FirstName, - LastName: wr.organization.Spec.OrganizationAdmin.LastName, - }, - Email: &pb.AddHumanUserRequest_Email{ - Email: wr.organization.Spec.OrganizationAdmin.Email, - IsEmailVerified: false, - }, - }) - userid = resp.UserId - if err != nil { - return fmt.Errorf("Error adding human user: %v", err) - } - { - if _, err := ztdClient.AddOrgMember(ctx, &pb.AddOrgMemberRequest{ - UserId: userid, - Roles: []string{ - "ORG_OWNER", - }, - }); err != nil { - if !strings.Contains(err.Error(), "Errors.Org.Member.RolesNotChanged") { - return fmt.Errorf("Error adding org member: %v", err) - } - } - } - - } else { - userid = adminUser.User.Id - } - - { - if _, err := ztdClient.UpdateOrgMember(ctx, &pb.UpdateOrgMemberRequest{ - UserId: userid, - Roles: []string{ - "ORG_OWNER", - }, - }); err != nil { - if !strings.Contains(err.Error(), "Errors.Org.Member.RolesNotChanged") { - return fmt.Errorf("Error updating org member: %v", err) - } - } - - if zitadelCluster.Spec.FirstOrgName == wr.organization.Name { - adminClient, err := zitadelClient.NewAdminClient(ctx, zitadelCluster, *wr.refResolver) - if err != nil { - return err - } - { - if _, err := adminClient.AddIAMMember(ctx, &adm.AddIAMMemberRequest{ - UserId: userid, - Roles: []string{ - "IAM_OWNER", - }, - }); err != nil { - if !strings.Contains(err.Error(), "Roles have not been changed") && !strings.Contains(err.Error(), "AlreadyExists") { - return fmt.Errorf("Error adding iam member: %v", err) - } - } - } - { - if _, err := adminClient.UpdateIAMMember(ctx, &adm.UpdateIAMMemberRequest{ - UserId: userid, - Roles: []string{ - "IAM_OWNER", - }, - }); err != nil { - if !strings.Contains(err.Error(), "Roles have not been changed") { - return fmt.Errorf("Error updating iam member: %v", err) - } - } - } - } - } - patch := client.MergeFrom(wr.organization.DeepCopy()) - wr.organization.Status.AdminId = userid - return wr.Status().Patch(ctx, wr.organization, patch) -} - -func (wr *wrappedOrganizationReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.organization.DeepCopy()) - patcher(&wr.organization.Status) - - if err := wr.Client.Status().Patch(ctx, wr.organization, patch); err != nil { - return fmt.Errorf("error patching Organization status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *OrganizationReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.Organization{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/organization_controller_finalizer.go b/src/internal/controller/organization_controller_finalizer.go deleted file mode 100644 index d9e5407..0000000 --- a/src/internal/controller/organization_controller_finalizer.go +++ /dev/null @@ -1,87 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - organizationFinalizerName = "organization.zitadel.topmanage.com/organization" -) - -type wrappedOrganizationFinalizer struct { - client.Client - organization *zitadelv1alpha1.Organization -} - -func newWrappedOrganizationFinalizer(client client.Client, organization *zitadelv1alpha1.Organization) zitadel.WrappedFinalizer { - return &wrappedOrganizationFinalizer{ - Client: client, - organization: organization, - } -} - -func (wf *wrappedOrganizationFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.organization, func(organization *zitadelv1alpha1.Organization) { - controllerutil.AddFinalizer(organization, organizationFinalizerName) - }) -} - -func (wf *wrappedOrganizationFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.organization, func(organization *zitadelv1alpha1.Organization) { - controllerutil.RemoveFinalizer(wf.organization, organizationFinalizerName) - }) -} - -func (wr *wrappedOrganizationFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.organization, organizationFinalizerName) -} - -func (wf *wrappedOrganizationFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.organization.Status.OrgId == "" { - return nil - } - { - _, err := ztdClient.GetMyOrg(middleware.SetOrgID(ctx, wf.organization.Status.OrgId), &pb.GetMyOrgRequest{}) - if err != nil { - if strings.Contains(err.Error(), `Organisation doesn't exist`) { - return nil - } - return err - } - } - _, err := ztdClient.RemoveOrg(middleware.SetOrgID(ctx, wf.organization.Status.OrgId), &pb.RemoveOrgRequest{}) - if err != nil { - return err - } - return nil -} - -func (wr *wrappedOrganizationFinalizer) patch(ctx context.Context, organization *zitadelv1alpha1.Organization, - patchFn func(*zitadelv1alpha1.Organization)) error { - patch := ctrlClient.MergeFrom(organization.DeepCopy()) - patchFn(organization) - - if err := wr.Client.Patch(ctx, organization, patch); err != nil { - return fmt.Errorf("error patching Organization finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/project_controller.go b/src/internal/controller/project_controller.go deleted file mode 100644 index b2db535..0000000 --- a/src/internal/controller/project_controller.go +++ /dev/null @@ -1,300 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "reflect" - "sort" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/project" - "golang.org/x/exp/maps" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// ProjectReconciler reconciles a Project object -type ProjectReconciler struct { - client.Client - RefResolver *zitadelv1alpha1.RefResolver - ConditionReady *condition.Ready - RequeueInterval time.Duration -} - -func NewProjectReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, conditionReady *condition.Ready, - requeueInterval time.Duration) *ProjectReconciler { - return &ProjectReconciler{ - Client: client, - RefResolver: refResolver, - ConditionReady: conditionReady, - RequeueInterval: requeueInterval, - } -} - -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=projects,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=projects/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=projects/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. -func (r *ProjectReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var project zitadelv1alpha1.Project - if err := r.Get(ctx, req.NamespacedName, &project); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - wr := newWrappedProjectReconciler(r.Client, r.RefResolver, &project) - wf := newWrappedProjectFinalizer(r.Client, &project, r.RefResolver) - tf := zitadel.NewZitadelFinalizer(r.Client, wf) - tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval) - - result, err := tr.Reconcile(ctx, &project) - if err != nil { - return result, fmt.Errorf("error reconciling in ProjectReconciler: %v", err) - } - return result, nil -} - -type wrappedProjectReconciler struct { - client.Client - refResolver *zitadelv1alpha1.RefResolver - project *zitadelv1alpha1.Project -} - -func newWrappedProjectReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, - project *zitadelv1alpha1.Project) zitadel.WrappedReconciler { - return &wrappedProjectReconciler{ - Client: client, - refResolver: refResolver, - project: project, - } -} - -type projectReconcilePhase struct { - Name string - Reconcile func(context.Context, *management.Client) error -} - -func (wr *wrappedProjectReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - phases := []projectReconcilePhase{ - { - Name: "project", - Reconcile: wr.reconcileProject, - }, - { - Name: "roles", - Reconcile: wr.reconcileRoles, - }, - { - Name: "grants", - Reconcile: wr.reconcileGrants, - }, - } - for _, p := range phases { - err := p.Reconcile(ctx, ztdClient) - if err != nil { - return err - } - } - return nil -} - -func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace) - if err != nil { - return err - } - if wr.project.Status.ProjectId != "" { - p, err := ztdClient.GetProjectByID(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetProjectByIDRequest{Id: wr.project.Status.ProjectId}) - if p != nil { - _, err := ztdClient.UpdateProject(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.UpdateProjectRequest{ - Id: wr.project.Status.ProjectId, - Name: wr.project.Name, - ProjectRoleAssertion: wr.project.Spec.ProjectRoleAssertion, - ProjectRoleCheck: wr.project.Spec.ProjectRoleAssertion, - HasProjectCheck: wr.project.Spec.HasProjectCheck}, - ) - - if err != nil { - if !strings.Contains(err.Error(), "No changes") { - return fmt.Errorf("Error updating Project: %v", err) - } - } - return nil - } - if err != nil { - if !strings.Contains(err.Error(), "not found") { - return fmt.Errorf("Error getting project: %v", err) - } - } - } - - resp, err := ztdClient.AddProject(middleware.SetOrgID(ctx, org.Status.OrgId), - &pb.AddProjectRequest{ - Name: wr.project.Name, - ProjectRoleAssertion: wr.project.Spec.ProjectRoleAssertion, - ProjectRoleCheck: wr.project.Spec.ProjectRoleAssertion, - HasProjectCheck: wr.project.Spec.HasProjectCheck}, - ) - if err != nil { - if strings.Contains(err.Error(), "AlreadyExists") { - return nil - } - return fmt.Errorf("error creating project in Zitadel: %v", err) - } - patch := ctrlClient.MergeFrom(wr.project.DeepCopy()) - wr.project.Status.ProjectId = resp.Id - return wr.Client.Status().Patch(ctx, wr.project, patch) -} - -func (wr *wrappedProjectReconciler) reconcileRoles(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace) - if err != nil { - return err - } - - resp, err := ztdClient.ListProjectRoles(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.ListProjectRolesRequest{ - ProjectId: wr.project.Status.ProjectId, - }) - if err != nil { - return fmt.Errorf("Could not list project roles: %v", err) - } - roles := map[string]*pb.BulkAddProjectRolesRequest_Role{} - deleteRolesKeys := []string{} - for _, role := range wr.project.Spec.Roles { - roles[role.Key] = &pb.BulkAddProjectRolesRequest_Role{ - Key: role.Key, - DisplayName: role.DisplayName, - Group: role.Group, - } - } - - for _, role := range resp.Result { - if r, ok := roles[role.Key]; ok { - if r.DisplayName != role.DisplayName || r.Group != role.Group { - deleteRolesKeys = append(deleteRolesKeys, role.Key) - } else { - delete(roles, role.Key) - } - } else { - deleteRolesKeys = append(deleteRolesKeys, role.Key) - } - } - - if len(deleteRolesKeys) > 0 { - for _, key := range deleteRolesKeys { - if _, err = ztdClient.RemoveProjectRole(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.RemoveProjectRoleRequest{ - ProjectId: wr.project.Status.ProjectId, - RoleKey: key, - }); err != nil { - return fmt.Errorf("Error removing project role: %v", err) - } - } - } - - if len(roles) > 0 { - _, err = ztdClient.BulkAddProjectRoles(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.BulkAddProjectRolesRequest{ - ProjectId: wr.project.Status.ProjectId, - Roles: maps.Values(roles)}) - if err != nil { - return fmt.Errorf("Could not add roles to project: %v", err) - } - } - return nil -} - -func (wr *wrappedProjectReconciler) reconcileGrants(ctx context.Context, ztdClient *management.Client) error { - org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace) - if err != nil { - return err - } - existingGrants, err := ztdClient.ListProjectGrants(ctx, &pb.ListProjectGrantsRequest{ - ProjectId: wr.project.Status.ProjectId, - }) - if err != nil { - return fmt.Errorf("Error listing project grants: %v", err) - } - ctx = middleware.SetOrgID(ctx, org.Status.OrgId) - for _, grant := range wr.project.DeepCopy().Spec.Grants { - grantedOrg, err := wr.refResolver.OrganizationRef(ctx, &grant.OrganizationRef, wr.project.Namespace) - if err != nil { - return err - } - var existingGrant *project.GrantedProject - for _, eGrant := range existingGrants.Result { - if eGrant.GrantedOrgId == grantedOrg.Status.OrgId { - existingGrant = eGrant - break - } - } - if existingGrant == nil { - _, err := ztdClient.AddProjectGrant(ctx, &pb.AddProjectGrantRequest{ - ProjectId: wr.project.Status.ProjectId, - GrantedOrgId: grantedOrg.Status.OrgId, - RoleKeys: grant.RoleKeys, - }) - if err != nil { - return fmt.Errorf("Error Adding project grant: %v", err) - } - } else { - sort.Strings(existingGrant.GrantedRoleKeys) - sort.Strings(grant.RoleKeys) - if !reflect.DeepEqual(existingGrant.GrantedRoleKeys, grant.RoleKeys) { - _, err := ztdClient.UpdateProjectGrant(ctx, &pb.UpdateProjectGrantRequest{ - ProjectId: wr.project.Status.ProjectId, - GrantId: existingGrant.GrantId, - RoleKeys: grant.RoleKeys, - }) - if err != nil { - return fmt.Errorf("Error Updating project grant: %v", err) - } - } - } - } - return nil -} - -func (wr *wrappedProjectReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { - patch := client.MergeFrom(wr.project.DeepCopy()) - patcher(&wr.project.Status) - - if err := wr.Client.Status().Patch(ctx, wr.project, patch); err != nil { - return fmt.Errorf("error patching Project status: %v", err) - } - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *ProjectReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.Project{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/internal/controller/project_controller_finalizer.go b/src/internal/controller/project_controller_finalizer.go deleted file mode 100644 index 6d0d110..0000000 --- a/src/internal/controller/project_controller_finalizer.go +++ /dev/null @@ -1,94 +0,0 @@ -package controller - -import ( - "strings" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel" - - "context" - "fmt" - - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/middleware" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/management" - "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - projectFinalizerName = "project.zitadel.topmanage.com/project" -) - -type wrappedProjectFinalizer struct { - client.Client - project *zitadelv1alpha1.Project - refresolver *zitadelv1alpha1.RefResolver -} - -func newWrappedProjectFinalizer(client client.Client, project *zitadelv1alpha1.Project, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer { - return &wrappedProjectFinalizer{ - Client: client, - project: project, - refresolver: refresolver, - } -} - -func (wf *wrappedProjectFinalizer) AddFinalizer(ctx context.Context) error { - if wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.project, func(project *zitadelv1alpha1.Project) { - controllerutil.AddFinalizer(project, projectFinalizerName) - }) -} - -func (wf *wrappedProjectFinalizer) RemoveFinalizer(ctx context.Context) error { - if !wf.ContainsFinalizer() { - return nil - } - return wf.patch(ctx, wf.project, func(project *zitadelv1alpha1.Project) { - controllerutil.RemoveFinalizer(wf.project, projectFinalizerName) - }) -} - -func (wr *wrappedProjectFinalizer) ContainsFinalizer() bool { - return controllerutil.ContainsFinalizer(wr.project, projectFinalizerName) -} - -func (wf *wrappedProjectFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error { - if wf.project.Status.ProjectId == "" { - return nil - } - org, err := wf.refresolver.OrganizationRef(ctx, &wf.project.Spec.OrganizationRef, wf.project.Namespace) - if err != nil { - return err - } - { - - _, err := ztdClient.GetProjectByID(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetProjectByIDRequest{Id: wf.project.Status.ProjectId}) - if err != nil { - if strings.Contains(err.Error(), `not found`) { - return nil - } - return err - } - } - _, err = ztdClient.RemoveProject(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.RemoveProjectRequest{Id: wf.project.Status.ProjectId}) - if err != nil { - return err - } - return nil -} - -func (wr *wrappedProjectFinalizer) patch(ctx context.Context, project *zitadelv1alpha1.Project, - patchFn func(*zitadelv1alpha1.Project)) error { - patch := ctrlClient.MergeFrom(project.DeepCopy()) - patchFn(project) - - if err := wr.Client.Patch(ctx, project, patch); err != nil { - return fmt.Errorf("error patching Project finalizer: %v", err) - } - return nil -} diff --git a/src/internal/controller/zitadelcluster_controller.go b/src/internal/controller/zitadelcluster_controller.go deleted file mode 100644 index 230e114..0000000 --- a/src/internal/controller/zitadelcluster_controller.go +++ /dev/null @@ -1,728 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "crypto/x509" - "encoding/base64" - "encoding/json" - "encoding/pem" - "fmt" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - builder "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/configuration" - configmap "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/configmap" - secret "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/secret" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/service" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/machinekey" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" - systemapiaccount "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/systemapi" - zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" - "github.com/hashicorp/go-multierror" - "github.com/zitadel/zitadel-go/v3/pkg/client/system" - adm "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/admin" - authn "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/authn" - object "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/object" - pb "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/system" - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -type reconcilePhase struct { - Name string - Reconcile func(context.Context, *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) -} - -type patcher func(*zitadelv1alpha1.ZitadelClusterStatus) error - -// ZitadelClusterReconciler reconciles a ZitadelCluster object -type ZitadelClusterReconciler struct { - client.Client - Scheme *runtime.Scheme - ConditionReady *condition.Ready - Builder *builder.Builder - SecretReconciler *secret.SecretReconciler - ConfigMapReconciler *configmap.ConfigMapReconciler - ServiceReconciler *service.ServiceReconciler - RefResolver *zitadelv1alpha1.RefResolver -} - -// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;patch -// +kubebuilder:rbac:groups="",resources=services,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups="",resources=secrets,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups="",resources=endpoints,verbs=create;patch;get;list;watch -// +kubebuilder:rbac:groups="",resources=endpoints/restricted,verbs=create;patch;get;list;watch -// +kubebuilder:rbac:groups="",resources=pods,verbs=get;delete -// +kubebuilder:rbac:groups="",resources=events,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings;clusterrolebindings,verbs=list;watch;create;patch -// +kubebuilder:rbac:groups=zitadel.topmanage.com,resources=zitadelclusters,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=zitadel.topmanage.com,resources=zitadelclusters/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=zitadel.topmanage.com,resources=zitadelclusters/finalizers,verbs=update -// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/finalizers,verbs=update -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests,verbs=get;list;watch;create;patch;delete -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests/approval,verbs=update -// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete - -func (r *ZitadelClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - logger.Info("Starting Reconcile") - - var zitadel zitadelv1alpha1.ZitadelCluster - - if err := r.Get(ctx, req.NamespacedName, &zitadel); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - phases := []reconcilePhase{ - { - Name: "Spec", - Reconcile: r.setSpecDefaults, - }, - { - Name: "Status", - Reconcile: r.setStatusDefaults, - }, - { - Name: "MasterkeySecret", - Reconcile: r.reconcileMasterKeySecret, - }, - { - Name: "ServiceAccount", - Reconcile: r.reconcileSystemAPIUser, - }, - { - Name: "Configuration", - Reconcile: r.reconcileConfig, - }, - { - Name: "InitJob", - Reconcile: r.reconcileInitJob, - }, - { - Name: "SetupJob", - Reconcile: r.reconcileSetupJob, - }, - { - Name: "Deployment", - Reconcile: r.reconcileDeployment, - }, - { - Name: "Service", - Reconcile: r.reconcileService, - }, - { - Name: "DefaultInstance", - Reconcile: r.reconcileDefaultInstance, - }, - { - Name: "SMTPConfig", - Reconcile: r.reconcileSMTPConfig, - }, - { - Name: "DomainPolicyConfig", - Reconcile: r.reconcileDomainPolicy, - }, - } - - for _, p := range phases { - result, err := p.Reconcile(ctx, &zitadel) - if err != nil { - if errors.IsNotFound(err) { - continue - } - - var errBundle *multierror.Error - errBundle = multierror.Append(errBundle, err) - - msg := fmt.Sprintf("Error reconciling %s: %v", p.Name, err) - patchErr := r.patchStatus(ctx, &zitadel, func(s *zitadelv1alpha1.ZitadelClusterStatus) error { - patcher := r.ConditionReady.PatcherFailed(msg) - patcher(s) - return nil - }) - if errors.IsNotFound(patchErr) { - errBundle = multierror.Append(errBundle, patchErr) - } - - if err := errBundle.ErrorOrNil(); err != nil { - return ctrl.Result{}, fmt.Errorf("error reconciling %s: %v", p.Name, err) - } - } - if !result.IsZero() { - return result, err - } - } - - if err := r.patchStatus(ctx, &zitadel, r.patcher(ctx, &zitadel)); err != nil && !errors.IsNotFound(err) { - return ctrl.Result{}, err - } - return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil -} - -func (r *ZitadelClusterReconciler) setSpecDefaults(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - return ctrl.Result{}, r.patch(ctx, zitadel, func(zit *zitadelv1alpha1.ZitadelCluster) { - zit.SetDefaults() - }) -} - -func (r *ZitadelClusterReconciler) setStatusDefaults(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - return ctrl.Result{}, r.patchStatus(ctx, zitadel, func(status *zitadelv1alpha1.ZitadelClusterStatus) error { - status.FillWithDefaults(zitadel) - return nil - }) -} - -func (r *ZitadelClusterReconciler) reconcileMasterKeySecret(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - secretName := masterkey.MasterKeyName(zitadel) - key := types.NamespacedName{ - Name: secretName, - Namespace: zitadel.Namespace, - } - _, err := r.SecretReconciler.ReconcileRandomPassword(ctx, key, masterkey.Key, zitadel) - - if err != nil { - return ctrl.Result{}, err - } - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileSystemAPIUser(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - secretName := systemapiaccount.SystemAPIAccountName(zitadel) - key := types.NamespacedName{ - Name: secretName, - Namespace: zitadel.Namespace, - } - _, err := r.SecretReconciler.ReconcileRandomPrivateRSA(ctx, key, systemapiaccount.Key, zitadel) - - if err != nil { - return ctrl.Result{}, err - } - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileConfig(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - postgres, err := r.RefResolver.PostgreSQLClusterRef(ctx, &zitadel.Spec.PostgreSQLClusterRef, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - configName := configuration.ConfigurationName(zitadel) - key := types.NamespacedName{ - Name: configName, - Namespace: zitadel.Namespace, - } - privateKeyData, err := r.RefResolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: systemapiaccount.SystemAPIAccountName(zitadel)}, Key: systemapiaccount.Key}, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - pemBlock, _ := pem.Decode([]byte(privateKeyData)) - if pemBlock == nil { - return ctrl.Result{}, fmt.Errorf("failed to decode PEM block") - } - privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) - publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) - if err != nil { - return ctrl.Result{}, err - } - publicKeyPem := pem.EncodeToMemory( - &pem.Block{ - Type: "RSA PUBLIC KEY", - Bytes: publicKeyBytes, - }, - ) - base64key := base64.StdEncoding.EncodeToString(publicKeyPem) - err = r.ConfigMapReconciler.ReconcileZitadelConfiguration(ctx, key, zitadel, postgres, base64key) - - if err != nil { - return ctrl.Result{}, err - } - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileInitJob(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - key := client.ObjectKeyFromObject(zitadel) - key.Name = "init-job-" + key.Name - - // Build the desired job - desiredInitJob, err := r.Builder.BuildInitJob(zitadel, key) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error building InitJob: %v", err) - } - - var existingJob batchv1.Job - err = r.Get(ctx, key, &existingJob) - if err != nil { - if !errors.IsNotFound(err) { - return ctrl.Result{}, fmt.Errorf("error getting InitJob: %v", err) - } - // If job is not found, create the job - if err := r.Create(ctx, desiredInitJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating InitJob: %v", err) - } - return ctrl.Result{}, nil - } - - // Compare the image in the existing job with the desired image - existingImage := existingJob.Spec.Template.Spec.Containers[0].Image - desiredImage := desiredInitJob.Spec.Template.Spec.Containers[0].Image - - // If the images don't match, delete the existing job and wait for deletion - if existingImage != desiredImage { - - if err := r.Delete(ctx, &existingJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error deleting existing InitJob: %v", err) - } - - // Wait for the job to be fully deleted before creating a new one - for { - err := r.Get(ctx, key, &existingJob) - if errors.IsNotFound(err) { - break // Job has been deleted, we can proceed - } - if err != nil { - return ctrl.Result{}, fmt.Errorf("error checking if InitJob is deleted: %v", err) - } - // Sleep for a short interval to avoid tight loop - time.Sleep(1 * time.Second) - } - - // Now create the new job - if err := r.Create(ctx, desiredInitJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating new InitJob: %v", err) - } - } - if err := r.Get(ctx, key, &existingJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error fetching existing InitJob status: %v", err) - } - - if existingJob.Status.Succeeded != 1 { // Replace with actual success condition - return ctrl.Result{}, fmt.Errorf("InitJob is not successful, current status: %v", existingJob.Status) - } - // If the job exists and the image matches, no action is needed - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileSetupJob(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - key := client.ObjectKeyFromObject(zitadel) - key.Name = "setup-job-" + key.Name - - // Build the desired job - desiredSetupJob, err := r.Builder.BuildSetupJob(zitadel, key) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error building SetupJob: %v", err) - } - - var existingJob batchv1.Job - err = r.Get(ctx, key, &existingJob) - if err != nil { - if !errors.IsNotFound(err) { - return ctrl.Result{}, fmt.Errorf("error getting SetupJob: %v", err) - } - // If job is not found, create the job - if err := r.Create(ctx, desiredSetupJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating SetupJob: %v", err) - } - return ctrl.Result{}, nil - } - - // Compare the image in the existing job with the desired image - existingImage := existingJob.Spec.Template.Spec.Containers[0].Image - desiredImage := desiredSetupJob.Spec.Template.Spec.Containers[0].Image - - // If the images don't match, delete the existing job and wait for deletion - if existingImage != desiredImage { - - if err := r.Delete(ctx, &existingJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error deleting existing SetupJob: %v", err) - } - - // Wait for the job to be fully deleted before creating a new one - for { - err := r.Get(ctx, key, &existingJob) - if errors.IsNotFound(err) { - break // Job has been deleted, we can proceed - } - if err != nil { - return ctrl.Result{}, fmt.Errorf("error checking if SetupJob is deleted: %v", err) - } - // Sleep for a short interval to avoid tight loop - time.Sleep(1 * time.Second) - } - - // Now create the new job - if err := r.Create(ctx, desiredSetupJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating new SetupJob: %v", err) - } - } - if err := r.Get(ctx, key, &existingJob); err != nil { - return ctrl.Result{}, fmt.Errorf("error fetching existing SetupJob status: %v", err) - } - - if existingJob.Status.Succeeded != 1 { // Replace with actual success condition - return ctrl.Result{}, fmt.Errorf("SetupJob is not successful, current status: %v", existingJob.Status) - } - // If the job exists and the image matches, no action is needed - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileDeployment(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - // TODO: Reload on config changed - key := client.ObjectKeyFromObject(zitadel) - desiredSts, err := r.Builder.BuildDeployment(zitadel, key) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error building Deployment: %v", err) - } - var existingDep appsv1.Deployment - if err := r.Get(ctx, key, &existingDep); err != nil { - if !errors.IsNotFound(err) { - return ctrl.Result{}, fmt.Errorf("error getting Deployment: %v", err) - } - if err := r.Create(ctx, desiredSts); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating Deployment: %v", err) - } - return ctrl.Result{}, nil - } - - patch := client.MergeFrom(existingDep.DeepCopy()) - existingDep.Spec.Template = desiredSts.Spec.Template - existingDep.Spec.Replicas = desiredSts.Spec.Replicas - return ctrl.Result{}, r.Patch(ctx, &existingDep, patch) -} - -func (r *ZitadelClusterReconciler) reconcileService(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - return ctrl.Result{}, r.reconcileDefaultService(ctx, zitadel) -} - -func (r *ZitadelClusterReconciler) reconcileDefaultService(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) error { - key := client.ObjectKeyFromObject(zitadel) - opts := builder.ServiceOpts{ - Ports: []corev1.ServicePort{ - { - Name: deployment.ZitadelName, - Port: deployment.ZitadelPort, - }, - }, - } - desiredSvc, err := r.Builder.BuildService(zitadel, key, opts) - if err != nil { - return fmt.Errorf("error building Service: %v", err) - } - return r.ServiceReconciler.Reconcile(ctx, desiredSvc) -} - -func (r *ZitadelClusterReconciler) reconcileDefaultInstance(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - // First create systemapi to get, delete and create instances - privateKeyData, err := r.RefResolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: systemapiaccount.SystemAPIAccountName(zitadel)}, Key: systemapiaccount.Key}, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - ztdClient, err := system.NewClient(ctx, GetIssuer(zitadel), GetAPI(zitadel), system.JWTProfileFromKey([]byte(privateKeyData), masterkey.OwnerName), system.WithInsecure()) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Error creating sytem client: %v", err) - } - defer ztdClient.Connection.Close() - - // Delete all Instances that isn't the default - { - resp, err := ztdClient.ListInstances(ctx, &pb.ListInstancesRequest{ - Query: &object.ListQuery{ - Offset: uint64(0), - Limit: uint32(100), - Asc: true, - }, - }) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Error listing instances: %v", err) - } - - for _, instance := range resp.Result { - if instance != nil { - if instance.Id != zitadel.Status.DefaultInstanceId || zitadel.Status.DefaultInstanceId == "" { - for _, domain := range instance.Domains { - if domain != nil { - if !domain.Generated { - if _, err := ztdClient.RemoveDomain(ctx, &pb.RemoveDomainRequest{ - InstanceId: instance.Id, - Domain: domain.Domain, - }); err != nil { - return ctrl.Result{}, fmt.Errorf("Error removing domain in instance: %v", err) - } - } - } - } - fmt.Println("DELETING INSTANCE") - _, err := ztdClient.RemoveInstance(ctx, &pb.RemoveInstanceRequest{InstanceId: instance.Id}) - if err != nil { - return ctrl.Result{}, err - } - } - } - } - } - - // Check if instance already exists - _, err = ztdClient.GetInstance(ctx, &pb.GetInstanceRequest{InstanceId: zitadel.Status.DefaultInstanceId}) - if err != nil { - if strings.Contains(err.Error(), "Instance not found") { - // if Instance doesn't exist, then create and assign secrets - resp, err := ztdClient.CreateInstance(ctx, &pb.CreateInstanceRequest{ - InstanceName: zitadel.Spec.FirstOrgName, - FirstOrgName: zitadel.Spec.FirstOrgName, - CustomDomain: zitadel.Spec.Host, - Owner: &pb.CreateInstanceRequest_Machine_{Machine: &pb.CreateInstanceRequest_Machine{ - Name: "k8s-operator", - UserName: "k8s-operator", - MachineKey: &pb.CreateInstanceRequest_MachineKey{ - Type: authn.KeyType_KEY_TYPE_JSON}, - PersonalAccessToken: &pb.CreateInstanceRequest_PersonalAccessToken{}}, - }}) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Error creating default instance: %v", err) - } - var machineKeyData zitadelClient.MachineKey - if err := json.Unmarshal(resp.MachineKey, &machineKeyData); err != nil { - return ctrl.Result{}, err - } - secretName := machinekey.MachineKeySecretName(zitadel) - key := types.NamespacedName{ - Name: secretName, - Namespace: zitadel.Namespace, - } - secretData := make(map[string][]byte) - jsonData, err := json.Marshal(machineKeyData) - if err != nil { - return ctrl.Result{}, err - } - secretData[machinekey.Key] = jsonData - secret, err := r.Builder.BuildSecret(builder.SecretOpts{Zitadel: zitadel, Key: key, Data: secretData}, zitadel) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error building machinekey Secret: %v", err) - } - if err := r.Create(ctx, secret); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating machinekey Secret: %v", err) - } - patch := client.MergeFrom(zitadel.DeepCopy()) - zitadel.Status.DefaultInstanceId = resp.InstanceId - return ctrl.Result{}, r.Status().Patch(ctx, zitadel, patch) - } else { - return ctrl.Result{}, fmt.Errorf("Error getting instance with id: %s: %v", zitadel.Status.DefaultInstanceId, err) - } - } - - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileSMTPConfig(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - privateKeyData, err := r.RefResolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: systemapiaccount.SystemAPIAccountName(zitadel)}, Key: systemapiaccount.Key}, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - ztdClient, err := system.NewClient(ctx, GetIssuer(zitadel), GetAPI(zitadel), system.JWTProfileFromKey([]byte(privateKeyData), masterkey.OwnerName), system.WithInsecure()) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Error creating sytem client: %v", err) - } - defer ztdClient.Connection.Close() - _, domain, _ := strings.Cut(zitadel.Spec.SMTPConfig.SenderAddress, "@") - _, err = ztdClient.AddDomain(ctx, &pb.AddDomainRequest{ - Domain: domain, - InstanceId: zitadel.Status.DefaultInstanceId, - }) - if err != nil { - if !strings.Contains(err.Error(), "AlreadyExists") { - return ctrl.Result{}, fmt.Errorf("Could add smtp trusted domain: %v", err) - } - } - - adminClient, err := zitadelClient.NewAdminClient(ctx, zitadel, *r.RefResolver) - if err != nil { - return ctrl.Result{}, err - } - defer adminClient.Connection.Close() - - _, err = adminClient.AddInstanceTrustedDomain(ctx, &adm.AddInstanceTrustedDomainRequest{ - Domain: domain, - }) - - resp, err := adminClient.GetEmailProvider(ctx, &adm.GetEmailProviderRequest{}) - if err != nil { - if strings.Contains(err.Error(), "not found") { - adminRequest := &adm.AddEmailProviderSMTPRequest{ - SenderAddress: zitadel.Spec.SMTPConfig.SenderAddress, - SenderName: zitadel.Spec.SMTPConfig.SenderName, - Tls: zitadel.Spec.SMTPConfig.TLS, - Host: zitadel.Spec.SMTPConfig.Host, - Description: "autogenerated by k8s-operator", - Password: "test", - } - if zitadel.Spec.SMTPConfig.User != nil && zitadel.Spec.SMTPConfig.Password != nil { - passwordSecret, err := r.RefResolver.SecretKeyRef(ctx, zitadel.Spec.SMTPConfig.Password.SecretKeyRef, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - adminRequest.Password = passwordSecret - adminRequest.User = *zitadel.Spec.SMTPConfig.User - } - if zitadel.Spec.SMTPConfig.ReplyToAddress != nil { - adminRequest.ReplyToAddress = *zitadel.Spec.SMTPConfig.ReplyToAddress - } - - addRes, err := adminClient.AddEmailProviderSMTP(ctx, adminRequest) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Could not add SMTP config: %v", err) - } - if _, err := adminClient.ActivateEmailProvider(ctx, &adm.ActivateEmailProviderRequest{ - Id: addRes.Id, - }); err != nil { - if !strings.Contains(err.Error(), "AlreadyActive") { - return ctrl.Result{}, fmt.Errorf("Error activating SMTP config: %v", err) - } - } - } else { - return ctrl.Result{}, fmt.Errorf("Error getting SMTP config: %v", err) - } - } else { - if zitadel.Spec.SMTPConfig.SenderAddress != resp.Config.GetSmtp().GetSenderAddress() || zitadel.Spec.SMTPConfig.SenderName != resp.Config.GetSmtp().SenderName || zitadel.Spec.SMTPConfig.TLS != resp.Config.GetSmtp().Tls || zitadel.Spec.SMTPConfig.Host != resp.Config.GetSmtp().Host { - adminRequest := &adm.UpdateEmailProviderSMTPRequest{ - SenderAddress: zitadel.Spec.SMTPConfig.SenderAddress, - SenderName: zitadel.Spec.SMTPConfig.SenderName, - Tls: zitadel.Spec.SMTPConfig.TLS, - Host: zitadel.Spec.SMTPConfig.Host, - Id: resp.Config.Id, - Password: "test", - Description: "autogenerated by k8s-operator", - } - if zitadel.Spec.SMTPConfig.User != nil && zitadel.Spec.SMTPConfig.Password != nil { - - passwordSecret, err := r.RefResolver.SecretKeyRef(ctx, zitadel.Spec.SMTPConfig.Password.SecretKeyRef, zitadel.Namespace) - if err != nil { - return ctrl.Result{}, err - } - adminRequest.Password = passwordSecret - adminRequest.User = *zitadel.Spec.SMTPConfig.User - } - if zitadel.Spec.SMTPConfig.ReplyToAddress != nil { - adminRequest.ReplyToAddress = *zitadel.Spec.SMTPConfig.ReplyToAddress - } - if _, err = adminClient.UpdateEmailProviderSMTP(ctx, adminRequest); err != nil { - if !strings.Contains(err.Error(), "No changes") { - return ctrl.Result{}, fmt.Errorf("Could not update SMTP config: %v", err) - } - } - - // patch := client.MergeFrom(zitadel.DeepCopy()) - // return ctrl.Result{}, r.Status().Patch(ctx, zitadel, patch) - } - } - return ctrl.Result{}, nil -} - -func (r *ZitadelClusterReconciler) reconcileDomainPolicy(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { - adminClient, err := zitadelClient.NewAdminClient(ctx, zitadel, *r.RefResolver) - if err != nil { - return ctrl.Result{}, err - } - - if _, err = adminClient.UpdateDomainPolicy(ctx, &adm.UpdateDomainPolicyRequest{ - UserLoginMustBeDomain: zitadel.Spec.DomainSettings.UserLoginMustBeDomain, - ValidateOrgDomains: zitadel.Spec.DomainSettings.ValidateOrgDomains, - SmtpSenderAddressMatchesInstanceDomain: zitadel.Spec.DomainSettings.SMTPSenderAddressMatchesInstanceDomain, - }); err != nil { - if !strings.Contains(err.Error(), "not been changed") { - return ctrl.Result{}, fmt.Errorf("Could not update domain policy config: %v", err) - } - } - return ctrl.Result{}, nil -} - -func GetIssuer(zitadel *zitadelv1alpha1.ZitadelCluster) string { - scheme := "http" - if zitadel.Spec.ExternalSecure { - scheme = "https" - } - if zitadel.Spec.ExternalPort == 443 { - return fmt.Sprintf("%s://%s", scheme, zitadel.Spec.Host) - } - return fmt.Sprintf("%s://%s:%d", scheme, zitadel.Spec.Host, zitadel.Spec.ExternalPort) -} - -func GetAPI(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return fmt.Sprintf("%s:%d", deployment.ServiceFQDN(zitadel.ObjectMeta), deployment.ZitadelPort) -} - -func (r *ZitadelClusterReconciler) patchStatus(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster, - patcher patcher) error { - patch := client.MergeFrom(zitadel.DeepCopy()) - if err := patcher(&zitadel.Status); err != nil { - return err - } - return r.Status().Patch(ctx, zitadel, patch) -} - -func (r *ZitadelClusterReconciler) patcher(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) patcher { - return func(s *zitadelv1alpha1.ZitadelClusterStatus) error { - var sts appsv1.Deployment - if err := r.Get(ctx, client.ObjectKeyFromObject(zitadel), &sts); err != nil { - return err - } - zitadel.Status.Replicas = sts.Status.ReadyReplicas - - condition.SetReadyWithDeployment(&zitadel.Status, &sts, zitadel.Status.DefaultInstanceId) - return nil - } -} - -func (r *ZitadelClusterReconciler) patch(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster, - patcher func(*zitadelv1alpha1.ZitadelCluster)) error { - patch := client.MergeFrom(zitadel.DeepCopy()) - patcher(zitadel) - return r.Patch(ctx, zitadel, patch) -} - -// SetupWithManager sets up the controller with the Manager. -func (r *ZitadelClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&zitadelv1alpha1.ZitadelCluster{}). - Owns(&appsv1.Deployment{}). - Owns(&corev1.Service{}). - Owns(&corev1.ConfigMap{}). - Owns(&corev1.Secret{}). - Owns(&zitadelv1alpha1.Organization{}). - WithOptions(controller.Options{RateLimiter: workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](time.Millisecond*500, time.Minute*3)}). - Complete(r) -} diff --git a/src/pkg/admin/admin.go b/src/pkg/admin/admin.go deleted file mode 100644 index fc06c9a..0000000 --- a/src/pkg/admin/admin.go +++ /dev/null @@ -1,14 +0,0 @@ -package admin - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -const ( - AccountName = "admin" - Key = "password" -) - -func AdminPasswordSecretName(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return zitadel.Name + "-admin-password-secret" -} diff --git a/src/pkg/builder/organization_builder.go b/src/pkg/builder/organization_builder.go deleted file mode 100644 index 7126491..0000000 --- a/src/pkg/builder/organization_builder.go +++ /dev/null @@ -1,42 +0,0 @@ -package builder - -import ( - "fmt" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -type OrganizationOpts struct { - Key types.NamespacedName - Zitadel *zitadelv1alpha1.ZitadelCluster -} - -func (b *Builder) BuildOrganization(opts OrganizationOpts, owner metav1.Object) (*zitadelv1alpha1.Organization, error) { - objMeta := - metadata.NewMetadataBuilder(opts.Key). - Build() - - org := &zitadelv1alpha1.Organization{ - ObjectMeta: objMeta, - Spec: zitadelv1alpha1.OrganizationSpec{ - ZitadelClusterRef: zitadelv1alpha1.ZitadelClusterRef{ - ObjectReference: corev1.ObjectReference{ - Kind: "ZitadelCluster", - Namespace: opts.Zitadel.Namespace, - Name: opts.Zitadel.Name, - APIVersion: "v1alpha1", - }, - }, - }, - } - - if err := controllerutil.SetControllerReference(owner, org, b.scheme); err != nil { - return nil, fmt.Errorf("error setting controller reference in Secret manifest: %v", err) - } - return org, nil -} diff --git a/src/pkg/builder/service_builder.go b/src/pkg/builder/service_builder.go deleted file mode 100644 index 1230ad0..0000000 --- a/src/pkg/builder/service_builder.go +++ /dev/null @@ -1,43 +0,0 @@ -package builder - -import ( - "fmt" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - labels "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/labels" - metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -type ServiceOpts struct { - Ports []corev1.ServicePort -} - -func (b *Builder) BuildService(zitadel *zitadelv1alpha1.ZitadelCluster, key types.NamespacedName, - opts ServiceOpts) (*corev1.Service, error) { - objMeta := - metadata.NewMetadataBuilder(key). - WithZitadel(zitadel). - Build() - - svc := &corev1.Service{ - ObjectMeta: objMeta, - Spec: corev1.ServiceSpec{ - Type: corev1.ServiceTypeClusterIP, - Ports: opts.Ports, - Selector: serviceSelectorLabels(opts, zitadel), - }, - } - if err := controllerutil.SetControllerReference(zitadel, svc, b.scheme); err != nil { - return nil, fmt.Errorf("error setting controller reference to Service: %v", err) - } - return svc, nil -} - -func serviceSelectorLabels(opts ServiceOpts, zitadel *zitadelv1alpha1.ZitadelCluster) map[string]string { - return labels.NewLabelsBuilder(). - WithZitadelSelectorLabels(zitadel). - Build() -} diff --git a/src/pkg/condition/pat.go b/src/pkg/condition/pat.go deleted file mode 100644 index 18ab0bc..0000000 --- a/src/pkg/condition/pat.go +++ /dev/null @@ -1,25 +0,0 @@ -package conditions - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -func SetPatOutOfDate(c Conditioner) { - c.SetCondition(metav1.Condition{ - Type: zitadelv1alpha1.ConditionTypePATUpToDate, - Status: metav1.ConditionFalse, - Reason: zitadelv1alpha1.ConditionReasonRolesChanged, - Message: "PAT out of date", - }) -} - -func SetPatUpToDate(c Conditioner) { - c.SetCondition(metav1.Condition{ - Type: zitadelv1alpha1.ConditionTypePATUpToDate, - Status: metav1.ConditionTrue, - Reason: zitadelv1alpha1.ConditionReasonPATUpToDate, - Message: "PAT up to date", - }) -} diff --git a/src/pkg/configuration/configuration.go b/src/pkg/configuration/configuration.go deleted file mode 100644 index 54eb46b..0000000 --- a/src/pkg/configuration/configuration.go +++ /dev/null @@ -1,9 +0,0 @@ -package configuration - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -func ConfigurationName(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return zitadel.Name + "-configuration-configmap" -} diff --git a/src/pkg/controller/zitadel/types.go b/src/pkg/controller/zitadel/types.go deleted file mode 100644 index 3080cb9..0000000 --- a/src/pkg/controller/zitadel/types.go +++ /dev/null @@ -1,39 +0,0 @@ -package zitadel - -import ( - "context" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - - condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrl "sigs.k8s.io/controller-runtime" -) - -type Resource interface { - v1.Object - ZitadelClusterRef(context.Context, *zitadelv1alpha1.RefResolver) (*zitadelv1alpha1.ZitadelClusterRef, error) - IsBeingDeleted() bool -} - -type Reconciler interface { - Reconcile(ctx context.Context, resource Resource) (ctrl.Result, error) -} - -type WrappedReconciler interface { - Reconcile(context.Context, *management.Client) error - PatchStatus(context.Context, condition.Patcher) error -} - -type Finalizer interface { - AddFinalizer(context.Context) error - Finalize(context.Context, Resource) error -} - -type WrappedFinalizer interface { - AddFinalizer(context.Context) error - RemoveFinalizer(context.Context) error - ContainsFinalizer() bool - Reconcile(context.Context, *management.Client) error -} diff --git a/src/pkg/machinekey/machinekey.go b/src/pkg/machinekey/machinekey.go deleted file mode 100644 index a344810..0000000 --- a/src/pkg/machinekey/machinekey.go +++ /dev/null @@ -1,13 +0,0 @@ -package machinekey - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -const ( - Key = "machinekey.json" -) - -func MachineKeySecretName(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return zitadel.Name + "-machinekey-secret" -} diff --git a/src/pkg/masterkey/masterkey.go b/src/pkg/masterkey/masterkey.go deleted file mode 100644 index 591bef5..0000000 --- a/src/pkg/masterkey/masterkey.go +++ /dev/null @@ -1,14 +0,0 @@ -package masterkey - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -const ( - OwnerName = "k8s-operator" - Key = "key" -) - -func MasterKeyName(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return zitadel.Name + "-masterkey-secret" -} diff --git a/src/pkg/systemapi/systemapi_account.go b/src/pkg/systemapi/systemapi_account.go deleted file mode 100644 index fae531c..0000000 --- a/src/pkg/systemapi/systemapi_account.go +++ /dev/null @@ -1,13 +0,0 @@ -package systemapiaccount - -import ( - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" -) - -const ( - Key = "private.pem" -) - -func SystemAPIAccountName(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return zitadel.Name + "-systemapiaccount-secret" -} diff --git a/src/pkg/zitadel/zitadel.go b/src/pkg/zitadel/zitadel.go deleted file mode 100644 index 85619f3..0000000 --- a/src/pkg/zitadel/zitadel.go +++ /dev/null @@ -1,195 +0,0 @@ -package zitadel - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "reflect" - "strings" - "time" - - zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" - "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/machinekey" - "github.com/gorilla/schema" - "google.golang.org/grpc" - - "github.com/zitadel/oidc/pkg/client" - httphelper "github.com/zitadel/oidc/pkg/http" - "github.com/zitadel/oidc/pkg/oidc" - "github.com/zitadel/zitadel-go/v3/pkg/client/admin" - "github.com/zitadel/zitadel-go/v3/pkg/client/management" - "github.com/zitadel/zitadel-go/v3/pkg/client/zitadel" - "golang.org/x/oauth2" - "gopkg.in/square/go-jose.v2" - corev1 "k8s.io/api/core/v1" -) - -type MachineKey struct { - Type string `json:"type"` - KeyID string `json:"keyId"` - Key string `json:"key"` - UserID string `json:"userId"` -} - -func NewClient(ctx context.Context, zitadelCluster *zitadelv1alpha1.ZitadelCluster, refresolver zitadelv1alpha1.RefResolver) (*management.Client, error) { - machineKeyData, err := refresolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: machinekey.MachineKeySecretName(zitadelCluster)}, Key: machinekey.Key}, zitadelCluster.Namespace) - if err != nil { - return nil, err - } - api, err := management.NewClient(ctx, GetIssuer(zitadelCluster), GetAPI(zitadelCluster), []string{oidc.ScopeOpenID, zitadel.ScopeZitadelAPI()}, zitadel.WithInsecure(), zitadel.WithJWTProfileTokenSource(Discover([]byte(machineKeyData), GetAPIUrl(zitadelCluster), GetAuthority(zitadelCluster), GetAPI(zitadelCluster))), - zitadel.WithDialOptions(grpc.WithAuthority(GetAuthority(zitadelCluster))), - ) - - if err != nil { - return nil, fmt.Errorf("ERROR CREATING CLIENT: %v", err) - } - return api, nil -} - -func NewAdminClient(ctx context.Context, zitadelCluster *zitadelv1alpha1.ZitadelCluster, refresolver zitadelv1alpha1.RefResolver) (*admin.Client, error) { - machineKeyData, err := refresolver.SecretKeyRef(ctx, corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: machinekey.MachineKeySecretName(zitadelCluster)}, Key: machinekey.Key}, zitadelCluster.Namespace) - if err != nil { - return nil, err - } - api, err := admin.NewClient(ctx, GetIssuer(zitadelCluster), GetAPI(zitadelCluster), []string{oidc.ScopeOpenID, zitadel.ScopeZitadelAPI()}, zitadel.WithInsecure(), zitadel.WithJWTProfileTokenSource(Discover([]byte(machineKeyData), GetAPIUrl(zitadelCluster), GetAuthority(zitadelCluster), GetAPI(zitadelCluster))), - zitadel.WithDialOptions(grpc.WithAuthority(GetAuthority(zitadelCluster))), - ) - if err != nil { - return nil, fmt.Errorf("ERROR CREATING CLIENT: %v", err) - } - return api, nil -} - -func GetAuthority(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return fmt.Sprintf("%s:%d", zitadel.Spec.Host, zitadel.Spec.ExternalPort) -} - -func GetIssuer(zitadel *zitadelv1alpha1.ZitadelCluster) string { - scheme := "http" - if zitadel.Spec.ExternalSecure { - scheme = "https" - } - return fmt.Sprintf("%s://%s:%d", scheme, zitadel.Spec.Host, zitadel.Spec.ExternalPort) -} - -func GetAPI(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return fmt.Sprintf("%s:%d", deployment.ServiceFQDN(zitadel.ObjectMeta), deployment.ZitadelPort) -} - -func GetAPIUrl(zitadel *zitadelv1alpha1.ZitadelCluster) string { - return fmt.Sprintf("http://%s:%d", deployment.ServiceFQDN(zitadel.ObjectMeta), deployment.ZitadelPort) -} - -type jwtProfileTokenSource struct { - clientID string - audience []string - signer jose.Signer - scopes []string - httpClient *http.Client - tokenEndpoint string - host string -} - -func Discover(key []byte, discoverUrl string, host string, api string) func(issuer string, scopes []string) (oauth2.TokenSource, error) { - return func(issuer string, scopes []string) (oauth2.TokenSource, error) { - var machineKeyData MachineKey - if err := json.Unmarshal(key, &machineKeyData); err != nil { - return nil, err - } - signer, err := client.NewSignerFromPrivateKeyByte([]byte(machineKeyData.Key), machineKeyData.KeyID) - if err != nil { - return nil, err - } - source := &jwtProfileTokenSource{ - host: host, - clientID: machineKeyData.UserID, - audience: []string{issuer}, - signer: signer, - scopes: scopes, - httpClient: http.DefaultClient, - } - config, err := GetDiscoveryConfig(discoverUrl, http.DefaultClient, host, api) - if err != nil { - return nil, err - } - source.tokenEndpoint = config.TokenEndpoint - return source, nil - } -} - -func GetDiscoveryConfig(issuer string, httpClient *http.Client, host string, api string, wellKnownUrl ...string) (*oidc.DiscoveryConfiguration, error) { - wellKnown := strings.TrimSuffix(issuer, "/") + oidc.DiscoveryEndpoint - if len(wellKnownUrl) == 1 && wellKnownUrl[0] != "" { - wellKnown = wellKnownUrl[0] - } - req, err := http.NewRequest("GET", wellKnown, nil) - if err != nil { - return nil, err - } - req.Host = host - discoveryConfig := new(oidc.DiscoveryConfiguration) - err = httphelper.HttpRequest(httpClient, req, &discoveryConfig) - discoveryConfig.TokenEndpoint = replaceEndpoint(discoveryConfig.TokenEndpoint, host, api) - discoveryConfig.AuthorizationEndpoint = replaceEndpoint(discoveryConfig.AuthorizationEndpoint, host, api) - discoveryConfig.IntrospectionEndpoint = replaceEndpoint(discoveryConfig.IntrospectionEndpoint, host, api) - discoveryConfig.EndSessionEndpoint = replaceEndpoint(discoveryConfig.EndSessionEndpoint, host, api) - discoveryConfig.RevocationEndpoint = replaceEndpoint(discoveryConfig.RevocationEndpoint, host, api) - discoveryConfig.UserinfoEndpoint = replaceEndpoint(discoveryConfig.UserinfoEndpoint, host, api) - - if err != nil { - return nil, err - } - return discoveryConfig, nil -} - -func replaceEndpoint(endpoint string, host string, api string) string { - return strings.ReplaceAll(strings.ReplaceAll(endpoint, host, api), "https", "http") -} - -func (j *jwtProfileTokenSource) TokenEndpoint() string { - return j.tokenEndpoint -} - -func (j *jwtProfileTokenSource) HttpClient() *http.Client { - return j.httpClient -} - -func (j *jwtProfileTokenSource) Token() (*oauth2.Token, error) { - assertion, err := client.SignedJWTProfileAssertion(j.clientID, j.audience, time.Hour, j.signer) - if err != nil { - return nil, err - } - token, err := callTokenEndpoint(oidc.NewJWTProfileGrantRequest(assertion, j.scopes...), nil, j, j.host) - if err != nil { - return nil, err - } - return token, err -} - -var Encoder = func() httphelper.Encoder { - e := schema.NewEncoder() - e.RegisterEncoder(oidc.SpaceDelimitedArray{}, func(value reflect.Value) string { - return value.Interface().(oidc.SpaceDelimitedArray).Encode() - }) - return e -}() - -func callTokenEndpoint(request interface{}, authFn interface{}, caller client.TokenEndpointCaller, host string) (newToken *oauth2.Token, err error) { - req, err := httphelper.FormRequest(caller.TokenEndpoint(), request, Encoder, authFn) - if err != nil { - return nil, err - } - tokenRes := new(oidc.AccessTokenResponse) - req.Host = host - if err := httphelper.HttpRequest(caller.HttpClient(), req, &tokenRes); err != nil { - return nil, fmt.Errorf("Error calling token endpoint: %v", err) - } - return &oauth2.Token{ - AccessToken: tokenRes.AccessToken, - TokenType: tokenRes.TokenType, - RefreshToken: tokenRes.RefreshToken, - Expiry: time.Now().UTC().Add(time.Duration(tokenRes.ExpiresIn) * time.Second), - }, nil -}