divide operators
Some checks failed
Build and Publish / build-release (push) Failing after 26s

This commit is contained in:
2026-04-07 13:41:25 -05:00
parent 66f38d90ee
commit da5d944430
179 changed files with 2996 additions and 10163 deletions

View File

@@ -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"

View File

@@ -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. # 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 # 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. # github.com/src-bundle:$VERSION and github.com/src-catalog:$VERSION.
IMAGE_TAG_BASE ?= topmanage.com/src IMAGE_TAG_BASE ?= github.com/src
# BUNDLE_IMG defines the image:tag used for the bundle. # BUNDLE_IMG defines the image:tag used for the bundle.
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>) # You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)

32
PROJECT Normal file
View File

@@ -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"

View File

@@ -22,18 +22,18 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // Image defines the container image name and tag.
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
type Image struct { type Image struct {
Name string `json:"name"` Name string `json:"name"`
Tag string `json:"tag"` Tag string `json:"tag"`
} }
// Password holds a reference to a Kubernetes Secret key containing a password.
type Password struct { type Password struct {
SecretKeyRef corev1.SecretKeySelector `json:"secretRef"` SecretKeyRef corev1.SecretKeySelector `json:"secretRef"`
} }
// SMTPConfig configures an SMTP provider.
type SMTPConfig struct { type SMTPConfig struct {
SenderAddress string `json:"senderAddress"` SenderAddress string `json:"senderAddress"`
SenderName string `json:"senderName"` SenderName string `json:"senderName"`
@@ -45,6 +45,7 @@ type SMTPConfig struct {
ReplyToAddress *string `json:"replyToAddress,omitempty"` ReplyToAddress *string `json:"replyToAddress,omitempty"`
} }
// DomainSettings configures domain-related behaviour.
type DomainSettings struct { type DomainSettings struct {
// +kubebuilder:default=true // +kubebuilder:default=true
UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"` UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"`
@@ -54,60 +55,65 @@ type DomainSettings struct {
SMTPSenderAddressMatchesInstanceDomain bool `json:"smtpSenderAddressMatchesInstanceDomain"` SMTPSenderAddressMatchesInstanceDomain bool `json:"smtpSenderAddressMatchesInstanceDomain"`
} }
// ZitadelClusterSpec defines the desired state of ZitadelCluster // ClusterSpec defines the desired state of Cluster.
type ZitadelClusterSpec struct { type ClusterSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Host is the external hostname used to reach Zitadel.
// Important: Run "make" to regenerate code after modifying this file Host string `json:"host"`
// +kubebuilder:default="DEFAULT"
FirstOrgName string `json:"firstOrgName"` // ExternalPort is the port exposed externally.
DomainSettings DomainSettings `json:"domainSettings"`
SMTPConfig SMTPConfig `json:"smtpConfig"`
Host string `json:"host"`
// +kubebuilder:default=443 // +kubebuilder:default=443
ExternalPort int64 `json:"externalPort"` ExternalPort int64 `json:"externalPort"`
// ExternalSecure indicates whether TLS is used on the external endpoint.
// +kubebuilder:default=true // +kubebuilder:default=true
ExternalSecure bool `json:"externalSecure"` ExternalSecure bool `json:"externalSecure"`
Image Image `json:"image"`
Resources corev1.ResourceRequirements `json:"resources"` // Image is the Zitadel container image to deploy.
PostgreSQLClusterRef PostgreSQLClusterRef `json:"postgresClusterRef"` Image Image `json:"image"`
// +kubebuilder:validation:Enum=demo;trial;staging;productive;testing
Purpose string `json:"purpose"` // Resources defines compute resource requests and limits for the Zitadel pods.
// PodAnnotations to add to the Pods metadata. 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 // +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec // +operator-sdk:csv:customresourcedefinitions:type=spec
PodAnnotations map[string]string `json:"podAnnotations,omitempty"` PodAnnotations map[string]string `json:"podAnnotations,omitempty"`
// ServiceAnnotations to add to the service metadata.
// ServiceAnnotations are extra annotations added to the Zitadel Service.
// +optional // +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec // +operator-sdk:csv:customresourcedefinitions:type=spec
ServiceAnnotations map[string]string `json:"serviceAnnotations,omitempty"` 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 // ClusterStatus defines the observed state of Cluster.
type ZitadelClusterStatus struct { type ClusterStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Conditions store the status conditions of the Cluster.
// Important: Run "make" to regenerate code after modifying this file
Conditions []metav1.Condition `json:"conditions,omitempty"` Conditions []metav1.Condition `json:"conditions,omitempty"`
// Replicas is the current number of running Zitadel pods.
// +kubebuilder:default=3 // +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"` Replicas int32 `json:"replicas,omitempty"`
// +kubebuilder:default=""
DefaultInstanceId string `json:"defaultInstanceId"`
// +kubebuilder:default=""
SMTPProviderId string `json:"smtpProviderId"`
} }
// SetCondition sets a status condition // SetCondition sets a status condition on the Cluster.
func (s *ZitadelClusterStatus) SetCondition(condition metav1.Condition) { func (s *ClusterStatus) SetCondition(condition metav1.Condition) {
if s.Conditions == nil { if s.Conditions == nil {
s.Conditions = make([]metav1.Condition, 0) s.Conditions = make([]metav1.Condition, 0)
} }
meta.SetStatusCondition(&s.Conditions, condition) 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 { for _, c := range s.Conditions {
if c.Type == ConditionTypeReady && c.Status == metav1.ConditionTrue { if c.Type == ConditionTypeReady && c.Status == metav1.ConditionTrue {
return true return true
@@ -116,35 +122,40 @@ func (s *ZitadelClusterStatus) IsReady() bool {
return false return false
} }
func (s *ZitadelClusterStatus) FillWithDefaults(zitadel *ZitadelCluster) { // FillWithDefaults populates default values on the Cluster status.
//(Haim ;^D ): No defaults yet func (s *ClusterStatus) FillWithDefaults(_ *Cluster) {
// (Haim ;^D): No defaults yet
} }
//+kubebuilder:object:root=true //+kubebuilder:object:root=true
//+kubebuilder:subresource:status //+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 // Cluster is the Schema for the clusters API.
type ZitadelCluster struct { type Cluster struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"` metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ZitadelClusterSpec `json:"spec,omitempty"` Spec ClusterSpec `json:"spec,omitempty"`
Status ZitadelClusterStatus `json:"status,omitempty"` Status ClusterStatus `json:"status,omitempty"`
} }
func (m *ZitadelCluster) SetDefaults() { // SetDefaults populates default values on the Cluster spec.
//(Haim ;^D ): No defaults yet func (m *Cluster) SetDefaults() {
// (Haim ;^D): No defaults yet
} }
//+kubebuilder:object:root=true //+kubebuilder:object:root=true
// ZitadelClusterList contains a list of ZitadelCluster // ClusterList contains a list of Cluster.
type ZitadelClusterList struct { type ClusterList struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"` metav1.ListMeta `json:"metadata,omitempty"`
Items []ZitadelCluster `json:"items"` Items []Cluster `json:"items"`
} }
func init() { func init() {
SchemeBuilder.Register(&ZitadelCluster{}, &ZitadelClusterList{}) SchemeBuilder.Register(&Cluster{}, &ClusterList{})
} }

View File

@@ -16,7 +16,7 @@ limitations under the License.
// Package v1alpha1 contains API Schema definitions for the zitadel v1alpha1 API group // Package v1alpha1 contains API Schema definitions for the zitadel v1alpha1 API group
// +kubebuilder:object:generate=true // +kubebuilder:object:generate=true
// +groupName=zitadel.topmanage.com // +groupName=zitadel.github.com
package v1alpha1 package v1alpha1
import ( import (
@@ -26,7 +26,7 @@ import (
var ( var (
// GroupVersion is group version used to register these objects // 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 is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

View File

@@ -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{})
}

23
api/v1alpha1/ref_types.go Normal file
View File

@@ -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"`
}

View File

@@ -22,9 +22,9 @@ func NewRefResolver(client client.Client) *RefResolver {
} }
} }
func (r *RefResolver) ZitadelCluster(ctx context.Context, ref *ZitadelClusterRef, func (r *RefResolver) Instance(ctx context.Context, ref *InstanceRef,
namespace string) (*ZitadelCluster, error) { namespace string) (*Instance, error) {
if ref.Kind != "" && ref.Kind != "ZitadelCluster" { if ref.Kind != "" && ref.Kind != "Instance" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) 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 key.Namespace = ref.Namespace
} }
var zitadel ZitadelCluster var zitadel Instance
if err := r.client.Get(ctx, key, &zitadel); err != nil { if err := r.client.Get(ctx, key, &zitadel); err != nil {
return nil, err return nil, err
} }
return &zitadel, nil return &zitadel, nil
} }
func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef, func (r *RefResolver) Cluster(ctx context.Context, ref *ClusterRef,
namespace string) (*OIDCApp, error) { namespace string) (*Cluster, error) {
if ref.Kind != "" && ref.Kind != "OIDCApp" { if ref.Kind != "" && ref.Kind != "Cluster" {
return nil, fmt.Errorf("Unsupported reference kind: '%s'", ref.Kind) 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 key.Namespace = ref.Namespace
} }
var zitadel OIDCApp var zitadel Cluster
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
if err := r.client.Get(ctx, key, &zitadel); err != nil { if err := r.client.Get(ctx, key, &zitadel); err != nil {
return nil, err return nil, err
} }

View File

@@ -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
}

