Skip to content

Commit 917bbad

Browse files
committed
[OCTRL-1088] first environment controller
1 parent 8ef9806 commit 917bbad

52 files changed

Lines changed: 10162 additions & 67 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

control-operator/Dockerfile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,26 @@
22
FROM golang:1.25 as builder
33
ARG TARGETOS
44
ARG TARGETARCH
5+
ARG MANAGER=task-manager
56

67
WORKDIR /workspace
78
# Copy the Go Modules manifests
89
COPY go.mod go.mod
910
COPY go.sum go.sum
10-
RUN sed -i '\,replace github.com/AliceO2Group/Control,d' go.mod
1111
# cache deps before building and copying source so that we don't need to re-download as much
1212
# and so that source changes don't invalidate our downloaded layer
1313
RUN go mod download
1414

1515
# Copy the go source
16-
COPY cmd/main.go cmd/main.go
16+
COPY cmd/ cmd/
1717
COPY api/ api/
1818
COPY internal/controller/ internal/controller/
19-
2019
# Build
2120
# the GOARCH has not a default value to allow the binary be built according to the host where the command
2221
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
2322
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
2423
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
25-
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
24+
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager ./cmd/${MANAGER}/
2625

2726
# Use distroless as minimal base image to package the manager binary
2827
# Refer to https://github.com/GoogleContainerTools/distroless for more details

control-operator/Makefile

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ IMAGE_TAG_BASE ?= gitlab-registry.cern.ch/aliceo2group/dockerfiles/aliecs
3333

3434
# BUNDLE_IMG defines the image:tag used for the bundle.
3535
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
36-
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)
36+
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)/bundle:v$(VERSION)
3737

3838
# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
3939
BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
@@ -51,7 +51,8 @@ endif
5151
OPERATOR_SDK_VERSION ?= unknown
5252

5353
# Image URL to use all building/pushing image targets
54-
IMG ?= gitlab-registry.cern.ch/aliceo2group/dockerfiles/aliecs/task-manager:latest
54+
TASK_IMG ?= gitlab-registry.cern.ch/aliceo2group/dockerfiles/aliecs/task-manager:latest
55+
ENVIRONMENT_IMG ?= gitlab-registry.cern.ch/aliceo2group/dockerfiles/aliecs/environment-manager:latest
5556
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
5657
ENVTEST_K8S_VERSION = 1.27.1
5758

@@ -97,11 +98,11 @@ help: ## Display this help.
9798

9899
.PHONY: manifests
99100
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
100-
# Note that the option maxDescLen=0 was added in the default scaffold in order to sort out the issue
101-
# Too long: must have at most 262144 bytes. By using kubectl apply to create / update resources an annotation
102-
# is created by K8s API to store the latest version of the resource ( kubectl.kubernetes.io/last-applied-configuration).
103-
# However, it has a size limit and if the CRD is too big with so many long descriptions as this one it will cause the failure.
104-
$(CONTROLLER_GEN) rbac:roleName=manager-role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases
101+
# Note that the option maxDescLen=0 was added in the default scaffold in order to sort out the issue
102+
# Too long: must have at most 262144 bytes. By using kubectl apply to create / update resources an annotation
103+
# is created by K8s API to store the latest version of the resource ( kubectl.kubernetes.io/last-applied-configuration).
104+
# However, it has a size limit and if the CRD is too big with so many long descriptions as this one it will cause the failure.
105+
$(CONTROLLER_GEN) rbac:roleName=manager-role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases
105106

106107
# .PHONY: manifests
107108
# manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
@@ -137,23 +138,42 @@ clean-proto: ## Remove generated protobuf and gRPC Go files.
137138
##@ Build
138139

139140
.PHONY: build
140-
build: manifests generate fmt vet ## Build manager binary.
141-
go build -o bin/manager cmd/main.go
141+
build: manifests generate fmt vet ## Build manager binaries.
142+
go build -o bin/task-manager ./cmd/task-manager/
143+
go build -o bin/environment-manager ./cmd/environment-manager/
142144

143-
.PHONY: run
144-
run: manifests generate fmt vet ## Run a controller from your host.
145-
go run ./cmd/main.go
145+
.PHONY: run-task
146+
run-task: manifests generate fmt vet ## Run the task controller from your host.
147+
go run ./cmd/task-manager/
148+
149+
.PHONY: run-environment
150+
run-environment: manifests generate fmt vet ## Run the environment controller from your host.
151+
go run ./cmd/environment-manager/
146152

