Merge "Added deployment for A1."
authorThoralf Czichy <thoralf.czichy@nokia.com>
Thu, 7 Dec 2023 09:22:16 +0000 (09:22 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Thu, 7 Dec 2023 09:22:16 +0000 (09:22 +0000)
depRicKubernetesOperator/Dockerfile
depRicKubernetesOperator/Makefile
depRicKubernetesOperator/go.mod
depRicKubernetesOperator/internal/controller/getConfigmap.go [new file with mode: 0644]
depRicKubernetesOperator/internal/controller/getIngress.go [new file with mode: 0644]
depRicKubernetesOperator/internal/controller/ricplatform_controller.go
depRicKubernetesOperator/internal/controller/suite_test.go [new file with mode: 0644]

index e69de29..e0309e2 100644 (file)
@@ -0,0 +1,33 @@
+# Build the manager binary\r
+FROM golang:1.20 as builder\r
+ARG TARGETOS\r
+ARG TARGETARCH\r
+\r
+WORKDIR /workspace\r
+# Copy the Go Modules manifests\r
+COPY go.mod go.mod\r
+COPY go.sum go.sum\r
+# cache deps before building and copying source so that we don't need to re-download as much\r
+# and so that source changes don't invalidate our downloaded layer\r
+RUN go mod download\r
+\r
+# Copy the go source\r
+COPY cmd/main.go cmd/main.go\r
+COPY api/ api/\r
+COPY internal/controller/ internal/controller/\r
+\r
+# Build\r
+# the GOARCH has not a default value to allow the binary be built according to the host where the command\r
+# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO\r
+# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,\r
+# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.\r
+RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go\r
+\r
+# Use distroless as minimal base image to package the manager binary\r
+# Refer to https://github.com/GoogleContainerTools/distroless for more details\r
+FROM gcr.io/distroless/static:nonroot\r
+WORKDIR /\r
+COPY --from=builder /workspace/manager .\r
+USER 65532:65532\r
+\r
+ENTRYPOINT ["/manager"]\r
index e69de29..75ac164 100644 (file)
@@ -0,0 +1,163 @@
+\r
+# Image URL to use all building/pushing image targets\r
+IMG ?= controller:latest\r
+# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.\r
+ENVTEST_K8S_VERSION = 1.27.1\r
+\r
+# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)\r
+ifeq (,$(shell go env GOBIN))\r
+GOBIN=$(shell go env GOPATH)/bin\r
+else\r
+GOBIN=$(shell go env GOBIN)\r
+endif\r
+\r
+# CONTAINER_TOOL defines the container tool to be used for building images.\r
+# Be aware that the target commands are only tested with Docker which is\r
+# scaffolded by default. However, you might want to replace it to use other\r
+# tools. (i.e. podman)\r
+CONTAINER_TOOL ?= docker\r
+\r
+# Setting SHELL to bash allows bash commands to be executed by recipes.\r
+# Options are set to exit when a recipe line exits non-zero or a piped command fails.\r
+SHELL = /usr/bin/env bash -o pipefail\r
+.SHELLFLAGS = -ec\r
+\r
+.PHONY: all\r
+all: build\r
+\r
+##@ General\r
+\r
+# The help target prints out all targets with their descriptions organized\r
+# beneath their categories. The categories are represented by '##@' and the\r
+# target descriptions by '##'. The awk commands is responsible for reading the\r
+# entire set of makefiles included in this invocation, looking for lines of the\r
+# file as xyz: ## something, and then pretty-format the target and help. Then,\r
+# if there's a line with ##@ something, that gets pretty-printed as a category.\r
+# More info on the usage of ANSI control characters for terminal formatting:\r
+# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters\r
+# More info on the awk command:\r
+# http://linuxcommand.org/lc3_adv_awk.php\r
+\r
+.PHONY: help\r
+help: ## Display this help.\r
+       @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)\r
+\r
+##@ Development\r
+\r
+.PHONY: manifests\r
+manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.\r
+       $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases\r
+\r
+.PHONY: generate\r
+generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.\r
+       $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."\r
+\r
+.PHONY: fmt\r
+fmt: ## Run go fmt against code.\r
+       go fmt ./...\r
+\r
+.PHONY: vet\r
+vet: ## Run go vet against code.\r
+       go vet ./...\r
+\r
+.PHONY: test\r
+test: manifests generate fmt vet envtest ## Run tests.\r
+       KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out\r
+\r
+##@ Build\r
+\r
+.PHONY: build\r
+build: manifests generate fmt vet ## Build manager binary.\r
+       go build -o bin/manager cmd/main.go\r
+\r
+.PHONY: run\r
+run: manifests generate fmt vet ## Run a controller from your host.\r
+       go run ./cmd/main.go\r
+\r
+# If you wish built the manager image targeting other platforms you can use the --platform flag.\r
+# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.\r
+# More info: https://docs.docker.com/develop/develop-images/build_enhancements/\r
+.PHONY: docker-build\r
+docker-build: test ## Build docker image with the manager.\r
+       $(CONTAINER_TOOL) build -t ${IMG} .\r
+\r
+.PHONY: docker-push\r
+docker-push: ## Push docker image with the manager.\r
+       $(CONTAINER_TOOL) push ${IMG}\r
+\r
+# PLATFORMS defines the target platforms for  the manager image be build to provide support to multiple\r
+# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:\r
+# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/\r
+# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/\r
+# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=<myregistry/image:<tag>> then the export will fail)\r
+# To properly provided solutions that supports more than one platform you should use this option.\r
+PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le\r
+.PHONY: docker-buildx\r
+docker-buildx: test ## Build and push docker image for the manager for cross-platform support\r
+       # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile\r
+       sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross\r
+       - $(CONTAINER_TOOL) buildx create --name project-v3-builder\r
+       $(CONTAINER_TOOL) buildx use project-v3-builder\r
+       - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .\r
+       - $(CONTAINER_TOOL) buildx rm project-v3-builder\r
+       rm Dockerfile.cross\r
+\r
+##@ Deployment\r
+\r
+ifndef ignore-not-found\r
+  ignore-not-found = false\r
+endif\r
+\r
+.PHONY: install\r
+install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.\r
+       $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -\r
+\r
+.PHONY: uninstall\r
+uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.\r
+       $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -\r
+\r
+.PHONY: deploy\r
+deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.\r
+       cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}\r
+       $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -\r
+\r
+.PHONY: undeploy\r
+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.\r
+       $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -\r
+\r
+##@ Build Dependencies\r
+\r
+## Location to install dependencies to\r
+LOCALBIN ?= $(shell pwd)/bin\r
+$(LOCALBIN):\r
+       mkdir -p $(LOCALBIN)\r
+\r
+## Tool Binaries\r
+KUBECTL ?= kubectl\r
+KUSTOMIZE ?= $(LOCALBIN)/kustomize\r
+CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen\r
+ENVTEST ?= $(LOCALBIN)/setup-envtest\r
+\r
+## Tool Versions\r
+KUSTOMIZE_VERSION ?= v5.0.1\r
+CONTROLLER_TOOLS_VERSION ?= v0.12.0\r
+\r
+.PHONY: kustomize\r
+kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.\r
+$(KUSTOMIZE): $(LOCALBIN)\r
+       @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \\r
+               echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \\r
+               rm -rf $(LOCALBIN)/kustomize; \\r
+       fi\r
+       test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION)\r
+\r
+.PHONY: controller-gen\r
+controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.\r
+$(CONTROLLER_GEN): $(LOCALBIN)\r
+       test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \\r
+       GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)\r
+\r
+.PHONY: envtest\r
+envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.\r
+$(ENVTEST): $(LOCALBIN)\r
+       test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest\r
index 55fe72a..d6e6614 100644 (file)
@@ -3,8 +3,6 @@ module ricdeploy
 go 1.20
 
 require (
-       github.com/onsi/ginkgo/v2 v2.9.5
-       github.com/onsi/gomega v1.27.7
        k8s.io/apimachinery v0.27.2
        k8s.io/client-go v0.27.2
        sigs.k8s.io/controller-runtime v0.15.0
@@ -22,14 +20,12 @@ require (
        github.com/go-openapi/jsonpointer v0.19.6 // indirect
        github.com/go-openapi/jsonreference v0.20.1 // indirect
        github.com/go-openapi/swag v0.22.3 // indirect
-       github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
        github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
        github.com/golang/protobuf v1.5.3 // indirect
        github.com/google/gnostic v0.5.7-v3refs // indirect
        github.com/google/go-cmp v0.5.9 // indirect
        github.com/google/gofuzz v1.1.0 // indirect
-       github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
        github.com/google/uuid v1.3.0 // indirect
        github.com/imdario/mergo v0.3.6 // indirect
        github.com/josharian/intern v1.0.0 // indirect
@@ -54,7 +50,6 @@ require (
        golang.org/x/term v0.8.0 // indirect
        golang.org/x/text v0.9.0 // indirect
        golang.org/x/time v0.3.0 // indirect
-       golang.org/x/tools v0.9.1 // indirect
        gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
        google.golang.org/appengine v1.6.7 // indirect
        google.golang.org/protobuf v1.30.0 // indirect
diff --git a/depRicKubernetesOperator/internal/controller/getConfigmap.go b/depRicKubernetesOperator/internal/controller/getConfigmap.go
new file mode 100644 (file)
index 0000000..05f1bbc
--- /dev/null
@@ -0,0 +1,54 @@
+package controller\r
+\r
+import (\r
+       corev1 "k8s.io/api/core/v1"\r
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"\r
+)\r
+\r
+func GetConfigMap() []*corev1.ConfigMap {\r
+\r
+       configMap1 := &corev1.ConfigMap{\r
+               ObjectMeta: metav1.ObjectMeta{\r
+                       Name: "configmap-ricplt-a1mediator-a1conf",\r
+               },\r
+               TypeMeta: metav1.TypeMeta{\r
+                       APIVersion: "v1",\r
+                       Kind:       "ConfigMap",\r
+               },\r
+               Data: map[string]string{\r
+                       "local.rt": "newrt|start\n" +\r
+                               "# Warning! this is not a functioning table because the subscription manager and route manager are now involved in a1 flows\n" +\r
+                               "# the real routing table requires subscription ids as routing is now done over sub ids, but this isn't known until xapp deploy time, it's a dynamic process triggered by the xapp manager\n" +\r
+                               "# there is a single message type for all messages a1 sends out now, subid is the other necessary piece of info\n" +\r
+                               "# there are two message types a1 listens for; 20011 (instance response) and 20012 (query)\n" +\r
+                               "# xapps likely use rts to reply with 20012 so the routing entry isn't needed for that in most cases\n" +\r
+                               "mse|20010|SUBID|service-ricxapp-admctrl-rmr.ricxapp:4563\n" +\r
+                               "rte|20011|service-ricplt-a1mediator-rmr.ricplt:4562\n" +\r
+                               "rte|20012|service-ricplt-a1mediator-rmr.ricplt:4562\n" +\r
+                               "newrt|end\n" +\r
+                               "",\r
+                       "loglevel.txt": "log-level:",\r
+               },\r
+       }\r
+\r
+       configMap2 := &corev1.ConfigMap{\r
+               Data: map[string]string{\r
+                       "CONFIG_MAP_NAME":             "/opt/route/loglevel.txt",\r
+                       "INSTANCE_DELETE_NO_RESP_TTL": "5",\r
+                       "INSTANCE_DELETE_RESP_TTL":    "10",\r
+                       "PYTHONUNBUFFERED":            "1",\r
+                       "RMR_RTG_SVC":                 "4561",\r
+                       "RMR_SRC_ID":                  "service-ricplt-a1mediator-rmr.ricplt",\r
+                       "A1_RMR_RETRY_TIMES":          "20",\r
+               },\r
+               ObjectMeta: metav1.ObjectMeta{\r
+                       Name: "configmap-ricplt-a1mediator-env",\r
+               },\r
+               TypeMeta: metav1.TypeMeta{\r
+                       APIVersion: "v1",\r
+                       Kind:       "ConfigMap",\r
+               },\r
+       }\r
+\r
+       return []*corev1.ConfigMap{configMap1, configMap2}\r
+}\r
diff --git a/depRicKubernetesOperator/internal/controller/getIngress.go b/depRicKubernetesOperator/internal/controller/getIngress.go
new file mode 100644 (file)
index 0000000..d44c553
--- /dev/null
@@ -0,0 +1,38 @@
+package controller\r
+\r
+import (\r
+       appsv1 "k8s.io/api/apps/v1"\r
+       corev1 "k8s.io/api/core/v1"\r
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"\r
+       "k8s.io/apimachinery/pkg/util/intstr"\r
+)\r
+\r
+\r
+func GetIngress() []*unstructured.Unstructured {\r
+\r
+       ingress1 := &unstructured.Unstructured{\r
+               Object: map[string]interface{}{\r
+                       "apiVersion": "networking.k8s.io/v1beta1",\r
+                       "kind":       "Ingress",\r
+                       "metadata": map[string]interface{}{\r
+                               "name": "ingress-ricplt-a1mediator",\r
+                       },\r
+                       "spec": map[string]interface{}{\r
+                               "rules": []interface{}{\r
+                                       map[string]interface{}{\r
+                                               "http": map[string]interface{}{\r
+                                                       "paths": []interface{}{\r
+                                                               map[string]interface{}{\r
+                                                                       "backend": map[string]interface{}{\r
+                                                                               "serviceName": "service-ricplt-a1mediator-http",\r
+                                                                               "servicePort": 10000,\r
+                                                                       },\r
+                                                                       "path": "/a1mediator",\r
+                                                               },\r
+                                                       },\r
+                                               },\r
+                                       },\r
+                               },\r
+                       },\r
+               },\r
+       }
\ No newline at end of file
index 21bcc6d..314b92e 100644 (file)
@@ -25,9 +25,12 @@ package controller
 import (
        "context"
 
+       "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/apimachinery/pkg/runtime"
        ctrl "sigs.k8s.io/controller-runtime"
        "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+       "sigs.k8s.io/controller-runtime/pkg/log"
 
        ricdeployv1 "ricdeploy/api/v1"
 )
@@ -53,7 +56,44 @@ type RicPlatformReconciler struct {
 // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.15.0/pkg/reconcile
 func (r *RicPlatformReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 
-       // TODO(user): your logic here
+       logger := log.FromContext(ctx)
+       logger.Info("Reconcilling RIC")
+       instance := &ricdeployv1.RicPlatform{}
+       err := r.Get(context.TODO(), req.NamespacedName, instance)
+       if err != nil {
+               if errors.IsNotFound(err) {
+                       // object not found, could have been deleted after reconcile request, hence don't requeue
+                       return ctrl.Result{}, nil
+               }
+               // error reading the object, requeue the request
+               return ctrl.Result{}, err
+       }
+
+       // name of our custom finalizer
+       myFinalizerName := "batch.tutorial.kubebuilder.io/finalizer"
+       // examine DeletionTimestamp to determine if object is under deletion
+       if instance.ObjectMeta.DeletionTimestamp.IsZero() {
+               // Adding a Finaliser also adds the DeletionTimestamp while deleting
+               if !controllerutil.ContainsFinalizer(instance, myFinalizerName) {
+                       controllerutil.AddFinalizer(instance, myFinalizerName)
+                       if err := r.Update(ctx, instance); err != nil {
+                               return ctrl.Result{}, err
+                       }
+               }
+       } else {
+               // The object is being deleted
+               if controllerutil.ContainsFinalizer(instance, myFinalizerName) {
+                       // remove our finalizer from the list and update it.
+                       controllerutil.RemoveFinalizer(instance, myFinalizerName)
+                       if err := r.Update(ctx, instance); err != nil {
+                               return ctrl.Result{}, err
+                       }
+               }
+
+               // Stop reconciliation as the item is being deleted
+               return ctrl.Result{}, nil
+       }
+
        return ctrl.Result{}, nil
 }
 
diff --git a/depRicKubernetesOperator/internal/controller/suite_test.go b/depRicKubernetesOperator/internal/controller/suite_test.go
new file mode 100644 (file)
index 0000000..c0f2769
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright 2023.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller
+
+import (
+       "path/filepath"
+       "testing"
+
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+
+       "k8s.io/client-go/kubernetes/scheme"
+       "k8s.io/client-go/rest"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/envtest"
+       logf "sigs.k8s.io/controller-runtime/pkg/log"
+       "sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+       ricdeployv1 "ricdeploy/api/v1"
+       //+kubebuilder:scaffold:imports
+)
+
+// These tests use Ginkgo (BDD-style Go testing framework). Refer to
+// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
+
+var cfg *rest.Config
+var k8sClient client.Client
+var testEnv *envtest.Environment
+
+func TestControllers(t *testing.T) {
+       RegisterFailHandler(Fail)
+
+       RunSpecs(t, "Controller Suite")
+}
+
+var _ = BeforeSuite(func() {
+       logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+       By("bootstrapping test environment")
+       testEnv = &envtest.Environment{
+               CRDDirectoryPaths:     []string{filepath.Join("..", "..", "config", "crd", "bases")},
+               ErrorIfCRDPathMissing: true,
+       }
+
+       var err error
+       // cfg is defined in this file globally.
+       cfg, err = testEnv.Start()
+       Expect(err).NotTo(HaveOccurred())
+       Expect(cfg).NotTo(BeNil())
+
+       err = ricdeployv1.AddToScheme(scheme.Scheme)
+       Expect(err).NotTo(HaveOccurred())
+
+       //+kubebuilder:scaffold:scheme
+
+       k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
+       Expect(err).NotTo(HaveOccurred())
+       Expect(k8sClient).NotTo(BeNil())
+
+})
+
+var _ = AfterSuite(func() {
+       By("tearing down the test environment")
+       err := testEnv.Stop()
+       Expect(err).NotTo(HaveOccurred())
+})