View File

@@ -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

13
build/flake.lock generated
View File

@@ -18,18 +18,6 @@
"type": "github" "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": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1743448293, "lastModified": 1743448293,
@@ -48,7 +36,6 @@
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgs-unstable": "nixpkgs-unstable"
} }
}, },

View File

@@ -6,17 +6,16 @@
nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
}; };
outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils }: outputs = { self, nixpkgs-unstable, flake-utils }:
flake-utils.lib.eachDefaultSystem (system: flake-utils.lib.eachDefaultSystem (system:
let let
unstable = nixpkgs-unstable.legacyPackages.${system}; pkgs = nixpkgs-unstable.legacyPackages.${system};
pkgs = nixpkgs.legacyPackages.${system}; package = pkgs.buildGoModule {
package = unstable.buildGoModule {
pname = "zitadel-k8s-operator"; pname = "zitadel-k8s-operator";
version = "0.0.0"; version = "0.0.0";
src = ../src; src = ../.;
doCheck = false; doCheck = false;
vendorHash = "sha256-HEXIHASdDC7chG9uF56f6pvZPVbxYs/fWFytDz6CAf4="; vendorHash = "sha256-HEXIHASdDC7chG9uF56frpvZPVbxYs/fWFytDz6CAf4=";
installPhase = '' installPhase = ''
runHook preInstall runHook preInstall
@@ -45,8 +44,7 @@
in with pkgs; { in with pkgs; {
packages.default = package; packages.default = package;
packages.dockerImage = dockerPackage; packages.dockerImage = dockerPackage;
devShells.default = mkShell { devShells.default =
buildInputs = [ nixfmt unstable.gopls operator-sdk unstable.go ]; mkShell { buildInputs = [ nixfmt gopls operator-sdk go ]; };
};
}); });
} }

View File