147153
# If you wish built the manager image targeting other platforms you can use the --platform flag.
148154
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
149155
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
150156
.PHONY: docker-build
151-
docker-build: test ## Build docker image with the manager.
152-
$(CONTAINER_TOOL) build -t ${IMG} .
157+
docker-build: docker-build-task docker-build-environment ## Build all docker images.
158+
159+
.PHONY: docker-build-task
160+
docker-build-task: test ## Build docker image for the task manager.
161+
$(CONTAINER_TOOL) build --build-arg MANAGER=task-manager -t ${TASK_IMG} .
162+
163+
.PHONY: docker-build-environment
164+
docker-build-environment: test ## Build docker image for the environment manager.
165+
$(CONTAINER_TOOL) build --build-arg MANAGER=environment-manager -t ${ENVIRONMENT_IMG} .
153166

154167
.PHONY: docker-push
155-
docker-push: ## Push docker image with the manager.
156-
$(CONTAINER_TOOL) push ${IMG}
168+
docker-push: docker-push-task docker-push-environment ## Push all docker images.
169+
170+
.PHONY: docker-push-task
171+
docker-push-task: ## Push docker image for the task manager.
172+
$(CONTAINER_TOOL) push ${TASK_IMG}
173+
174+
.PHONY: docker-push-environment
175+
docker-push-environment: ## Push docker image for the environment manager.
176+
$(CONTAINER_TOOL) push ${ENVIRONMENT_IMG}
157177

158178
# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple
159179
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
@@ -187,12 +207,20 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
187207
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
188208

189209
.PHONY: deploy
190-
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
191-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
192-
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - --server-side
210+
deploy: deploy-task deploy-environment ## Deploy both controllers to the K8s cluster specified in ~/.kube/config.
211+
212+
.PHONY: deploy-task
213+
deploy-task: manifests kustomize ## Deploy task controller to the K8s cluster specified in ~/.kube/config.
214+
cd config/task && $(KUSTOMIZE) edit set image task-manager=${TASK_IMG}
215+
$(KUSTOMIZE) build config/task | $(KUBECTL) apply -f - --server-side
216+
217+
.PHONY: deploy-environment
218+
deploy-environment: manifests kustomize ## Deploy environment controller to the K8s cluster specified in ~/.kube/config.
219+
cd config/environment && $(KUSTOMIZE) edit set image environment-manager=${ENVIRONMENT_IMG}
220+
$(KUSTOMIZE) build config/environment | $(KUBECTL) apply -f - --server-side
193221

194222
.PHONY: undeploy
195-
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
223+
undeploy: ## Undeploy both controllers from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
196224
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
197225

198226
##@ Build Dependencies
@@ -252,7 +280,8 @@ endif
252280
.PHONY: bundle
253281
bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files.
254282
$(OPERATOR_SDK) generate kustomize manifests -q
255-
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
283+
cd config/manager && $(KUSTOMIZE) edit set image task-manager=$(TASK_IMG)
284+
cd config/manager && $(KUSTOMIZE) edit set image environment-manager=$(ENVIRONMENT_IMG)
256285
$(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS)
257286
$(OPERATOR_SDK) bundle validate ./bundle
258287

@@ -286,7 +315,7 @@ endif
286315
BUNDLE_IMGS ?= $(BUNDLE_IMG)
287316

288317
# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0).
289-
CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION)
318+
CATALOG_IMG ?= $(IMAGE_TAG_BASE)/catalog:v$(VERSION)
290319

291320
# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image.
292321
ifneq ($(origin CATALOG_BASE_IMG), undefined)

