Add Flows and Actions
[ZITADOPER-4]
This commit is contained in:
173
ops/chart/crds/action-crd.yaml
Normal file
173
ops/chart/crds/action-crd.yaml
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.11.1
|
||||||
|
creationTimestamp: null
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. --- This struct is intended for direct
|
||||||
|
use as an array at the field path .status.conditions. For example,
|
||||||
|
\n type FooStatus struct{ // Represents the observations of a
|
||||||
|
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||||
|
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||||
|
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||||
|
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||||
|
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||||
|
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.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
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: {}
|
||||||
221
ops/chart/crds/flow-crd.yaml
Normal file
221
ops/chart/crds/flow-crd.yaml
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.11.1
|
||||||
|
creationTimestamp: null
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. --- This struct is intended for direct
|
||||||
|
use as an array at the field path .status.conditions. For example,
|
||||||
|
\n type FooStatus struct{ // Represents the observations of a
|
||||||
|
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||||
|
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||||
|
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||||
|
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||||
|
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||||
|
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.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
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: {}
|
||||||
@@ -170,6 +170,32 @@ rules:
|
|||||||
- list
|
- list
|
||||||
- patch
|
- patch
|
||||||
- watch
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- zitadel.topmanage.com
|
- zitadel.topmanage.com
|
||||||
resources:
|
resources:
|
||||||
@@ -196,6 +222,32 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- zitadel.topmanage.com
|
- zitadel.topmanage.com
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
18
src/PROJECT
18
src/PROJECT
@@ -65,4 +65,22 @@ resources:
|
|||||||
kind: APIApp
|
kind: APIApp
|
||||||
path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1
|
path: bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1
|
||||||
version: 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"
|
version: "3"
|
||||||
|
|||||||
109
src/api/v1alpha1/action_types.go
Normal file
109
src/api/v1alpha1/action_types.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
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{})
|
||||||
|
}
|
||||||
106
src/api/v1alpha1/flow_types.go
Normal file
106
src/api/v1alpha1/flow_types.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
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{})
|
||||||
|
}
|
||||||
@@ -38,3 +38,10 @@ type ProjectRef struct {
|
|||||||
// +operator-sdk:csv:customresourcedefinitions:type=spec
|
// +operator-sdk:csv:customresourcedefinitions:type=spec
|
||||||
corev1.ObjectReference `json:",inline"`
|
corev1.ObjectReference `json:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ActionRef struct {
|
||||||
|
// ObjectReference is a reference to a object.
|
||||||
|
// +kubebuilder:validation:Required
|
||||||
|
// +operator-sdk:csv:customresourcedefinitions:type=spec
|
||||||
|
corev1.ObjectReference `json:",inline"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,6 +63,27 @@ func (r *RefResolver) OIDCAppRef(ctx context.Context, ref *OIDCAppRef,
|
|||||||
return &zitadel, nil
|
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,
|
func (r *RefResolver) ProjectRef(ctx context.Context, ref *ProjectRef,
|
||||||
namespace string) (*Project, error) {
|
namespace string) (*Project, error) {
|
||||||
if ref.Kind != "" && ref.Kind != "Project" {
|
if ref.Kind != "" && ref.Kind != "Project" {
|
||||||
|
|||||||
@@ -123,6 +123,124 @@ func (in *APIAppStatus) DeepCopy() *APIAppStatus {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Action) DeepCopyInto(out *Action) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Action.
|
||||||
|
func (in *Action) DeepCopy() *Action {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Action)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Action) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ActionList) DeepCopyInto(out *ActionList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]Action, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionList.
|
||||||
|
func (in *ActionList) DeepCopy() *ActionList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ActionList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *ActionList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ActionRef) DeepCopyInto(out *ActionRef) {
|
||||||
|
*out = *in
|
||||||
|
out.ObjectReference = in.ObjectReference
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionRef.
|
||||||
|
func (in *ActionRef) DeepCopy() *ActionRef {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ActionRef)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ActionSpec) DeepCopyInto(out *ActionSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.OrganizationRef = in.OrganizationRef
|
||||||
|
if in.Timeout != nil {
|
||||||
|
in, out := &in.Timeout, &out.Timeout
|
||||||
|
*out = new(v1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionSpec.
|
||||||
|
func (in *ActionSpec) DeepCopy() *ActionSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ActionSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ActionStatus) DeepCopyInto(out *ActionStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]v1.Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionStatus.
|
||||||
|
func (in *ActionStatus) DeepCopy() *ActionStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ActionStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CrdbClusterRef) DeepCopyInto(out *CrdbClusterRef) {
|
func (in *CrdbClusterRef) DeepCopyInto(out *CrdbClusterRef) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -154,6 +272,108 @@ func (in *DomainSettings) DeepCopy() *DomainSettings {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Flow) DeepCopyInto(out *Flow) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Flow.
|
||||||
|
func (in *Flow) DeepCopy() *Flow {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Flow)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Flow) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FlowList) DeepCopyInto(out *FlowList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]Flow, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowList.
|
||||||
|
func (in *FlowList) DeepCopy() *FlowList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FlowList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *FlowList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FlowSpec) DeepCopyInto(out *FlowSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.OrganizationRef = in.OrganizationRef
|
||||||
|
if in.ActionRefs != nil {
|
||||||
|
in, out := &in.ActionRefs, &out.ActionRefs
|
||||||
|
*out = make([]ActionRef, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowSpec.
|
||||||
|
func (in *FlowSpec) DeepCopy() *FlowSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FlowSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FlowStatus) DeepCopyInto(out *FlowStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]v1.Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowStatus.
|
||||||
|
func (in *FlowStatus) DeepCopy() *FlowStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FlowStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Grant) DeepCopyInto(out *Grant) {
|
func (in *Grant) DeepCopyInto(out *Grant) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|||||||
@@ -137,6 +137,14 @@ func main() {
|
|||||||
setupLog.Error(err, "unable to create controller", "controller", "APIApp")
|
setupLog.Error(err, "unable to create controller", "controller", "APIApp")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
if err = controller.NewActionReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Action")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err = controller.NewFlowReconciler(client, refResolver, builder, conditionReady, requeueZitadel).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Flow")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
//+kubebuilder:scaffold:builder
|
//+kubebuilder:scaffold:builder
|
||||||
|
|
||||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||||
|
|||||||
174
src/config/crd/bases/zitadel.topmanage.com_actions.yaml
Normal file
174
src/config/crd/bases/zitadel.topmanage.com_actions.yaml
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.11.1
|
||||||
|
creationTimestamp: null
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. --- This struct is intended for direct
|
||||||
|
use as an array at the field path .status.conditions. For example,
|
||||||
|
\n type FooStatus struct{ // Represents the observations of a
|
||||||
|
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||||
|
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||||
|
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||||
|
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||||
|
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||||
|
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.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
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: {}
|
||||||
222
src/config/crd/bases/zitadel.topmanage.com_flows.yaml
Normal file
222
src/config/crd/bases/zitadel.topmanage.com_flows.yaml
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.11.1
|
||||||
|
creationTimestamp: null
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. TODO: this design is not final and this field is
|
||||||
|
subject to change in the future.'
|
||||||
|
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. --- This struct is intended for direct
|
||||||
|
use as an array at the field path .status.conditions. For example,
|
||||||
|
\n type FooStatus struct{ // Represents the observations of a
|
||||||
|
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||||
|
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||||
|
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||||
|
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||||
|
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||||
|
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.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
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: {}
|
||||||
@@ -8,6 +8,8 @@ resources:
|
|||||||
- bases/zitadel.topmanage.com_oidcapps.yaml
|
- bases/zitadel.topmanage.com_oidcapps.yaml
|
||||||
- bases/zitadel.topmanage.com_machineusers.yaml
|
- bases/zitadel.topmanage.com_machineusers.yaml
|
||||||
- bases/zitadel.topmanage.com_apiapps.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:
|
||||||
@@ -19,6 +21,8 @@ patchesStrategicMerge:
|
|||||||
#- patches/webhook_in_oidcapps.yaml
|
#- patches/webhook_in_oidcapps.yaml
|
||||||
#- patches/webhook_in_machineusers.yaml
|
#- patches/webhook_in_machineusers.yaml
|
||||||
#- patches/webhook_in_apiapps.yaml
|
#- patches/webhook_in_apiapps.yaml
|
||||||
|
#- patches/webhook_in_actions.yaml
|
||||||
|
#- patches/webhook_in_flows.yaml
|
||||||
#+kubebuilder:scaffold:crdkustomizewebhookpatch
|
#+kubebuilder:scaffold:crdkustomizewebhookpatch
|
||||||
|
|
||||||
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
|
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
|
||||||
@@ -29,6 +33,8 @@ patchesStrategicMerge:
|
|||||||
#- patches/cainjection_in_oidcapps.yaml
|
#- patches/cainjection_in_oidcapps.yaml
|
||||||
#- patches/cainjection_in_machineusers.yaml
|
#- patches/cainjection_in_machineusers.yaml
|
||||||
#- patches/cainjection_in_apiapps.yaml
|
#- patches/cainjection_in_apiapps.yaml
|
||||||
|
#- patches/cainjection_in_actions.yaml
|
||||||
|
#- patches/cainjection_in_flows.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.
|
||||||
|
|||||||
7
src/config/crd/patches/cainjection_in_actions.yaml
Normal file
7
src/config/crd/patches/cainjection_in_actions.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# The following patch adds a directive for certmanager to inject CA into the CRD
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
|
||||||
|
name: actions.zitadel.topmanage.com
|
||||||
7
src/config/crd/patches/cainjection_in_flows.yaml
Normal file
7
src/config/crd/patches/cainjection_in_flows.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# The following patch adds a directive for certmanager to inject CA into the CRD
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
|
||||||
|
name: flows.zitadel.topmanage.com
|
||||||
16
src/config/crd/patches/webhook_in_actions.yaml
Normal file
16
src/config/crd/patches/webhook_in_actions.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# The following patch enables a conversion webhook for the CRD
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: actions.zitadel.topmanage.com
|
||||||
|
spec:
|
||||||
|
conversion:
|
||||||
|
strategy: Webhook
|
||||||
|
webhook:
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
namespace: system
|
||||||
|
name: webhook-service
|
||||||
|
path: /convert
|
||||||
|
conversionReviewVersions:
|
||||||
|
- v1
|
||||||
16
src/config/crd/patches/webhook_in_flows.yaml
Normal file
16
src/config/crd/patches/webhook_in_flows.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# The following patch enables a conversion webhook for the CRD
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: flows.zitadel.topmanage.com
|
||||||
|
spec:
|
||||||
|
conversion:
|
||||||
|
strategy: Webhook
|
||||||
|
webhook:
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
namespace: system
|
||||||
|
name: webhook-service
|
||||||
|
path: /convert
|
||||||
|
conversionReviewVersions:
|
||||||
|
- v1
|
||||||
31
src/config/rbac/action_editor_role.yaml
Normal file
31
src/config/rbac/action_editor_role.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# permissions for end users to edit actions.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: clusterrole
|
||||||
|
app.kubernetes.io/instance: action-editor-role
|
||||||
|
app.kubernetes.io/component: rbac
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: action-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
27
src/config/rbac/action_viewer_role.yaml
Normal file
27
src/config/rbac/action_viewer_role.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# permissions for end users to view actions.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: clusterrole
|
||||||
|
app.kubernetes.io/instance: action-viewer-role
|
||||||
|
app.kubernetes.io/component: rbac
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: action-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
31
src/config/rbac/flow_editor_role.yaml
Normal file
31
src/config/rbac/flow_editor_role.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# permissions for end users to edit flows.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: clusterrole
|
||||||
|
app.kubernetes.io/instance: flow-editor-role
|
||||||
|
app.kubernetes.io/component: rbac
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: flow-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
27
src/config/rbac/flow_viewer_role.yaml
Normal file
27
src/config/rbac/flow_viewer_role.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# permissions for end users to view flows.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: clusterrole
|
||||||
|
app.kubernetes.io/instance: flow-viewer-role
|
||||||
|
app.kubernetes.io/component: rbac
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: flow-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -170,6 +170,32 @@ rules:
|
|||||||
- list
|
- list
|
||||||
- patch
|
- patch
|
||||||
- watch
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- actions/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- zitadel.topmanage.com
|
- zitadel.topmanage.com
|
||||||
resources:
|
resources:
|
||||||
@@ -196,6 +222,32 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- zitadel.topmanage.com
|
||||||
|
resources:
|
||||||
|
- flows/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- zitadel.topmanage.com
|
- zitadel.topmanage.com
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -6,4 +6,6 @@ resources:
|
|||||||
- zitadel_v1alpha1_oidcapp.yaml
|
- zitadel_v1alpha1_oidcapp.yaml
|
||||||
- zitadel_v1alpha1_machineuser.yaml
|
- zitadel_v1alpha1_machineuser.yaml
|
||||||
- zitadel_v1alpha1_apiapp.yaml
|
- zitadel_v1alpha1_apiapp.yaml
|
||||||
|
- zitadel_v1alpha1_action.yaml
|
||||||
|
- zitadel_v1alpha1_flow.yaml
|
||||||
#+kubebuilder:scaffold:manifestskustomizesamples
|
#+kubebuilder:scaffold:manifestskustomizesamples
|
||||||
|
|||||||
12
src/config/samples/zitadel_v1alpha1_action.yaml
Normal file
12
src/config/samples/zitadel_v1alpha1_action.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: zitadel.topmanage.com/v1alpha1
|
||||||
|
kind: Action
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: action
|
||||||
|
app.kubernetes.io/instance: action-sample
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
name: action-sample
|
||||||
|
spec:
|
||||||
|
# TODO(user): Add fields here
|
||||||
12
src/config/samples/zitadel_v1alpha1_flow.yaml
Normal file
12
src/config/samples/zitadel_v1alpha1_flow.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: zitadel.topmanage.com/v1alpha1
|
||||||
|
kind: Flow
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: flow
|
||||||
|
app.kubernetes.io/instance: flow-sample
|
||||||
|
app.kubernetes.io/part-of: src
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
app.kubernetes.io/created-by: src
|
||||||
|
name: flow-sample
|
||||||
|
spec:
|
||||||
|
# TODO(user): Add fields here
|
||||||
191
src/internal/controller/action_controller.go
Normal file
191
src/internal/controller/action_controller.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder"
|
||||||
|
condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||||
|
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||||
|
durationpb "google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
"k8s.io/client-go/util/workqueue"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ActionReconciler reconciles a Action object
|
||||||
|
type ActionReconciler struct {
|
||||||
|
client.Client
|
||||||
|
RefResolver *zitadelv1alpha1.RefResolver
|
||||||
|
ConditionReady *condition.Ready
|
||||||
|
RequeueInterval time.Duration
|
||||||
|
Builder *builder.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewActionReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready,
|
||||||
|
requeueInterval time.Duration) *ActionReconciler {
|
||||||
|
return &ActionReconciler{
|
||||||
|
Client: client,
|
||||||
|
RefResolver: refResolver,
|
||||||
|
ConditionReady: conditionReady,
|
||||||
|
RequeueInterval: requeueInterval,
|
||||||
|
Builder: builder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions,verbs=get;list;watch;create;update;patch;delete
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions/status,verbs=get;update;patch
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=actions/finalizers,verbs=update
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *ActionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
var Action zitadelv1alpha1.Action
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, &Action); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
wr := newWrappedActionReconciler(r.Client, r.RefResolver, r.Builder, &Action)
|
||||||
|
wf := newWrappedActionFinalizer(r.Client, &Action, r.RefResolver)
|
||||||
|
tf := zitadel.NewZitadelFinalizer(r.Client, wf)
|
||||||
|
tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval)
|
||||||
|
|
||||||
|
result, err := tr.Reconcile(ctx, &Action)
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("error reconciling in ActionReconciler: %v", err)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappedActionReconciler struct {
|
||||||
|
client.Client
|
||||||
|
refResolver *zitadelv1alpha1.RefResolver
|
||||||
|
Action *zitadelv1alpha1.Action
|
||||||
|
Builder *builder.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedActionReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder,
|
||||||
|
Action *zitadelv1alpha1.Action) zitadel.WrappedReconciler {
|
||||||
|
return &wrappedActionReconciler{
|
||||||
|
Client: client,
|
||||||
|
refResolver: refResolver,
|
||||||
|
Action: Action,
|
||||||
|
Builder: builder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type actionReoncilePhase struct {
|
||||||
|
Name string
|
||||||
|
Reconcile func(context.Context, *management.Client) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedActionReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
phases := []actionReoncilePhase{
|
||||||
|
{
|
||||||
|
Name: "action",
|
||||||
|
Reconcile: wr.reconcileAction,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, p := range phases {
|
||||||
|
err := p.Reconcile(ctx, ztdClient)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedActionReconciler) reconcileAction(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
org, err := wr.refResolver.OrganizationRef(ctx, &wr.Action.Spec.OrganizationRef, wr.Action.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx = middleware.SetOrgID(ctx, org.Status.OrgId)
|
||||||
|
|
||||||
|
if wr.Action.Status.ActionId != "" {
|
||||||
|
p, err := ztdClient.GetAction(ctx, &pb.GetActionRequest{Id: wr.Action.Status.ActionId})
|
||||||
|
if p != nil {
|
||||||
|
_, err := ztdClient.UpdateAction(ctx,
|
||||||
|
&pb.UpdateActionRequest{
|
||||||
|
Id: p.Action.Id,
|
||||||
|
Name: wr.Action.Name,
|
||||||
|
Script: wr.Action.Spec.Script,
|
||||||
|
Timeout: durationpb.New(wr.Action.Spec.Timeout.Duration),
|
||||||
|
AllowedToFail: wr.Action.Spec.AllowedToFail,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "No changes") {
|
||||||
|
return fmt.Errorf("Error updating Action: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "not found") {
|
||||||
|
return fmt.Errorf("Error getting Action: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := ztdClient.CreateAction(ctx,
|
||||||
|
&pb.CreateActionRequest{
|
||||||
|
Name: wr.Action.Name,
|
||||||
|
Script: wr.Action.Spec.Script,
|
||||||
|
Timeout: durationpb.New(wr.Action.Spec.Timeout.Duration),
|
||||||
|
AllowedToFail: wr.Action.Spec.AllowedToFail,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "AlreadyExists") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("error creating action in Zitadel: %v", err)
|
||||||
|
}
|
||||||
|
patch := ctrlClient.MergeFrom(wr.Action.DeepCopy())
|
||||||
|
wr.Action.Status.ActionId = resp.Id
|
||||||
|
return wr.Client.Status().Patch(ctx, wr.Action, patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedActionReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error {
|
||||||
|
patch := client.MergeFrom(wr.Action.DeepCopy())
|
||||||
|
patcher(&wr.Action.Status)
|
||||||
|
|
||||||
|
if err := wr.Client.Status().Patch(ctx, wr.Action, patch); err != nil {
|
||||||
|
return fmt.Errorf("error patching Action status: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *ActionReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&zitadelv1alpha1.Action{}).
|
||||||
|
WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(time.Millisecond*500, time.Minute*3)}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
94
src/internal/controller/action_controller_finalizer.go
Normal file
94
src/internal/controller/action_controller_finalizer.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||||
|
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
actionFinalizerName = "action.zitadel.topmanage.com/action"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrappedActionFinalizer struct {
|
||||||
|
client.Client
|
||||||
|
action *zitadelv1alpha1.Action
|
||||||
|
refresolver *zitadelv1alpha1.RefResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedActionFinalizer(client client.Client, action *zitadelv1alpha1.Action, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer {
|
||||||
|
return &wrappedActionFinalizer{
|
||||||
|
Client: client,
|
||||||
|
action: action,
|
||||||
|
refresolver: refresolver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedActionFinalizer) AddFinalizer(ctx context.Context) error {
|
||||||
|
if wf.ContainsFinalizer() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wf.patch(ctx, wf.action, func(action *zitadelv1alpha1.Action) {
|
||||||
|
controllerutil.AddFinalizer(action, actionFinalizerName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedActionFinalizer) RemoveFinalizer(ctx context.Context) error {
|
||||||
|
if !wf.ContainsFinalizer() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wf.patch(ctx, wf.action, func(action *zitadelv1alpha1.Action) {
|
||||||
|
controllerutil.RemoveFinalizer(wf.action, actionFinalizerName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedActionFinalizer) ContainsFinalizer() bool {
|
||||||
|
return controllerutil.ContainsFinalizer(wr.action, actionFinalizerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedActionFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
if wf.action.Status.ActionId == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
org, err := wf.refresolver.OrganizationRef(ctx, &wf.action.Spec.OrganizationRef, wf.action.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
{
|
||||||
|
|
||||||
|
_, err := ztdClient.GetAction(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.GetActionRequest{Id: wf.action.Status.ActionId})
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), `doesn't exist`) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = ztdClient.DeleteAction(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.DeleteActionRequest{Id: wf.action.Status.ActionId})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedActionFinalizer) patch(ctx context.Context, action *zitadelv1alpha1.Action,
|
||||||
|
patchFn func(*zitadelv1alpha1.Action)) error {
|
||||||
|
patch := ctrlClient.MergeFrom(action.DeepCopy())
|
||||||
|
patchFn(action)
|
||||||
|
|
||||||
|
if err := wr.Client.Patch(ctx, action, patch); err != nil {
|
||||||
|
return fmt.Errorf("error patching Action finalizer: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
164
src/internal/controller/flow_controller.go
Normal file
164
src/internal/controller/flow_controller.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
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 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder"
|
||||||
|
condition "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/condition"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||||
|
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||||
|
"k8s.io/client-go/util/workqueue"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FlowReconciler reconciles a Flow object
|
||||||
|
type FlowReconciler struct {
|
||||||
|
client.Client
|
||||||
|
RefResolver *zitadelv1alpha1.RefResolver
|
||||||
|
ConditionReady *condition.Ready
|
||||||
|
RequeueInterval time.Duration
|
||||||
|
Builder *builder.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFlowReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder, conditionReady *condition.Ready,
|
||||||
|
requeueInterval time.Duration) *FlowReconciler {
|
||||||
|
return &FlowReconciler{
|
||||||
|
Client: client,
|
||||||
|
RefResolver: refResolver,
|
||||||
|
ConditionReady: conditionReady,
|
||||||
|
RequeueInterval: requeueInterval,
|
||||||
|
Builder: builder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows,verbs=get;list;watch;create;update;patch;delete
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows/status,verbs=get;update;patch
|
||||||
|
//+kubebuilder:rbac:groups=zitadel.topmanage.com,resources=flows/finalizers,verbs=update
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *FlowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
var Flow zitadelv1alpha1.Flow
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, &Flow); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
wr := newWrappedFlowReconciler(r.Client, r.RefResolver, r.Builder, &Flow)
|
||||||
|
wf := newWrappedFlowFinalizer(r.Client, &Flow, r.RefResolver)
|
||||||
|
tf := zitadel.NewZitadelFinalizer(r.Client, wf)
|
||||||
|
tr := zitadel.NewZitadelReconciler(r.Client, r.ConditionReady, wr, tf, r.RequeueInterval)
|
||||||
|
|
||||||
|
result, err := tr.Reconcile(ctx, &Flow)
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("error reconciling in FlowReconciler: %v", err)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappedFlowReconciler struct {
|
||||||
|
client.Client
|
||||||
|
refResolver *zitadelv1alpha1.RefResolver
|
||||||
|
Flow *zitadelv1alpha1.Flow
|
||||||
|
Builder *builder.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedFlowReconciler(client client.Client, refResolver *zitadelv1alpha1.RefResolver, builder *builder.Builder,
|
||||||
|
Flow *zitadelv1alpha1.Flow) zitadel.WrappedReconciler {
|
||||||
|
return &wrappedFlowReconciler{
|
||||||
|
Client: client,
|
||||||
|
refResolver: refResolver,
|
||||||
|
Flow: Flow,
|
||||||
|
Builder: builder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type flowReoncilePhase struct {
|
||||||
|
Name string
|
||||||
|
Reconcile func(context.Context, *management.Client) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedFlowReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
phases := []flowReoncilePhase{
|
||||||
|
{
|
||||||
|
Name: "flow",
|
||||||
|
Reconcile: wr.reconcileFlow,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, p := range phases {
|
||||||
|
err := p.Reconcile(ctx, ztdClient)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedFlowReconciler) reconcileFlow(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
org, err := wr.refResolver.OrganizationRef(ctx, &wr.Flow.Spec.OrganizationRef, wr.Flow.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx = middleware.SetOrgID(ctx, org.Status.OrgId)
|
||||||
|
|
||||||
|
actionIds := []string{}
|
||||||
|
for _, actionRef := range wr.Flow.Spec.ActionRefs {
|
||||||
|
action, err := wr.refResolver.ActionRef(ctx, &actionRef, wr.Flow.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error resolving action reference: %v", err)
|
||||||
|
}
|
||||||
|
if action.Status.ActionId == "" {
|
||||||
|
return fmt.Errorf("Action with name: %s not ready for trigger", action.Name)
|
||||||
|
}
|
||||||
|
actionIds = append(actionIds, action.Status.ActionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ztdClient.SetTriggerActions(ctx, &pb.SetTriggerActionsRequest{
|
||||||
|
FlowType: wr.Flow.Spec.FlowType,
|
||||||
|
TriggerType: wr.Flow.Spec.TriggerType,
|
||||||
|
ActionIds: actionIds,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error triggering action flow: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedFlowReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error {
|
||||||
|
patch := client.MergeFrom(wr.Flow.DeepCopy())
|
||||||
|
patcher(&wr.Flow.Status)
|
||||||
|
|
||||||
|
if err := wr.Client.Status().Patch(ctx, wr.Flow, patch); err != nil {
|
||||||
|
return fmt.Errorf("error patching Flow status: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *FlowReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&zitadelv1alpha1.Flow{}).
|
||||||
|
WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(time.Millisecond*500, time.Minute*3)}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
82
src/internal/controller/flow_controller_finalizer.go
Normal file
82
src/internal/controller/flow_controller_finalizer.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
|
||||||
|
"bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/controller/zitadel"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||||
|
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||||
|
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flowFinalizerName = "flow.zitadel.topmanage.com/flow"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrappedFlowFinalizer struct {
|
||||||
|
client.Client
|
||||||
|
flow *zitadelv1alpha1.Flow
|
||||||
|
refresolver *zitadelv1alpha1.RefResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedFlowFinalizer(client client.Client, flow *zitadelv1alpha1.Flow, refresolver *zitadelv1alpha1.RefResolver) zitadel.WrappedFinalizer {
|
||||||
|
return &wrappedFlowFinalizer{
|
||||||
|
Client: client,
|
||||||
|
flow: flow,
|
||||||
|
refresolver: refresolver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedFlowFinalizer) AddFinalizer(ctx context.Context) error {
|
||||||
|
if wf.ContainsFinalizer() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wf.patch(ctx, wf.flow, func(flow *zitadelv1alpha1.Flow) {
|
||||||
|
controllerutil.AddFinalizer(flow, flowFinalizerName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedFlowFinalizer) RemoveFinalizer(ctx context.Context) error {
|
||||||
|
if !wf.ContainsFinalizer() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wf.patch(ctx, wf.flow, func(flow *zitadelv1alpha1.Flow) {
|
||||||
|
controllerutil.RemoveFinalizer(wf.flow, flowFinalizerName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedFlowFinalizer) ContainsFinalizer() bool {
|
||||||
|
return controllerutil.ContainsFinalizer(wr.flow, flowFinalizerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wf *wrappedFlowFinalizer) Reconcile(ctx context.Context, ztdClient *management.Client) error {
|
||||||
|
org, err := wf.refresolver.OrganizationRef(ctx, &wf.flow.Spec.OrganizationRef, wf.flow.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ztdClient.ClearFlow(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.ClearFlowRequest{
|
||||||
|
Type: wf.flow.Spec.FlowType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wr *wrappedFlowFinalizer) patch(ctx context.Context, flow *zitadelv1alpha1.Flow,
|
||||||
|
patchFn func(*zitadelv1alpha1.Flow)) error {
|
||||||
|
patch := ctrlClient.MergeFrom(flow.DeepCopy())
|
||||||
|
patchFn(flow)
|
||||||
|
|
||||||
|
if err := wr.Client.Patch(ctx, flow, patch); err != nil {
|
||||||
|
return fmt.Errorf("error patching Flow finalizer: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user