@@ -21,6 +21,8 @@ import (
"os" "os"
"time" "time"
// "time"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them. // to ensure that exec-entrypoint and run can make use of them.
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@@ -32,14 +34,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/log/zap"
server "sigs.k8s.io/controller-runtime/pkg/metrics/server" 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" 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 //+kubebuilder:scaffold:imports
) )
@@ -51,6 +56,7 @@ var (
func init() { func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(cloudnativepgv1.AddToScheme(scheme)) utilruntime.Must(cloudnativepgv1.AddToScheme(scheme))
utilruntime.Must(zitadelresourcesv1alpha1.AddToScheme(scheme))
utilruntime.Must(zitadelv1alpha1.AddToScheme(scheme)) utilruntime.Must(zitadelv1alpha1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme //+kubebuilder:scaffold:scheme
} }
@@ -77,7 +83,7 @@ func main() {
Metrics: server.Options{BindAddress: metricsAddr}, Metrics: server.Options{BindAddress: metricsAddr},
HealthProbeBindAddress: probeAddr, HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection, LeaderElection: enableLeaderElection,
LeaderElectionID: "88a0b43c.topmanage.com", LeaderElectionID: "88a0b43c.github.com",
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the // when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
@@ -103,7 +109,7 @@ func main() {
refResolver := zitadelv1alpha1.NewRefResolver(client) refResolver := zitadelv1alpha1.NewRefResolver(client)
conditionReady := conditions.NewReady() conditionReady := conditions.NewReady()
requeueZitadel := 5 * time.Minute requeueZitadel := 5 * time.Minute
if err = (&controller.ZitadelClusterReconciler{ if err = (&controller.ClusterReconciler{
Client: client, Client: client,
Scheme: scheme, Scheme: scheme,
ConditionReady: conditionReady, ConditionReady: conditionReady,
@@ -116,35 +122,41 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "ZitadelCluster") setupLog.Error(err, "unable to create controller", "controller", "ZitadelCluster")
os.Exit(1) 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) os.Exit(1)
} }
if err = controller.NewProjectReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil { // if err = controller.NewOrganizationReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Project") // setupLog.Error(err, "unable to create controller", "controller", "Organization")
os.Exit(1) // 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") // if err = controller.NewProjectReconciler(client, refResolver, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
os.Exit(1) // setupLog.Error(err, "unable to create controller", "controller", "Project")
} // 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") // if err = controller.NewOIDCAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
os.Exit(1) // setupLog.Error(err, "unable to create controller", "controller", "OIDCApp")
} // 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") // if err = controller.NewMachineUserReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
os.Exit(1) // setupLog.Error(err, "unable to create controller", "controller", "MachineUser")
} // 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") // if err = controller.NewAPIAppReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
os.Exit(1) // setupLog.Error(err, "unable to create controller", "controller", "APIApp")
} // 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") // if err = controller.NewActionReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
os.Exit(1) // 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 //+kubebuilder:scaffold:builder
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {

View File

@@ -4,20 +4,30 @@ kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.3 controller-gen.kubebuilder.io/version: v0.17.3
name: zitadelclusters.zitadel.topmanage.com name: clusters.zitadel.github.com
spec: spec:
group: zitadel.topmanage.com group: zitadel.github.com
names: names:
kind: ZitadelCluster kind: Cluster
listKind: ZitadelClusterList listKind: ClusterList
plural: zitadelclusters plural: clusters
singular: zitadelcluster singular: cluster
scope: Namespaced scope: Namespaced
versions: 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: schema:
openAPIV3Schema: openAPIV3Schema:
description: ZitadelCluster is the Schema for the zitadelclusters API description: Cluster is the Schema for the clusters API.
properties: properties:
apiVersion: apiVersion:
description: |- description: |-
@@ -37,40 +47,23 @@ spec:
metadata: metadata:
type: object type: object
spec: spec:
description: ZitadelClusterSpec defines the desired state of ZitadelCluster description: ClusterSpec defines the desired state of Cluster.
properties: 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: externalPort:
default: 443 default: 443
description: ExternalPort is the port exposed externally.
format: int64 format: int64
type: integer type: integer
externalSecure: externalSecure:
default: true default: true
description: ExternalSecure indicates whether TLS is used on the external
endpoint.
type: boolean 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: host:
description: Host is the external hostname used to reach Zitadel.
type: string type: string
image: image:
description: Image is the Zitadel container image to deploy.
properties: properties:
name: name:
type: string type: string
@@ -83,9 +76,12 @@ spec:
podAnnotations: podAnnotations:
additionalProperties: additionalProperties:
type: string type: string
description: PodAnnotations to add to the Pods metadata. description: PodAnnotations are extra annotations added to each Zitadel
Pod.
type: object type: object
postgresClusterRef: postgresClusterRef:
description: PostgreSQLClusterRef references the backing PostgreSQL
cluster.
properties: properties:
apiVersion: apiVersion:
description: API version of the referent. description: API version of the referent.
@@ -127,20 +123,14 @@ spec:
type: string type: string
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
purpose:
enum:
- demo
- trial
- staging
- productive
- testing
type: string
replicas: replicas:
default: 3 default: 3
description: Replicas is the desired number of Zitadel pods.
format: int32 format: int32
type: integer type: integer
resources: resources:
description: ResourceRequirements describes the compute resource requirements. description: Resources defines compute resource requests and limits
for the Zitadel pods.
properties: properties:
claims: claims:
description: |- description: |-
@@ -201,77 +191,22 @@ spec:
serviceAnnotations: serviceAnnotations:
additionalProperties: additionalProperties:
type: string type: string
description: ServiceAnnotations to add to the service metadata. description: ServiceAnnotations are extra annotations added to the
type: object Zitadel Service.
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
type: object type: object
required: required:
- domainSettings
- externalPort - externalPort
- externalSecure - externalSecure
- firstOrgName
- host - host
- image - image
- postgresClusterRef - postgresClusterRef
- purpose
- resources - resources
- smtpConfig
type: object type: object
status: status:
description: ZitadelClusterStatus defines the observed state of ZitadelCluster description: ClusterStatus defines the observed state of Cluster.
properties: properties:
conditions: conditions:
description: |- description: Conditions store the status conditions of the Cluster.
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
Important: Run "make" to regenerate code after modifying this file
items: items:
description: Condition contains details for one aspect of the current description: Condition contains details for one aspect of the current
state of this API Resource. state of this API Resource.
@@ -327,19 +262,11 @@ spec:
- type - type
type: object type: object
type: array type: array
defaultInstanceId:
default: ""
type: string
replicas: replicas:
default: 3 default: 3
description: Replicas is the current number of running Zitadel pods.
format: int32 format: int32
type: integer type: integer
smtpProviderId:
default: ""
type: string
required:
- defaultInstanceId
- smtpProviderId
type: object type: object
type: object type: object
served: true served: true

View File

@@ -4,20 +4,36 @@ kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.3 controller-gen.kubebuilder.io/version: v0.17.3
name: machineusers.zitadel.topmanage.com name: instances.zitadel.github.com
spec: spec:
group: zitadel.topmanage.com group: zitadel.github.com
names: names:
kind: MachineUser kind: Instance
listKind: MachineUserList listKind: InstanceList
plural: machineusers plural: instances
singular: machineuser singular: instance
scope: Namespaced scope: Namespaced
versions: 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: schema:
openAPIV3Schema: openAPIV3Schema:
description: MachineUser is the Schema for the machineusers API description: Instance is the Schema for the instances API.
properties: properties:
apiVersion: apiVersion:
description: |- description: |-
@@ -37,17 +53,13 @@ spec:
metadata: metadata:
type: object type: object
spec: 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: properties:
accessTokenType: clusterRef:
enum: description: ClusterRef references the Cluster this instance will
- ACCESS_TOKEN_TYPE_BEARER be provisioned on.
- 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
properties: properties:
apiVersion: apiVersion:
description: API version of the referent. description: API version of the referent.
@@ -89,70 +101,120 @@ spec:
type: string type: string
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
userGrants: customDomain:
items: type: string
properties: defaultLanguage:
projectRef: default: en
properties: description: DefaultLanguage is the BCP-47 language tag used as the
apiVersion: instance default (e.g. "en").
description: API version of the referent. type: string
type: string instanceName:
fieldPath: description: InstanceName is the display name of the Zitadel instance.
description: |- type: string
If referring to a piece of an object instead of an entire object, this string loginUI:
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. default:
For example, if the object reference is to a container within a pod, this would take on a value like: image:
"spec.containers{name}" (where "name" refers to the name of the container that triggered name: ghcr.io/zitadel/zitadel-login
the event) or if no container name is specified "spec.containers[2]" (container with resources: {}
index 2 in this pod). This syntax is chosen only to have some well-defined way of properties:
referencing a part of an object. image:
type: string properties:
kind: name:
description: |- default: ghcr.io/zitadel/zitadel-login
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: string
type: array tag:
required: description: if empty it uses the same tag as zitadel cluster
- projectRef type: string
type: object required:
type: array - 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: required:
- accessTokenType - clusterRef
- organizationRef - customDomain
- instanceName
- loginUI
- org
type: object type: object
status: status:
description: MachineUserStatus defines the observed state of MachineUser description: InstanceStatus defines the observed state of Instance.
properties: properties:
conditions: conditions:
description: |- description: Conditions store the status conditions of the Instance.
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
Important: Run "make" to regenerate code after modifying this file
items: items:
description: Condition contains details for one aspect of the current description: Condition contains details for one aspect of the current
state of this API Resource. state of this API Resource.
@@ -208,19 +270,10 @@ spec:
- type - type
type: object type: object
type: array type: array
keyId: instanceId:
default: "" description: InstanceId is the instance ID returned by Zitadel after
successful provisioning.
type: string type: string
patId:
default: ""
type: string
userId:
default: ""
type: string
required:
- keyId
- patId
- userId
type: object type: object
type: object type: object
served: true served: true

View File

@@ -2,14 +2,8 @@
# since it depends on service name and namespace that are out of this kustomize package. # since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default # It should be run by config/default
resources: resources:
- bases/zitadel.topmanage.com_zitadelclusters.yaml - bases/zitadel.github.com_clusters.yaml
- bases/zitadel.topmanage.com_organizations.yaml - bases/zitadel.github.com_instances.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
#+kubebuilder:scaffold:crdkustomizeresource #+kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge: patchesStrategicMerge:
@@ -35,6 +29,7 @@ patchesStrategicMerge:
#- patches/cainjection_in_apiapps.yaml #- patches/cainjection_in_apiapps.yaml
#- patches/cainjection_in_actions.yaml #- patches/cainjection_in_actions.yaml
#- patches/cainjection_in_flows.yaml #- patches/cainjection_in_flows.yaml
#- path: patches/cainjection_in_connections.yaml
#+kubebuilder:scaffold:crdkustomizecainjectionpatch #+kubebuilder:scaffold:crdkustomizecainjectionpatch
# the following config is for teaching kustomize how to do kustomization for CRDs. # the following config is for teaching kustomize how to do kustomization for CRDs.

View File

@@ -12,9 +12,9 @@ metadata:
name: zitadelcluster-editor-role name: zitadelcluster-editor-role
rules: rules:
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.github.com
resources: resources:
- zitadelclusters - clusters
verbs: verbs:
- create - create
- delete - delete
@@ -24,8 +24,8 @@ rules:
- update - update
- watch - watch
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.github.com
resources: resources:
- zitadelclusters/status - clusters/status
verbs: verbs:
- get - get

View File

@@ -16,3 +16,8 @@ resources:
- auth_proxy_role.yaml - auth_proxy_role.yaml
- auth_proxy_role_binding.yaml - auth_proxy_role_binding.yaml
- auth_proxy_client_clusterrole.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.

View File

@@ -127,17 +127,48 @@ rules:
- list - list
- patch - patch
- watch - 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: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions - instances
- apiapps
- flows
- machineusers
- oidcapps
- organizations
- projects
- zitadelclusters
verbs: verbs:
- create - create
- delete - delete
@@ -149,27 +180,13 @@ rules:
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions/finalizers - instances/finalizers
- apiapps/finalizers
- flows/finalizers
- machineusers/finalizers
- oidcapps/finalizers
- organizations/finalizers
- projects/finalizers
- zitadelclusters/finalizers
verbs: verbs:
- update - update
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions/status - instances/status
- apiapps/status
- flows/status
- machineusers/status
- oidcapps/status
- organizations/status
- projects/status
- zitadelclusters/status
verbs: verbs:
- get - get
- patch - patch

View File

@@ -0,0 +1,4 @@
## Append samples of your project ##
resources:
- zitadel_v1alpha1_connection.yaml
# +kubebuilder:scaffold:manifestskustomizesamples

View File

@@ -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

View File

@@ -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 ( 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/cloudnative-pg/cloudnative-pg v1.25.1
github.com/gorilla/schema v1.4.1
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/onsi/ginkgo/v2 v2.23.3 github.com/onsi/ginkgo/v2 v2.23.3
github.com/onsi/gomega v1.36.3 github.com/onsi/gomega v1.36.3
github.com/sethvargo/go-password v0.3.1 github.com/sethvargo/go-password v0.3.1
github.com/zitadel/oidc v1.13.5 github.com/zitadel/zitadel-go/v3 v3.27.0
github.com/zitadel/zitadel-go/v3 v3.5.0 google.golang.org/grpc v1.79.3
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
k8s.io/api v0.32.3 k8s.io/api v0.32.3
k8s.io/apimachinery v0.32.3 k8s.io/apimachinery v0.32.3
k8s.io/client-go 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/cloudnative-pg/machinery v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 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/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/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.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-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.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/google/uuid v1.6.0 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/websocket v1.5.0 // 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/hashicorp/errwrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // 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/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // 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/spf13/pflag v1.0.6 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/zitadel/logging v0.6.1 // indirect github.com/zitadel/logging v0.7.0 // indirect
github.com/zitadel/oidc/v3 v3.36.1 // indirect github.com/zitadel/oidc/v3 v3.45.5 // indirect
github.com/zitadel/schema v1.3.0 // indirect github.com/zitadel/schema v1.3.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect go.opentelemetry.io/otel v1.40.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.40.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.49.0 // indirect
golang.org/x/net v0.37.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect
golang.org/x/sync v0.12.0 // indirect golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.31.0 // indirect golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.30.0 // indirect golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.34.0 // indirect
golang.org/x/time v0.9.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 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/api v0.0.0-20260209200024-4cfbd4190f57 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // 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/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@@ -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 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= 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 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= 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/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 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 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.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= 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 h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 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= 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/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 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= 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.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= 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.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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= 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/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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= 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 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= 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 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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= 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/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 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 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.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 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 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 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 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU=
github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= 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.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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/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.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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= 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/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 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 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.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/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.7.0 h1:eugftwMM95Wgqwftsvj81isL0JK/hoScVqp/7iA2adQ=
github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= github.com/zitadel/logging v0.7.0/go.mod h1:9A6h9feBF/3u0IhA4uffdzSDY7mBaf7RE78H5sFMINQ=
github.com/zitadel/oidc v1.13.5 h1:7jhh68NGZitLqwLiVU9Dtwa4IraJPFF1vS+4UupO93U= github.com/zitadel/oidc/v3 v3.45.5 h1:CubfcXQiqtysk+FZyIcvj1+1ayvdSV89v5xWu5asrDQ=
github.com/zitadel/oidc v1.13.5/go.mod h1:rHs1DhU3Sv3tnI6bQRVlFa3u0lCwtR7S21WHY+yXgPA= github.com/zitadel/oidc/v3 v3.45.5/go.mod h1:MKHUazeiNX/jxRc6HD/Dv9qhL/wNuzrJAadBEGXiBeE=
github.com/zitadel/oidc/v3 v3.36.1 h1:1AT1NqKKEqAwx4GmKJZ9fYkWH2WIn/VKMfQ46nBtRf0= github.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI=
github.com/zitadel/oidc/v3 v3.36.1/go.mod h1:dApGZLvWZTHRuxmcbQlW5d2XVjVYR3vGOdq536igmTs= github.com/zitadel/schema v1.3.2/go.mod h1:IZmdfF9Wu62Zu6tJJTH3UsArevs3Y4smfJIj3L8fzxw=
github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= github.com/zitadel/zitadel-go/v3 v3.27.0 h1:1BumImnIk3D9JYTq+IlVq793vZCXuMZuz1meWzeMQN4=
github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= github.com/zitadel/zitadel-go/v3 v3.27.0/go.mod h1:8UaWIIUR+c9jstT6bjoiknaxttxFZKNc7RYs32v03jw=
github.com/zitadel/zitadel-go/v3 v3.5.0 h1:8LnUiOCvwhgZxwBY15tk7Yzhv5vEJF+qiM3qWJGtxCI= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
github.com/zitadel/zitadel-go/v3 v3.5.0/go.mod h1:YPfMqfpyOIuKdHNsZwWHAR/BWSIFOSIL41TyMnef/aU= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 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/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.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-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-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-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.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.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 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-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-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.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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 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-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-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-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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 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 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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-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-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-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.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= 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-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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= 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= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 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 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/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 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -30,7 +30,7 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log" logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap" "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 //+kubebuilder:scaffold:imports
) )