control-operator/PROJECT

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,21 @@ resources:
2020
kind: Task
2121
path: github.com/AliceO2Group/Control/operator/api/v1alpha1
2222
version: v1alpha1
23+
- api:
24+
crdVersion: v1
25+
namespaced: true
26+
controller: true
27+
domain: alice.cern
28+
group: aliecs
29+
kind: Environment
30+
path: github.com/AliceO2Group/Control/operator/api/v1alpha1
31+
version: v1alpha1
32+
- api:
33+
crdVersion: v1
34+
namespaced: true
35+
domain: alice.cern
36+
group: aliecs
37+
kind: TaskTemplate
38+
path: github.com/AliceO2Group/Control/operator/api/v1alpha1
39+
version: v1alpha1
2340
version: "3"
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* === This file is part of ALICE O² ===
3+
*
4+
* Copyright 2024 CERN and copyright holders of ALICE O².
5+
* Author: Teo Mrnjavac <teo.mrnjavac@cern.ch>
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
* In applying this license CERN does not waive the privileges and
21+
* immunities granted to it by virtue of its status as an
22+
* Intergovernmental Organization or submit itself to any jurisdiction.
23+
*/
24+
25+
package v1alpha1
26+
27+
import (
28+
v1 "k8s.io/api/core/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
)
31+
32+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
33+
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
34+
35+
// EnvironmentSpec defines the desired state of Environment
36+
type EnvironmentSpec struct {
37+
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
38+
// Important: Run "make" to regenerate code after modifying this file
39+
// The following markers will use OpenAPI v3 schema to validate the value
40+
// More info: https://book.kubebuilder.io/reference/markers/crd-validation.html
41+
42+
Tasks map[string][]TaskTemplate `json:"tasks"`
43+
// +kubebuilder:validation:Enum=standby;deployed;configured;running
44+
State string `json:"state"`
45+
}
46+
47+
// EnvironmentStatus defines the observed state of Environment.
48+
type EnvironmentStatus struct {
49+
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
50+
// Important: Run "make" to regenerate code after modifying this file
51+
52+
// For Kubernetes API conventions, see:
53+
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
54+
// conditions represent the current state of the Environment resource.
55+
// Each condition has a unique type and reflects the status of a specific aspect of the resource.
56+
//
57+
// Standard condition types include:
58+
// - "Available": the resource is fully functional
59+
// - "Progressing": the resource is being created or updated
60+
// - "Degraded": the resource failed to reach or maintain its desired state
61+
//
62+
// The status of each condition is one of True, False, or Unknown.
63+
// +listType=map
64+
// +listMapKey=type
65+
// +optional
66+
Conditions []metav1.Condition `json:"conditions,omitempty"`
67+
68+
Tasks map[string]map[string]string `json:"tasks"`
69+
State string `json:"state,omitempty"`
70+
}
71+
72+
type TaskReference struct {
73+
Name string `json:"name"`
74+
Env []v1.EnvVar `json:"env"`
75+
ArgsCLI []string `json:"argsCLI"`
76+
ArgsTransition map[string]string `json:"argsTransition"`
77+
}
78+
79+
type TemplateSpecification struct {
80+
Tasks map[string][]TaskReference `json:"tasks"`
81+
}
82+
83+
// +kubebuilder:object:root=true
84+
// +kubebuilder:subresource:status
85+
// +kubebuilder:printcolumn:name="Desired",type="string",JSONPath=".spec.state"
86+
// +kubebuilder:printcolumn:name="Actual",type="string",JSONPath=".status.state"
87+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
88+
89+
// Environment is the Schema for the environments API
90+
type Environment struct {
91+
metav1.TypeMeta `json:",inline"`
92+
93+
// metadata is a standard object metadata
94+
// +optional
95+
metav1.ObjectMeta `json:"metadata,omitzero"`
96+
97+
// taskTemplates defines templates stored in cluster to be used
98+
// for task creation, meant for more common tasks
99+
// +optional
100+
TaskTemplates TemplateSpecification `json:"taskTemplates"`
101+
102+
// spec defines the desired state of Environment
103+
// +required
104+
Spec EnvironmentSpec `json:"spec"`
105+
106+
// status defines the observed state of Environment
107+
// +optional
108+
Status EnvironmentStatus `json:"status,omitzero"`
109+
}
110+
111+
// +kubebuilder:object:root=true
112+
113+
// EnvironmentList contains a list of Environment
114+
type EnvironmentList struct {
115+
metav1.TypeMeta `json:",inline"`
116+
metav1.ListMeta `json:"metadata,omitzero"`
117+
Items []Environment `json:"items"`
118+
}
119+
120+
func init() {
121+
SchemeBuilder.Register(&Environment{}, &EnvironmentList{})
122+
}

control-operator/api/v1alpha1/task_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ type TaskSpec struct {
8484
Properties map[string]string `json:"properties,omitempty"`
8585
Arguments map[string]string `json:"arguments,omitempty"`
8686
// +kubebuilder:validation:Enum=standby;deployed;configured;running
87-
State string `json:"state,omitempty"` // this is the *requested* state, there are other states the task may end up in but cannot be requested
87+
State string `json:"state,omitempty"` // this is the *requested* state, there are other states the task may end up in but cannot be requested
88+
NodeName string `json:"nodeName,omitempty"`
8889
}
8990

9091
// TaskStatus defines the observed state of Task

0 commit comments

Comments
 (0)