├── chart
├── templates
│ ├── NOTES.txt
│ ├── _helpers.yaml
│ ├── deployment.yaml
│ ├── rbac.yaml
│ └── crds
│ │ └── integration.rock8s.com_deferredresources.yaml
├── app-readme.md
├── Makefile
├── .helmignore
├── values.yaml
├── Chart.yaml
└── questions.yaml
├── config
├── manager
│ ├── kustomization.yaml
│ └── manager.yaml
├── prometheus
│ ├── kustomization.yaml
│ └── monitor.yaml
├── scorecard
│ ├── bases
│ │ └── config.yaml
│ ├── patches
│ │ ├── basic.config.yaml
│ │ └── olm.config.yaml
│ └── kustomization.yaml
├── default
│ ├── manager_config_patch.yaml
│ ├── manager_auth_proxy_patch.yaml
│ └── kustomization.yaml
├── samples
│ ├── integration_v1beta1_plug.yaml
│ ├── kustomization.yaml
│ ├── integration_v1beta1_deferredresource.yaml
│ ├── rbac.yaml
│ └── integration_v1beta1_socket.yaml
├── crd
│ ├── patches
│ │ ├── cainjection_in_plugs.yaml
│ │ ├── cainjection_in_sockets.yaml
│ │ ├── cainjection_in_deferredresources.yaml
│ │ ├── webhook_in_plugs.yaml
│ │ ├── webhook_in_sockets.yaml
│ │ └── webhook_in_deferredresources.yaml
│ ├── kustomizeconfig.yaml
│ ├── kustomization.yaml
│ └── bases
│ │ └── integration.rock8s.com_deferredresources.yaml
├── rbac
│ ├── service_account.yaml
│ ├── auth_proxy_client_clusterrole.yaml
│ ├── role_binding.yaml
│ ├── auth_proxy_role_binding.yaml
│ ├── leader_election_role_binding.yaml
│ ├── auth_proxy_role.yaml
│ ├── auth_proxy_service.yaml
│ ├── plug_viewer_role.yaml
│ ├── socket_viewer_role.yaml
│ ├── kustomization.yaml
│ ├── plug_editor_role.yaml
│ ├── deferredresource_viewer_role.yaml
│ ├── socket_editor_role.yaml
│ ├── deferredresource_editor_role.yaml
│ ├── leader_election_role.yaml
│ └── role.yaml
├── manifests
│ └── kustomization.yaml
└── main.go
├── .gitattributes
├── images
├── typea.png
├── typed.png
├── integration-operator.jpg
└── icon.svg
├── operator
├── ci.yaml
└── 1.2.0
│ └── metadata
│ └── annotations.yaml
├── .mkpm
└── cache.tar.gz
├── .editorconfig
├── mkpm.json
├── .vscode
├── extensions.json
└── settings.json
├── cspell.json
├── .gitignore
├── .dockerignore
├── hack
└── boilerplate.go.txt
├── docker
├── docker-bake.hcl
├── Dockerfile
└── Makefile
├── project-words.txt
├── coupler
├── main.go
├── decouple.go
├── update.go
├── plug.go
├── socket.go
└── couple.go
├── PROJECT
├── Mkpmfile
├── .envrc
├── api
└── v1beta1
│ ├── groupversion_info.go
│ ├── deferredresource_types.go
│ ├── shared_types.go
│ ├── plug_types.go
│ └── socket_types.go
├── mkpm
├── util
├── main.go
├── data.go
├── helpers.go
├── var.go
├── kubectl.go
├── event.go
├── plug.go
└── config.go
├── settings.json
├── controllers
├── suite_test.go
├── plug_controller.go
├── deferredresource_controller.go
└── socket_controller.go
├── go.mod
└── main.go
/chart/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | Thank you for installing
2 |
--------------------------------------------------------------------------------
/config/manager/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - manager.yaml
3 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | .mkpm/cache.tar.gz filter=lfs diff=lfs merge=lfs -text
2 |
--------------------------------------------------------------------------------
/config/prometheus/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - monitor.yaml
3 |
--------------------------------------------------------------------------------
/chart/app-readme.md:
--------------------------------------------------------------------------------
1 | # integration-operator
2 |
3 | > kubernetes operator to integrate deployments
4 |
--------------------------------------------------------------------------------
/images/typea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clayrisser/integration-operator/HEAD/images/typea.png
--------------------------------------------------------------------------------
/images/typed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clayrisser/integration-operator/HEAD/images/typed.png
--------------------------------------------------------------------------------
/images/integration-operator.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clayrisser/integration-operator/HEAD/images/integration-operator.jpg
--------------------------------------------------------------------------------
/operator/ci.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Use `replaces-mode` or `semver-mode`. Once you switch to `semver-mode`, there is no easy way back.
3 | updateGraph: semver-mode
4 |
--------------------------------------------------------------------------------
/.mkpm/cache.tar.gz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b323bcf98a52ea178a4623eeb24138c5b1e9351ccc47c4163983e1ede69100f2
3 | size 17814
4 |
--------------------------------------------------------------------------------
/config/scorecard/bases/config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scorecard.operatorframework.io/v1alpha3
2 | kind: Configuration
3 | metadata:
4 | name: config
5 | stages:
6 | - parallel: true
7 | tests: []
8 |
--------------------------------------------------------------------------------
/chart/Makefile:
--------------------------------------------------------------------------------
1 | include $(MKPM)/mkpm
2 | include $(MKPM)/gnu
3 |
4 | export DOCKER_DEFAULT_PLATFORM=linux/amd64
5 | export PATCHES :=
6 |
7 | include $(MKPM)/patch
8 |
9 | .PHONY: prepack
10 | prepack: patch-apply
11 |
--------------------------------------------------------------------------------
/config/default/manager_config_patch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: controller-manager
5 | namespace: system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: manager
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [Mkpmfile]
2 | charset = utf-8
3 | indent_size = 4
4 | indent_style = tab
5 | [{M,m}akefile{,.*}]
6 | charset = utf-8
7 | indent_size = 4
8 | indent_style = tab
9 | [*.mk]
10 | charset = utf-8
11 | indent_size = 4
12 | indent_style = tab
13 |
--------------------------------------------------------------------------------
/mkpm.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": {
3 | "default": {
4 | "docker": "0.2.0",
5 | "gnu": "0.1.0",
6 | "patch": "0.0.5"
7 | }
8 | },
9 | "repos": {
10 | "default": "https://gitlab.com/bitspur/mkpm/packages.git"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chart/.helmignore:
--------------------------------------------------------------------------------
1 | *.bak
2 | *.orig
3 | *.swp
4 | *.tmp
5 | *.tmproj
6 | *~
7 | .DS_Store
8 | .bzr/
9 | .bzrignore
10 | .git/
11 | .gitignore
12 | .hg/
13 | .hgignore
14 | .idea/
15 | .mkpm/
16 | .project
17 | .svn/
18 | .vscode/
19 | /Makefile
20 | /patches
21 |
--------------------------------------------------------------------------------
/config/samples/integration_v1beta1_plug.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: integration.rock8s.com/v1beta1
2 | kind: Plug
3 | metadata:
4 | name: postgres
5 | namespace: app
6 | spec:
7 | socket:
8 | name: postgres
9 | namespace: postgres-namespace
10 | config:
11 | database: app
12 |
--------------------------------------------------------------------------------
/config/scorecard/patches/basic.config.yaml:
--------------------------------------------------------------------------------
1 | - op: add
2 | path: /stages/0/tests/-
3 | value:
4 | entrypoint:
5 | - scorecard-test
6 | - basic-check-spec
7 | image: quay.io/operator-framework/scorecard-test:v1.32.0
8 | labels:
9 | suite: basic
10 | test: basic-check-spec-test
11 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "golang.go",
4 | "ms-azuretools.vscode-docker",
5 | "ms-kubernetes-tools.vscode-kubernetes-tools",
6 | "streetsidesoftware.code-spell-checker",
7 | "mkhl.direnv",
8 | "hashicorp.hcl",
9 | "fredwangwang.vscode-hcl-format"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_plugs.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
7 | name: plugs.integration.rock8s.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_sockets.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
7 | name: sockets.integration.rock8s.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_deferredresources.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
7 | name: deferredresources.integration.rock8s.com
8 |
--------------------------------------------------------------------------------
/config/samples/kustomization.yaml:
--------------------------------------------------------------------------------
1 | ## Append samples you want in your CSV to this file as resources ##
2 | resources:
3 | - integration_v1beta1_socket.yaml
4 | - integration_v1beta1_plug.yaml
5 | - rbac.yaml
6 | - integration_v1beta1_deferresource.yaml
7 | - integration_v1beta1_deferedresource.yaml
8 | - integration_v1beta1_deferredresource.yaml
9 | #+kubebuilder:scaffold:manifestskustomizesamples
10 |
--------------------------------------------------------------------------------
/cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
3 | "version": "0.2",
4 | "dictionaryDefinitions": [
5 | {
6 | "name": "project-words",
7 | "path": "./project-words.txt",
8 | "addWords": true
9 | }
10 | ],
11 | "dictionaries": ["project-words"],
12 | "ignorePaths": ["node_modules", "/project-words.txt"]
13 | }
14 |
--------------------------------------------------------------------------------
/operator/1.2.0/metadata/annotations.yaml:
--------------------------------------------------------------------------------
1 | annotations:
2 | operators.operatorframework.io.bundle.channel.default.v1: stable
3 | operators.operatorframework.io.bundle.channels.v1: stable
4 | operators.operatorframework.io.bundle.manifests.v1: manifests/
5 | operators.operatorframework.io.bundle.mediatype.v1: registry+v1
6 | operators.operatorframework.io.bundle.metadata.v1: metadata/
7 | operators.operatorframework.io.bundle.package.v1: integration-operator
8 |
--------------------------------------------------------------------------------
/config/rbac/service_account.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: serviceaccount
6 | app.kubernetes.io/instance: controller-manager
7 | app.kubernetes.io/component: rbac
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: controller-manager
12 | namespace: system
13 |
--------------------------------------------------------------------------------
/config/scorecard/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - bases/config.yaml
3 | patchesJson6902:
4 | - path: patches/basic.config.yaml
5 | target:
6 | group: scorecard.operatorframework.io
7 | version: v1alpha3
8 | kind: Configuration
9 | name: config
10 | - path: patches/olm.config.yaml
11 | target:
12 | group: scorecard.operatorframework.io
13 | version: v1alpha3
14 | kind: Configuration
15 | name: config
16 | #+kubebuilder:scaffold:patchesJson6902
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_plugs.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: plugs.integration.rock8s.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_sockets.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: sockets.integration.rock8s.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/samples/integration_v1beta1_deferredresource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: integration.rock8s.com/v1beta1
2 | kind: DeferredResource
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: deferredresource
6 | app.kubernetes.io/instance: deferredresource-sample
7 | app.kubernetes.io/part-of: integration-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | app.kubernetes.io/created-by: integration-operator
10 | name: deferredresource-sample
11 | spec:
12 | # TODO(user): Add fields here
13 |
--------------------------------------------------------------------------------
/chart/values.yaml:
--------------------------------------------------------------------------------
1 | images:
2 | resourceBindingOperator:
3 | repository: registry.gitlab.com/bitspur/rock8s/integration-operator
4 | tag: 1.2.0
5 |
6 | config:
7 | imagePullPolicy: Always
8 | updateStrategy: RollingUpdate
9 | debug: false
10 | replicas: 1
11 | maxConcurrentReconciles: 3
12 | resourceBindingOperator:
13 | resources:
14 | enabled: defaults
15 | requests:
16 | cpu: 100m
17 | memory: 50Mi
18 | limits:
19 | cpu: 200m
20 | memory: 100Mi
21 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_deferredresources.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: deferredresources.integration.rock8s.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/chart/Chart.yaml:
--------------------------------------------------------------------------------
1 | name: integration-operator
2 | apiVersion: v1
3 | home: https://gitlab.com/bitspur/rock8s/integration-operator
4 | icon: https://gitlab.com/bitspur/rock8s/integration-operator/-/raw/main/images/icon.svg
5 | version: 1.2.0
6 | appVersion: 1.2.0
7 | description: "bind a resource to a resource"
8 | keywords:
9 | - controller
10 | - operator
11 | - crossplane
12 | sources:
13 | - https://gitlab.com/bitspur/rock8s/integration-operator.git
14 | maintainers:
15 | - name: "Clay Risser"
16 | email: email@clayrisser.com
17 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_client_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterrole
6 | app.kubernetes.io/instance: metrics-reader
7 | app.kubernetes.io/component: kube-rbac-proxy
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: metrics-reader
12 | rules:
13 | - nonResourceURLs:
14 | - "/metrics"
15 | verbs:
16 | - get
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | bin
8 | testbin/*
9 | Dockerfile.cross
10 |
11 | # Test binary, build with `go test -c`
12 | *.test
13 |
14 | # Output of the go coverage tool, specifically when used with LiteIDE
15 | *.out
16 |
17 | # Kubernetes Generated files - skip generated files, except for vendored files
18 |
19 | !vendor/**/zz_generated.*
20 |
21 | # editor and IDE paraphernalia
22 | .idea
23 | *.swp
24 | *.swo
25 | *~
26 |
27 | # mkpm
28 | .mkpm/mkpm
29 |
30 | # app
31 | /integration-operator
32 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | bin
8 | testbin/*
9 | Dockerfile.cross
10 |
11 | # Test binary, build with `go test -c`
12 | *.test
13 |
14 | # Output of the go coverage tool, specifically when used with LiteIDE
15 | *.out
16 |
17 | # Kubernetes Generated files - skip generated files, except for vendored files
18 |
19 | !vendor/**/zz_generated.*
20 |
21 | # editor and IDE paraphernalia
22 | .idea
23 | *.swp
24 | *.swo
25 | *~
26 |
27 | # mkpm
28 | .mkpm/mkpm
29 |
30 | # app
31 | /integration-operator
32 |
--------------------------------------------------------------------------------
/config/crd/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD
2 | nameReference:
3 | - kind: Service
4 | version: v1
5 | fieldSpecs:
6 | - kind: CustomResourceDefinition
7 | version: v1
8 | group: apiextensions.k8s.io
9 | path: spec/conversion/webhook/clientConfig/service/name
10 |
11 | namespace:
12 | - kind: CustomResourceDefinition
13 | version: v1
14 | group: apiextensions.k8s.io
15 | path: spec/conversion/webhook/clientConfig/service/namespace
16 | create: false
17 |
18 | varReference:
19 | - path: metadata/annotations
20 |
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2023.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
--------------------------------------------------------------------------------
/chart/templates/_helpers.yaml:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/**
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "integration-operator.name" }}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
7 | {{- end }}
8 |
9 | {{/**
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this
12 | (by the DNS naming spec).
13 | */}}
14 | {{- define "integration-operator.fullname" }}
15 | {{- $name := default .Chart.Name .Values.nameOverride }}
16 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
17 | {{- end }}
18 |
--------------------------------------------------------------------------------
/config/samples/rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: Role
3 | metadata:
4 | name: plug-role
5 | namespace: default
6 | rules:
7 | - apiGroups:
8 | - ''
9 | resources:
10 | - configmaps
11 | verbs:
12 | - create
13 | - delete
14 | - get
15 | - list
16 | - patch
17 | - update
18 | - watch
19 | ---
20 | apiVersion: rbac.authorization.k8s.io/v1
21 | kind: RoleBinding
22 | metadata:
23 | name: plug-rolebinding
24 | namespace: default
25 | roleRef:
26 | apiGroup: rbac.authorization.k8s.io
27 | kind: Role
28 | name: plug-role
29 | subjects:
30 | - kind: ServiceAccount
31 | name: default
32 | namespace: default
33 |
--------------------------------------------------------------------------------
/config/rbac/role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterrolebinding
6 | app.kubernetes.io/instance: manager-rolebinding
7 | app.kubernetes.io/component: rbac
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: manager-rolebinding
12 | roleRef:
13 | apiGroup: rbac.authorization.k8s.io
14 | kind: ClusterRole
15 | name: manager-role
16 | subjects:
17 | - kind: ServiceAccount
18 | name: controller-manager
19 | namespace: system
20 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterrolebinding
6 | app.kubernetes.io/instance: proxy-rolebinding
7 | app.kubernetes.io/component: kube-rbac-proxy
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: proxy-rolebinding
12 | roleRef:
13 | apiGroup: rbac.authorization.k8s.io
14 | kind: ClusterRole
15 | name: proxy-role
16 | subjects:
17 | - kind: ServiceAccount
18 | name: controller-manager
19 | namespace: system
20 |
--------------------------------------------------------------------------------
/config/rbac/leader_election_role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: rolebinding
6 | app.kubernetes.io/instance: leader-election-rolebinding
7 | app.kubernetes.io/component: rbac
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: leader-election-rolebinding
12 | roleRef:
13 | apiGroup: rbac.authorization.k8s.io
14 | kind: Role
15 | name: leader-election-role
16 | subjects:
17 | - kind: ServiceAccount
18 | name: controller-manager
19 | namespace: system
20 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterrole
6 | app.kubernetes.io/instance: proxy-role
7 | app.kubernetes.io/component: kube-rbac-proxy
8 | app.kubernetes.io/created-by: integration-operator
9 | app.kubernetes.io/part-of: integration-operator
10 | app.kubernetes.io/managed-by: kustomize
11 | name: proxy-role
12 | rules:
13 | - apiGroups:
14 | - authentication.k8s.io
15 | resources:
16 | - tokenreviews
17 | verbs:
18 | - create
19 | - apiGroups:
20 | - authorization.k8s.io
21 | resources:
22 | - subjectaccessreviews
23 | verbs:
24 | - create
25 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | control-plane: controller-manager
6 | app.kubernetes.io/name: service
7 | app.kubernetes.io/instance: controller-manager-metrics-service
8 | app.kubernetes.io/component: kube-rbac-proxy
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: controller-manager-metrics-service
13 | namespace: system
14 | spec:
15 | ports:
16 | - name: https
17 | port: 8443
18 | protocol: TCP
19 | targetPort: https
20 | selector:
21 | control-plane: controller-manager
22 |
--------------------------------------------------------------------------------
/docker/docker-bake.hcl:
--------------------------------------------------------------------------------
1 | variable "REGISTRY" {
2 | default = "docker.io/library"
3 | }
4 |
5 | variable "NAME" {
6 | default = ""
7 | }
8 |
9 | variable "VERSION" {
10 | default = ""
11 | }
12 |
13 | variable "GIT_COMMIT" {
14 | default = ""
15 | }
16 |
17 | target "default" {
18 | context = ".."
19 | dockerfile = "docker/Dockerfile"
20 | platforms = ["linux/amd64", "linux/arm64"]
21 | output = ["type=registry"]
22 | tags = [
23 | "${REGISTRY}/${NAME}:${GIT_COMMIT}",
24 | "${REGISTRY}/${NAME}:${VERSION}",
25 | "${REGISTRY}/${NAME}:${split(".", VERSION)[0]}",
26 | "${REGISTRY}/${NAME}:${split(".", VERSION)[0]}.${split(".", VERSION)[1]}",
27 | "${REGISTRY}/${NAME}:latest",
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/config/rbac/plug_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view plugs.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: plug-viewer-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: plug-viewer-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - plugs
18 | verbs:
19 | - get
20 | - list
21 | - watch
22 | - apiGroups:
23 | - integration.rock8s.com
24 | resources:
25 | - plugs/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/socket_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view sockets.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: socket-viewer-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: socket-viewer-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - sockets
18 | verbs:
19 | - get
20 | - list
21 | - watch
22 | - apiGroups:
23 | - integration.rock8s.com
24 | resources:
25 | - sockets/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | # All RBAC will be applied under this service account in
3 | # the deployment namespace. You may comment out this resource
4 | # if your manager will use a service account that exists at
5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding
6 | # subjects if changing service account names.
7 | - service_account.yaml
8 | - role.yaml
9 | - role_binding.yaml
10 | - leader_election_role.yaml
11 | - leader_election_role_binding.yaml
12 | # Comment the following 4 lines if you want to disable
13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy)
14 | # which protects your /metrics endpoint.
15 | - auth_proxy_service.yaml
16 | - auth_proxy_role.yaml
17 | - auth_proxy_role_binding.yaml
18 | - auth_proxy_client_clusterrole.yaml
19 |
--------------------------------------------------------------------------------
/config/rbac/plug_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit plugs.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: plug-editor-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: plug-editor-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - plugs
18 | verbs:
19 | - create
20 | - delete
21 | - get
22 | - list
23 | - patch
24 | - update
25 | - watch
26 | - apiGroups:
27 | - integration.rock8s.com
28 | resources:
29 | - plugs/status
30 | verbs:
31 | - get
32 |
--------------------------------------------------------------------------------
/config/rbac/deferredresource_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view deferredresources.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: deferredresource-viewer-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: deferredresource-viewer-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - deferredresources
18 | verbs:
19 | - get
20 | - list
21 | - watch
22 | - apiGroups:
23 | - integration.rock8s.com
24 | resources:
25 | - deferredresources/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/socket_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit sockets.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: socket-editor-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: socket-editor-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - sockets
18 | verbs:
19 | - create
20 | - delete
21 | - get
22 | - list
23 | - patch
24 | - update
25 | - watch
26 | - apiGroups:
27 | - integration.rock8s.com
28 | resources:
29 | - sockets/status
30 | verbs:
31 | - get
32 |
--------------------------------------------------------------------------------
/config/rbac/deferredresource_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit deferredresources.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: clusterrole
7 | app.kubernetes.io/instance: deferredresource-editor-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: deferredresource-editor-role
13 | rules:
14 | - apiGroups:
15 | - integration.rock8s.com
16 | resources:
17 | - deferredresources
18 | verbs:
19 | - create
20 | - delete
21 | - get
22 | - list
23 | - patch
24 | - update
25 | - watch
26 | - apiGroups:
27 | - integration.rock8s.com
28 | resources:
29 | - deferredresources/status
30 | verbs:
31 | - get
32 |
--------------------------------------------------------------------------------
/config/prometheus/monitor.yaml:
--------------------------------------------------------------------------------
1 |
2 | # Prometheus Monitor Service (Metrics)
3 | apiVersion: monitoring.coreos.com/v1
4 | kind: ServiceMonitor
5 | metadata:
6 | labels:
7 | control-plane: controller-manager
8 | app.kubernetes.io/name: servicemonitor
9 | app.kubernetes.io/instance: controller-manager-metrics-monitor
10 | app.kubernetes.io/component: metrics
11 | app.kubernetes.io/created-by: integration-operator
12 | app.kubernetes.io/part-of: integration-operator
13 | app.kubernetes.io/managed-by: kustomize
14 | name: controller-manager-metrics-monitor
15 | namespace: system
16 | spec:
17 | endpoints:
18 | - path: /metrics
19 | port: https
20 | scheme: https
21 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
22 | tlsConfig:
23 | insecureSkipVerify: true
24 | selector:
25 | matchLabels:
26 | control-plane: controller-manager
27 |
--------------------------------------------------------------------------------
/config/rbac/leader_election_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions to do leader election.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: role
7 | app.kubernetes.io/instance: leader-election-role
8 | app.kubernetes.io/component: rbac
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: leader-election-role
13 | rules:
14 | - apiGroups:
15 | - ""
16 | resources:
17 | - configmaps
18 | verbs:
19 | - get
20 | - list
21 | - watch
22 | - create
23 | - update
24 | - patch
25 | - delete
26 | - apiGroups:
27 | - coordination.k8s.io
28 | resources:
29 | - leases
30 | verbs:
31 | - get
32 | - list
33 | - watch
34 | - create
35 | - update
36 | - patch
37 | - delete
38 | - apiGroups:
39 | - ""
40 | resources:
41 | - events
42 | verbs:
43 | - create
44 | - patch
45 |
--------------------------------------------------------------------------------
/project-words.txt:
--------------------------------------------------------------------------------
1 | apiextensions
2 | apiextensionsv
3 | apiextv
4 | apimachinery
5 | apiserver
6 | automount
7 | bitspur
8 | cainjection
9 | certmanager
10 | clientgoscheme
11 | clientset
12 | configmap
13 | controllerutil
14 | corev
15 | crdkustomizecainjectionpatch
16 | crdkustomizeresource
17 | crdkustomizewebhookpatch
18 | crds
19 | crossplane
20 | customresourcedefinitions
21 | deepcopy
22 | deferredresource
23 | deferredresources
24 | devel
25 | fieldref
26 | finalizer
27 | finalizers
28 | gjson
29 | groupversion
30 | healthz
31 | integrationv
32 | intstr
33 | istio
34 | keycloak
35 | kubebuilder
36 | kustomization
37 | kustomize
38 | kustomizeconfig
39 | kyverno
40 | logr
41 | mediatype
42 | metav
43 | mkpm
44 | nerr
45 | objref
46 | oidc
47 | operatorframework
48 | protobuf
49 | readyz
50 | resid
51 | restmapper
52 | resty
53 | risser
54 | rolebinding
55 | serrors
56 | serviceaccount
57 | serviceaccounts
58 | servicemonitor
59 | sjson
60 | subresource
61 | tdewolff
62 | templating
63 | tidwall
64 | utilruntime
65 |
--------------------------------------------------------------------------------
/coupler/main.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/main.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 15:18:21
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
--------------------------------------------------------------------------------
/config/crd/kustomization.yaml:
--------------------------------------------------------------------------------
1 | # This kustomization.yaml is not intended to be run by itself,
2 | # since it depends on service name and namespace that are out of this kustomize package.
3 | # It should be run by config/default
4 | resources:
5 | - bases/integration.rock8s.com_sockets.yaml
6 | - bases/integration.rock8s.com_plugs.yaml
7 | - bases/integration.rock8s.com_deferredresources.yaml
8 | #+kubebuilder:scaffold:crdkustomizeresource
9 |
10 | patchesStrategicMerge: []
11 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
12 | # patches here are for enabling the conversion webhook for each CRD
13 | #- patches/webhook_in_sockets.yaml
14 | #- patches/webhook_in_plugs.yaml
15 | #- patches/webhook_in_deferredresources.yaml
16 | #+kubebuilder:scaffold:crdkustomizewebhookpatch
17 |
18 | # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
19 | # patches here are for enabling the CA injection for each CRD
20 | #- patches/cainjection_in_sockets.yaml
21 | #- patches/cainjection_in_plugs.yaml
22 | #- patches/cainjection_in_deferredresources.yaml
23 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch
24 |
25 | # the following config is for teaching kustomize how to do kustomization for CRDs.
26 | configurations:
27 | - kustomizeconfig.yaml
28 |
--------------------------------------------------------------------------------
/config/manifests/kustomization.yaml:
--------------------------------------------------------------------------------
1 | # These resources constitute the fully configured set of manifests
2 | # used to generate the 'manifests/' directory in a bundle.
3 | resources:
4 | - bases/integration-operator.clusterserviceversion.yaml
5 | - ../default
6 | - ../samples
7 | - ../scorecard
8 |
9 | # [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix.
10 | # Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager.
11 | # These patches remove the unnecessary "cert" volume and its manager container volumeMount.
12 | #patchesJson6902:
13 | #- target:
14 | # group: apps
15 | # version: v1
16 | # kind: Deployment
17 | # name: controller-manager
18 | # namespace: system
19 | # patch: |-
20 | # # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
21 | # # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
22 | # - op: remove
23 | # path: /spec/template/spec/containers/1/volumeMounts/0
24 | # # Remove the "cert" volume, since OLM will create and mount a set of certs.
25 | # # Update the indices in this path if adding or removing volumes in the manager's Deployment.
26 | # - op: remove
27 | # path: /spec/template/spec/volumes/0
28 |
--------------------------------------------------------------------------------
/PROJECT:
--------------------------------------------------------------------------------
1 | # Code generated by tool. DO NOT EDIT.
2 | # This file is used to track the info used to scaffold your project
3 | # and allow the plugins properly work.
4 | # More info: https://book.kubebuilder.io/reference/project-config.html
5 | domain: rock8s.com
6 | layout:
7 | - go.kubebuilder.io/v3
8 | plugins:
9 | manifests.sdk.operatorframework.io/v2: {}
10 | scorecard.sdk.operatorframework.io/v2: {}
11 | projectName: integration-operator
12 | repo: gitlab.com/bitspur/rock8s/integration-operator
13 | resources:
14 | - api:
15 | crdVersion: v1
16 | namespaced: true
17 | controller: true
18 | domain: rock8s.com
19 | group: integration
20 | kind: Socket
21 | path: gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1
22 | version: v1beta1
23 | - api:
24 | crdVersion: v1
25 | namespaced: true
26 | controller: true
27 | domain: rock8s.com
28 | group: integration
29 | kind: Plug
30 | path: gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1
31 | version: v1beta1
32 | - api:
33 | crdVersion: v1
34 | namespaced: true
35 | controller: true
36 | domain: rock8s.com
37 | group: integration
38 | kind: DeferredResource
39 | path: gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1
40 | version: v1beta1
41 | version: "3"
42 |
--------------------------------------------------------------------------------
/config/scorecard/patches/olm.config.yaml:
--------------------------------------------------------------------------------
1 | - op: add
2 | path: /stages/0/tests/-
3 | value:
4 | entrypoint:
5 | - scorecard-test
6 | - olm-bundle-validation
7 | image: quay.io/operator-framework/scorecard-test:v1.32.0
8 | labels:
9 | suite: olm
10 | test: olm-bundle-validation-test
11 | - op: add
12 | path: /stages/0/tests/-
13 | value:
14 | entrypoint:
15 | - scorecard-test
16 | - olm-crds-have-validation
17 | image: quay.io/operator-framework/scorecard-test:v1.32.0
18 | labels:
19 | suite: olm
20 | test: olm-crds-have-validation-test
21 | - op: add
22 | path: /stages/0/tests/-
23 | value:
24 | entrypoint:
25 | - scorecard-test
26 | - olm-crds-have-resources
27 | image: quay.io/operator-framework/scorecard-test:v1.32.0
28 | labels:
29 | suite: olm
30 | test: olm-crds-have-resources-test
31 | - op: add
32 | path: /stages/0/tests/-
33 | value:
34 | entrypoint:
35 | - scorecard-test
36 | - olm-spec-descriptors
37 | image: quay.io/operator-framework/scorecard-test:v1.32.0
38 | labels:
39 | suite: olm
40 | test: olm-spec-descriptors-test
41 | - op: add
42 | path: /stages/0/tests/-
43 | value:
44 | entrypoint:
45 | - scorecard-test
46 | - olm-status-descriptors
47 | image: quay.io/operator-framework/scorecard-test:v1.32.0
48 | labels:
49 | suite: olm
50 | test: olm-status-descriptors-test
51 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the manager binary
2 | FROM golang:1.19 as builder
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 |
6 | WORKDIR /workspace
7 | # Copy the Go Modules manifests
8 | COPY go.mod go.mod
9 | COPY go.sum go.sum
10 | # cache deps before building and copying source so that we don't need to re-download as much
11 | # and so that source changes don't invalidate our downloaded layer
12 | RUN go mod download
13 |
14 | # Copy the go source
15 | COPY main.go main.go
16 | COPY api/ api/
17 | COPY controllers/ controllers/
18 | COPY config/ config/
19 | COPY coupler/ coupler/
20 | COPY util/ util/
21 |
22 | # Build
23 | # the GOARCH has not a default value to allow the binary be built according to the host where the command
24 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
25 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
26 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
27 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go
28 |
29 | # Use distroless as minimal base image to package the manager binary
30 | # Refer to https://github.com/GoogleContainerTools/distroless for more details
31 | FROM gcr.io/distroless/static:nonroot
32 | WORKDIR /
33 | COPY --from=builder /workspace/manager .
34 | USER 65532:65532
35 |
36 | ENTRYPOINT ["/manager"]
37 |
--------------------------------------------------------------------------------
/config/main.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /config/main.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 14:02:00
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package config
28 |
29 | import (
30 | "os"
31 | "time"
32 |
33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 | )
35 |
36 | var MaxRequeueDuration time.Duration = time.Duration(float64(time.Hour.Nanoseconds() * 6))
37 |
38 | var StartTime metav1.Time = metav1.Now()
39 |
40 | var DebugPlugEndpoint = os.Getenv("DEBUG_PLUG_ENDPOINT")
41 |
42 | var DebugSocketEndpoint = os.Getenv("DEBUG_SOCKET_ENDPOINT")
43 |
--------------------------------------------------------------------------------
/docker/Makefile:
--------------------------------------------------------------------------------
1 | # File: /docker/Makefile
2 | # Project: integration-operator
3 | # File Created: 13-10-2023 15:44:20
4 | # Author: Clay Risser
5 | # -----
6 | # BitSpur (c) Copyright 2021 - 2023
7 | #
8 | # Licensed under the GNU Affero General Public License (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # https://www.gnu.org/licenses/agpl-3.0.en.html
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 | #
20 | # You can be released from the requirements of the license by purchasing
21 | # a commercial license. Buying such a license is mandatory as soon as you
22 | # develop commercial activities involving this software without disclosing
23 | # the source code of your own applications.
24 |
25 | include $(MKPM)/mkpm
26 | include $(MKPM)/gnu
27 |
28 | export DOCKER_COMPOSE := docker-compose
29 | export CONTEXT := ..
30 | export NAME := bitspur/rock8s/integration-operator
31 | export REGISTRY := registry.gitlab.com
32 | export VERSION := 1.2.0
33 | export GIT_COMMIT ?= $(shell git describe --tags --always --dirty 2>/dev/null)
34 |
35 | include $(MKPM)/docker
36 |
37 | BUILDX ?= $(call ternary,$(WHICH) buildx,buildx,$(call ternary,$(WHICH) docker-buildx,docker-buildx,$(DOCKER) buildx))
38 |
39 | .PHONY: bake
40 | bake:
41 | @$(BUILDX) bake --provenance false
42 |
--------------------------------------------------------------------------------
/Mkpmfile:
--------------------------------------------------------------------------------
1 | # File: /Mkpmfile
2 | # Project: integration-operator
3 | # File Created: 13-10-2023 15:40:24
4 | # Author: Clay Risser
5 | # -----
6 | # BitSpur (c) Copyright 2021 - 2023
7 | #
8 | # Licensed under the GNU Affero General Public License (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # https://www.gnu.org/licenses/agpl-3.0.en.html
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 | #
20 | # You can be released from the requirements of the license by purchasing
21 | # a commercial license. Buying such a license is mandatory as soon as you
22 | # develop commercial activities involving this software without disclosing
23 | # the source code of your own applications.
24 |
25 | include $(MKPM)/mkpm
26 | include $(MKPM)/gnu
27 |
28 | CLOC ?= cloc
29 |
30 | .PHONY: of/% build generate manifests install uninstall start reinstall
31 | build: of/build
32 | dev: of/run
33 | generate: of/generate
34 | install: of/install
35 | manifests: generate of/manifests
36 | uninstall: of/uninstall
37 | reinstall: uninstall install
38 | of/%:
39 | @$(MAKE) -s $*
40 |
41 | .PHONY: count
42 | count:
43 | @$(CLOC) $(shell ($(GIT) ls-files && ($(GIT) lfs ls-files | $(CUT) -d' ' -f3)) | $(SORT) | $(UNIQ) -u)
44 |
45 | .PHONY: docker/%
46 | docker/%:
47 | @$(MAKE) -sC docker $*
48 |
--------------------------------------------------------------------------------
/config/default/manager_auth_proxy_patch.yaml:
--------------------------------------------------------------------------------
1 | # This patch inject a sidecar container which is a HTTP proxy for the
2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
3 | apiVersion: apps/v1
4 | kind: Deployment
5 | metadata:
6 | name: controller-manager
7 | namespace: system
8 | spec:
9 | template:
10 | spec:
11 | affinity:
12 | nodeAffinity:
13 | requiredDuringSchedulingIgnoredDuringExecution:
14 | nodeSelectorTerms:
15 | - matchExpressions:
16 | - key: kubernetes.io/arch
17 | operator: In
18 | values:
19 | - amd64
20 | - arm64
21 | - ppc64le
22 | - s390x
23 | - key: kubernetes.io/os
24 | operator: In
25 | values:
26 | - linux
27 | containers:
28 | - name: kube-rbac-proxy
29 | securityContext:
30 | allowPrivilegeEscalation: false
31 | capabilities:
32 | drop:
33 | - "ALL"
34 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1
35 | args:
36 | - "--secure-listen-address=0.0.0.0:8443"
37 | - "--upstream=http://127.0.0.1:8080/"
38 | - "--logtostderr=true"
39 | - "--v=0"
40 | ports:
41 | - containerPort: 8443
42 | protocol: TCP
43 | name: https
44 | resources:
45 | limits:
46 | cpu: 500m
47 | memory: 128Mi
48 | requests:
49 | cpu: 5m
50 | memory: 64Mi
51 | - name: manager
52 | args:
53 | - "--health-probe-bind-address=:8081"
54 | - "--metrics-bind-address=127.0.0.1:8080"
55 | - "--leader-elect"
56 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | # File: /.envrc
2 | # Project: integration-operator
3 | # File Created: 17-10-2023 10:51:29
4 | # Author: Clay Risser
5 | # -----
6 | # BitSpur (c) Copyright 2021 - 2023
7 | #
8 | # Licensed under the GNU Affero General Public License (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # https://www.gnu.org/licenses/agpl-3.0.en.html
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 | #
20 | # You can be released from the requirements of the license by purchasing
21 | # a commercial license. Buying such a license is mandatory as soon as you
22 | # develop commercial activities involving this software without disclosing
23 | # the source code of your own applications.
24 |
25 | export GO_VERSION="$(cat go.mod | grep -E '^go ' | sed 's|^go ||g')"
26 |
27 | use_golang() {
28 | export GVM_PKGSET=$(pwd | sed 's|.*\/||g')
29 | [[ -s "$GVM_ROOT/scripts/gvm" ]] && source "$GVM_ROOT/scripts/gvm"
30 | if ! (gvm list | grep -q "$GO_VERSION"); then
31 | INSTALL_LOG=$(mktemp)
32 | gvm install go$GO_VERSION -B 2>&1 | tee $INSTALL_LOG
33 | cat $INSTALL_LOG
34 | if (cat $INSTALL_LOG | grep -q "ERROR: Binary Go unavailable for this platform"); then
35 | gvm install go$GO_VERSION
36 | fi
37 | rm -rf $INSTALL_LOG 2>/dev/null || true
38 | fi
39 | gvm use go$GO_VERSION
40 | if ! (gvm pkgset list | grep -q "$GVM_PKGSET"); then
41 | gvm pkgset create $GVM_PKGSET
42 | fi
43 | gvm pkgset use $GVM_PKGSET
44 | }
45 |
46 | use_golang
47 |
--------------------------------------------------------------------------------
/api/v1beta1/groupversion_info.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /api/v1beta1/groupversion_info.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:35
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | // Package v1beta1 contains API Schema definitions for the integration v1beta1 API group
28 | // +kubebuilder:object:generate=true
29 | // +groupName=integration.rock8s.com
30 | package v1beta1
31 |
32 | import (
33 | "k8s.io/apimachinery/pkg/runtime/schema"
34 | "sigs.k8s.io/controller-runtime/pkg/scheme"
35 | )
36 |
37 | var (
38 | // GroupVersion is group version used to register these objects
39 | GroupVersion = schema.GroupVersion{Group: "integration.rock8s.com", Version: "v1beta1"}
40 |
41 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme
42 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
43 |
44 | // AddToScheme adds the types in this group-version to the given scheme.
45 | AddToScheme = SchemeBuilder.AddToScheme
46 | )
47 |
--------------------------------------------------------------------------------
/config/samples/integration_v1beta1_socket.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: integration.rock8s.com/v1beta1
2 | kind: Socket
3 | metadata:
4 | name: postgres
5 | namespace: postgres-namespace
6 | spec:
7 | interface:
8 | config:
9 | socket:
10 | protocol:
11 | required: true
12 | username:
13 | required: true
14 | password:
15 | required: true
16 | hostname:
17 | required: true
18 | port:
19 | required: true
20 | plug:
21 | database:
22 | required: true
23 | config:
24 | protocol: psql
25 | username: postgres
26 | hostname: postgres-service.postgres-namespace.svc.cluster.local
27 | port: "5432"
28 | configSecretName: postgres-secret
29 | resources:
30 | - when: [coupled, updated]
31 | do: recreate
32 | template:
33 | apiVersion: batch/v1
34 | kind: Job
35 | metadata:
36 | name: postgres-coupled-or-updated-{% .plug.metadata.namespace %}
37 | spec:
38 | template:
39 | spec:
40 | containers:
41 | - name: psql
42 | image: registry.gitlab.com/bitspur/rock8s/images/kube-commands-psql:0.0.1
43 | env:
44 | - name: POSTGRES_PROTOCOL
45 | value: "{% .socketConfig.protocol %}"
46 | - name: POSTGRES_USERNAME
47 | value: "{% .socketConfig.username %}"
48 | - name: POSTGRES_HOSTNAME
49 | value: "{% .socketConfig.hostname %}"
50 | - name: POSTGRES_PORT
51 | value: "{% .socketConfig.port %}"
52 | - name: POSTGRES_DATABASE
53 | value: "{% .plugConfig.database %}"
54 | - name: POSTGRES_PASSWORD
55 | value: "{% .socketConfig.password %}"
56 | command:
57 | - sh
58 | - -c
59 | - |
60 | export PGPASSFILE="/tmp/.pgpass"
61 | export STDOUT="/tmp/createdb.out"
62 | echo "*:*:*:*:$POSTGRES_PASSWORD" > $PGPASSFILE
63 | chmod 600 $PGPASSFILE
64 | createdb -h $POSTGRES_HOSTNAME -U $POSTGRES_USERNAME -p $POSTGRES_PORT -w $POSTGRES_DATABASE || true
65 |
--------------------------------------------------------------------------------
/mkpm:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | MKPM_VERSION="1.1.0"
4 | MKPM_SH_URL="${MKPM_SH_URL:-https://gitlab.com/api/v4/projects/48207162/packages/generic/mkpm/${MKPM_VERSION}/mkpm.sh}"
5 | alias download="$(curl --version >/dev/null 2>&1 && echo curl -Lo || echo wget -O)"
6 | alias echo="$([ "$(echo -e)" = "-e" ] && echo "echo" || echo "echo -e")"
7 | _SUPPORTS_COLORS=$( (which tput >/dev/null 2>&1 && [ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]) && echo 1 || true)
8 | _CWD="$(pwd)"
9 | if [ "$_SUPPORTS_COLORS" = "1" ]; then
10 | export C_END='\033[0m'
11 | export C_RED='\033[31m'
12 | export C_YELLOW='\033[33m'
13 | fi
14 | _error() { echo "${C_RED}MKPM [E]:${C_END} $@" 1>&2; }
15 | _debug() { [ "$MKPM_DEBUG" = "1" ] && echo "${C_YELLOW}MKPM [D]:${C_END} $@" || true; }
16 | _project_root() {
17 | _ROOT="$1"
18 | if [ "$_ROOT" = "" ]; then
19 | _ROOT="$(pwd)"
20 | fi
21 | if [ -f "$_ROOT/mkpm.json" ]; then
22 | echo "$_ROOT"
23 | return
24 | fi
25 | _PARENT="$(echo "$_ROOT" | sed 's|\/[^\/]\+$||g')"
26 | if ([ "$_PARENT" = "" ] || [ "$_PARENT" = "/" ]); then
27 | echo "/"
28 | return
29 | fi
30 | echo "$(_project_root "$_PARENT")"
31 | return
32 | }
33 | _is_mkpm_proxy_required() {
34 | while test $# -gt 0; do
35 | case "$1" in
36 | -h | --help)
37 | return 1
38 | ;;
39 | -*)
40 | shift
41 | ;;
42 | v | version | init)
43 | return 1
44 | ;;
45 | *)
46 | break
47 | ;;
48 | esac
49 | done
50 | [ "$1" = "" ] && return 1 || true
51 | }
52 | export PROJECT_ROOT="$(_project_root)"
53 | if [ "$PROJECT_ROOT" = "/" ]; then
54 | if _is_mkpm_proxy_required "$@"; then
55 | _error "not an mkpm project" && exit 1
56 | else
57 | PROJECT_ROOT="$_CWD"
58 | fi
59 | fi
60 | MKPM_ROOT="$PROJECT_ROOT/.mkpm"
61 | MKPM="$MKPM_ROOT/mkpm"
62 | MKPM_BIN="$MKPM/.bin"
63 | if [ ! -f "$MKPM_BIN/mkpm" ]; then
64 | mkdir -p "$MKPM_BIN"
65 | if [ -f "$MKPM_ROOT/cache.tar.gz" ]; then
66 | mkdir -p "$MKPM"
67 | cd "$MKPM"
68 | tar -xzf "$MKPM_ROOT/cache.tar.gz"
69 | cd "$_CWD"
70 | _debug restored cache
71 | else
72 | download "$MKPM_BIN/mkpm" "$MKPM_SH_URL" >/dev/null
73 | _debug downloaded mkpm.sh
74 | fi
75 | chmod +x "$MKPM_BIN/mkpm"
76 | fi
77 | exec "$MKPM_BIN/mkpm" "$@"
78 |
--------------------------------------------------------------------------------
/images/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
62 |
--------------------------------------------------------------------------------
/config/rbac/role.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | creationTimestamp: null
6 | name: manager-role
7 | rules:
8 | - apiGroups:
9 | - ""
10 | resources:
11 | - configmaps
12 | - secrets
13 | verbs:
14 | - get
15 | - list
16 | - watch
17 | - apiGroups:
18 | - ""
19 | resources:
20 | - events
21 | verbs:
22 | - create
23 | - delete
24 | - get
25 | - list
26 | - patch
27 | - update
28 | - watch
29 | - apiGroups:
30 | - ""
31 | resources:
32 | - pods
33 | - services
34 | verbs:
35 | - create
36 | - delete
37 | - get
38 | - list
39 | - patch
40 | - update
41 | - watch
42 | - apiGroups:
43 | - ""
44 | resources:
45 | - serviceaccounts
46 | verbs:
47 | - impersonate
48 | - apiGroups:
49 | - coordination.k8s.io
50 | resources:
51 | - leases
52 | verbs:
53 | - create
54 | - delete
55 | - get
56 | - list
57 | - patch
58 | - update
59 | - watch
60 | - apiGroups:
61 | - integration.rock8s.com
62 | resources:
63 | - deferredresources
64 | verbs:
65 | - create
66 | - delete
67 | - get
68 | - list
69 | - patch
70 | - update
71 | - watch
72 | - apiGroups:
73 | - integration.rock8s.com
74 | resources:
75 | - deferredresources/finalizers
76 | verbs:
77 | - update
78 | - apiGroups:
79 | - integration.rock8s.com
80 | resources:
81 | - deferredresources/status
82 | verbs:
83 | - get
84 | - patch
85 | - update
86 | - apiGroups:
87 | - integration.rock8s.com
88 | resources:
89 | - plugs
90 | verbs:
91 | - create
92 | - delete
93 | - get
94 | - list
95 | - patch
96 | - update
97 | - watch
98 | - apiGroups:
99 | - integration.rock8s.com
100 | resources:
101 | - plugs/finalizers
102 | verbs:
103 | - update
104 | - apiGroups:
105 | - integration.rock8s.com
106 | resources:
107 | - plugs/status
108 | verbs:
109 | - get
110 | - patch
111 | - update
112 | - apiGroups:
113 | - integration.rock8s.com
114 | resources:
115 | - sockets
116 | verbs:
117 | - create
118 | - delete
119 | - get
120 | - list
121 | - patch
122 | - update
123 | - watch
124 | - apiGroups:
125 | - integration.rock8s.com
126 | resources:
127 | - sockets/finalizers
128 | verbs:
129 | - update
130 | - apiGroups:
131 | - integration.rock8s.com
132 | resources:
133 | - sockets/status
134 | verbs:
135 | - get
136 | - patch
137 | - update
138 |
--------------------------------------------------------------------------------
/chart/questions.yaml:
--------------------------------------------------------------------------------
1 | categories:
2 | - Server
3 | questions:
4 | # Config
5 | - variable: config.imagePullPolicy
6 | description: ""
7 | type: enum
8 | options:
9 | - IfNotPresent
10 | - Always
11 | required: true
12 | label: "pull policy"
13 | group: Config
14 | - variable: config.updateStrategy
15 | description: ""
16 | type: enum
17 | options:
18 | - RollingUpdate
19 | - Recreate
20 | - OnDelete
21 | required: true
22 | label: "update strategy"
23 | group: Config
24 | - variable: config.debug
25 | description: ""
26 | type: boolean
27 | required: true
28 | label: debug
29 | group: Config
30 | - variable: config.replicas
31 | description: ""
32 | type: int
33 | required: true
34 | label: "replicas"
35 | group: Config
36 | - variable: config.maxConcurrentReconciles
37 | description: ""
38 | type: int
39 | required: true
40 | label: "max concurrent reconciles"
41 | group: Config
42 | - variable: config.resourceBindingOperator.resources.enabled
43 | description: ""
44 | type: enum
45 | options:
46 | - defaults
47 | - custom
48 | - "false"
49 | required: true
50 | label: "resource binding operator resources enabled"
51 | show_subquestion_if: custom
52 | group: Config
53 | subquestions:
54 | - variable: config.resourceBindingOperator.resources.requests.cpu
55 | description: ""
56 | type: string
57 | required: true
58 | label: "resource binding operator resources requests cpu"
59 | - variable: config.resourceBindingOperator.resources.requests.memory
60 | description: ""
61 | type: string
62 | required: true
63 | label: "resource binding operator resources requests memory"
64 | - variable: config.resourceBindingOperator.resources.limits.cpu
65 | description: ""
66 | type: string
67 | required: true
68 | label: "resource binding operator resources limits cpu"
69 | - variable: config.resourceBindingOperator.resources.limits.memory
70 | description: ""
71 | type: string
72 | required: true
73 | label: "resource binding operator resources limits memory"
74 |
75 | # Images
76 | - variable: images.resourceBindingOperator.repository
77 | description: ""
78 | type: string
79 | required: true
80 | label: "resource binding operator repository"
81 | group: Images
82 | - variable: images.resourceBindingOperator.tag
83 | description: ""
84 | type: string
85 | required: true
86 | label: "resource binding operator tag"
87 | group: Images
88 |
--------------------------------------------------------------------------------
/config/default/kustomization.yaml:
--------------------------------------------------------------------------------
1 | # Adds namespace to all resources.
2 | namespace: rock8s-system
3 |
4 | # Value of this field is prepended to the
5 | # names of all resources, e.g. a deployment named
6 | # "wordpress" becomes "alices-wordpress".
7 | # Note that it should also match with the prefix (text before '-') of the namespace
8 | # field above.
9 | namePrefix: rock8s-
10 |
11 | # Labels to add to all resources and selectors.
12 | #commonLabels:
13 | # someName: someValue
14 |
15 | bases:
16 | - ../crd
17 | - ../rbac
18 | - ../manager
19 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
20 | # crd/kustomization.yaml
21 | #- ../webhook
22 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
23 | #- ../certmanager
24 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
25 | #- ../prometheus
26 |
27 | patchesStrategicMerge:
28 | # Protect the /metrics endpoint by putting it behind auth.
29 | # If you want your controller-manager to expose the /metrics
30 | # endpoint w/o any authn/z, please comment the following line.
31 | - manager_auth_proxy_patch.yaml
32 |
33 |
34 |
35 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
36 | # crd/kustomization.yaml
37 | #- manager_webhook_patch.yaml
38 |
39 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
40 | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
41 | # 'CERTMANAGER' needs to be enabled to use ca injection
42 | #- webhookcainjection_patch.yaml
43 |
44 | # the following config is for teaching kustomize how to do var substitution
45 | vars: []
46 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
47 | #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
48 | # objref:
49 | # kind: Certificate
50 | # group: cert-manager.io
51 | # version: v1
52 | # name: serving-cert # this name should match the one in certificate.yaml
53 | # fieldref:
54 | # fieldpath: metadata.namespace
55 | #- name: CERTIFICATE_NAME
56 | # objref:
57 | # kind: Certificate
58 | # group: cert-manager.io
59 | # version: v1
60 | # name: serving-cert # this name should match the one in certificate.yaml
61 | #- name: SERVICE_NAMESPACE # namespace of the service
62 | # objref:
63 | # kind: Service
64 | # version: v1
65 | # name: webhook-service
66 | # fieldref:
67 | # fieldpath: metadata.namespace
68 | #- name: SERVICE_NAME
69 | # objref:
70 | # kind: Service
71 | # version: v1
72 | # name: webhook-service
73 |
--------------------------------------------------------------------------------
/coupler/decouple.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/decouple.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 18:17:21
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | "gitlab.com/bitspur/rock8s/integration-operator/util"
34 | "k8s.io/client-go/tools/record"
35 | ctrl "sigs.k8s.io/controller-runtime"
36 | "sigs.k8s.io/controller-runtime/pkg/client"
37 | )
38 |
39 | func Decouple(
40 | client *client.Client,
41 | ctx context.Context,
42 | req *ctrl.Request,
43 | plugUtil *util.PlugUtil,
44 | socketUtil *util.SocketUtil,
45 | plug *integrationv1beta1.Plug,
46 | socket *integrationv1beta1.Socket,
47 | recorder record.EventRecorder,
48 | ) error {
49 | configUtil := util.NewConfigUtil(ctx)
50 | if plug == nil {
51 | var err error
52 | plug, err = plugUtil.Get()
53 | if err != nil {
54 | return err
55 | }
56 | }
57 | if socket == nil {
58 | var err error
59 | socket, err = socketUtil.Get()
60 | if err != nil {
61 | return err
62 | }
63 | }
64 |
65 | plugConfig, err := configUtil.GetPlugConfig(plug, socket)
66 | if err != nil {
67 | return err
68 | }
69 | socketConfig, err := configUtil.GetSocketConfig(plug, socket)
70 | if err != nil {
71 | socketUtil.Error(err, socket)
72 | return err
73 | }
74 |
75 | if err := DecoupledPlug(plug, socket, plugConfig, socketConfig, recorder); err != nil {
76 | return err
77 | }
78 | if err := DecoupledSocket(plug, socket, plugConfig, socketConfig, recorder); err != nil {
79 | socketUtil.Error(err, socket)
80 | return err
81 | }
82 |
83 | if _, err := socketUtil.UpdateRemoveCoupledPlugStatus(plug.UID, socket, false); err != nil {
84 | return err
85 | }
86 | return nil
87 | }
88 |
--------------------------------------------------------------------------------
/coupler/update.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/update.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 16:09:52
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | "gitlab.com/bitspur/rock8s/integration-operator/util"
34 | "k8s.io/client-go/tools/record"
35 | ctrl "sigs.k8s.io/controller-runtime"
36 | "sigs.k8s.io/controller-runtime/pkg/client"
37 | )
38 |
39 | func Update(
40 | client *client.Client,
41 | ctx context.Context,
42 | req *ctrl.Request,
43 | plugUtil *util.PlugUtil,
44 | socketUtil *util.SocketUtil,
45 | plug *integrationv1beta1.Plug,
46 | socket *integrationv1beta1.Socket,
47 | recorder record.EventRecorder,
48 | ) error {
49 | configUtil := util.NewConfigUtil(ctx)
50 | if plug == nil {
51 | var err error
52 | plug, err = plugUtil.Get()
53 | if err != nil {
54 | return err
55 | }
56 | }
57 | if socket == nil {
58 | var err error
59 | socket, err = socketUtil.Get()
60 | if err != nil {
61 | return err
62 | }
63 | }
64 |
65 | if !socketUtil.CoupledPlugExists(socket.Status.CoupledPlugs, plug.UID) || plug.Status.CoupledSocket == nil {
66 | return nil
67 | }
68 |
69 | plugConfig, err := configUtil.GetPlugConfig(plug, socket)
70 | if err != nil {
71 | return err
72 | }
73 | socketConfig, err := configUtil.GetSocketConfig(plug, socket)
74 | if err != nil {
75 | socketUtil.Error(err, socket)
76 | return err
77 | }
78 |
79 | if err = UpdatedPlug(plug, socket, plugConfig, socketConfig, recorder); err != nil {
80 | return err
81 | }
82 | if err = UpdatedSocket(plug, socket, plugConfig, socketConfig, recorder); err != nil {
83 | socketUtil.Error(err, socket)
84 | return err
85 | }
86 |
87 | return nil
88 | }
89 |
--------------------------------------------------------------------------------
/util/main.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/main.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
31 | "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
32 | )
33 |
34 | var (
35 | decUnstructured = yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
36 | )
37 |
38 | type ConditionCoupledReason string
39 |
40 | const (
41 | CouplingInProcess ConditionCoupledReason = "CouplingInProcess"
42 | CouplingSucceeded ConditionCoupledReason = "CouplingSucceeded"
43 | Error ConditionCoupledReason = "Error"
44 | PlugCreated ConditionCoupledReason = "PlugCreated"
45 | SocketCoupled ConditionCoupledReason = "SocketCoupled"
46 | SocketCreated ConditionCoupledReason = "SocketCreated"
47 | SocketEmpty ConditionCoupledReason = "SocketEmpty"
48 | SocketNotCreated ConditionCoupledReason = "SocketNotCreated"
49 | UpdatingInProcess ConditionCoupledReason = "UpdatingInProcess"
50 | )
51 |
52 | type ConditionType string
53 |
54 | const (
55 | ConditionTypeCoupled ConditionType = "Coupled"
56 | ConditionTypeFailed ConditionType = "Failed"
57 | )
58 |
59 | type DeferredResourceConditionResolvedReason string
60 |
61 | const (
62 | DeferredResourcePending DeferredResourceConditionResolvedReason = "Pending"
63 | DeferredResourceError DeferredResourceConditionResolvedReason = "Error"
64 | DeferredResourceSuccess DeferredResourceConditionResolvedReason = "Success"
65 | )
66 |
67 | type DeferredResourceConditionType string
68 |
69 | const (
70 | DeferredResourceConditionTypeResolved ConditionType = "Resolved"
71 | DeferredResourceConditionTypeFailed ConditionType = "Failed"
72 | )
73 |
74 | type Config map[string]string
75 |
76 | type Result map[string]string
77 |
--------------------------------------------------------------------------------
/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "psi-header.variables": [["projectCreationYear", "2021"]],
3 | "psi-header.config": {
4 | "blankLinesAfter": 1,
5 | "company": "BitSpur",
6 | "copyrightHolder": "BitSpur",
7 | "creationDateZero": "asIs",
8 | "forceToTop": true,
9 | "initials": "CR",
10 | "license": "Custom"
11 | },
12 | "psi-header.license-text": [
13 | " Licensed under the Apache License, Version 2.0 (the \"License\");",
14 | " you may not use this file except in compliance with the License.",
15 | " You may obtain a copy of the License at",
16 | "",
17 | " http://www.apache.org/licenses/LICENSE-2.0",
18 | "",
19 | " Unless required by applicable law or agreed to in writing, software",
20 | " distributed under the License is distributed on an \"AS IS\" BASIS,",
21 | " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
22 | " See the License for the specific language governing permissions and",
23 | " limitations under the License."
24 | ],
25 | "psi-header.templates": [
26 | {
27 | "language": "*",
28 | "template": [
29 | " File: <>",
30 | " Project: <>",
31 | " File Created: <>",
32 | " Author: <>",
33 | " -----",
34 | " <> (c) Copyright <>, now)>>",
35 | "",
36 | "<>"
37 | ]
38 | }
39 | ],
40 | "psi-header.lang-config": [
41 | {
42 | "language": "*",
43 | "begin": "/**",
44 | "blankLinesAfter": 1,
45 | "end": " */",
46 | "forceToTop": true,
47 | "lineLength": 80,
48 | "modAuthor": "Modified By:",
49 | "modDate": "Last Modified:",
50 | "modDateFormat": "dd-MM-yyyy HH:mm:ss",
51 | "prefix": " *",
52 | "replace": ["File:"],
53 | "rootDirFileName": "LICENSE",
54 | "suffix": ""
55 | },
56 | {
57 | "language": "makefile",
58 | "begin": "",
59 | "blankLinesAfter": 1,
60 | "end": "",
61 | "forceToTop": true,
62 | "lineLength": 80,
63 | "modAuthor": "Modified By:",
64 | "modDate": "Last Modified:",
65 | "modDateFormat": "dd-MM-yyyy HH:mm:ss",
66 | "prefix": "#",
67 | "replace": ["File:"],
68 | "rootDirFileName": "LICENSE",
69 | "suffix": ""
70 | }
71 | ],
72 | "psi-header.changes-tracking": {
73 | "autoHeader": "autoSave",
74 | "enforceHeader": true,
75 | "include": ["javascript", "makefile", "typescript", "typescriptreact"],
76 | "isActive": true,
77 | "modAuthor": "Modified By:",
78 | "modDate": "Last Modified:",
79 | "modDateFormat": "dd-MM-yyyy hh:nn:ss",
80 | "replace": ["Filename:"],
81 | "updateLicenseVariables": true
82 | },
83 | "psi-header.license-reference": {
84 | "uri": "../LICENSE",
85 | "uriIsLocalFile": true
86 | },
87 | "files.associations": {
88 | "Mkpmfile": "makefile"
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/controllers/suite_test.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /controllers/suite_test.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:35
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package controllers
28 |
29 | import (
30 | "path/filepath"
31 | "testing"
32 |
33 | . "github.com/onsi/ginkgo/v2"
34 | . "github.com/onsi/gomega"
35 |
36 | "k8s.io/client-go/kubernetes/scheme"
37 | "k8s.io/client-go/rest"
38 | "sigs.k8s.io/controller-runtime/pkg/client"
39 | "sigs.k8s.io/controller-runtime/pkg/envtest"
40 | logf "sigs.k8s.io/controller-runtime/pkg/log"
41 | "sigs.k8s.io/controller-runtime/pkg/log/zap"
42 |
43 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
44 | //+kubebuilder:scaffold:imports
45 | )
46 |
47 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to
48 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
49 |
50 | var cfg *rest.Config
51 | var k8sClient client.Client
52 | var testEnv *envtest.Environment
53 |
54 | func TestAPIs(t *testing.T) {
55 | RegisterFailHandler(Fail)
56 |
57 | RunSpecs(t, "Controller Suite")
58 | }
59 |
60 | var _ = BeforeSuite(func() {
61 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
62 |
63 | By("bootstrapping test environment")
64 | testEnv = &envtest.Environment{
65 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
66 | ErrorIfCRDPathMissing: true,
67 | }
68 |
69 | var err error
70 | // cfg is defined in this file globally.
71 | cfg, err = testEnv.Start()
72 | Expect(err).NotTo(HaveOccurred())
73 | Expect(cfg).NotTo(BeNil())
74 |
75 | err = integrationv1beta1.AddToScheme(scheme.Scheme)
76 | Expect(err).NotTo(HaveOccurred())
77 |
78 | //+kubebuilder:scaffold:scheme
79 |
80 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
81 | Expect(err).NotTo(HaveOccurred())
82 | Expect(k8sClient).NotTo(BeNil())
83 |
84 | })
85 |
86 | var _ = AfterSuite(func() {
87 | By("tearing down the test environment")
88 | err := testEnv.Stop()
89 | Expect(err).NotTo(HaveOccurred())
90 | })
91 |
--------------------------------------------------------------------------------
/coupler/plug.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/plug.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 15:20:41
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | "gitlab.com/bitspur/rock8s/integration-operator/util"
34 | "k8s.io/client-go/tools/record"
35 | )
36 |
37 | func CreatedPlug(
38 | plug *integrationv1beta1.Plug,
39 | recorder record.EventRecorder,
40 | ) error {
41 | ctx, cancel := context.WithCancel(context.Background())
42 | defer cancel()
43 | eventUtil := util.NewEventUtil(ctx)
44 | return eventUtil.PlugCreated(plug, recorder)
45 | }
46 |
47 | func DeletedPlug(
48 | plug *integrationv1beta1.Plug,
49 | recorder record.EventRecorder,
50 | ) error {
51 | ctx, cancel := context.WithCancel(context.Background())
52 | defer cancel()
53 | eventUtil := util.NewEventUtil(ctx)
54 | return eventUtil.PlugDeleted(plug, recorder)
55 | }
56 |
57 | func CoupledPlug(
58 | plug *integrationv1beta1.Plug,
59 | socket *integrationv1beta1.Socket,
60 | plugConfig util.Config,
61 | socketConfig util.Config,
62 | recorder record.EventRecorder,
63 | ) error {
64 | ctx, cancel := context.WithCancel(context.Background())
65 | defer cancel()
66 | eventUtil := util.NewEventUtil(ctx)
67 | return eventUtil.PlugCoupled(plug, socket, &plugConfig, &socketConfig, recorder)
68 | }
69 |
70 | func UpdatedPlug(
71 | plug *integrationv1beta1.Plug,
72 | socket *integrationv1beta1.Socket,
73 | plugConfig util.Config,
74 | socketConfig util.Config,
75 | recorder record.EventRecorder,
76 | ) error {
77 | ctx, cancel := context.WithCancel(context.Background())
78 | defer cancel()
79 | eventUtil := util.NewEventUtil(ctx)
80 | return eventUtil.PlugUpdated(plug, socket, &plugConfig, &socketConfig, recorder)
81 | }
82 |
83 | func DecoupledPlug(
84 | plug *integrationv1beta1.Plug,
85 | socket *integrationv1beta1.Socket,
86 | plugConfig util.Config,
87 | socketConfig util.Config,
88 | recorder record.EventRecorder,
89 | ) error {
90 | ctx, cancel := context.WithCancel(context.Background())
91 | defer cancel()
92 | eventUtil := util.NewEventUtil(ctx)
93 | return eventUtil.PlugDecoupled(plug, socket, &plugConfig, &socketConfig, recorder)
94 | }
95 |
--------------------------------------------------------------------------------
/chart/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: {{ template "integration-operator.name" . }}
5 | labels:
6 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
7 | helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
8 | app.kubernetes.io/instance: {{ .Release.Name }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | spec:
11 | selector:
12 | matchLabels:
13 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
14 | app.kubernetes.io/instance: {{ .Release.Name }}
15 | replicas: {{ .Values.config.replicas }}
16 | strategy:
17 | type: {{ .Values.config.updateStrategy }}
18 | template:
19 | metadata:
20 | labels:
21 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
22 | app.kubernetes.io/instance: {{ .Release.Name }}
23 | spec:
24 | serviceAccountName: {{ template "integration-operator.name" . }}
25 | affinity:
26 | nodeAffinity:
27 | requiredDuringSchedulingIgnoredDuringExecution:
28 | nodeSelectorTerms:
29 | - matchExpressions:
30 | - key: kubernetes.io/arch
31 | operator: In
32 | values:
33 | - amd64
34 | containers:
35 | - image: {{ .Values.images.resourceBindingOperator.repository }}:{{ .Values.images.resourceBindingOperator.tag }}
36 | imagePullPolicy: {{ .Values.config.imagePullPolicy }}
37 | name: {{ template "integration-operator.name" . }}
38 | args:
39 | - '--leader-elect'
40 | - '--health-probe-bind-address=:8081'
41 | - '--zap-devel={{ .Values.config.debug | ternary "true" "false" }}'
42 | {{- if (and .Values.config.resourceBindingOperator.resources.enabled (not (eq .Values.config.resourceBindingOperator.resources.enabled "false"))) }}
43 | resources:
44 | requests:
45 | {{ toYaml .Values.config.resourceBindingOperator.resources.requests | indent 14 }}
46 | limits:
47 | {{ toYaml .Values.config.resourceBindingOperator.resources.limits | indent 14 }}
48 | {{- else }}
49 | resources: {}
50 | {{- end }}
51 | env:
52 | - name: WATCH_NAMESPACE
53 | valueFrom:
54 | fieldRef:
55 | fieldPath: "metadata.annotations['olm.targetNamespaces']"
56 | - name: POD_NAME
57 | valueFrom:
58 | fieldRef:
59 | fieldPath: metadata.name
60 | - name: OPERATOR_NAME
61 | value: integration-operator
62 | - name: MAX_CONCURRENT_RECONCILES
63 | value: {{ .Values.config.maxConcurrentReconciles | quote }}
64 | nodeSelector:
65 | beta.kubernetes.io/os: linux
66 | livenessProbe:
67 | httpGet:
68 | path: /healthz
69 | port: 8081
70 | initialDelaySeconds: 15
71 | periodSeconds: 20
72 | readinessProbe:
73 | httpGet:
74 | path: /readyz
75 | port: 8081
76 | initialDelaySeconds: 5
77 | periodSeconds: 10
78 |
--------------------------------------------------------------------------------
/coupler/socket.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/socket.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 15:20:41
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | "gitlab.com/bitspur/rock8s/integration-operator/util"
34 | "k8s.io/client-go/tools/record"
35 | )
36 |
37 | func CreatedSocket(
38 | socket *integrationv1beta1.Socket,
39 | recorder record.EventRecorder,
40 | ) error {
41 | ctx, cancel := context.WithCancel(context.Background())
42 | defer cancel()
43 | eventUtil := util.NewEventUtil(ctx)
44 | return eventUtil.SocketCreated(socket, recorder)
45 | }
46 |
47 | func DeletedSocket(
48 | socket *integrationv1beta1.Socket,
49 | recorder record.EventRecorder,
50 | ) error {
51 | ctx, cancel := context.WithCancel(context.Background())
52 | defer cancel()
53 | eventUtil := util.NewEventUtil(ctx)
54 | return eventUtil.SocketDeleted(socket, recorder)
55 | }
56 |
57 | func CoupledSocket(
58 | plug *integrationv1beta1.Plug,
59 | socket *integrationv1beta1.Socket,
60 | plugConfig util.Config,
61 | socketConfig util.Config,
62 | recorder record.EventRecorder,
63 | ) error {
64 | ctx, cancel := context.WithCancel(context.Background())
65 | defer cancel()
66 | eventUtil := util.NewEventUtil(ctx)
67 | return eventUtil.SocketCoupled(plug, socket, &plugConfig, &socketConfig, recorder)
68 | }
69 |
70 | func UpdatedSocket(
71 | plug *integrationv1beta1.Plug,
72 | socket *integrationv1beta1.Socket,
73 | plugConfig util.Config,
74 | socketConfig util.Config,
75 | recorder record.EventRecorder,
76 | ) error {
77 | ctx, cancel := context.WithCancel(context.Background())
78 | defer cancel()
79 | eventUtil := util.NewEventUtil(ctx)
80 | return eventUtil.SocketUpdated(plug, socket, &plugConfig, &socketConfig, recorder)
81 | }
82 |
83 | func DecoupledSocket(
84 | plug *integrationv1beta1.Plug,
85 | socket *integrationv1beta1.Socket,
86 | plugConfig util.Config,
87 | socketConfig util.Config,
88 | recorder record.EventRecorder,
89 | ) error {
90 | ctx, cancel := context.WithCancel(context.Background())
91 | defer cancel()
92 | eventUtil := util.NewEventUtil(ctx)
93 | return eventUtil.SocketDecoupled(plug, socket, &plugConfig, &socketConfig, recorder)
94 | }
95 |
--------------------------------------------------------------------------------
/util/data.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/data.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 | "k8s.io/client-go/kubernetes"
35 | ctrl "sigs.k8s.io/controller-runtime"
36 | )
37 |
38 | type DataUtil struct {
39 | client *kubernetes.Clientset
40 | ctx context.Context
41 | }
42 |
43 | func NewDataUtil(ctx context.Context) *DataUtil {
44 | return &DataUtil{
45 | client: kubernetes.NewForConfigOrDie(ctrl.GetConfigOrDie()),
46 | }
47 | }
48 |
49 | func (u *DataUtil) GetPlugData(plug *integrationv1beta1.Plug) (map[string]string, error) {
50 | plugData := make(map[string]string)
51 | if plug.Spec.DataSecretName != "" {
52 | secret, err := u.client.CoreV1().Secrets(plug.Namespace).Get(
53 | u.ctx,
54 | plug.Spec.DataSecretName,
55 | metav1.GetOptions{},
56 | )
57 | if err != nil {
58 | return nil, err
59 | }
60 | for key, value := range secret.Data {
61 | plugData[key] = string(value)
62 | }
63 | }
64 | if plug.Spec.Data != nil {
65 | for key, value := range plug.Spec.Data {
66 | plugData[key] = value
67 | }
68 | }
69 | if plug.Spec.ConfigConfigMapName != "" {
70 | configMap, err := u.client.CoreV1().ConfigMaps(plug.Namespace).Get(
71 | u.ctx,
72 | plug.Spec.ConfigConfigMapName,
73 | metav1.GetOptions{},
74 | )
75 | if err != nil {
76 | return nil, err
77 | }
78 | for key, value := range configMap.Data {
79 | plugData[key] = value
80 | }
81 | }
82 | return plugData, nil
83 | }
84 |
85 | func (u *DataUtil) GetSocketData(socket *integrationv1beta1.Socket) (map[string]string, error) {
86 | socketData := make(map[string]string)
87 | if socket.Spec.DataSecretName != "" {
88 | secret, err := u.client.CoreV1().Secrets(socket.Namespace).Get(
89 | u.ctx,
90 | socket.Spec.DataSecretName,
91 | metav1.GetOptions{},
92 | )
93 | if err != nil {
94 | return nil, err
95 | }
96 | for key, value := range secret.Data {
97 | socketData[key] = string(value)
98 | }
99 | }
100 | if socket.Spec.Data != nil {
101 | for key, value := range socket.Spec.Data {
102 | socketData[key] = value
103 | }
104 | }
105 | if socket.Spec.ConfigConfigMapName != "" {
106 | configMap, err := u.client.CoreV1().ConfigMaps(socket.Namespace).Get(
107 | u.ctx,
108 | socket.Spec.DataConfigMapName,
109 | metav1.GetOptions{},
110 | )
111 | if err != nil {
112 | return nil, err
113 | }
114 | for key, value := range configMap.Data {
115 | socketData[key] = value
116 | }
117 | }
118 | return socketData, nil
119 | }
120 |
--------------------------------------------------------------------------------
/api/v1beta1/deferredresource_types.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /api/v1beta1/deferredresource_types.go
3 | * Project: integration-operator
4 | * File Created: 17-12-2023 11:14:58
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package v1beta1
28 |
29 | import (
30 | apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
31 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 | "sigs.k8s.io/kustomize/api/resid"
33 | )
34 |
35 | // DeferredResourceSpec defines the desired state of DeferredResource
36 | type DeferredResourceSpec struct {
37 | // Timeout is the maximum time to wait before creating the resource
38 | Timeout int64 `json:"timeout,omitempty"`
39 |
40 | // WaitFor is a list of resources to wait for before creating the resource
41 | WaitFor *[]*WaitForTarget `json:"waitFor,omitempty"`
42 |
43 | // Resource is the resource to create after the defer is resolved
44 | Resource *apiextv1.JSON `json:"resource,omitempty"`
45 | // ServiceAccountName is the name of the ServiceAccount to use to create deferred resources from.
46 | // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
47 | // +optional
48 | ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"`
49 | }
50 |
51 | // DeferredResourceStatus defines the observed state of DeferredResource
52 | type DeferredResourceStatus struct {
53 | Conditions []metav1.Condition `json:"conditions,omitempty"`
54 | OwnerReference metav1.OwnerReference `json:"ownerReferences,omitempty"`
55 | }
56 |
57 | //+kubebuilder:object:root=true
58 | //+kubebuilder:subresource:status
59 |
60 | // DeferredResource is the Schema for the deferredresources API
61 | type DeferredResource struct {
62 | metav1.TypeMeta `json:",inline"`
63 | metav1.ObjectMeta `json:"metadata,omitempty"`
64 |
65 | Spec DeferredResourceSpec `json:"spec,omitempty"`
66 | Status DeferredResourceStatus `json:"status,omitempty"`
67 | }
68 |
69 | //+kubebuilder:object:root=true
70 |
71 | // DeferredResourceList contains a list of DeferredResource
72 | type DeferredResourceList struct {
73 | metav1.TypeMeta `json:",inline"`
74 | metav1.ListMeta `json:"metadata,omitempty"`
75 | Items []DeferredResource `json:"items"`
76 | }
77 |
78 | // Target refers to a kubernetes object by Group, Version, Kind and Name
79 | // gvk.Gvk contains Group, Version and Kind
80 | // APIVersion is added to keep the backward compatibility of using ObjectReference
81 | // for Var.ObjRef
82 | type WaitForTarget struct {
83 | resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
84 | APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
85 | Name string `json:"name,omitempty" yaml:"name,omitempty"`
86 | }
87 |
88 | func init() {
89 | SchemeBuilder.Register(&DeferredResource{}, &DeferredResourceList{})
90 | }
91 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "psi-header.variables": [["projectCreationYear", "2021"]],
3 | "psi-header.config": {
4 | "blankLinesAfter": 1,
5 | "company": "BitSpur",
6 | "copyrightHolder": "BitSpur",
7 | "creationDateZero": "asIs",
8 | "forceToTop": true,
9 | "initials": "CR",
10 | "license": "Custom"
11 | },
12 | "psi-header.license-text": [
13 | " Licensed under the GNU Affero General Public License (the \"License\");",
14 | " you may not use this file except in compliance with the License.",
15 | " You may obtain a copy of the License at",
16 | "",
17 | " https://www.gnu.org/licenses/agpl-3.0.en.html",
18 | "",
19 | " Unless required by applicable law or agreed to in writing, software",
20 | " distributed under the License is distributed on an \"AS IS\" BASIS,",
21 | " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
22 | " See the License for the specific language governing permissions and",
23 | " limitations under the License.",
24 | "",
25 | " You can be released from the requirements of the license by purchasing",
26 | " a commercial license. Buying such a license is mandatory as soon as you",
27 | " develop commercial activities involving this software without disclosing",
28 | " the source code of your own applications."
29 | ],
30 | "psi-header.templates": [
31 | {
32 | "language": "*",
33 | "template": [
34 | " File: <>",
35 | " Project: <>",
36 | " File Created: <>",
37 | " Author: <>",
38 | " -----",
39 | " <> (c) Copyright <>, now)>>",
40 | "",
41 | "<>"
42 | ]
43 | }
44 | ],
45 | "psi-header.lang-config": [
46 | {
47 | "language": "*",
48 | "begin": "/**",
49 | "blankLinesAfter": 1,
50 | "end": " */",
51 | "forceToTop": true,
52 | "lineLength": 80,
53 | "modAuthor": "Modified By:",
54 | "modDate": "Last Modified:",
55 | "modDateFormat": "dd-MM-yyyy HH:mm:ss",
56 | "prefix": " *",
57 | "replace": ["File:"],
58 | "rootDirFileName": "LICENSE",
59 | "suffix": ""
60 | },
61 | {
62 | "language": "makefile",
63 | "begin": "",
64 | "blankLinesAfter": 1,
65 | "end": "",
66 | "forceToTop": true,
67 | "lineLength": 80,
68 | "modAuthor": "Modified By:",
69 | "modDate": "Last Modified:",
70 | "modDateFormat": "dd-MM-yyyy HH:mm:ss",
71 | "prefix": "#",
72 | "replace": ["File:"],
73 | "rootDirFileName": "LICENSE",
74 | "suffix": ""
75 | },
76 | {
77 | "language": "shellscript",
78 | "begin": "",
79 | "blankLinesAfter": 1,
80 | "end": "",
81 | "forceToTop": true,
82 | "lineLength": 80,
83 | "modAuthor": "Modified By:",
84 | "modDate": "Last Modified:",
85 | "modDateFormat": "dd-MM-yyyy HH:mm:ss",
86 | "prefix": "#",
87 | "replace": ["File:"],
88 | "rootDirFileName": "LICENSE",
89 | "suffix": ""
90 | }
91 | ],
92 | "psi-header.changes-tracking": {
93 | "autoHeader": "autoSave",
94 | "enforceHeader": true,
95 | "include": ["go", "makefile", "shellscript"],
96 | "isActive": true,
97 | "modAuthor": "Modified By:",
98 | "modDate": "Last Modified:",
99 | "modDateFormat": "dd-MM-yyyy hh:nn:ss",
100 | "replace": ["Filename:"],
101 | "updateLicenseVariables": true
102 | },
103 | "psi-header.license-reference": {
104 | "uri": "../LICENSE",
105 | "uriIsLocalFile": true
106 | },
107 | "files.associations": {
108 | "Mkpmfile": "makefile"
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/config/manager/manager.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | labels:
5 | control-plane: controller-manager
6 | app.kubernetes.io/name: namespace
7 | app.kubernetes.io/instance: system
8 | app.kubernetes.io/component: manager
9 | app.kubernetes.io/created-by: integration-operator
10 | app.kubernetes.io/part-of: integration-operator
11 | app.kubernetes.io/managed-by: kustomize
12 | name: system
13 | ---
14 | apiVersion: apps/v1
15 | kind: Deployment
16 | metadata:
17 | name: controller-manager
18 | namespace: system
19 | labels:
20 | control-plane: controller-manager
21 | app.kubernetes.io/name: deployment
22 | app.kubernetes.io/instance: controller-manager
23 | app.kubernetes.io/component: manager
24 | app.kubernetes.io/created-by: integration-operator
25 | app.kubernetes.io/part-of: integration-operator
26 | app.kubernetes.io/managed-by: kustomize
27 | spec:
28 | selector:
29 | matchLabels:
30 | control-plane: controller-manager
31 | replicas: 1
32 | template:
33 | metadata:
34 | annotations:
35 | kubectl.kubernetes.io/default-container: manager
36 | labels:
37 | control-plane: controller-manager
38 | spec:
39 | # TODO(user): Uncomment the following code to configure the nodeAffinity expression
40 | # according to the platforms which are supported by your solution.
41 | # It is considered best practice to support multiple architectures. You can
42 | # build your manager image using the makefile target docker-buildx.
43 | # affinity:
44 | # nodeAffinity:
45 | # requiredDuringSchedulingIgnoredDuringExecution:
46 | # nodeSelectorTerms:
47 | # - matchExpressions:
48 | # - key: kubernetes.io/arch
49 | # operator: In
50 | # values:
51 | # - amd64
52 | # - arm64
53 | # - ppc64le
54 | # - s390x
55 | # - key: kubernetes.io/os
56 | # operator: In
57 | # values:
58 | # - linux
59 | securityContext:
60 | runAsNonRoot: true
61 | # TODO(user): For common cases that do not require escalating privileges
62 | # it is recommended to ensure that all your Pods/Containers are restrictive.
63 | # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
64 | # Please uncomment the following code if your project does NOT have to work on old Kubernetes
65 | # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ).
66 | # seccompProfile:
67 | # type: RuntimeDefault
68 | containers:
69 | - command:
70 | - /manager
71 | args:
72 | - --leader-elect
73 | image: controller:latest
74 | name: manager
75 | securityContext:
76 | allowPrivilegeEscalation: false
77 | capabilities:
78 | drop:
79 | - "ALL"
80 | livenessProbe:
81 | httpGet:
82 | path: /healthz
83 | port: 8081
84 | initialDelaySeconds: 15
85 | periodSeconds: 20
86 | readinessProbe:
87 | httpGet:
88 | path: /readyz
89 | port: 8081
90 | initialDelaySeconds: 5
91 | periodSeconds: 10
92 | # TODO(user): Configure the resources accordingly based on the project requirements.
93 | # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
94 | resources:
95 | limits:
96 | cpu: 500m
97 | memory: 128Mi
98 | requests:
99 | cpu: 10m
100 | memory: 64Mi
101 | serviceAccountName: controller-manager
102 | terminationGracePeriodSeconds: 10
103 |
--------------------------------------------------------------------------------
/util/helpers.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/helpers.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "bytes"
31 | "encoding/json"
32 | "fmt"
33 | "os"
34 | "regexp"
35 | "text/template"
36 |
37 | "github.com/Masterminds/sprig"
38 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
39 | "k8s.io/apimachinery/pkg/types"
40 | )
41 |
42 | func Default(value string, defaultValue string) string {
43 | if value == "" {
44 | value = defaultValue
45 | }
46 | return value
47 | }
48 |
49 | func EnsureServiceAccount(serviceAccountName string) string {
50 | return Default(serviceAccountName, "default")
51 | }
52 |
53 | func EnsureNamespacedName(
54 | partialNamespacedName *integrationv1beta1.NamespacedName,
55 | defaultNamespace string,
56 | ) types.NamespacedName {
57 | return types.NamespacedName{
58 | Name: partialNamespacedName.Name,
59 | Namespace: Default(partialNamespacedName.Namespace, defaultNamespace),
60 | }
61 | }
62 |
63 | func GetOperatorNamespace() string {
64 | operatorNamespace := os.Getenv("POD_NAMESPACE")
65 | if operatorNamespace == "" {
66 | operatorNamespace = "kube-system"
67 | }
68 | return operatorNamespace
69 | }
70 |
71 | func JsonToHashMap(body []byte) (map[string]string, error) {
72 | hashMap := make(map[string]string)
73 | var obj map[string]interface{}
74 | if err := json.Unmarshal(body, &obj); err != nil {
75 | return nil, err
76 | }
77 | for key, value := range obj {
78 | hashMap[key] = fmt.Sprintf("%v", value)
79 | }
80 | return hashMap, nil
81 | }
82 |
83 | func WhenInWhenSlice(when integrationv1beta1.When, whenSlice *[]integrationv1beta1.When) bool {
84 | if whenSlice == nil {
85 | return false
86 | }
87 | for _, whenItem := range *whenSlice {
88 | if when == whenItem {
89 | return true
90 | }
91 | }
92 | return false
93 | }
94 |
95 | func Validate(plug *integrationv1beta1.Plug, socket *integrationv1beta1.Socket) error {
96 | if socket.Spec.Validation == nil {
97 | return nil
98 | }
99 | if socket.Spec.Validation.NamespaceBlacklist != nil {
100 | for _, namespace := range socket.Spec.Validation.NamespaceBlacklist {
101 | match, _ := regexp.MatchString(namespace, plug.Namespace)
102 | if match {
103 | return fmt.Errorf("namespace %s is blacklisted", plug.Namespace)
104 | }
105 | }
106 | }
107 | if socket.Spec.Validation.NamespaceWhitelist != nil {
108 | for _, namespace := range socket.Spec.Validation.NamespaceWhitelist {
109 | match, _ := regexp.MatchString(namespace, plug.Namespace)
110 | if match {
111 | return nil
112 | }
113 | }
114 | return fmt.Errorf("namespace %s is not whitelisted", plug.Namespace)
115 | }
116 | return nil
117 | }
118 |
119 | func Template(
120 | data *map[string]interface{},
121 | templateValue string,
122 | ) (string, error) {
123 | t, err := template.New("").Funcs(sprig.TxtFuncMap()).Delims("{%", "%}").Parse(templateValue)
124 | if err != nil {
125 | return "", err
126 | }
127 | var buff bytes.Buffer
128 | err = t.Execute(&buff, data)
129 | if err != nil {
130 | return "", err
131 | }
132 | return buff.String(), nil
133 | }
134 |
--------------------------------------------------------------------------------
/chart/templates/rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: {{ template "integration-operator.name" . }}
5 | labels:
6 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
7 | helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
8 | app.kubernetes.io/instance: {{ .Release.Name }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | ---
11 | apiVersion: rbac.authorization.k8s.io/v1
12 | kind: ClusterRoleBinding
13 | metadata:
14 | name: {{ template "integration-operator.name" . }}
15 | labels:
16 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
17 | helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
18 | app.kubernetes.io/instance: {{ .Release.Name }}
19 | app.kubernetes.io/managed-by: {{ .Release.Service }}
20 | roleRef:
21 | apiGroup: rbac.authorization.k8s.io
22 | kind: ClusterRole
23 | name: {{ template "integration-operator.name" . }}
24 | subjects:
25 | - kind: ServiceAccount
26 | name: {{ template "integration-operator.name" . }}
27 | namespace: {{ .Release.Namespace }}
28 | ---
29 | apiVersion: rbac.authorization.k8s.io/v1
30 | kind: ClusterRole
31 | metadata:
32 | name: {{ template "integration-operator.name" . }}
33 | labels:
34 | app.kubernetes.io/name: {{ template "integration-operator.name" . }}
35 | helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
36 | app.kubernetes.io/instance: {{ .Release.Name }}
37 | app.kubernetes.io/managed-by: {{ .Release.Service }}
38 | rules:
39 | - apiGroups:
40 | - ""
41 | resources:
42 | - configmaps
43 | - secrets
44 | verbs:
45 | - get
46 | - list
47 | - watch
48 | - apiGroups:
49 | - ""
50 | resources:
51 | - events
52 | verbs:
53 | - create
54 | - delete
55 | - get
56 | - list
57 | - patch
58 | - update
59 | - watch
60 | - apiGroups:
61 | - ""
62 | resources:
63 | - pods
64 | - services
65 | verbs:
66 | - create
67 | - delete
68 | - get
69 | - list
70 | - patch
71 | - update
72 | - watch
73 | - apiGroups:
74 | - ""
75 | resources:
76 | - serviceaccounts
77 | verbs:
78 | - impersonate
79 | - apiGroups:
80 | - coordination.k8s.io
81 | resources:
82 | - leases
83 | verbs:
84 | - create
85 | - delete
86 | - get
87 | - list
88 | - patch
89 | - update
90 | - watch
91 | - apiGroups:
92 | - integration.rock8s.com
93 | resources:
94 | - deferredresources
95 | verbs:
96 | - create
97 | - delete
98 | - get
99 | - list
100 | - patch
101 | - update
102 | - watch
103 | - apiGroups:
104 | - integration.rock8s.com
105 | resources:
106 | - deferredresources/finalizers
107 | verbs:
108 | - update
109 | - apiGroups:
110 | - integration.rock8s.com
111 | resources:
112 | - deferredresources/status
113 | verbs:
114 | - get
115 | - patch
116 | - update
117 | - apiGroups:
118 | - integration.rock8s.com
119 | resources:
120 | - plugs
121 | verbs:
122 | - create
123 | - delete
124 | - get
125 | - list
126 | - patch
127 | - update
128 | - watch
129 | - apiGroups:
130 | - integration.rock8s.com
131 | resources:
132 | - plugs/finalizers
133 | verbs:
134 | - update
135 | - apiGroups:
136 | - integration.rock8s.com
137 | resources:
138 | - plugs/status
139 | verbs:
140 | - get
141 | - patch
142 | - update
143 | - apiGroups:
144 | - integration.rock8s.com
145 | resources:
146 | - sockets
147 | verbs:
148 | - create
149 | - delete
150 | - get
151 | - list
152 | - patch
153 | - update
154 | - watch
155 | - apiGroups:
156 | - integration.rock8s.com
157 | resources:
158 | - sockets/finalizers
159 | verbs:
160 | - update
161 | - apiGroups:
162 | - integration.rock8s.com
163 | resources:
164 | - sockets/status
165 | verbs:
166 | - get
167 | - patch
168 | - update
169 |
--------------------------------------------------------------------------------
/util/var.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/var.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 | "encoding/json"
32 |
33 | "github.com/tidwall/gjson"
34 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
35 | "k8s.io/client-go/kubernetes"
36 | ctrl "sigs.k8s.io/controller-runtime"
37 | kustomizeTypes "sigs.k8s.io/kustomize/api/types"
38 | )
39 |
40 | type VarUtil struct {
41 | client *kubernetes.Clientset
42 | resourceUtil *ResourceUtil
43 | }
44 |
45 | func NewVarUtil(ctx context.Context) *VarUtil {
46 | return &VarUtil{
47 | client: kubernetes.NewForConfigOrDie(ctrl.GetConfigOrDie()),
48 | resourceUtil: NewResourceUtil(ctx),
49 | }
50 | }
51 |
52 | func (u *VarUtil) GetVars(
53 | namespace string,
54 | vars []*integrationv1beta1.Var,
55 | kubectlUtil *KubectlUtil,
56 | plug *integrationv1beta1.Plug,
57 | socket *integrationv1beta1.Socket,
58 | ) (map[string]string, error) {
59 | resultMap := make(map[string]string)
60 | for _, v := range vars {
61 | varResult, err := u.GetVar(namespace, v, kubectlUtil, plug, socket)
62 | if err != nil {
63 | return nil, err
64 | }
65 | resultMap[v.Name] = varResult
66 | }
67 | return resultMap, nil
68 | }
69 |
70 | func (u *VarUtil) GetVar(
71 | namespace string,
72 | v *integrationv1beta1.Var,
73 | kubectlUtil *KubectlUtil,
74 | plug *integrationv1beta1.Plug,
75 | socket *integrationv1beta1.Socket,
76 | ) (string, error) {
77 | objRef := kustomizeTypes.Target{
78 | APIVersion: v.ObjRef.APIVersion,
79 | Name: v.ObjRef.Name,
80 | Namespace: v.ObjRef.Namespace,
81 | }
82 | objRef.Kind = v.ObjRef.Kind
83 | var err error
84 | if v.ObjRef.TemplateNamespace != "" {
85 | objRef.Namespace, err = u.varTemplateLookup(v.ObjRef.TemplateNamespace, plug, socket)
86 | if err != nil {
87 | return "", err
88 | }
89 | }
90 | if v.ObjRef.TemplateName != "" {
91 | objRef.Name, err = u.varTemplateLookup(v.ObjRef.TemplateName, plug, socket)
92 | if err != nil {
93 | return "", err
94 | }
95 | }
96 | resource, err := u.resourceUtil.GetResource(namespace, objRef, kubectlUtil)
97 | if err != nil {
98 | return "", err
99 | }
100 | bResource, err := json.Marshal(resource)
101 | if err != nil {
102 | return "", err
103 | }
104 | return gjson.Parse(string(bResource)).Get(v.FieldRef.FieldPath).String(), nil
105 | }
106 |
107 | func (u *VarUtil) varTemplateLookup(
108 | varTemplate string,
109 | plug *integrationv1beta1.Plug,
110 | socket *integrationv1beta1.Socket,
111 | ) (string, error) {
112 | data, err := u.buildVarTemplateData(socket, plug)
113 | if err != nil {
114 | return "", err
115 | }
116 | return Template(&data, varTemplate)
117 | }
118 |
119 | func (u *VarUtil) buildVarTemplateData(
120 | socket *integrationv1beta1.Socket,
121 | plug *integrationv1beta1.Plug,
122 | ) (map[string]interface{}, error) {
123 | dataMap := map[string]interface{}{}
124 | if socket != nil {
125 | dataMap["socket"] = socket
126 | }
127 | if plug != nil {
128 | dataMap["plug"] = plug
129 | }
130 | bData, err := json.Marshal(dataMap)
131 | if err != nil {
132 | return nil, err
133 | }
134 | var data map[string]interface{}
135 | if err := json.Unmarshal(bData, &data); err != nil {
136 | return nil, err
137 | }
138 | return data, nil
139 | }
140 |
--------------------------------------------------------------------------------
/api/v1beta1/shared_types.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /api/v1beta1/shared_types.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 12:06:48
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package v1beta1
28 |
29 | import (
30 | v1 "k8s.io/api/core/v1"
31 | apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
32 | "sigs.k8s.io/kustomize/api/resid"
33 | kustomizeTypes "sigs.k8s.io/kustomize/api/types"
34 | )
35 |
36 | const Finalizer = "integration.rock8s.com/finalizer"
37 |
38 | type When string
39 |
40 | const (
41 | CoupledWhen When = "coupled"
42 | CreatedWhen When = "created"
43 | DecoupledWhen When = "decoupled"
44 | DeletedWhen When = "deleted"
45 | UpdatedWhen When = "updated"
46 | )
47 |
48 | type Do string
49 |
50 | const (
51 | ApplyDo Do = "apply"
52 | DeleteDo Do = "delete"
53 | RecreateDo Do = "recreate"
54 | )
55 |
56 | type ResourceAction struct {
57 | Do Do `json:"do,omitempty"`
58 | Template *apiextv1.JSON `json:"template,omitempty"`
59 | Templates *[]*apiextv1.JSON `json:"templates,omitempty"`
60 | StringTemplate string `json:"stringTemplate,omitempty"`
61 | StringTemplates *[]string `json:"stringTemplates,omitempty"`
62 | }
63 |
64 | type Resource struct {
65 | ResourceAction `json:",inline"`
66 | RetainWhenDecoupled bool `json:"retainWhenDecoupled,omitempty"`
67 | When *[]When `json:"when,omitempty"`
68 | }
69 |
70 | type NamespacedName struct {
71 | // name
72 | Name string `json:"name"`
73 |
74 | // namespace
75 | Namespace string `json:"namespace,omitempty"`
76 | }
77 |
78 | type SpecApparatus struct {
79 | // endpoint
80 | Endpoint string `json:"endpoint,omitempty"`
81 |
82 | // terminate apparatus after idle for timeout in milliseconds
83 | IdleTimeout uint `json:"idleTimeout,omitempty"`
84 |
85 | // List of containers belonging to the apparatus.
86 | // Containers cannot currently be added or removed.
87 | // There must be at least one container in an apparatus.
88 | // Cannot be updated.
89 | // +patchMergeKey=name
90 | // +patchStrategy=merge
91 | Containers *[]v1.Container `json:"containers"`
92 | }
93 |
94 | // Var represents a variable whose value will be sourced
95 | // from a field in a Kubernetes object.
96 | type Var struct {
97 | // Value of identifier name e.g. FOO used in container args, annotations
98 | // Appears in pod template as $(FOO)
99 | Name string `json:"name" yaml:"name"`
100 |
101 | // ObjRef must refer to a Kubernetes resource under the
102 | // purview of this kustomization. ObjRef should use the
103 | // raw name of the object (the name specified in its YAML,
104 | // before addition of a namePrefix and a nameSuffix).
105 | ObjRef Target `json:"objref" yaml:"objref"`
106 |
107 | // FieldRef refers to the field of the object referred to by
108 | // ObjRef whose value will be extracted for use in
109 | // replacing $(FOO).
110 | // If unspecified, this defaults to fieldPath: $defaultFieldPath
111 | FieldRef kustomizeTypes.FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
112 | }
113 |
114 | // Target refers to a kubernetes object by Group, Version, Kind and Name
115 | // gvk.Gvk contains Group, Version and Kind
116 | // APIVersion is added to keep the backward compatibility of using ObjectReference
117 | // for Var.ObjRef
118 | type Target struct {
119 | APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
120 | resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
121 | Name string `json:"name,omitempty" yaml:"name,omitempty"`
122 | Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
123 | TemplateName string `json:"templateName,omitempty" yaml:"templateName,omitempty"`
124 | TemplateNamespace string `json:"templateNamespace,omitempty" yaml:"templateNamespace,omitempty"`
125 | }
126 |
--------------------------------------------------------------------------------
/util/kubectl.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/kubectl.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 | "encoding/json"
32 | "fmt"
33 |
34 | "k8s.io/apimachinery/pkg/api/meta"
35 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
37 | "k8s.io/apimachinery/pkg/types"
38 | "k8s.io/client-go/discovery"
39 | memory "k8s.io/client-go/discovery/cached"
40 | "k8s.io/client-go/dynamic"
41 | "k8s.io/client-go/rest"
42 | "k8s.io/client-go/restmapper"
43 | ctrl "sigs.k8s.io/controller-runtime"
44 | )
45 |
46 | type KubectlUtil struct {
47 | ctx context.Context
48 | cfg *rest.Config
49 | }
50 |
51 | func NewKubectlUtil(ctx context.Context, namespace string, serviceAccountName string) *KubectlUtil {
52 | cfg := ctrl.GetConfigOrDie()
53 | cfg.Impersonate = rest.ImpersonationConfig{
54 | UserName: fmt.Sprintf("system:serviceaccount:%s:%s", namespace, Default(serviceAccountName, "default")),
55 | }
56 | return &KubectlUtil{
57 | cfg: cfg,
58 | ctx: ctx,
59 | }
60 | }
61 |
62 | func (u *KubectlUtil) Create(body []byte) error {
63 | dr, obj, err := u.prepareDynamic(body)
64 | if err != nil {
65 | return err
66 | }
67 | if _, err := dr.Create(u.ctx, obj, metav1.CreateOptions{
68 | FieldManager: "integration-operator",
69 | }); err != nil {
70 | return err
71 | }
72 | return nil
73 | }
74 |
75 | func (u *KubectlUtil) Update(body []byte) error {
76 | dr, obj, err := u.prepareDynamic(body)
77 | if err != nil {
78 | return err
79 | }
80 | if _, err := dr.Update(u.ctx, obj, metav1.UpdateOptions{
81 | FieldManager: "integration-operator",
82 | }); err != nil {
83 | return err
84 | }
85 | return nil
86 | }
87 |
88 | func (u *KubectlUtil) Apply(body []byte) error {
89 | dr, obj, err := u.prepareDynamic(body)
90 | if err != nil {
91 | return err
92 | }
93 | data, err := json.Marshal(obj)
94 | if err != nil {
95 | return err
96 | }
97 | if _, err = dr.Patch(u.ctx, obj.GetName(), types.ApplyPatchType, data, metav1.PatchOptions{
98 | FieldManager: "integration-operator",
99 | }); err != nil {
100 | return err
101 | }
102 | return nil
103 | }
104 |
105 | func (u *KubectlUtil) Delete(body []byte) error {
106 | dr, obj, err := u.prepareDynamic(body)
107 | if err != nil {
108 | return err
109 | }
110 | if err = dr.Delete(u.ctx, obj.GetName(), metav1.DeleteOptions{}); err != nil {
111 | return err
112 | }
113 | return nil
114 | }
115 |
116 | func (u *KubectlUtil) Get(body []byte) (*unstructured.Unstructured, error) {
117 | dr, obj, err := u.prepareDynamic(body)
118 | if err != nil {
119 | return nil, err
120 | }
121 | return dr.Get(u.ctx, obj.GetName(), metav1.GetOptions{})
122 | }
123 |
124 | // https://ymmt2005.hatenablog.com/entry/2020/04/14/An_example_of_using_dynamic_client_of_k8s.io/client-go
125 | func (u *KubectlUtil) prepareDynamic(resource []byte) (dynamic.ResourceInterface, *unstructured.Unstructured, error) {
126 | // 1. Prepare a RESTMapper to find GVR
127 | dc, err := discovery.NewDiscoveryClientForConfig(u.cfg)
128 | if err != nil {
129 | return nil, nil, err
130 | }
131 | mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc))
132 |
133 | // 2. Prepare the dynamic client
134 | dyn, err := dynamic.NewForConfig(u.cfg)
135 | if err != nil {
136 | return nil, nil, err
137 | }
138 |
139 | // 3. Decode YAML manifest into unstructured.Unstructured
140 | obj := &unstructured.Unstructured{}
141 | _, gvk, err := decUnstructured.Decode(resource, nil, obj)
142 | if err != nil {
143 | return nil, nil, err
144 | }
145 |
146 | // 4. Find GVR
147 | mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
148 | if err != nil {
149 | return nil, nil, err
150 | }
151 |
152 | // 5. Obtain REST interface for the GVR
153 | var dr dynamic.ResourceInterface
154 | if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
155 | // namespaced resources should specify the namespace
156 | dr = dyn.Resource(mapping.Resource).Namespace(obj.GetNamespace())
157 | } else {
158 | // for cluster-wide resources
159 | dr = dyn.Resource(mapping.Resource)
160 | }
161 |
162 | return dr, obj, nil
163 | }
164 |
--------------------------------------------------------------------------------
/api/v1beta1/plug_types.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /api/v1beta1/plug_types.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:57
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package v1beta1
28 |
29 | import (
30 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 | "k8s.io/apimachinery/pkg/types"
32 | )
33 |
34 | // PlugSpec defines the desired state of Plug
35 | type PlugSpec struct {
36 | // socket
37 | Socket NamespacedName `json:"socket,omitempty"`
38 |
39 | // vars
40 | Vars []*Var `json:"vars,omitempty" yaml:"vars,omitempty"`
41 |
42 | // result vars
43 | ResultVars []*Var `json:"resultVars,omitempty" yaml:"vars,omitempty"`
44 |
45 | // data
46 | Data map[string]string `json:"data,omitempty"`
47 |
48 | // data configmap name
49 | DataConfigMapName string `json:"dataConfigMapName,omitempty"`
50 |
51 | // data secret name
52 | DataSecretName string `json:"dataSecretName,omitempty"`
53 |
54 | // config
55 | Config map[string]string `json:"config,omitempty"`
56 |
57 | // config configmap name
58 | ConfigConfigMapName string `json:"configConfigMapName,omitempty"`
59 |
60 | // config secret name
61 | ConfigSecretName string `json:"configSecretName,omitempty"`
62 |
63 | // config template
64 | ConfigTemplate map[string]string `json:"configTemplate,omitempty"`
65 |
66 | // result
67 | Result map[string]string `json:"result,omitempty"`
68 |
69 | // result configmap name
70 | ResultConfigMapName string `json:"resultConfigMapName,omitempty"`
71 |
72 | // result secret name
73 | ResultSecretName string `json:"resultSecretName,omitempty"`
74 |
75 | // result template
76 | ResultTemplate map[string]string `json:"resultTemplate,omitempty"`
77 |
78 | // ServiceAccountName is the name of the ServiceAccount to use to run integrations.
79 | // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
80 | // +optional
81 | ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"`
82 |
83 | // apparatus
84 | Apparatus *SpecApparatus `json:"apparatus,omitempty"`
85 |
86 | // resources
87 | Resources []*Resource `json:"resources,omitempty"`
88 |
89 | // result resources
90 | ResultResources []*ResourceAction `json:"resultResources,omitempty"`
91 |
92 | // change epoch to force an update
93 | Epoch string `json:"epoch,omitempty"`
94 | }
95 |
96 | // PlugStatus defines the observed state of Plug
97 | type PlugStatus struct {
98 | // Conditions represent the latest available observations of an object's state
99 | Conditions []metav1.Condition `json:"conditions,omitempty"`
100 |
101 | // socket coupled to plug
102 | CoupledSocket *CoupledSocket `json:"coupledSocket,omitempty"`
103 |
104 | // coupled result
105 | CoupledResult *CoupledResultStatus `json:"coupledResult,omitempty"`
106 | }
107 |
108 | type CoupledResult struct {
109 | // plug result
110 | Plug map[string]string `json:"plug,omitempty"`
111 |
112 | // socket result
113 | Socket map[string]string `json:"socket,omitempty"`
114 | }
115 |
116 | type CoupledResultStatus struct {
117 | CoupledResult `json:",inline"`
118 |
119 | // observed generation
120 | ObservedGeneration int64 `json:"observedGeneration,omitempty"`
121 | }
122 |
123 | type CoupledSocket struct {
124 | // API version of the socket
125 | APIVersion string `json:"apiVersion,omitempty"`
126 |
127 | // Kind of the socket
128 | Kind string `json:"kind,omitempty"`
129 |
130 | // Name of the socket
131 | Name string `json:"name,omitempty"`
132 |
133 | // Namespace of the socket
134 | Namespace string `json:"namespace,omitempty"`
135 |
136 | // UID of the socket
137 | UID types.UID `json:"uid,omitempty"`
138 | }
139 |
140 | //+kubebuilder:object:root=true
141 | //+kubebuilder:subresource:status
142 |
143 | // Plug is the Schema for the plugs API
144 | type Plug struct {
145 | metav1.TypeMeta `json:",inline"`
146 | metav1.ObjectMeta `json:"metadata,omitempty"`
147 |
148 | Spec PlugSpec `json:"spec,omitempty"`
149 | Status PlugStatus `json:"status,omitempty"`
150 | }
151 |
152 | //+kubebuilder:object:root=true
153 |
154 | // PlugList contains a list of Plug
155 | type PlugList struct {
156 | metav1.TypeMeta `json:",inline"`
157 | metav1.ListMeta `json:"metadata,omitempty"`
158 | Items []Plug `json:"items"`
159 | }
160 |
161 | func init() {
162 | SchemeBuilder.Register(&Plug{}, &PlugList{})
163 | }
164 |
--------------------------------------------------------------------------------
/coupler/couple.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /coupler/couple.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 19:02:43
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package coupler
28 |
29 | import (
30 | "context"
31 |
32 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
33 | "gitlab.com/bitspur/rock8s/integration-operator/util"
34 | k8serrors "k8s.io/apimachinery/pkg/api/errors"
35 | "k8s.io/client-go/tools/record"
36 | ctrl "sigs.k8s.io/controller-runtime"
37 | "sigs.k8s.io/controller-runtime/pkg/client"
38 | )
39 |
40 | func Couple(
41 | client *client.Client,
42 | ctx context.Context,
43 | req *ctrl.Request,
44 | plugUtil *util.PlugUtil,
45 | socketUtil *util.SocketUtil,
46 | plug *integrationv1beta1.Plug,
47 | socket *integrationv1beta1.Socket,
48 | recorder record.EventRecorder,
49 | ) (ctrl.Result, error) {
50 | configUtil := util.NewConfigUtil(ctx)
51 | if plug == nil {
52 | var err error
53 | plug, err = plugUtil.Get()
54 | if err != nil {
55 | return ctrl.Result{}, err
56 | }
57 | }
58 | if socket == nil {
59 | var err error
60 | socket, err = socketUtil.Get()
61 | if err != nil {
62 | if k8serrors.IsNotFound(err) {
63 | return plugUtil.UpdateCoupledStatus(util.SocketNotCreated, plug, nil, true)
64 | }
65 | return plugUtil.Error(err, plug)
66 | }
67 | }
68 |
69 | if socketUtil.CoupledPlugExists(socket.Status.CoupledPlugs, plug.UID) &&
70 | plug.Status.CoupledSocket != nil &&
71 | plug.Status.CoupledResult != nil {
72 | coupledCondition, err := plugUtil.GetCoupledCondition(plug)
73 | if err != nil {
74 | return plugUtil.Error(err, plug)
75 | }
76 | if plug.Generation > coupledCondition.ObservedGeneration {
77 | return plugUtil.UpdateCoupledStatus(util.UpdatingInProcess, plug, socket, true)
78 | }
79 | if plug.Generation > plug.Status.CoupledResult.ObservedGeneration {
80 | if err := Update(client, ctx, req, plugUtil, socketUtil, plug, socket, recorder); err != nil {
81 | return plugUtil.Error(err, plug)
82 | }
83 | plugConfig, err := configUtil.GetPlugConfig(plug, socket)
84 | if err != nil {
85 | return plugUtil.Error(err, plug)
86 | }
87 | socketConfig, err := configUtil.GetSocketConfig(plug, socket)
88 | if err != nil {
89 | socketUtil.Error(err, socket)
90 | return plugUtil.Error(err, plug)
91 | }
92 | if _, err := socketUtil.UpdateCoupledStatus(util.SocketCoupled, socket, nil, false); err != nil {
93 | socketUtil.Error(err, socket)
94 | return plugUtil.Error(err, plug)
95 | }
96 | return plugUtil.UpdateResultStatus(plug, socket, plugConfig, socketConfig)
97 | }
98 | return ctrl.Result{}, nil
99 | }
100 |
101 | if err := util.Validate(plug, socket); err != nil {
102 | return plugUtil.Error(err, plug)
103 | }
104 |
105 | plugConfig, err := configUtil.GetPlugConfig(plug, socket)
106 | if err != nil {
107 | return plugUtil.Error(err, plug)
108 | }
109 | socketConfig, err := configUtil.GetSocketConfig(plug, socket)
110 | if err != nil {
111 | socketUtil.Error(err, socket)
112 | return plugUtil.Error(err, plug)
113 | }
114 |
115 | if !socketUtil.CoupledPlugExists(socket.Status.CoupledPlugs, plug.UID) {
116 | if plug.Status.CoupledSocket != nil {
117 | if _, err := socketUtil.UpdateAppendCoupledPlugStatus(plug, socket, false); err != nil {
118 | return plugUtil.Error(err, plug)
119 | }
120 | return plugUtil.UpdateCoupledStatus(util.CouplingInProcess, plug, socket, true)
121 | }
122 | coupledCondition, err := plugUtil.GetCoupledCondition(plug)
123 | if err != nil {
124 | return plugUtil.Error(err, plug)
125 | }
126 | if coupledCondition.Reason != string(util.CouplingInProcess) {
127 | return plugUtil.UpdateCoupledStatus(util.CouplingInProcess, plug, nil, true)
128 | }
129 | err = CoupledPlug(plug, socket, plugConfig, socketConfig, recorder)
130 | if err != nil {
131 | return plugUtil.Error(err, plug)
132 | }
133 | err = CoupledSocket(plug, socket, plugConfig, socketConfig, recorder)
134 | if err != nil {
135 | socketUtil.Error(err, socket)
136 | return plugUtil.Error(err, plug)
137 | }
138 | if _, err := socketUtil.UpdateAppendCoupledPlugStatus(plug, socket, false); err != nil {
139 | return plugUtil.Error(err, plug)
140 | }
141 | return plugUtil.UpdateCoupledStatus(util.CouplingInProcess, plug, socket, true)
142 | }
143 |
144 | if plug.Status.CoupledResult == nil {
145 | if _, err := socketUtil.UpdateCoupledStatus(util.SocketCoupled, socket, nil, false); err != nil {
146 | socketUtil.Error(err, socket)
147 | return plugUtil.Error(err, plug)
148 | }
149 | return plugUtil.UpdateResultStatus(plug, socket, plugConfig, socketConfig)
150 | }
151 |
152 | return ctrl.Result{}, nil
153 | }
154 |
--------------------------------------------------------------------------------
/controllers/plug_controller.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /controllers/plug_controller.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:57
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package controllers
28 |
29 | import (
30 | "context"
31 | "os"
32 | "strconv"
33 |
34 | "k8s.io/apimachinery/pkg/api/errors"
35 | "k8s.io/apimachinery/pkg/runtime"
36 | "k8s.io/client-go/tools/record"
37 | ctrl "sigs.k8s.io/controller-runtime"
38 | "sigs.k8s.io/controller-runtime/pkg/client"
39 | "sigs.k8s.io/controller-runtime/pkg/controller"
40 | "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
41 | "sigs.k8s.io/controller-runtime/pkg/event"
42 | "sigs.k8s.io/controller-runtime/pkg/log"
43 | "sigs.k8s.io/controller-runtime/pkg/predicate"
44 |
45 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
46 | "gitlab.com/bitspur/rock8s/integration-operator/coupler"
47 | "gitlab.com/bitspur/rock8s/integration-operator/util"
48 | )
49 |
50 | // PlugReconciler reconciles a Plug object
51 | type PlugReconciler struct {
52 | client.Client
53 | Scheme *runtime.Scheme
54 | Recorder record.EventRecorder
55 | }
56 |
57 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=plugs,verbs=get;list;watch;create;update;patch;delete
58 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=plugs/status,verbs=get;update;patch
59 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=plugs/finalizers,verbs=update
60 |
61 | func (r *PlugReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
62 | logger := log.FromContext(ctx)
63 | logger.V(1).Info("Plug Reconcile")
64 | namespacedName := integrationv1beta1.NamespacedName{
65 | Name: req.NamespacedName.Name,
66 | Namespace: req.NamespacedName.Namespace,
67 | }
68 | plug := &integrationv1beta1.Plug{}
69 | if err := r.Client.Get(ctx, util.EnsureNamespacedName(&namespacedName, util.GetOperatorNamespace()), plug); err != nil {
70 | return ctrl.Result{}, client.IgnoreNotFound(err)
71 | }
72 | plug = plug.DeepCopy()
73 | socketUtil := util.NewSocketUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
74 | Name: plug.Spec.Socket.Name,
75 | Namespace: util.Default(plug.Spec.Socket.Namespace, req.NamespacedName.Namespace),
76 | })
77 | socket, err := socketUtil.Get()
78 | plugUtil := util.NewPlugUtil(&r.Client, ctx, &req, &namespacedName, socket)
79 | if err != nil && !errors.IsNotFound(err) {
80 | return plugUtil.Error(err, plug)
81 | }
82 |
83 | if plug.GetDeletionTimestamp() != nil {
84 | if controllerutil.ContainsFinalizer(plug, integrationv1beta1.Finalizer) {
85 | if plug.Status.CoupledSocket != nil && socket != nil {
86 | if err := coupler.Decouple(&r.Client, ctx, &req, plugUtil, socketUtil, plug, socket, r.Recorder); err != nil {
87 | return plugUtil.Error(err, plug)
88 | }
89 | }
90 | if err := coupler.DeletedPlug(plug, r.Recorder); err != nil {
91 | return plugUtil.Error(err, plug)
92 | }
93 | controllerutil.RemoveFinalizer(plug, integrationv1beta1.Finalizer)
94 | return plugUtil.Update(plug, true)
95 | }
96 | return ctrl.Result{}, nil
97 | }
98 |
99 | if !controllerutil.ContainsFinalizer(plug, integrationv1beta1.Finalizer) {
100 | controllerutil.AddFinalizer(plug, integrationv1beta1.Finalizer)
101 | return plugUtil.Update(plug, true)
102 | }
103 |
104 | coupledCondition, err := plugUtil.GetCoupledCondition(plug)
105 | if err != nil {
106 | return plugUtil.Error(err, plug)
107 | }
108 | if coupledCondition == nil {
109 | if err := coupler.CreatedPlug(plug, r.Recorder); err != nil {
110 | return plugUtil.Error(err, plug)
111 | }
112 | return plugUtil.UpdateCoupledStatus(util.PlugCreated, plug, nil, true)
113 | }
114 |
115 | return coupler.Couple(&r.Client, ctx, &req, plugUtil, socketUtil, plug, socket, r.Recorder)
116 | }
117 |
118 | func filterPlugPredicate() predicate.Predicate {
119 | return predicate.Funcs{
120 | UpdateFunc: func(e event.UpdateEvent) bool {
121 | return e.ObjectNew.GetDeletionTimestamp() != nil || e.ObjectNew.GetGeneration() > e.ObjectOld.GetGeneration()
122 | },
123 | DeleteFunc: func(e event.DeleteEvent) bool {
124 | return !e.DeleteStateUnknown
125 | },
126 | }
127 | }
128 |
129 | // SetupWithManager sets up the controller with the Manager.
130 | func (r *PlugReconciler) SetupWithManager(mgr ctrl.Manager) error {
131 | maxConcurrentReconciles := 3
132 | if value := os.Getenv("MAX_CONCURRENT_RECONCILES"); value != "" {
133 | if val, err := strconv.Atoi(value); err == nil {
134 | maxConcurrentReconciles = val
135 | }
136 | }
137 | return ctrl.NewControllerManagedBy(mgr).
138 | WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
139 | WithEventFilter(filterPlugPredicate()).
140 | For(&integrationv1beta1.Plug{}).
141 | Complete(r)
142 | }
143 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module gitlab.com/bitspur/rock8s/integration-operator
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/Masterminds/sprig v2.22.0+incompatible
7 | github.com/go-logr/logr v1.2.4
8 | github.com/go-resty/resty/v2 v2.10.0
9 | github.com/onsi/ginkgo/v2 v2.11.0
10 | github.com/onsi/gomega v1.27.10
11 | github.com/tdewolff/minify v2.3.6+incompatible
12 | github.com/tidwall/gjson v1.17.0
13 | github.com/tidwall/sjson v1.2.5
14 | k8s.io/api v0.26.1
15 | k8s.io/apiextensions-apiserver v0.26.1
16 | k8s.io/apimachinery v0.26.9
17 | k8s.io/apiserver v0.26.1
18 | k8s.io/client-go v0.26.1
19 | sigs.k8s.io/controller-runtime v0.14.6
20 | sigs.k8s.io/kustomize/api v0.8.9
21 | )
22 |
23 | require (
24 | github.com/Masterminds/goutils v1.1.1 // indirect
25 | github.com/Masterminds/semver v1.5.0 // indirect
26 | github.com/beorn7/perks v1.0.1 // indirect
27 | github.com/blang/semver/v4 v4.0.0 // indirect
28 | github.com/cenkalti/backoff/v4 v4.2.1 // indirect
29 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
30 | github.com/coreos/go-semver v0.3.1 // indirect
31 | github.com/coreos/go-systemd/v22 v22.5.0 // indirect
32 | github.com/davecgh/go-spew v1.1.1 // indirect
33 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect
34 | github.com/evanphx/json-patch/v5 v5.7.0 // indirect
35 | github.com/felixge/httpsnoop v1.0.3 // indirect
36 | github.com/fsnotify/fsnotify v1.6.0 // indirect
37 | github.com/go-errors/errors v1.5.1 // indirect
38 | github.com/go-logr/stdr v1.2.2 // indirect
39 | github.com/go-logr/zapr v1.2.4 // indirect
40 | github.com/go-openapi/jsonpointer v0.20.0 // indirect
41 | github.com/go-openapi/jsonreference v0.20.2 // indirect
42 | github.com/go-openapi/swag v0.22.4 // indirect
43 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
44 | github.com/gogo/protobuf v1.3.2 // indirect
45 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
46 | github.com/golang/protobuf v1.5.3 // indirect
47 | github.com/google/gnostic v0.7.0 // indirect
48 | github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
49 | github.com/google/go-cmp v0.6.0 // indirect
50 | github.com/google/gofuzz v1.2.0 // indirect
51 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
52 | github.com/google/uuid v1.3.1 // indirect
53 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
54 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
55 | github.com/huandu/xstrings v1.4.0 // indirect
56 | github.com/imdario/mergo v0.3.16 // indirect
57 | github.com/josharian/intern v1.0.0 // indirect
58 | github.com/json-iterator/go v1.1.12 // indirect
59 | github.com/mailru/easyjson v0.7.7 // indirect
60 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
61 | github.com/mitchellh/copystructure v1.2.0 // indirect
62 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
63 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
64 | github.com/modern-go/reflect2 v1.0.2 // indirect
65 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
66 | github.com/pkg/errors v0.9.1 // indirect
67 | github.com/prometheus/client_golang v1.17.0 // indirect
68 | github.com/prometheus/client_model v0.5.0 // indirect
69 | github.com/prometheus/common v0.44.0 // indirect
70 | github.com/prometheus/procfs v0.12.0 // indirect
71 | github.com/spf13/pflag v1.0.5 // indirect
72 | github.com/tdewolff/parse v2.3.4+incompatible // indirect
73 | github.com/tdewolff/test v1.0.9 // indirect
74 | github.com/tidwall/match v1.1.1 // indirect
75 | github.com/tidwall/pretty v1.2.1 // indirect
76 | go.etcd.io/etcd/api/v3 v3.5.9 // indirect
77 | go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
78 | go.etcd.io/etcd/client/v3 v3.5.9 // indirect
79 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect
80 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
81 | go.opentelemetry.io/otel v1.19.0 // indirect
82 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
83 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
84 | go.opentelemetry.io/otel/metric v1.19.0 // indirect
85 | go.opentelemetry.io/otel/sdk v1.19.0 // indirect
86 | go.opentelemetry.io/otel/trace v1.19.0 // indirect
87 | go.opentelemetry.io/proto/otlp v1.0.0 // indirect
88 | go.uber.org/multierr v1.11.0 // indirect
89 | go.uber.org/zap v1.26.0 // indirect
90 | golang.org/x/crypto v0.14.0 // indirect
91 | golang.org/x/net v0.17.0 // indirect
92 | golang.org/x/oauth2 v0.13.0 // indirect
93 | golang.org/x/sys v0.13.0 // indirect
94 | golang.org/x/term v0.13.0 // indirect
95 | golang.org/x/text v0.13.0 // indirect
96 | golang.org/x/time v0.3.0 // indirect
97 | golang.org/x/tools v0.14.0 // indirect
98 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
99 | google.golang.org/appengine v1.6.8 // indirect
100 | google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
101 | google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
102 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
103 | google.golang.org/grpc v1.58.3 // indirect
104 | google.golang.org/protobuf v1.31.0 // indirect
105 | gopkg.in/inf.v0 v0.9.1 // indirect
106 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
107 | gopkg.in/yaml.v2 v2.4.0 // indirect
108 | gopkg.in/yaml.v3 v3.0.1 // indirect
109 | k8s.io/component-base v0.26.1 // indirect
110 | k8s.io/klog/v2 v2.100.1 // indirect
111 | k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
112 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
113 | sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect
114 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
115 | sigs.k8s.io/kustomize/kyaml v0.14.3 // indirect
116 | sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
117 | sigs.k8s.io/yaml v1.3.0 // indirect
118 | )
119 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /main.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:48:34
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package main
28 |
29 | import (
30 | "flag"
31 | "os"
32 |
33 | // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
34 | // to ensure that exec-entrypoint and run can make use of them.
35 | _ "k8s.io/client-go/plugin/pkg/client/auth"
36 |
37 | "k8s.io/apimachinery/pkg/runtime"
38 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
39 | clientgoscheme "k8s.io/client-go/kubernetes/scheme"
40 | ctrl "sigs.k8s.io/controller-runtime"
41 | "sigs.k8s.io/controller-runtime/pkg/healthz"
42 | "sigs.k8s.io/controller-runtime/pkg/log/zap"
43 |
44 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
45 | "gitlab.com/bitspur/rock8s/integration-operator/controllers"
46 | //+kubebuilder:scaffold:imports
47 | )
48 |
49 | var (
50 | scheme = runtime.NewScheme()
51 | setupLog = ctrl.Log.WithName("setup")
52 | )
53 |
54 | func init() {
55 | utilruntime.Must(clientgoscheme.AddToScheme(scheme))
56 |
57 | utilruntime.Must(integrationv1beta1.AddToScheme(scheme))
58 | //+kubebuilder:scaffold:scheme
59 | }
60 |
61 | //+kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;patch;delete
62 | //+kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;update;patch;delete
63 | //+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=impersonate
64 | //+kubebuilder:rbac:groups="",resources=services;pods,verbs=create;delete;get;list;patch;update;watch
65 | //+kubebuilder:rbac:groups="",resources=configmaps;secrets,verbs=get;list;watch
66 |
67 | func main() {
68 | var enableLeaderElection bool
69 | var metricsAddr string
70 | var probeAddr string
71 | flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
72 | flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
73 | flag.BoolVar(&enableLeaderElection, "leader-elect", false,
74 | "Enable leader election for controller manager. "+
75 | "Enabling this will ensure there is only one active controller manager.")
76 | opts := zap.Options{
77 | Development: true,
78 | }
79 | opts.BindFlags(flag.CommandLine)
80 | flag.Parse()
81 |
82 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
83 |
84 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
85 | Scheme: scheme,
86 | MetricsBindAddress: metricsAddr,
87 | Port: 9443,
88 | HealthProbeBindAddress: probeAddr,
89 | LeaderElection: enableLeaderElection,
90 | LeaderElectionID: "cb0904ca.rock8s.com",
91 | Namespace: os.Getenv("WATCH_NAMESPACE"),
92 | // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
93 | // when the Manager ends. This requires the binary to immediately end when the
94 | // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
95 | // speeds up voluntary leader transitions as the new leader don't have to wait
96 | // LeaseDuration time first.
97 | //
98 | // In the default scaffold provided, the program ends immediately after
99 | // the manager stops, so would be fine to enable this option. However,
100 | // if you are doing or is intended to do any operation such as perform cleanups
101 | // after the manager stops then its usage might be unsafe.
102 | // LeaderElectionReleaseOnCancel: true,
103 | })
104 | if err != nil {
105 | setupLog.Error(err, "unable to start manager")
106 | os.Exit(1)
107 | }
108 |
109 | if err = (&controllers.SocketReconciler{
110 | Client: mgr.GetClient(),
111 | Scheme: mgr.GetScheme(),
112 | Recorder: mgr.GetEventRecorderFor("socket-controller"),
113 | }).SetupWithManager(mgr); err != nil {
114 | setupLog.Error(err, "unable to create controller", "controller", "Socket")
115 | os.Exit(1)
116 | }
117 | if err = (&controllers.PlugReconciler{
118 | Client: mgr.GetClient(),
119 | Scheme: mgr.GetScheme(),
120 | Recorder: mgr.GetEventRecorderFor("plug-controller"),
121 | }).SetupWithManager(mgr); err != nil {
122 | setupLog.Error(err, "unable to create controller", "controller", "Plug")
123 | os.Exit(1)
124 | }
125 | if err = (&controllers.DeferredResourceReconciler{
126 | Client: mgr.GetClient(),
127 | Scheme: mgr.GetScheme(),
128 | }).SetupWithManager(mgr); err != nil {
129 | setupLog.Error(err, "unable to create controller", "controller", "DeferredResource")
130 | os.Exit(1)
131 | }
132 | //+kubebuilder:scaffold:builder
133 |
134 | if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
135 | setupLog.Error(err, "unable to set up health check")
136 | os.Exit(1)
137 | }
138 | if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
139 | setupLog.Error(err, "unable to set up ready check")
140 | os.Exit(1)
141 | }
142 |
143 | setupLog.Info("starting manager")
144 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
145 | setupLog.Error(err, "problem running manager")
146 | os.Exit(1)
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/api/v1beta1/socket_types.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /api/v1beta1/socket_types.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:35
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package v1beta1
28 |
29 | import (
30 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 | "k8s.io/apimachinery/pkg/types"
32 | )
33 |
34 | // SocketSpec defines the desired state of Socket
35 | type SocketSpec struct {
36 | // interface
37 | Interface *Interface `json:"interface,omitempty"`
38 |
39 | // limit
40 | Limit int32 `json:"limit,omitempty"`
41 |
42 | // vars
43 | Vars []*Var `json:"vars,omitempty" yaml:"vars,omitempty"`
44 |
45 | // result vars
46 | ResultVars []*Var `json:"resultVars,omitempty" yaml:"vars,omitempty"`
47 |
48 | // data
49 | Data map[string]string `json:"data,omitempty"`
50 |
51 | // data configmap name
52 | DataConfigMapName string `json:"dataConfigMapName,omitempty"`
53 |
54 | // data secret name
55 | DataSecretName string `json:"dataSecretName,omitempty"`
56 |
57 | // config
58 | Config map[string]string `json:"config,omitempty"`
59 |
60 | // config configmap name
61 | ConfigConfigMapName string `json:"configConfigMapName,omitempty"`
62 |
63 | // config secret name
64 | ConfigSecretName string `json:"configSecretName,omitempty"`
65 |
66 | // config template
67 | ConfigTemplate map[string]string `json:"configTemplate,omitempty"`
68 |
69 | // result
70 | Result map[string]string `json:"result,omitempty"`
71 |
72 | // result configmap name
73 | ResultConfigMapName string `json:"resultConfigMapName,omitempty"`
74 |
75 | // result secret name
76 | ResultSecretName string `json:"resultSecretName,omitempty"`
77 |
78 | // result template
79 | ResultTemplate map[string]string `json:"resultTemplate,omitempty"`
80 |
81 | // ServiceAccountName is the name of the ServiceAccount to use to run integrations.
82 | // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
83 | // +optional
84 | ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"`
85 |
86 | // apparatus
87 | Apparatus *SpecApparatus `json:"apparatus,omitempty"`
88 |
89 | // resources
90 | Resources []*Resource `json:"resources,omitempty"`
91 |
92 | // result resources
93 | ResultResources []*ResourceAction `json:"resultResources,omitempty"`
94 |
95 | // change epoch to force an update
96 | Epoch string `json:"epoch,omitempty"`
97 |
98 | // validation
99 | Validation *SocketSpecValidation `json:"validation,omitempty"`
100 | }
101 |
102 | type Interface struct {
103 | // config interface
104 | Config *ConfigInterface `json:"config,omitempty"`
105 |
106 | // result interface
107 | Result *ResultInterface `json:"result,omitempty"`
108 | }
109 |
110 | type ConfigInterface struct {
111 | // plug config properties
112 | Plug map[string]*SchemaProperty `json:"plug,omitempty"`
113 |
114 | // socket config properties
115 | Socket map[string]*SchemaProperty `json:"socket,omitempty"`
116 | }
117 |
118 | type ResultInterface struct {
119 | // plug result properties
120 | Plug map[string]*SchemaProperty `json:"plug,omitempty"`
121 |
122 | // socket result properties
123 | Socket map[string]*SchemaProperty `json:"socket,omitempty"`
124 | }
125 |
126 | type SchemaProperty struct {
127 | Default string `json:"default,omitempty"`
128 | Description string `json:"description,omitempty"`
129 | Required bool `json:"required,omitempty"`
130 | }
131 |
132 | type SocketSpecValidation struct {
133 | // namespace whitelist
134 | NamespaceWhitelist []string `json:"namespaceWhitelist,omitempty"`
135 |
136 | // namespace blacklist
137 | NamespaceBlacklist []string `json:"namespaceBlacklist,omitempty"`
138 | }
139 |
140 | // SocketStatus defines the observed state of Socket
141 | type SocketStatus struct {
142 | // Conditions represent the latest available observations of an object's state
143 | Conditions []metav1.Condition `json:"conditions,omitempty"`
144 |
145 | // plugs coupled to socket
146 | CoupledPlugs []*CoupledPlug `json:"coupledPlugs,omitempty"`
147 | }
148 |
149 | type CoupledPlug struct {
150 | // API version of the plug
151 | APIVersion string `json:"apiVersion"`
152 |
153 | // Kind of the plug
154 | Kind string `json:"kind"`
155 |
156 | // Name of the plug
157 | Name string `json:"name"`
158 |
159 | // Namespace of the plug
160 | Namespace string `json:"namespace"`
161 |
162 | // UID of the plug
163 | UID types.UID `json:"uid"`
164 | }
165 |
166 | //+kubebuilder:object:root=true
167 | //+kubebuilder:subresource:status
168 |
169 | // Socket is the Schema for the sockets API
170 | type Socket struct {
171 | metav1.TypeMeta `json:",inline"`
172 | metav1.ObjectMeta `json:"metadata,omitempty"`
173 |
174 | Spec SocketSpec `json:"spec,omitempty"`
175 | Status SocketStatus `json:"status,omitempty"`
176 | }
177 |
178 | //+kubebuilder:object:root=true
179 |
180 | // SocketList contains a list of Socket
181 | type SocketList struct {
182 | metav1.TypeMeta `json:",inline"`
183 | metav1.ListMeta `json:"metadata,omitempty"`
184 | Items []Socket `json:"items"`
185 | }
186 |
187 | func init() {
188 | SchemeBuilder.Register(&Socket{}, &SocketList{})
189 | }
190 |
--------------------------------------------------------------------------------
/controllers/deferredresource_controller.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /controllers/deferredresource_controller.go
3 | * Project: integration-operator
4 | * File Created: 17-12-2023 03:35:18
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | /*
28 | Copyright 2023.
29 |
30 | Licensed under the Apache License, Version 2.0 (the "License");
31 | you may not use this file except in compliance with the License.
32 | You may obtain a copy of the License at
33 |
34 | http://www.apache.org/licenses/LICENSE-2.0
35 |
36 | Unless required by applicable law or agreed to in writing, software
37 | distributed under the License is distributed on an "AS IS" BASIS,
38 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39 | See the License for the specific language governing permissions and
40 | limitations under the License.
41 | */
42 |
43 | package controllers
44 |
45 | import (
46 | "context"
47 | "encoding/json"
48 | "os"
49 | "strconv"
50 | "time"
51 |
52 | "k8s.io/apimachinery/pkg/runtime"
53 | ctrl "sigs.k8s.io/controller-runtime"
54 | "sigs.k8s.io/controller-runtime/pkg/client"
55 | "sigs.k8s.io/controller-runtime/pkg/controller"
56 | "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
57 | "sigs.k8s.io/controller-runtime/pkg/log"
58 |
59 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
60 | "gitlab.com/bitspur/rock8s/integration-operator/util"
61 | k8serrors "k8s.io/apimachinery/pkg/api/errors"
62 | )
63 |
64 | // DeferredResourceReconciler reconciles a DeferredResource object
65 | type DeferredResourceReconciler struct {
66 | client.Client
67 | Scheme *runtime.Scheme
68 | }
69 |
70 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=deferredresources,verbs=get;list;watch;create;update;patch;delete
71 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=deferredresources/status,verbs=get;update;patch
72 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=deferredresources/finalizers,verbs=update
73 |
74 | func (r *DeferredResourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
75 | logger := log.FromContext(ctx)
76 | logger.V(1).Info("DeferredResource Reconcile")
77 | deferredResourceUtil := util.NewDeferredResourceUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
78 | Name: req.NamespacedName.Name,
79 | Namespace: req.NamespacedName.Namespace,
80 | })
81 | deferredResource, err := deferredResourceUtil.Get()
82 | if err != nil {
83 | return ctrl.Result{}, client.IgnoreNotFound(err)
84 | }
85 | kubectlUtil := util.NewKubectlUtil(
86 | ctx, deferredResource.Namespace,
87 | util.EnsureServiceAccount(deferredResource.Spec.ServiceAccountName),
88 | )
89 |
90 | if deferredResource.GetDeletionTimestamp() != nil {
91 | if controllerutil.ContainsFinalizer(deferredResource, integrationv1beta1.Finalizer) {
92 | if err := deferredResourceUtil.DeleteResource(deferredResource, kubectlUtil); err != nil {
93 | return deferredResourceUtil.Error(err, deferredResource)
94 | }
95 | controllerutil.RemoveFinalizer(deferredResource, integrationv1beta1.Finalizer)
96 | return deferredResourceUtil.Update(deferredResource, true)
97 | }
98 | return ctrl.Result{}, nil
99 | }
100 |
101 | if deferredResource.Spec.Timeout > 0 {
102 | if time.Since(deferredResource.CreationTimestamp.Time) < time.Duration(deferredResource.Spec.Timeout)*time.Second {
103 | return deferredResourceUtil.UpdateResolvedStatus(
104 | util.DeferredResourcePending,
105 | deferredResource,
106 | nil,
107 | "waiting for timeout",
108 | deferredResource.Spec.Timeout,
109 | )
110 | }
111 | }
112 |
113 | if deferredResource.Spec.WaitFor != nil {
114 | for _, waitFor := range *deferredResource.Spec.WaitFor {
115 | apiVersion := waitFor.APIVersion
116 | if apiVersion == "" {
117 | group := ""
118 | if waitFor.Group != "" {
119 | group = waitFor.Group + "/"
120 | }
121 | apiVersion = group + waitFor.Version
122 | }
123 | body, err := json.Marshal(
124 | map[string]interface{}{
125 | "apiVersion": apiVersion,
126 | "kind": waitFor.Kind,
127 | "metadata": map[string]interface{}{
128 | "name": waitFor.Name,
129 | "namespace": deferredResource.Namespace,
130 | },
131 | },
132 | )
133 | if err != nil {
134 | return deferredResourceUtil.Error(err, deferredResource)
135 | }
136 | if _, err := kubectlUtil.Get(body); err != nil {
137 | if k8serrors.IsNotFound(err) {
138 | return deferredResourceUtil.UpdateResolvedStatus(
139 | util.DeferredResourcePending,
140 | deferredResource,
141 | nil,
142 | "waiting for resource",
143 | 1,
144 | )
145 | }
146 | return deferredResourceUtil.Error(err, deferredResource)
147 | }
148 | }
149 | }
150 |
151 | return deferredResourceUtil.ApplyResource(deferredResource, kubectlUtil)
152 | }
153 |
154 | // SetupWithManager sets up the controller with the Manager.
155 | func (r *DeferredResourceReconciler) SetupWithManager(mgr ctrl.Manager) error {
156 | maxConcurrentReconciles := 3
157 | if value := os.Getenv("MAX_CONCURRENT_RECONCILES"); value != "" {
158 | if val, err := strconv.Atoi(value); err == nil {
159 | maxConcurrentReconciles = val
160 | }
161 | }
162 | return ctrl.NewControllerManagedBy(mgr).
163 | WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
164 | For(&integrationv1beta1.DeferredResource{}).
165 | Complete(r)
166 | }
167 |
--------------------------------------------------------------------------------
/controllers/socket_controller.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /controllers/socket_controller.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 10:50:35
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package controllers
28 |
29 | import (
30 | "context"
31 | "os"
32 | "strconv"
33 | "time"
34 |
35 | "k8s.io/apimachinery/pkg/api/errors"
36 | "k8s.io/apimachinery/pkg/runtime"
37 | "k8s.io/client-go/tools/record"
38 | ctrl "sigs.k8s.io/controller-runtime"
39 | "sigs.k8s.io/controller-runtime/pkg/client"
40 | "sigs.k8s.io/controller-runtime/pkg/controller"
41 | "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
42 | "sigs.k8s.io/controller-runtime/pkg/event"
43 | "sigs.k8s.io/controller-runtime/pkg/log"
44 | "sigs.k8s.io/controller-runtime/pkg/predicate"
45 |
46 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
47 | "gitlab.com/bitspur/rock8s/integration-operator/coupler"
48 | "gitlab.com/bitspur/rock8s/integration-operator/util"
49 | )
50 |
51 | // SocketReconciler reconciles a Socket object
52 | type SocketReconciler struct {
53 | client.Client
54 | Scheme *runtime.Scheme
55 | Recorder record.EventRecorder
56 | }
57 |
58 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=sockets,verbs=get;list;watch;create;update;patch;delete
59 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=sockets/status,verbs=get;update;patch
60 | //+kubebuilder:rbac:groups=integration.rock8s.com,resources=sockets/finalizers,verbs=update
61 |
62 | func (r *SocketReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
63 | logger := log.FromContext(ctx)
64 | logger.V(1).Info("Socket Reconcile")
65 | socketUtil := util.NewSocketUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
66 | Name: req.NamespacedName.Name,
67 | Namespace: req.NamespacedName.Namespace,
68 | })
69 | socket, err := socketUtil.Get()
70 | if err != nil {
71 | return ctrl.Result{}, client.IgnoreNotFound(err)
72 | }
73 |
74 | if socket.GetDeletionTimestamp() != nil {
75 | if controllerutil.ContainsFinalizer(socket, integrationv1beta1.Finalizer) {
76 | coupledPlugs := socket.Status.CoupledPlugs
77 | if len(coupledPlugs) > 0 {
78 | for _, coupledPlug := range coupledPlugs {
79 | if _, err := socketUtil.RemoveCoupledPlugStatus(coupledPlug.UID, socket); err != nil {
80 | return socketUtil.Error(err, socket)
81 | }
82 | }
83 | if _, err := socketUtil.UpdateCoupledStatus(util.SocketEmpty, socket, nil, true); err != nil {
84 | return socketUtil.Error(err, socket)
85 | }
86 | for _, coupledPlug := range coupledPlugs {
87 | plugUtil := util.NewPlugUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
88 | Name: coupledPlug.Name,
89 | Namespace: coupledPlug.Namespace,
90 | }, socket)
91 | plug, err := plugUtil.Get()
92 | if err != nil {
93 | if errors.IsNotFound(err) {
94 | continue
95 | }
96 | return socketUtil.Error(err, socket)
97 | }
98 | if _, err := plugUtil.Delete(plug); err != nil {
99 | return socketUtil.Error(err, socket)
100 | }
101 | }
102 | return ctrl.Result{Requeue: true, RequeueAfter: 0}, nil
103 | }
104 | if socket == nil {
105 | return ctrl.Result{}, nil
106 | }
107 | if err := coupler.DeletedSocket(socket, r.Recorder); err != nil {
108 | return socketUtil.Error(err, socket)
109 | }
110 | controllerutil.RemoveFinalizer(socket, integrationv1beta1.Finalizer)
111 | return socketUtil.Update(socket, true)
112 | }
113 | return ctrl.Result{}, nil
114 | }
115 |
116 | if !controllerutil.ContainsFinalizer(socket, integrationv1beta1.Finalizer) {
117 | controllerutil.AddFinalizer(socket, integrationv1beta1.Finalizer)
118 | return socketUtil.Update(socket, true)
119 | }
120 |
121 | coupledCondition, err := socketUtil.GetCoupledCondition(socket)
122 | if err != nil {
123 | return socketUtil.Error(err, socket)
124 | }
125 | if coupledCondition == nil {
126 | if err := coupler.CreatedSocket(socket, r.Recorder); err != nil {
127 | return socketUtil.Error(err, socket)
128 | }
129 | return socketUtil.UpdateCoupledStatus(util.SocketCreated, socket, nil, true)
130 | }
131 |
132 | setSocketStatus := false
133 | for _, coupledPlug := range socket.Status.CoupledPlugs {
134 | plugUtil := util.NewPlugUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
135 | Name: coupledPlug.Name,
136 | Namespace: coupledPlug.Namespace,
137 | }, socket)
138 | if _, err := plugUtil.Get(); err != nil {
139 | if errors.IsNotFound(err) {
140 | if _, err := socketUtil.RemoveCoupledPlugStatus(coupledPlug.UID, socket); err != nil {
141 | return socketUtil.Error(err, socket)
142 | }
143 | setSocketStatus = true
144 | continue
145 | }
146 | return socketUtil.Error(err, socket)
147 | }
148 | }
149 | if setSocketStatus {
150 | return socketUtil.UpdateStatus(socket, true)
151 | }
152 |
153 | for _, coupledPlug := range socket.Status.CoupledPlugs {
154 | plugUtil := util.NewPlugUtil(&r.Client, ctx, &req, &integrationv1beta1.NamespacedName{
155 | Name: coupledPlug.Name,
156 | Namespace: coupledPlug.Namespace,
157 | }, socket)
158 | plug, err := plugUtil.Get()
159 | if err != nil {
160 | return socketUtil.Error(err, socket)
161 | }
162 | plug.Spec.Epoch = strconv.FormatInt(time.Now().Unix(), 10)
163 | if _, err := plugUtil.Update(plug, false); err != nil {
164 | return socketUtil.Error(err, socket)
165 | }
166 | }
167 |
168 | return socketUtil.UpdateCoupledStatus(util.SocketCoupled, socket, nil, false)
169 | }
170 |
171 | func filterSocketPredicate() predicate.Predicate {
172 | return predicate.Funcs{
173 | UpdateFunc: func(e event.UpdateEvent) bool {
174 | return e.ObjectNew.GetDeletionTimestamp() != nil || e.ObjectNew.GetGeneration() > e.ObjectOld.GetGeneration()
175 | },
176 | DeleteFunc: func(e event.DeleteEvent) bool {
177 | return !e.DeleteStateUnknown
178 | },
179 | }
180 | }
181 |
182 | // SetupWithManager sets up the controller with the Manager.
183 | func (r *SocketReconciler) SetupWithManager(mgr ctrl.Manager) error {
184 | maxConcurrentReconciles := 3
185 | if value := os.Getenv("MAX_CONCURRENT_RECONCILES"); value != "" {
186 | if val, err := strconv.Atoi(value); err == nil {
187 | maxConcurrentReconciles = val
188 | }
189 | }
190 | return ctrl.NewControllerManagedBy(mgr).
191 | WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
192 | WithEventFilter(filterSocketPredicate()).
193 | For(&integrationv1beta1.Socket{}).
194 | Complete(r)
195 | }
196 |
--------------------------------------------------------------------------------
/util/event.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/event.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 | "fmt"
32 |
33 | "github.com/go-logr/logr"
34 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
35 | "k8s.io/client-go/tools/record"
36 | "sigs.k8s.io/controller-runtime/pkg/log"
37 | )
38 |
39 | type EventUtil struct {
40 | apparatusUtil *ApparatusUtil
41 | resourceUtil *ResourceUtil
42 | logger logr.Logger
43 | }
44 |
45 | func NewEventUtil(
46 | ctx context.Context,
47 | ) *EventUtil {
48 | return &EventUtil{
49 | apparatusUtil: NewApparatusUtil(ctx),
50 | resourceUtil: NewResourceUtil(ctx),
51 | logger: log.FromContext(ctx),
52 | }
53 | }
54 |
55 | func (u *EventUtil) PlugCreated(
56 | plug *integrationv1beta1.Plug,
57 | recorder record.EventRecorder,
58 | ) error {
59 | u.logger.Info(fmt.Sprintf("plug %s/%s created", plug.Name, plug.Namespace))
60 | if err := u.apparatusUtil.PlugCreated(plug); err != nil {
61 | return err
62 | }
63 | if err := u.resourceUtil.PlugCreated(plug); err != nil {
64 | return err
65 | }
66 | recorder.Event(plug, "Normal", "PlugCreated", fmt.Sprintf("plug %s/%s created", plug.Name, plug.Namespace))
67 | return nil
68 | }
69 |
70 | func (u *EventUtil) PlugCoupled(
71 | plug *integrationv1beta1.Plug,
72 | socket *integrationv1beta1.Socket,
73 | plugConfig *Config,
74 | socketConfig *Config,
75 | recorder record.EventRecorder,
76 | ) error {
77 | u.logger.Info(fmt.Sprintf("plug %s/%s coupled", plug.Name, plug.Namespace))
78 | if err := u.apparatusUtil.PlugCoupled(plug, socket, plugConfig, socketConfig); err != nil {
79 | return err
80 | }
81 | if err := u.resourceUtil.PlugCoupled(plug, socket, plugConfig, socketConfig); err != nil {
82 | return err
83 | }
84 | recorder.Event(plug, "Normal", "PlugCoupled", fmt.Sprintf("plug %s/%s coupled", plug.Name, plug.Namespace))
85 | return nil
86 | }
87 |
88 | func (u *EventUtil) PlugUpdated(
89 | plug *integrationv1beta1.Plug,
90 | socket *integrationv1beta1.Socket,
91 | plugConfig *Config,
92 | socketConfig *Config,
93 | recorder record.EventRecorder,
94 | ) error {
95 | u.logger.Info(fmt.Sprintf("plug %s/%s updated", plug.Name, plug.Namespace))
96 | if err := u.apparatusUtil.PlugUpdated(plug, socket, plugConfig, socketConfig); err != nil {
97 | return err
98 | }
99 | if err := u.resourceUtil.PlugUpdated(plug, socket, plugConfig, socketConfig); err != nil {
100 | return err
101 | }
102 | recorder.Event(plug, "Normal", "PlugUpdated", fmt.Sprintf("plug %s/%s updated", plug.Name, plug.Namespace))
103 | return nil
104 | }
105 |
106 | func (u *EventUtil) PlugDecoupled(
107 | plug *integrationv1beta1.Plug,
108 | socket *integrationv1beta1.Socket,
109 | plugConfig *Config,
110 | socketConfig *Config,
111 | recorder record.EventRecorder,
112 | ) error {
113 | u.logger.Info(fmt.Sprintf("plug %s/%s decoupled", plug.Name, plug.Namespace))
114 | if err := u.apparatusUtil.PlugDecoupled(plug, socket, plugConfig, socketConfig); err != nil {
115 | return err
116 | }
117 | if err := u.resourceUtil.PlugDecoupled(plug, socket, plugConfig, socketConfig); err != nil {
118 | return err
119 | }
120 | recorder.Event(plug, "Normal", "PlugDecoupled", fmt.Sprintf("plug %s/%s decoupled", plug.Name, plug.Namespace))
121 | return nil
122 | }
123 |
124 | func (u *EventUtil) PlugDeleted(
125 | plug *integrationv1beta1.Plug,
126 | recorder record.EventRecorder,
127 | ) error {
128 | u.logger.Info(fmt.Sprintf("plug %s/%s deleted", plug.Name, plug.Namespace))
129 | if err := u.apparatusUtil.PlugDeleted(plug); err != nil {
130 | return err
131 | }
132 | if err := u.resourceUtil.PlugDeleted(plug); err != nil {
133 | return err
134 | }
135 | recorder.Event(plug, "Normal", "PlugDeleted", fmt.Sprintf("plug %s/%s deleted", plug.Name, plug.Namespace))
136 | return nil
137 | }
138 |
139 | func (u *EventUtil) SocketCreated(
140 | socket *integrationv1beta1.Socket,
141 | recorder record.EventRecorder,
142 | ) error {
143 | u.logger.Info(fmt.Sprintf("socket %s/%s created", socket.Name, socket.Namespace))
144 | if err := u.apparatusUtil.SocketCreated(socket); err != nil {
145 | return err
146 | }
147 | if err := u.resourceUtil.SocketCreated(socket); err != nil {
148 | return err
149 | }
150 | recorder.Event(socket, "Normal", "SocketCreated", fmt.Sprintf("socket %s/%s created", socket.Name, socket.Namespace))
151 | return nil
152 | }
153 |
154 | func (u *EventUtil) SocketCoupled(
155 | plug *integrationv1beta1.Plug,
156 | socket *integrationv1beta1.Socket,
157 | plugConfig *Config,
158 | socketConfig *Config,
159 | recorder record.EventRecorder,
160 | ) error {
161 | u.logger.Info(fmt.Sprintf("socket %s/%s coupled", socket.Name, socket.Namespace))
162 | if err := u.apparatusUtil.SocketCoupled(plug, socket, plugConfig, socketConfig); err != nil {
163 | return err
164 | }
165 | if err := u.resourceUtil.SocketCoupled(plug, socket, plugConfig, socketConfig); err != nil {
166 | return err
167 | }
168 | recorder.Event(socket, "Normal", "SocketCoupled", fmt.Sprintf("socket %s/%s coupled", socket.Name, socket.Namespace))
169 | return nil
170 | }
171 |
172 | func (u *EventUtil) SocketUpdated(
173 | plug *integrationv1beta1.Plug,
174 | socket *integrationv1beta1.Socket,
175 | plugConfig *Config,
176 | socketConfig *Config,
177 | recorder record.EventRecorder,
178 | ) error {
179 | u.logger.Info(fmt.Sprintf("socket %s/%s updated", socket.Name, socket.Namespace))
180 | if err := u.apparatusUtil.SocketUpdated(plug, socket, plugConfig, socketConfig); err != nil {
181 | return err
182 | }
183 | if err := u.resourceUtil.SocketUpdated(plug, socket, plugConfig, socketConfig); err != nil {
184 | return err
185 | }
186 | recorder.Event(socket, "Normal", "SocketUpdated", fmt.Sprintf("socket %s/%s updated", socket.Name, socket.Namespace))
187 | return nil
188 | }
189 |
190 | func (u *EventUtil) SocketDecoupled(
191 | plug *integrationv1beta1.Plug,
192 | socket *integrationv1beta1.Socket,
193 | plugConfig *Config,
194 | socketConfig *Config,
195 | recorder record.EventRecorder,
196 | ) error {
197 | u.logger.Info(fmt.Sprintf("socket %s/%s decoupled", socket.Name, socket.Namespace))
198 | if err := u.apparatusUtil.SocketDecoupled(plug, socket, plugConfig, socketConfig); err != nil {
199 | return err
200 | }
201 | if err := u.resourceUtil.SocketDecoupled(plug, socket, plugConfig, socketConfig); err != nil {
202 | return err
203 | }
204 | recorder.Event(socket, "Normal", "SocketDecoupled", fmt.Sprintf("socket %s/%s decoupled", socket.Name, socket.Namespace))
205 | return nil
206 | }
207 |
208 | func (u *EventUtil) SocketDeleted(
209 | socket *integrationv1beta1.Socket,
210 | recorder record.EventRecorder,
211 | ) error {
212 | u.logger.Info(fmt.Sprintf("socket %s/%s deleted", socket.Name, socket.Namespace))
213 | if err := u.apparatusUtil.SocketDeleted(socket); err != nil {
214 | return err
215 | }
216 | if err := u.resourceUtil.SocketDeleted(socket); err != nil {
217 | return err
218 | }
219 | recorder.Event(socket, "Normal", "SocketDeleted", fmt.Sprintf("socket %s/%s deleted", socket.Name, socket.Namespace))
220 | return nil
221 | }
222 |
--------------------------------------------------------------------------------
/config/crd/bases/integration.rock8s.com_deferredresources.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | controller-gen.kubebuilder.io/version: v0.11.1
7 | creationTimestamp: null
8 | name: deferredresources.integration.rock8s.com
9 | spec:
10 | group: integration.rock8s.com
11 | names:
12 | kind: DeferredResource
13 | listKind: DeferredResourceList
14 | plural: deferredresources
15 | singular: deferredresource
16 | scope: Namespaced
17 | versions:
18 | - name: v1beta1
19 | schema:
20 | openAPIV3Schema:
21 | description: DeferredResource is the Schema for the deferredresources API
22 | properties:
23 | apiVersion:
24 | description: 'APIVersion defines the versioned schema of this representation
25 | of an object. Servers should convert recognized schemas to the latest
26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
27 | type: string
28 | kind:
29 | description: 'Kind is a string value representing the REST resource this
30 | object represents. Servers may infer this from the endpoint the client
31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
32 | type: string
33 | metadata:
34 | type: object
35 | spec:
36 | description: DeferredResourceSpec defines the desired state of DeferredResource
37 | properties:
38 | resource:
39 | description: Resource is the resource to create after the defer is
40 | resolved
41 | x-kubernetes-preserve-unknown-fields: true
42 | serviceAccountName:
43 | description: 'ServiceAccountName is the name of the ServiceAccount
44 | to use to create deferred resources from. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/'
45 | type: string
46 | timeout:
47 | description: Timeout is the maximum time to wait before creating the
48 | resource
49 | format: int64
50 | type: integer
51 | waitFor:
52 | description: WaitFor is a list of resources to wait for before creating
53 | the resource
54 | items:
55 | description: Target refers to a kubernetes object by Group, Version,
56 | Kind and Name gvk.Gvk contains Group, Version and Kind APIVersion
57 | is added to keep the backward compatibility of using ObjectReference
58 | for Var.ObjRef
59 | properties:
60 | apiVersion:
61 | type: string
62 | group:
63 | type: string
64 | kind:
65 | type: string
66 | name:
67 | type: string
68 | version:
69 | type: string
70 | type: object
71 | type: array
72 | type: object
73 | status:
74 | description: DeferredResourceStatus defines the observed state of DeferredResource
75 | properties:
76 | conditions:
77 | items:
78 | description: "Condition contains details for one aspect of the current
79 | state of this API Resource. --- This struct is intended for direct
80 | use as an array at the field path .status.conditions. For example,
81 | \n type FooStatus struct{ // Represents the observations of a
82 | foo's current state. // Known .status.conditions.type are: \"Available\",
83 | \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
84 | // +listType=map // +listMapKey=type Conditions []metav1.Condition
85 | `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
86 | protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
87 | properties:
88 | lastTransitionTime:
89 | description: lastTransitionTime is the last time the condition
90 | transitioned from one status to another. This should be when
91 | the underlying condition changed. If that is not known, then
92 | using the time when the API field changed is acceptable.
93 | format: date-time
94 | type: string
95 | message:
96 | description: message is a human readable message indicating
97 | details about the transition. This may be an empty string.
98 | maxLength: 32768
99 | type: string
100 | observedGeneration:
101 | description: observedGeneration represents the .metadata.generation
102 | that the condition was set based upon. For instance, if .metadata.generation
103 | is currently 12, but the .status.conditions[x].observedGeneration
104 | is 9, the condition is out of date with respect to the current
105 | state of the instance.
106 | format: int64
107 | minimum: 0
108 | type: integer
109 | reason:
110 | description: reason contains a programmatic identifier indicating
111 | the reason for the condition's last transition. Producers
112 | of specific condition types may define expected values and
113 | meanings for this field, and whether the values are considered
114 | a guaranteed API. The value should be a CamelCase string.
115 | This field may not be empty.
116 | maxLength: 1024
117 | minLength: 1
118 | pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
119 | type: string
120 | status:
121 | description: status of the condition, one of True, False, Unknown.
122 | enum:
123 | - "True"
124 | - "False"
125 | - Unknown
126 | type: string
127 | type:
128 | description: type of condition in CamelCase or in foo.example.com/CamelCase.
129 | --- Many .condition.type values are consistent across resources
130 | like Available, but because arbitrary conditions can be useful
131 | (see .node.status.conditions), the ability to deconflict is
132 | important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
133 | maxLength: 316
134 | 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])$
135 | type: string
136 | required:
137 | - lastTransitionTime
138 | - message
139 | - reason
140 | - status
141 | - type
142 | type: object
143 | type: array
144 | ownerReferences:
145 | description: OwnerReference contains enough information to let you
146 | identify an owning object. An owning object must be in the same
147 | namespace as the dependent, or be cluster-scoped, so there is no
148 | namespace field.
149 | properties:
150 | apiVersion:
151 | description: API version of the referent.
152 | type: string
153 | blockOwnerDeletion:
154 | description: If true, AND if the owner has the "foregroundDeletion"
155 | finalizer, then the owner cannot be deleted from the key-value
156 | store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion
157 | for how the garbage collector interacts with this field and
158 | enforces the foreground deletion. Defaults to false. To set
159 | this field, a user needs "delete" permission of the owner, otherwise
160 | 422 (Unprocessable Entity) will be returned.
161 | type: boolean
162 | controller:
163 | description: If true, this reference points to the managing controller.
164 | type: boolean
165 | kind:
166 | description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
167 | type: string
168 | name:
169 | description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
170 | type: string
171 | uid:
172 | description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids'
173 | type: string
174 | required:
175 | - apiVersion
176 | - kind
177 | - name
178 | - uid
179 | type: object
180 | x-kubernetes-map-type: atomic
181 | type: object
182 | type: object
183 | served: true
184 | storage: true
185 | subresources:
186 | status: {}
187 |
--------------------------------------------------------------------------------
/util/plug.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/plug.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 | "strings"
32 | "time"
33 |
34 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
35 | "k8s.io/apimachinery/pkg/api/meta"
36 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37 | "k8s.io/apimachinery/pkg/types"
38 | "k8s.io/apiserver/pkg/registry/generic/registry"
39 | ctrl "sigs.k8s.io/controller-runtime"
40 | "sigs.k8s.io/controller-runtime/pkg/client"
41 | )
42 |
43 | type PlugUtil struct {
44 | apparatusUtil *ApparatusUtil
45 | client *client.Client
46 | ctx context.Context
47 | namespacedName types.NamespacedName
48 | req *ctrl.Request
49 | resultUtil *ResultUtil
50 | socket *integrationv1beta1.Socket
51 | }
52 |
53 | func NewPlugUtil(
54 | client *client.Client,
55 | ctx context.Context,
56 | req *ctrl.Request,
57 | namespacedName *integrationv1beta1.NamespacedName,
58 | socket *integrationv1beta1.Socket,
59 | ) *PlugUtil {
60 | operatorNamespace := GetOperatorNamespace()
61 | return &PlugUtil{
62 | apparatusUtil: NewApparatusUtil(ctx),
63 | client: client,
64 | ctx: ctx,
65 | namespacedName: EnsureNamespacedName(namespacedName, operatorNamespace),
66 | req: req,
67 | resultUtil: NewResultUtil(ctx),
68 | socket: socket,
69 | }
70 | }
71 |
72 | func (u *PlugUtil) Get() (*integrationv1beta1.Plug, error) {
73 | client := *u.client
74 | ctx := u.ctx
75 | plug := &integrationv1beta1.Plug{}
76 | if err := client.Get(ctx, u.namespacedName, plug); err != nil {
77 | return nil, err
78 | }
79 | return plug.DeepCopy(), nil
80 | }
81 |
82 | func (u *PlugUtil) Update(plug *integrationv1beta1.Plug, requeue bool) (ctrl.Result, error) {
83 | client := *u.client
84 | ctx := u.ctx
85 | if err := client.Update(ctx, plug); err != nil {
86 | return u.Error(err, plug)
87 | }
88 | if requeue {
89 | return ctrl.Result{Requeue: true, RequeueAfter: 0}, nil
90 | }
91 | return ctrl.Result{}, nil
92 | }
93 |
94 | func (u *PlugUtil) UpdateStatus(
95 | plug *integrationv1beta1.Plug,
96 | requeue bool,
97 | ) (ctrl.Result, error) {
98 | client := *u.client
99 | ctx := u.ctx
100 | if err := client.Status().Update(ctx, plug); err != nil {
101 | if strings.Contains(err.Error(), registry.OptimisticLockErrorMsg) {
102 | return ctrl.Result{Requeue: true}, nil
103 | }
104 | return ctrl.Result{}, err
105 | }
106 | if requeue {
107 | return ctrl.Result{Requeue: true, RequeueAfter: 0}, nil
108 | }
109 | return ctrl.Result{}, nil
110 | }
111 |
112 | func (u *PlugUtil) Delete(plug *integrationv1beta1.Plug) (ctrl.Result, error) {
113 | client := *u.client
114 | ctx := u.ctx
115 | if err := client.Delete(ctx, plug); err != nil {
116 | return u.Error(err, plug)
117 | }
118 | return ctrl.Result{}, nil
119 | }
120 |
121 | func (u *PlugUtil) GetCoupledCondition(
122 | plug *integrationv1beta1.Plug,
123 | ) (*metav1.Condition, error) {
124 | if plug == nil {
125 | var err error
126 | plug, err = u.Get()
127 | if err != nil {
128 | return nil, err
129 | }
130 | }
131 | coupledCondition := meta.FindStatusCondition(plug.Status.Conditions, string(ConditionTypeCoupled))
132 | return coupledCondition, nil
133 | }
134 |
135 | func (u *PlugUtil) Error(
136 | err error,
137 | plug *integrationv1beta1.Plug,
138 | ) (ctrl.Result, error) {
139 | e := err
140 | if plug == nil {
141 | var err error
142 | plug, err = u.Get()
143 | if err != nil {
144 | return ctrl.Result{}, err
145 | }
146 | }
147 | if u.apparatusUtil.NotRunning(err) {
148 | requeueAfter := time.Duration(time.Second.Nanoseconds() * 10)
149 | started, err := u.apparatusUtil.Start(plug, u.socket, &requeueAfter)
150 | if err != nil {
151 | return u.UpdateErrorStatus(err, plug)
152 | }
153 | if started {
154 | return ctrl.Result{
155 | Requeue: true,
156 | RequeueAfter: requeueAfter,
157 | }, nil
158 | }
159 | }
160 | result, err := u.UpdateErrorStatus(e, plug)
161 | if strings.Contains(e.Error(), "result property") &&
162 | strings.Contains(e.Error(), "is required") {
163 | return ctrl.Result{Requeue: true}, nil
164 | }
165 | return result, err
166 | }
167 |
168 | func (u *PlugUtil) UpdateErrorStatus(
169 | err error,
170 | plug *integrationv1beta1.Plug,
171 | ) (ctrl.Result, error) {
172 | e := err
173 | if plug == nil {
174 | var err error
175 | plug, err = u.Get()
176 | if err != nil {
177 | return ctrl.Result{}, err
178 | }
179 | }
180 | if err = u.setErrorStatus(e, plug); err != nil {
181 | return ctrl.Result{}, err
182 | }
183 | if _, err := u.UpdateStatus(plug, true); err != nil {
184 | return ctrl.Result{}, err
185 | }
186 | if strings.Contains(e.Error(), registry.OptimisticLockErrorMsg) {
187 | return ctrl.Result{Requeue: true}, nil
188 | }
189 | return ctrl.Result{}, e
190 | }
191 |
192 | func (u *PlugUtil) UpdateCoupledStatus(
193 | conditionCoupledReason ConditionCoupledReason,
194 | plug *integrationv1beta1.Plug,
195 | socket *integrationv1beta1.Socket,
196 | requeue bool,
197 | ) (ctrl.Result, error) {
198 | if plug == nil {
199 | var err error
200 | plug, err = u.Get()
201 | if err != nil {
202 | return ctrl.Result{}, err
203 | }
204 | }
205 | if socket != nil {
206 | u.setCoupledSocketStatus(plug, socket)
207 | }
208 | if conditionCoupledReason != "" {
209 | u.setCoupledStatusCondition(conditionCoupledReason, "", plug)
210 | }
211 | return u.UpdateStatus(plug, requeue)
212 | }
213 |
214 | func (u *PlugUtil) UpdateResultStatus(
215 | plug *integrationv1beta1.Plug,
216 | socket *integrationv1beta1.Socket,
217 | plugConfig Config,
218 | socketConfig Config,
219 | ) (ctrl.Result, error) {
220 | coupledResult, err := u.resultUtil.GetResult(plug, socket, plugConfig, socketConfig)
221 | if err != nil {
222 | return u.Error(err, plug)
223 | }
224 | if err := u.resultUtil.SocketTemplateResultResources(
225 | plug,
226 | socket,
227 | plugConfig,
228 | socketConfig,
229 | coupledResult.Plug,
230 | coupledResult.Socket,
231 | ); err != nil {
232 | return u.Error(err, plug)
233 | }
234 | if err := u.resultUtil.PlugTemplateResultResources(
235 | plug,
236 | socket,
237 | plugConfig,
238 | socketConfig,
239 | coupledResult.Plug,
240 | coupledResult.Socket,
241 | ); err != nil {
242 | return u.Error(err, plug)
243 | }
244 | coupledResultStatus := integrationv1beta1.CoupledResultStatus{
245 | ObservedGeneration: plug.Generation,
246 | }
247 | coupledResultStatus.Plug = coupledResult.Plug
248 | coupledResultStatus.Socket = coupledResult.Socket
249 | plug.Status.CoupledResult = &coupledResultStatus
250 | return u.UpdateCoupledStatus(CouplingSucceeded, plug, socket, false)
251 | }
252 |
253 | func (u *PlugUtil) setCoupledStatusCondition(
254 | conditionCoupledReason ConditionCoupledReason,
255 | message string,
256 | plug *integrationv1beta1.Plug,
257 | ) {
258 | coupledStatus := false
259 | if message == "" {
260 | if conditionCoupledReason == PlugCreated {
261 | message = "plug created"
262 | } else if conditionCoupledReason == SocketNotCreated {
263 | message = "waiting for socket to be created"
264 | } else if conditionCoupledReason == CouplingInProcess {
265 | message = "coupling to socket"
266 | } else if conditionCoupledReason == CouplingSucceeded {
267 | message = "coupling succeeded"
268 | } else if conditionCoupledReason == UpdatingInProcess {
269 | message = "updating coupling"
270 | } else if conditionCoupledReason == Error {
271 | message = "unknown error"
272 | }
273 | }
274 | if conditionCoupledReason != Error {
275 | plug.Status.Conditions = []metav1.Condition{}
276 | }
277 | if conditionCoupledReason == CouplingSucceeded {
278 | coupledStatus = true
279 | }
280 | condition := metav1.Condition{
281 | Message: message,
282 | ObservedGeneration: plug.Generation,
283 | Reason: string(conditionCoupledReason),
284 | Status: "False",
285 | Type: string(ConditionTypeCoupled),
286 | }
287 | if coupledStatus {
288 | condition.Status = "True"
289 | }
290 | meta.SetStatusCondition(&plug.Status.Conditions, condition)
291 | }
292 |
293 | func (u *PlugUtil) setErrorStatus(err error, plug *integrationv1beta1.Plug) error {
294 | e := err
295 | if e == nil {
296 | return nil
297 | }
298 | if plug == nil {
299 | return nil
300 | }
301 | if strings.Contains(e.Error(), registry.OptimisticLockErrorMsg) {
302 | return nil
303 | }
304 | message := e.Error()
305 | coupledCondition, err := u.GetCoupledCondition(plug)
306 | if err != nil {
307 | return err
308 | }
309 | if coupledCondition != nil {
310 | u.setCoupledStatusCondition(Error, "coupling failed", plug)
311 | }
312 | failedCondition := metav1.Condition{
313 | Message: message,
314 | ObservedGeneration: plug.Generation,
315 | Reason: "Error",
316 | Status: "True",
317 | Type: string(ConditionTypeFailed),
318 | }
319 | meta.SetStatusCondition(&plug.Status.Conditions, failedCondition)
320 | return nil
321 | }
322 |
323 | func (u *PlugUtil) setCoupledSocketStatus(
324 | plug *integrationv1beta1.Plug,
325 | socket *integrationv1beta1.Socket,
326 | ) {
327 | plug.Status.CoupledSocket = &integrationv1beta1.CoupledSocket{
328 | APIVersion: socket.APIVersion,
329 | Kind: socket.Kind,
330 | Name: socket.Name,
331 | Namespace: socket.Namespace,
332 | UID: socket.UID,
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/util/config.go:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /util/config.go
3 | * Project: integration-operator
4 | * File Created: 17-10-2023 13:49:54
5 | * Author: Clay Risser
6 | * -----
7 | * BitSpur (c) Copyright 2021 - 2023
8 | *
9 | * Licensed under the GNU Affero General Public License (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * https://www.gnu.org/licenses/agpl-3.0.en.html
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | *
21 | * You can be released from the requirements of the license by purchasing
22 | * a commercial license. Buying such a license is mandatory as soon as you
23 | * develop commercial activities involving this software without disclosing
24 | * the source code of your own applications.
25 | */
26 |
27 | package util
28 |
29 | import (
30 | "context"
31 | "encoding/json"
32 | "errors"
33 |
34 | integrationv1beta1 "gitlab.com/bitspur/rock8s/integration-operator/api/v1beta1"
35 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36 | "k8s.io/client-go/kubernetes"
37 | ctrl "sigs.k8s.io/controller-runtime"
38 | )
39 |
40 | type ConfigUtil struct {
41 | apparatusUtil *ApparatusUtil
42 | client *kubernetes.Clientset
43 | ctx context.Context
44 | dataUtil *DataUtil
45 | varUtil *VarUtil
46 | }
47 |
48 | func NewConfigUtil(
49 | ctx context.Context,
50 | ) *ConfigUtil {
51 | return &ConfigUtil{
52 | apparatusUtil: NewApparatusUtil(ctx),
53 | client: kubernetes.NewForConfigOrDie(ctrl.GetConfigOrDie()),
54 | ctx: ctx,
55 | dataUtil: NewDataUtil(ctx),
56 | varUtil: NewVarUtil(ctx),
57 | }
58 | }
59 |
60 | func (u *ConfigUtil) GetPlugConfig(
61 | plug *integrationv1beta1.Plug,
62 | socket *integrationv1beta1.Socket,
63 | ) (map[string]string, error) {
64 | plugConfig := make(map[string]string)
65 | if plug.Spec.ConfigSecretName != "" {
66 | secret, err := u.client.CoreV1().Secrets(plug.Namespace).Get(
67 | u.ctx,
68 | plug.Spec.ConfigSecretName,
69 | metav1.GetOptions{},
70 | )
71 | if err != nil {
72 | return nil, err
73 | }
74 | for key, value := range secret.Data {
75 | plugConfig[key] = string(value)
76 | }
77 | }
78 | if plug.Spec.Config != nil {
79 | for key, value := range plug.Spec.Config {
80 | plugConfig[key] = value
81 | }
82 | }
83 | if plug.Spec.ConfigTemplate != nil {
84 | for key, value := range plug.Spec.ConfigTemplate {
85 | result, err := u.plugConfigTemplateLookup(plug, value, socket)
86 | if err != nil {
87 | return nil, err
88 | }
89 | plugConfig[key] = result
90 | }
91 | }
92 | if plug.Spec.ConfigConfigMapName != "" {
93 | configMap, err := u.client.CoreV1().ConfigMaps(plug.Namespace).Get(
94 | u.ctx,
95 | plug.Spec.ConfigConfigMapName,
96 | metav1.GetOptions{},
97 | )
98 | if err != nil {
99 | return nil, err
100 | }
101 | for key, value := range configMap.Data {
102 | plugConfig[key] = string(value)
103 | }
104 | }
105 | if plug.Spec.Apparatus != nil {
106 | body, err := u.apparatusUtil.GetPlugConfig(plug, socket)
107 | if err != nil {
108 | return nil, err
109 | }
110 | apparatusPlugConfig, err := JsonToHashMap(body)
111 | if err != nil {
112 | return nil, err
113 | }
114 | for key, value := range apparatusPlugConfig {
115 | plugConfig[key] = value
116 | }
117 | }
118 | if socket.Spec.Interface == nil {
119 | return plugConfig, nil
120 | }
121 | plugConfig, err := u.ValidatePlugConfig(plug, socket.Spec.Interface.Config, plugConfig)
122 | if err != nil {
123 | return nil, err
124 | }
125 | return plugConfig, nil
126 | }
127 |
128 | func (u *ConfigUtil) GetSocketConfig(
129 | plug *integrationv1beta1.Plug,
130 | socket *integrationv1beta1.Socket,
131 | ) (map[string]string, error) {
132 | socketConfig := make(map[string]string)
133 | if socket.Spec.ConfigSecretName != "" {
134 | secret, err := u.client.CoreV1().Secrets(socket.Namespace).Get(
135 | u.ctx,
136 | socket.Spec.ConfigSecretName,
137 | metav1.GetOptions{},
138 | )
139 | if err != nil {
140 | return nil, err
141 | }
142 | for key, value := range secret.Data {
143 | socketConfig[key] = string(value)
144 | }
145 | }
146 | if socket.Spec.Config != nil {
147 | for key, value := range socket.Spec.Config {
148 | socketConfig[key] = value
149 | }
150 | }
151 | if socket.Spec.ConfigTemplate != nil {
152 | for key, value := range socket.Spec.ConfigTemplate {
153 | result, err := u.socketConfigTemplateLookup(socket, value, plug)
154 | if err != nil {
155 | return nil, err
156 | }
157 | socketConfig[key] = result
158 | }
159 | }
160 | if socket.Spec.ConfigConfigMapName != "" {
161 | configMap, err := u.client.CoreV1().ConfigMaps(socket.Namespace).Get(
162 | u.ctx,
163 | socket.Spec.ConfigConfigMapName,
164 | metav1.GetOptions{},
165 | )
166 | if err != nil {
167 | return nil, err
168 | }
169 | for key, value := range configMap.Data {
170 | socketConfig[key] = value
171 | }
172 | }
173 | if socket.Spec.Apparatus != nil {
174 | body, err := u.apparatusUtil.GetSocketConfig(socket, plug)
175 | if err != nil {
176 | return nil, err
177 | }
178 | apparatusSocketConfig, err := JsonToHashMap(body)
179 | if err != nil {
180 | return nil, err
181 | }
182 | for key, value := range apparatusSocketConfig {
183 | socketConfig[key] = value
184 | }
185 | }
186 | socketConfig, err := u.ValidateSocketConfig(socket, socketConfig)
187 | if err != nil {
188 | return nil, err
189 | }
190 | return socketConfig, nil
191 | }
192 |
193 | func (u *ConfigUtil) ValidatePlugConfig(
194 | plug *integrationv1beta1.Plug,
195 | configInterface *integrationv1beta1.ConfigInterface,
196 | plugConfig map[string]string,
197 | ) (map[string]string, error) {
198 | if configInterface == nil {
199 | return plugConfig, nil
200 | }
201 | validatedPlugConfig := make(map[string]string)
202 | for propertyName, property := range configInterface.Plug {
203 | if value, found := plugConfig[propertyName]; found && value != "" {
204 | validatedPlugConfig[propertyName] = plugConfig[propertyName]
205 | } else {
206 | if property.Required {
207 | return plugConfig, errors.New("plug config property '" + propertyName + "' is required")
208 | } else if property.Default != "" {
209 | validatedPlugConfig[propertyName] = property.Default
210 | }
211 | }
212 | }
213 | return validatedPlugConfig, nil
214 | }
215 |
216 | func (u *ConfigUtil) ValidateSocketConfig(
217 | socket *integrationv1beta1.Socket,
218 | socketConfig map[string]string,
219 | ) (map[string]string, error) {
220 | if socket.Spec.Interface == nil {
221 | return socketConfig, nil
222 | }
223 | configInterface := socket.Spec.Interface.Config
224 | if configInterface == nil {
225 | return socketConfig, nil
226 | }
227 | validatedSocketConfig := make(map[string]string)
228 | for propertyName, property := range configInterface.Socket {
229 | if _, found := socketConfig[propertyName]; found {
230 | validatedSocketConfig[propertyName] = socketConfig[propertyName]
231 | } else {
232 | if property.Required {
233 | return socketConfig, errors.New("socket config property '" + propertyName + "' is required")
234 | } else if property.Default != "" {
235 | validatedSocketConfig[propertyName] = property.Default
236 | }
237 | }
238 | }
239 | return validatedSocketConfig, nil
240 | }
241 |
242 | func (u *ConfigUtil) plugConfigTemplateLookup(plug *integrationv1beta1.Plug, configTemplate string, socket *integrationv1beta1.Socket) (string, error) {
243 | data, err := u.buildPlugConfigTemplateData(*plug, socket)
244 | if err != nil {
245 | return "", err
246 | }
247 | return Template(&data, configTemplate)
248 | }
249 |
250 | func (u *ConfigUtil) socketConfigTemplateLookup(
251 | socket *integrationv1beta1.Socket,
252 | configTemplate string,
253 | plug *integrationv1beta1.Plug,
254 | ) (string, error) {
255 | data, err := u.buildSocketConfigTemplateData(*socket, plug)
256 | if err != nil {
257 | return "", err
258 | }
259 | return Template(&data, configTemplate)
260 | }
261 |
262 | func (u *ConfigUtil) buildPlugConfigTemplateData(
263 | plug integrationv1beta1.Plug,
264 | socket *integrationv1beta1.Socket,
265 | ) (map[string]interface{}, error) {
266 | kubectlUtil := NewKubectlUtil(u.ctx, plug.Namespace, EnsureServiceAccount(plug.Spec.ServiceAccountName))
267 | dataMap := map[string]interface{}{}
268 | dataMap["plug"] = plug
269 | if socket != nil {
270 | dataMap["socket"] = socket
271 | }
272 | plugData, err := u.dataUtil.GetPlugData(&plug)
273 | if err != nil {
274 | return dataMap, err
275 | }
276 | dataMap["plugData"] = plugData
277 | socketData, err := u.dataUtil.GetSocketData(socket)
278 | if err != nil {
279 | return dataMap, err
280 | }
281 | dataMap["socketData"] = socketData
282 | if plug.Spec.Vars != nil {
283 | varsMap, err := u.varUtil.GetVars(plug.Namespace, plug.Spec.Vars, kubectlUtil, &plug, socket)
284 | if err != nil {
285 | return dataMap, err
286 | }
287 | dataMap["vars"] = varsMap
288 | }
289 | bData, err := json.Marshal(dataMap)
290 | if err != nil {
291 | return nil, err
292 | }
293 | var data map[string]interface{}
294 | if err := json.Unmarshal(bData, &data); err != nil {
295 | return nil, err
296 | }
297 | return data, nil
298 | }
299 |
300 | func (u *ConfigUtil) buildSocketConfigTemplateData(
301 | socket integrationv1beta1.Socket,
302 | plug *integrationv1beta1.Plug,
303 | ) (map[string]interface{}, error) {
304 | kubectlUtil := NewKubectlUtil(u.ctx, socket.Namespace, EnsureServiceAccount(socket.Spec.ServiceAccountName))
305 | dataMap := map[string]interface{}{}
306 | dataMap["socket"] = socket
307 | if plug != nil {
308 | dataMap["plug"] = plug
309 | }
310 | socketData, err := u.dataUtil.GetSocketData(&socket)
311 | if err != nil {
312 | return dataMap, err
313 | }
314 | dataMap["socketData"] = socketData
315 | plugData, err := u.dataUtil.GetPlugData(plug)
316 | if err != nil {
317 | return dataMap, err
318 | }
319 | dataMap["plugData"] = plugData
320 | if socket.Spec.Vars != nil {
321 | varsMap, err := u.varUtil.GetVars(socket.Namespace, socket.Spec.Vars, kubectlUtil, plug, &socket)
322 | if err != nil {
323 | return dataMap, err
324 | }
325 | dataMap["vars"] = varsMap
326 | }
327 | bData, err := json.Marshal(dataMap)
328 | if err != nil {
329 | return nil, err
330 | }
331 | var data map[string]interface{}
332 | if err := json.Unmarshal(bData, &data); err != nil {
333 | return nil, err
334 | }
335 | return data, nil
336 | }
337 |
--------------------------------------------------------------------------------
/chart/templates/crds/integration.rock8s.com_deferredresources.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | controller-gen.kubebuilder.io/version: v0.11.1
7 | creationTimestamp: null
8 | name: deferredresources.integration.rock8s.com
9 | spec:
10 | group: integration.rock8s.com
11 | names:
12 | kind: DeferredResource
13 | listKind: DeferredResourceList
14 | plural: deferredresources
15 | singular: deferredresource
16 | scope: Namespaced
17 | versions:
18 | - name: v1beta1
19 | schema:
20 | openAPIV3Schema:
21 | description: DeferredResource is the Schema for the deferredresources API
22 | properties:
23 | apiVersion:
24 | description:
25 | "APIVersion defines the versioned schema of this representation
26 | of an object. Servers should convert recognized schemas to the latest
27 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
28 | type: string
29 | kind:
30 | description:
31 | "Kind is a string value representing the REST resource this
32 | object represents. Servers may infer this from the endpoint the client
33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
34 | type: string
35 | metadata:
36 | type: object
37 | spec:
38 | description: DeferredResourceSpec defines the desired state of DeferredResource
39 | properties:
40 | resource:
41 | description:
42 | Resource is the resource to create after the defer is
43 | resolved
44 | x-kubernetes-preserve-unknown-fields: true
45 | serviceAccountName:
46 | description:
47 | "ServiceAccountName is the name of the ServiceAccount
48 | to use to create deferred resources from. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/"
49 | type: string
50 | timeout:
51 | description:
52 | Timeout is the maximum time to wait before creating the
53 | resource
54 | format: int64
55 | type: integer
56 | waitFor:
57 | description:
58 | WaitFor is a list of resources to wait for before creating
59 | the resource
60 | items:
61 | description:
62 | Target refers to a kubernetes object by Group, Version,
63 | Kind and Name gvk.Gvk contains Group, Version and Kind APIVersion
64 | is added to keep the backward compatibility of using ObjectReference
65 | for Var.ObjRef
66 | properties:
67 | apiVersion:
68 | type: string
69 | group:
70 | type: string
71 | kind:
72 | type: string
73 | name:
74 | type: string
75 | version:
76 | type: string
77 | type: object
78 | type: array
79 | type: object
80 | status:
81 | description: DeferredResourceStatus defines the observed state of DeferredResource
82 | properties:
83 | conditions:
84 | items:
85 | description:
86 | "Condition contains details for one aspect of the current
87 | state of this API Resource. --- This struct is intended for direct
88 | use as an array at the field path .status.conditions. For example,
89 | \n type FooStatus struct{ // Represents the observations of a
90 | foo's current state. // Known .status.conditions.type are: \"Available\",
91 | \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
92 | // +listType=map // +listMapKey=type Conditions []metav1.Condition
93 | `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
94 | protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
95 | properties:
96 | lastTransitionTime:
97 | description:
98 | lastTransitionTime is the last time the condition
99 | transitioned from one status to another. This should be when
100 | the underlying condition changed. If that is not known, then
101 | using the time when the API field changed is acceptable.
102 | format: date-time
103 | type: string
104 | message:
105 | description:
106 | message is a human readable message indicating
107 | details about the transition. This may be an empty string.
108 | maxLength: 32768
109 | type: string
110 | observedGeneration:
111 | description:
112 | observedGeneration represents the .metadata.generation
113 | that the condition was set based upon. For instance, if .metadata.generation
114 | is currently 12, but the .status.conditions[x].observedGeneration
115 | is 9, the condition is out of date with respect to the current
116 | state of the instance.
117 | format: int64
118 | minimum: 0
119 | type: integer
120 | reason:
121 | description:
122 | reason contains a programmatic identifier indicating
123 | the reason for the condition's last transition. Producers
124 | of specific condition types may define expected values and
125 | meanings for this field, and whether the values are considered
126 | a guaranteed API. The value should be a CamelCase string.
127 | This field may not be empty.
128 | maxLength: 1024
129 | minLength: 1
130 | pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
131 | type: string
132 | status:
133 | description: status of the condition, one of True, False, Unknown.
134 | enum:
135 | - "True"
136 | - "False"
137 | - Unknown
138 | type: string
139 | type:
140 | description:
141 | type of condition in CamelCase or in foo.example.com/CamelCase.
142 | --- Many .condition.type values are consistent across resources
143 | like Available, but because arbitrary conditions can be useful
144 | (see .node.status.conditions), the ability to deconflict is
145 | important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
146 | maxLength: 316
147 | 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])$
148 | type: string
149 | required:
150 | - lastTransitionTime
151 | - message
152 | - reason
153 | - status
154 | - type
155 | type: object
156 | type: array
157 | ownerReferences:
158 | description:
159 | OwnerReference contains enough information to let you
160 | identify an owning object. An owning object must be in the same
161 | namespace as the dependent, or be cluster-scoped, so there is no
162 | namespace field.
163 | properties:
164 | apiVersion:
165 | description: API version of the referent.
166 | type: string
167 | blockOwnerDeletion:
168 | description:
169 | If true, AND if the owner has the "foregroundDeletion"
170 | finalizer, then the owner cannot be deleted from the key-value
171 | store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion
172 | for how the garbage collector interacts with this field and
173 | enforces the foreground deletion. Defaults to false. To set
174 | this field, a user needs "delete" permission of the owner, otherwise
175 | 422 (Unprocessable Entity) will be returned.
176 | type: boolean
177 | controller:
178 | description: If true, this reference points to the managing controller.
179 | type: boolean
180 | kind:
181 | description: "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
182 | type: string
183 | name:
184 | description: "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
185 | type: string
186 | uid:
187 | description: "UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids"
188 | type: string
189 | required:
190 | - apiVersion
191 | - kind
192 | - name
193 | - uid
194 | type: object
195 | x-kubernetes-map-type: atomic
196 | type: object
197 | type: object
198 | served: true
199 | storage: true
200 | subresources:
201 | status: {}
202 |
--------------------------------------------------------------------------------