View File

@@ -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: {}

View File

@@ -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: {}

View File

@@ -3,20 +3,30 @@ kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.3 controller-gen.kubebuilder.io/version: v0.17.3
name: zitadelclusters.zitadel.topmanage.com name: clusters.zitadel.github.com
spec: spec:
group: zitadel.topmanage.com group: zitadel.github.com
names: names:
kind: ZitadelCluster kind: Cluster
listKind: ZitadelClusterList listKind: ClusterList
plural: zitadelclusters plural: clusters
singular: zitadelcluster singular: cluster
scope: Namespaced scope: Namespaced
versions: 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: schema:
openAPIV3Schema: openAPIV3Schema:
description: ZitadelCluster is the Schema for the zitadelclusters API description: Cluster is the Schema for the clusters API.
properties: properties:
apiVersion: apiVersion:
description: |- description: |-
@@ -36,40 +46,23 @@ spec:
metadata: metadata:
type: object type: object
spec: spec:
description: ZitadelClusterSpec defines the desired state of ZitadelCluster description: ClusterSpec defines the desired state of Cluster.
properties: 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: externalPort:
default: 443 default: 443
description: ExternalPort is the port exposed externally.
format: int64 format: int64
type: integer type: integer
externalSecure: externalSecure:
default: true default: true
description: ExternalSecure indicates whether TLS is used on the external
endpoint.
type: boolean 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: host:
description: Host is the external hostname used to reach Zitadel.
type: string type: string
image: image:
description: Image is the Zitadel container image to deploy.
properties: properties:
name: name:
type: string type: string
@@ -82,9 +75,12 @@ spec:
podAnnotations: podAnnotations:
additionalProperties: additionalProperties:
type: string type: string
description: PodAnnotations to add to the Pods metadata. description: PodAnnotations are extra annotations added to each Zitadel
Pod.
type: object type: object
postgresClusterRef: postgresClusterRef:
description: PostgreSQLClusterRef references the backing PostgreSQL
cluster.
properties: properties:
apiVersion: apiVersion:
description: API version of the referent. description: API version of the referent.
@@ -126,20 +122,14 @@ spec:
type: string type: string
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
purpose:
enum:
- demo
- trial
- staging
- productive
- testing
type: string
replicas: replicas:
default: 3 default: 3
description: Replicas is the desired number of Zitadel pods.
format: int32 format: int32
type: integer type: integer
resources: resources:
description: ResourceRequirements describes the compute resource requirements. description: Resources defines compute resource requests and limits
for the Zitadel pods.
properties: properties:
claims: claims:
description: |- description: |-
@@ -200,77 +190,22 @@ spec:
serviceAnnotations: serviceAnnotations:
additionalProperties: additionalProperties:
type: string type: string
description: ServiceAnnotations to add to the service metadata. description: ServiceAnnotations are extra annotations added to the
type: object Zitadel Service.
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
type: object type: object
required: required:
- domainSettings
- externalPort - externalPort
- externalSecure - externalSecure
- firstOrgName
- host - host
- image - image
- postgresClusterRef - postgresClusterRef
- purpose
- resources - resources
- smtpConfig
type: object type: object
status: status:
description: ZitadelClusterStatus defines the observed state of ZitadelCluster description: ClusterStatus defines the observed state of Cluster.
properties: properties:
conditions: conditions:
description: |- description: Conditions store the status conditions of the Cluster.
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
Important: Run "make" to regenerate code after modifying this file
items: items:
description: Condition contains details for one aspect of the current description: Condition contains details for one aspect of the current
state of this API Resource. state of this API Resource.
@@ -326,19 +261,11 @@ spec:
- type - type
type: object type: object
type: array type: array
defaultInstanceId:
default: ""
type: string
replicas: replicas:
default: 3 default: 3
description: Replicas is the current number of running Zitadel pods.
format: int32 format: int32
type: integer type: integer
smtpProviderId:
default: ""
type: string
required:
- defaultInstanceId
- smtpProviderId
type: object type: object
type: object type: object
served: true served: true

View File

@@ -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: {}

View File

@@ -3,20 +3,36 @@ kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.17.3 controller-gen.kubebuilder.io/version: v0.17.3
name: machineusers.zitadel.topmanage.com name: instances.zitadel.github.com
spec: spec:
group: zitadel.topmanage.com group: zitadel.github.com
names: names:
kind: MachineUser kind: Instance
listKind: MachineUserList listKind: InstanceList
plural: machineusers plural: instances
singular: machineuser singular: instance
scope: Namespaced scope: Namespaced
versions: 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: schema:
openAPIV3Schema: openAPIV3Schema:
description: MachineUser is the Schema for the machineusers API description: Instance is the Schema for the instances API.
properties: properties:
apiVersion: apiVersion:
description: |- description: |-
@@ -36,17 +52,13 @@ spec:
metadata: metadata:
type: object type: object
spec: 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: properties:
accessTokenType: clusterRef:
enum: description: ClusterRef references the Cluster this instance will
- ACCESS_TOKEN_TYPE_BEARER be provisioned on.
- 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
properties: properties:
apiVersion: apiVersion:
description: API version of the referent. description: API version of the referent.
@@ -88,70 +100,120 @@ spec:
type: string type: string
type: object type: object
x-kubernetes-map-type: atomic x-kubernetes-map-type: atomic
userGrants: customDomain:
items: type: string
properties: defaultLanguage:
projectRef: default: en
properties: description: DefaultLanguage is the BCP-47 language tag used as the
apiVersion: instance default (e.g. "en").
description: API version of the referent. type: string
type: string instanceName:
fieldPath: description: InstanceName is the display name of the Zitadel instance.
description: |- type: string
If referring to a piece of an object instead of an entire object, this string loginUI:
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. default:
For example, if the object reference is to a container within a pod, this would take on a value like: image:
"spec.containers{name}" (where "name" refers to the name of the container that triggered name: ghcr.io/zitadel/zitadel-login
the event) or if no container name is specified "spec.containers[2]" (container with resources: {}
index 2 in this pod). This syntax is chosen only to have some well-defined way of properties:
referencing a part of an object. image:
type: string properties:
kind: name:
description: |- default: ghcr.io/zitadel/zitadel-login
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: string
type: array tag:
required: description: if empty it uses the same tag as zitadel cluster
- projectRef type: string
type: object required:
type: array - 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: required:
- accessTokenType - clusterRef
- organizationRef - customDomain
- instanceName
- loginUI
- org
type: object type: object
status: status:
description: MachineUserStatus defines the observed state of MachineUser description: InstanceStatus defines the observed state of Instance.
properties: properties:
conditions: conditions:
description: |- description: Conditions store the status conditions of the Instance.
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
Important: Run "make" to regenerate code after modifying this file
items: items:
description: Condition contains details for one aspect of the current description: Condition contains details for one aspect of the current
state of this API Resource. state of this API Resource.
@@ -207,19 +269,10 @@ spec:
- type - type
type: object type: object
type: array type: array
keyId: instanceId:
default: "" description: InstanceId is the instance ID returned by Zitadel after
successful provisioning.
type: string type: string
patId:
default: ""
type: string
userId:
default: ""
type: string
required:
- keyId
- patId
- userId
type: object type: object
type: object type: object
served: true served: true

View File

@@ -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: {}

View File

@@ -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: {}

View File

@@ -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: {}

View File

@@ -54,9 +54,12 @@ app.kubernetes.io/instance: {{ .Release.Name }}
Create the name of the service account to use Create the name of the service account to use
*/}} */}}
{{- define "zitadel-k8s-operator.serviceAccountName" -}} {{- define "zitadel-k8s-operator.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }} {{- $default := (include "zitadel-k8s-operator.fullname" .) }}
{{- default (include "zitadel-k8s-operator.fullname" .) .Values.serviceAccount.name }} {{- with .Values.serviceAccount }}
{{- if .create }}
{{- default $default .name }}
{{- else }} {{- else }}
{{- default "default" .Values.serviceAccount.name }} {{- default "default" .name }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}

View File

@@ -79,7 +79,11 @@ spec:
}} }}
securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext
| nindent 10 }} | nindent 10 }}
securityContext: nodeSelector: {{- toYaml .Values.controllerManager.nodeSelector | nindent 8 }}
runAsNonRoot: true securityContext: {{- toYaml .Values.controllerManager.podSecurityContext | nindent
serviceAccountName: {{ include "zitadel-k8s-operator.fullname" . }}-controller-manager 8 }}
terminationGracePeriodSeconds: 10 serviceAccountName: {{ include "zitadel-k8s-operator.serviceAccountName" . }}
terminationGracePeriodSeconds: 10
tolerations: {{- toYaml .Values.controllerManager.tolerations | nindent 8 }}
topologySpreadConstraints: {{- toYaml .Values.controllerManager.topologySpreadConstraints
| nindent 8 }}

View File

@@ -55,5 +55,5 @@ roleRef:
name: '{{ include "zitadel-k8s-operator.fullname" . }}-leader-election-role' name: '{{ include "zitadel-k8s-operator.fullname" . }}-leader-election-role'
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}'
namespace: '{{ .Release.Namespace }}' namespace: '{{ .Release.Namespace }}'

View File

@@ -128,17 +128,48 @@ rules:
- list - list
- patch - patch
- watch - 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: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions - instances
- apiapps
- flows
- machineusers
- oidcapps
- organizations
- projects
- zitadelclusters
verbs: verbs:
- create - create
- delete - delete
@@ -150,27 +181,13 @@ rules:
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions/finalizers - instances/finalizers
- apiapps/finalizers
- flows/finalizers
- machineusers/finalizers
- oidcapps/finalizers
- organizations/finalizers
- projects/finalizers
- zitadelclusters/finalizers
verbs: verbs:
- update - update
- apiGroups: - apiGroups:
- zitadel.topmanage.com - zitadel.topmanage.com
resources: resources:
- actions/status - instances/status
- apiapps/status
- flows/status
- machineusers/status
- oidcapps/status
- organizations/status
- projects/status
- zitadelclusters/status
verbs: verbs:
- get - get
- patch - patch
@@ -191,5 +208,5 @@ roleRef:
name: '{{ include "zitadel-k8s-operator.fullname" . }}-manager-role' name: '{{ include "zitadel-k8s-operator.fullname" . }}-manager-role'
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}'
namespace: '{{ .Release.Namespace }}' namespace: '{{ .Release.Namespace }}'

View File

@@ -11,4 +11,4 @@ rules:
- nonResourceURLs: - nonResourceURLs:
- /metrics - /metrics
verbs: verbs:
- get - get

View File

@@ -12,6 +12,6 @@ spec:
type: {{ .Values.metricsService.type }} type: {{ .Values.metricsService.type }}
selector: selector:
control-plane: controller-manager control-plane: controller-manager
{{- include "zitadel-k8s-operator.selectorLabels" . | nindent 4 }} {{- include "zitadel-k8s-operator.selectorLabels" . | nindent 4 }}
ports: ports:
{{- .Values.metricsService.ports | toYaml | nindent 2 }} {{- .Values.metricsService.ports | toYaml | nindent 2 }}

View File

@@ -36,5 +36,5 @@ roleRef:
name: '{{ include "zitadel-k8s-operator.fullname" . }}-proxy-role' name: '{{ include "zitadel-k8s-operator.fullname" . }}-proxy-role'
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: '{{ include "zitadel-k8s-operator.fullname" . }}-controller-manager' name: '{{ include "zitadel-k8s-operator.serviceAccountName" . }}'
namespace: '{{ .Release.Namespace }}' namespace: '{{ .Release.Namespace }}'

View File

@@ -1,11 +1,13 @@
{{ if .Values.serviceAccount.create }}
apiVersion: v1 apiVersion: v1
kind: ServiceAccount kind: ServiceAccount
metadata: metadata:
name: {{ include "zitadel-k8s-operator.fullname" . }}-controller-manager name: {{ include "zitadel-k8s-operator.serviceAccountName" . }}
labels: 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 }} {{- include "zitadel-k8s-operator.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations: annotations:
{{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

View File

@@ -1,3 +1,4 @@
controllerManager: controllerManager:
kubeRbacProxy: kubeRbacProxy:
args: args:
@@ -11,7 +12,7 @@ controllerManager:
drop: drop:
- ALL - ALL
image: image:
repository: gcr.io/kubebuilder/kube-rbac-proxy repository: registry.k8s.io/kubebuilder/kube-rbac-proxy
tag: v0.13.1 tag: v0.13.1
resources: resources:
limits: limits:
@@ -31,8 +32,7 @@ controllerManager:
drop: drop:
- ALL - ALL
image: image:
repository: controller repository: gitea.corredorconect.com/software-engineering/zitadel-k8s-operator
tag: latest
resources: resources:
limits: limits:
cpu: 500m cpu: 500m
@@ -40,9 +40,12 @@ controllerManager:
requests: requests:
cpu: 10m cpu: 10m
memory: 64Mi memory: 64Mi
nodeSelector: {}
podSecurityContext:
runAsNonRoot: true
replicas: 1 replicas: 1
serviceAccount: tolerations: []
annotations: {} topologySpreadConstraints: []
kubernetesClusterDomain: cluster.local kubernetesClusterDomain: cluster.local
metricsService: metricsService:
ports: ports:
@@ -51,3 +54,8 @@ metricsService:
protocol: TCP protocol: TCP
targetPort: https targetPort: https
type: ClusterIP type: ClusterIP
serviceAccount:
annotations: {}
automount: true
create: true
name: ""

14
pkg/admin/admin.go Normal file
View File

@@ -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"
}

View File

@@ -1,9 +1,9 @@
package builder package builder
import ( 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" "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" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@@ -11,7 +11,7 @@ import (
) )
type ConfigMapOpts struct { type ConfigMapOpts struct {
Zitadel *zitadelv1alpha1.ZitadelCluster Zitadel *zitadelv1alpha1.Cluster
Key types.NamespacedName Key types.NamespacedName
Data map[string]string Data map[string]string
Labels map[string]string Labels map[string]string

View File

@@ -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
}

View File

@@ -3,12 +3,12 @@ package builder
import ( import (
"fmt" "fmt"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
labels "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/labels" labels "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/labels"
metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" metadata "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder/metadata"
configuration "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/configuration" configuration "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/configuration"
deployment "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" deployment "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment"
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/masterkey"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -18,7 +18,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "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 replicas := zitadel.Spec.Replicas
objMeta := objMeta :=
metadata.NewMetadataBuilder(key). metadata.NewMetadataBuilder(key).
@@ -51,7 +51,7 @@ func (b *Builder) BuildDeployment(zitadel *zitadelv1alpha1.ZitadelCluster, key t
return dep, nil 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 := objMeta :=
metadata.NewMetadataBuilder(client.ObjectKeyFromObject(zitadel)). metadata.NewMetadataBuilder(client.ObjectKeyFromObject(zitadel)).
WithZitadel(zitadel). WithZitadel(zitadel).
@@ -80,7 +80,7 @@ func (b *Builder) buildDepPodTemplate(zitadel *zitadelv1alpha1.ZitadelCluster, l
nil nil
} }
func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.ZitadelCluster) *[]corev1.Container { func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.Cluster) *[]corev1.Container {
readyProbeHandle := corev1.ProbeHandler{ readyProbeHandle := corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{HTTPHeaders: []corev1.HTTPHeader{}, HTTPGet: &corev1.HTTPGetAction{HTTPHeaders: []corev1.HTTPHeader{},
Port: intstr.FromInt(deployment.ZitadelPort), Port: intstr.FromInt(deployment.ZitadelPort),
@@ -119,7 +119,7 @@ func (b *Builder) buildDepContainers(zitadel *zitadelv1alpha1.ZitadelCluster) *[
{ {
Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", 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"}},
}, },
// { // {

View File

@@ -3,9 +3,9 @@ package builder
import ( import (
"fmt" "fmt"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
configuration "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/configuration" configuration "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/configuration"
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/masterkey"
batchv1 "k8s.io/api/batch/v1" batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -13,7 +13,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "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) backOffLimit := int32(5)
activeDeadlineSeconds := int64(1800) 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, Image: zitadel.Spec.Image.Name + ":" + zitadel.Spec.Image.Tag,
Args: []string{ Args: []string{
"init", "init",
"zitadel",
"--config", "/config/zitadel-config-yaml", "--config", "/config/zitadel-config-yaml",
}, },
Env: []corev1.EnvVar{ Env: []corev1.EnvVar{
@@ -86,7 +87,7 @@ func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key type
{ {
Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", 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{ VolumeMounts: []corev1.VolumeMount{
@@ -105,7 +106,7 @@ func (b *Builder) BuildInitJob(zitadel *zitadelv1alpha1.ZitadelCluster, key type
return initJob, nil 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) backOffLimit := int32(5)
activeDeadlineSeconds := int64(1800) activeDeadlineSeconds := int64(1800)
@@ -192,7 +193,7 @@ func (b *Builder) BuildSetupJob(zitadel *zitadelv1alpha1.ZitadelCluster, key typ
{ {
Name: "ZITADEL_DATABASE_POSTGRES_USER_PASSWORD", 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{ VolumeMounts: []corev1.VolumeMount{

View File

@@ -1,8 +1,8 @@
package builder package builder
import ( import (
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
deployment "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" deployment "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment"
) )
const ( const (
@@ -10,6 +10,7 @@ const (
instanceLabel = "app.kubernetes.io/instance" instanceLabel = "app.kubernetes.io/instance"
deploymentPodName = "deployment.kubernetes.io/pod-name" deploymentPodName = "deployment.kubernetes.io/pod-name"
appZitadel = "zitadel" appZitadel = "zitadel"
appLoginUI = "zitadel-login-ui"
appExporter = "exporter" appExporter = "exporter"
) )
@@ -33,12 +34,17 @@ func (b *LabelsBuilder) WithInstance(instance string) *LabelsBuilder {
return b return b
} }
func (b *LabelsBuilder) WithZitadel(zitadel *zitadelv1alpha1.ZitadelCluster) *LabelsBuilder { func (b *LabelsBuilder) WithZitadel(zitadel *zitadelv1alpha1.Cluster) *LabelsBuilder {
return b.WithApp(appZitadel). return b.WithApp(appZitadel).
WithInstance(zitadel.Name) 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) b.labels[deploymentPodName] = deployment.PodName(zitadel.ObjectMeta, podIndex)
return b return b
} }
@@ -50,12 +56,17 @@ func (b *LabelsBuilder) WithLabels(labels map[string]string) *LabelsBuilder {
return b return b
} }
func (b *LabelsBuilder) WithZitadelSelectorLabels(zitadel *zitadelv1alpha1.ZitadelCluster) *LabelsBuilder { func (b *LabelsBuilder) WithZitadelSelectorLabels(zitadel *zitadelv1alpha1.Cluster) *LabelsBuilder {
b = b.WithZitadel(zitadel) b = b.WithZitadel(zitadel)
return b 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). return b.WithApp(appExporter).
WithInstance(zitadel.Name) WithInstance(zitadel.Name)
} }

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -1,7 +1,7 @@
package metadata package metadata
import ( 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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "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 { if zitadel == nil {
return b return b
} }

View File

@@ -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
}

View File

@@ -1,9 +1,9 @@
package builder package builder
import ( 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" "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" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@@ -11,7 +11,7 @@ import (
) )
type SecretOpts struct { type SecretOpts struct {
Zitadel *zitadelv1alpha1.ZitadelCluster Zitadel *zitadelv1alpha1.Cluster
Key types.NamespacedName Key types.NamespacedName
Data map[string][]byte Data map[string][]byte
Labels map[string]string Labels map[string]string

View File

@@ -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()
}

View File

@@ -4,7 +4,7 @@ import (
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/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) { func SetReadyHealthty(c Conditioner) {
@@ -51,8 +51,8 @@ func SetReadyFailed(c Conditioner) {
SetReadyFailedWithMessage(c, "Failed") SetReadyFailedWithMessage(c, "Failed")
} }
func SetReadyWithDeployment(c Conditioner, sts *appsv1.Deployment, instanceId string) { func SetReadyWithDeployment(c Conditioner, sts *appsv1.Deployment) {
if sts.Status.Replicas == 0 || sts.Status.ReadyReplicas != sts.Status.Replicas || instanceId == "" { if sts.Status.Replicas == 0 || sts.Status.ReadyReplicas != sts.Status.Replicas {
c.SetCondition(metav1.Condition{ c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeReady, Type: zitadelv1alpha1.ConditionTypeReady,
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,

View File

@@ -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"
}

View File

@@ -4,10 +4,10 @@ import (
"context" "context"
"fmt" "fmt"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
builder "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" builder "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder"
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/deployment" "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/deployment"
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/masterkey" systemapiaccount "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/systemapi"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client" "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 := make(map[string]string)
config["zitadel-config-yaml"] = config["zitadel-config-yaml"] =
fmt.Sprintf(` fmt.Sprintf(`Database:
Database:
Postgres: Postgres:
Host: %s Host: %s
Port: 5432 Port: 5432
@@ -57,6 +56,8 @@ Projections:
Customizations: Customizations:
smtp_configs: smtp_configs:
BulkLimit: 2000 BulkLimit: 2000
FirstInstance:
Skip: true
SystemAPIUsers: SystemAPIUsers:
- %s: - %s:
KeyData: %s KeyData: %s
@@ -66,7 +67,7 @@ SystemAPIUsers:
- "SYSTEM_OWNER" - "SYSTEM_OWNER"
- "IAM_OWNER" - "IAM_OWNER"
- "ORG_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{ opts := builder.ConfigMapOpts{
Zitadel: zitadel, Zitadel: zitadel,

View File

@@ -8,8 +8,8 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
builder "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder" builder "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/builder"
"github.com/sethvargo/go-password/password" "github.com/sethvargo/go-password/password"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "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, 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 var existingSecret corev1.Secret
if err := r.Get(ctx, key, &existingSecret); err == nil { if err := r.Get(ctx, key, &existingSecret); err == nil {
return string(existingSecret.Data[secretKey]), 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, 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 var existingSecret corev1.Secret
if err := r.Get(ctx, key, &existingSecret); err == nil { if err := r.Get(ctx, key, &existingSecret); err == nil {
return string(existingSecret.Data[secretKey]), nil return string(existingSecret.Data[secretKey]), nil

View File

@@ -1,4 +1,4 @@
package zitadel package system
import ( import (
"context" "context"
@@ -6,29 +6,29 @@ import (
"fmt" "fmt"
"time" "time"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition" condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition"
health "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/health" health "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/health"
zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" zitadelClient "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/zitadel"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log"
) )
type ZitadelReconciler struct { type SystemReconciler struct {
Client client.Client Client client.Client
RefResolver *zitadelv1alpha1.RefResolver RefResolver *zitadelv1alpha1.RefResolver
ConditionReady *condition.Ready ConditionReady *condition.Ready
WrappedReconciler WrappedReconciler WrappedReconciler WrappedSystemReconciler
Finalizer Finalizer Finalizer Finalizer
RequeueInterval time.Duration 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 { requeueInterval time.Duration) Reconciler {
return &ZitadelReconciler{ return &SystemReconciler{
Client: client, Client: client,
RefResolver: zitadelv1alpha1.NewRefResolver(client), RefResolver: zitadelv1alpha1.NewRefResolver(client),
ConditionReady: cr, 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 resource.IsBeingDeleted() {
if err := r.Finalizer.Finalize(ctx, resource); err != nil { if err := r.Finalizer.Finalize(ctx, resource); err != nil {
return ctrl.Result{}, fmt.Errorf("error finalizing %s: %v", resource.GetName(), err) return ctrl.Result{}, fmt.Errorf("error finalizing %s: %v", resource.GetName(), err)
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
zitadelRef, err := resource.ZitadelClusterRef(ctx, r.RefResolver) clusterRef, err := resource.ClusterRef(ctx, r.RefResolver)
if err != nil { if err != nil {
return ctrl.Result{}, err 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 { if err != nil {
var errBundle *multierror.Error var errBundle *multierror.Error
errBundle = multierror.Append(errBundle, err) 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) 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 var errBundle *multierror.Error
errBundle = multierror.Append(errBundle, err) errBundle = multierror.Append(errBundle, err)
err := r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherWithError(err)) err := r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherWithError(err))
errBundle = multierror.Append(errBundle, 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 { if err != nil {
var errBundle *multierror.Error var errBundle *multierror.Error
errBundle = multierror.Append(errBundle, err) 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)) err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherFailed(msg))
errBundle = multierror.Append(errBundle, err) errBundle = multierror.Append(errBundle, err)
@@ -107,27 +107,27 @@ func (r *ZitadelReconciler) Reconcile(ctx context.Context, resource Resource) (c
return r.requeueResult(ctx, resource) 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 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 { 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{RequeueAfter: r.RequeueInterval}, nil
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func waitForZitadelCluster(ctx context.Context, client client.Client, resource Resource, func waitForCluster(ctx context.Context, client client.Client, resource Resource,
zitadel *zitadelv1alpha1.ZitadelCluster) error { system *zitadelv1alpha1.Cluster) error {
var zitadelErr *multierror.Error var systemErr *multierror.Error
healthy, err := health.IsZitadelClusterHealthy(ctx, client, zitadel) healthy, err := health.IsClusterHealthy(ctx, client, system)
if err != nil { if err != nil {
zitadelErr = multierror.Append(zitadelErr, err) systemErr = multierror.Append(systemErr, err)
} }
if !healthy { 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()
} }

View File

@@ -1,31 +1,31 @@
package zitadel package system
import ( import (
"context" "context"
"fmt" "fmt"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1"
zitadelClient "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/zitadel" zitadelClient "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/zitadel"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
) )
type ZitadelFinalizer struct { type SystemFinalizer struct {
Client client.Client Client client.Client
RefResolver *zitadelv1alpha1.RefResolver RefResolver *zitadelv1alpha1.RefResolver
WrappedFinalizer WrappedFinalizer WrappedFinalizer WrappedSystemFinalizer
} }
func NewZitadelFinalizer(client client.Client, wf WrappedFinalizer) Finalizer { func NewSystemFinalizer(client client.Client, wf WrappedSystemFinalizer) Finalizer {
return &ZitadelFinalizer{ return &SystemFinalizer{
Client: client, Client: client,
RefResolver: zitadelv1alpha1.NewRefResolver(client), RefResolver: zitadelv1alpha1.NewRefResolver(client),
WrappedFinalizer: wf, WrappedFinalizer: wf,
} }
} }
func (tf *ZitadelFinalizer) AddFinalizer(ctx context.Context) error { func (tf *SystemFinalizer) AddFinalizer(ctx context.Context) error {
if tf.WrappedFinalizer.ContainsFinalizer() { if tf.WrappedFinalizer.ContainsFinalizer() {
return nil return nil
} }
@@ -35,16 +35,16 @@ func (tf *ZitadelFinalizer) AddFinalizer(ctx context.Context) error {
return nil 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() { if !tf.WrappedFinalizer.ContainsFinalizer() {
return nil return nil
} }
zitadelRef, err := resource.ZitadelClusterRef(ctx, tf.RefResolver) clusterRef, err := resource.ClusterRef(ctx, tf.RefResolver)
if err != nil { if err != nil {
return err return err
} }
zitadel, err := tf.RefResolver.ZitadelCluster(ctx, zitadelRef, resource.GetNamespace()) system, err := tf.RefResolver.Cluster(ctx, clusterRef, resource.GetNamespace())
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
if err := tf.WrappedFinalizer.RemoveFinalizer(ctx); err != nil { 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 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 { if err := waitForCluster(ctx, tf.Client, resource, system); err != nil {
return fmt.Errorf("error waiting for ZitadelCluster: %v", err) 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 { 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() defer ztdClient.Connection.Close()

View File

@@ -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
}

View File

@@ -12,6 +12,8 @@ import (
const ( const (
ZitadelName = "zitadel" ZitadelName = "zitadel"
ZitadelPort = 8080 ZitadelPort = 8080
LoginName = "login-ui"
LoginPort = 3000
SecretMountPath = "/var/secrets/" SecretMountPath = "/var/secrets/"
) )

View File

@@ -3,9 +3,9 @@ package health
import ( import (
"context" "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" appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -13,7 +13,7 @@ import (
type EndpointPolicy string 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) key := ctrlclient.ObjectKeyFromObject(zitadel)
var dep appsv1.Deployment var dep appsv1.Deployment
if err := client.Get(ctx, key, &dep); err != nil { if err := client.Get(ctx, key, &dep); err != nil {

View File

@@ -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"
}

View File

@@ -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"
}

76
pkg/zitadel/zitadel.go Normal file
View File

@@ -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)
}

View File

@@ -1,4 +0,0 @@
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/
testbin/

26
src/.gitignore vendored
View File

@@ -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
*~

View File

@@ -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"

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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{})
}

View File

@@ -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"`
}

Some files were not shown because too many files have changed in this diff Show More