diff --git a/Dockerfile b/Dockerfile index 7c180977..0705e49b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,22 +12,20 @@ COPY go.mod go.sum ./ RUN go mod download # Copy the go source -COPY cmd/main.go cmd/main.go -COPY api/ api/ -COPY internal/controllers/ internal/controllers/ +COPY . . # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details FROM gcr.io/distroless/static:nonroot WORKDIR / -COPY --from=builder /workspace/manager . +COPY --from=builder /workspace/oran-o2ims . USER 65532:65532 -ENTRYPOINT ["/manager"] +ENTRYPOINT ["/oran-o2ims"] diff --git a/Makefile b/Makefile index fc08bc1b..f1ed1912 100644 --- a/Makefile +++ b/Makefile @@ -119,11 +119,11 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and ##@ Build .PHONY: build build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go + go build .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go + go run main.go start controller-manager --log-level=debug # If you wish to build the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 978f9b70..00000000 --- a/cmd/main.go +++ /dev/null @@ -1,129 +0,0 @@ -/* -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 main - -import ( - "flag" - "os" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/healthz" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - - oranv1alpha1 "github.com/openshift-kni/oran-o2ims/api/v1alpha1" - "github.com/openshift-kni/oran-o2ims/internal/controllers" - //+kubebuilder:scaffold:imports -) - -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) - -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - - utilruntime.Must(oranv1alpha1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme -} - -func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - - // Restrict to the following namespaces - subject to change. - namespaces := [...]string{"default", "oran", "o2ims", "oran-o2ims"} // List of Namespaces - defaultNamespaces := make(map[string]cache.Config) - - for _, ns := range namespaces { - defaultNamespaces[ns] = cache.Config{} - } - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - Metrics: metricsserver.Options{BindAddress: metricsAddr}, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "a73bc4d2.openshift.io", - Cache: cache.Options{ - DefaultNamespaces: defaultNamespaces, - }, - - // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily - // when the Manager ends. This requires the binary to immediately end when the - // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - // speeds up voluntary leader transitions as the new leader don't have to wait - // LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so would be fine to enable this option. However, - // if you are doing or is intended to do any operation such as perform cleanups - // after the manager stops then its usage might be unsafe. - // LeaderElectionReleaseOnCancel: true, - }) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } - - if err = (&controllers.ORANO2IMSReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName("ORAN-O2IMS"), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "ORANO2IMS") - os.Exit(1) - } - //+kubebuilder:scaffold:builder - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) - } - - setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } -} diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index c643ea6a..4b82bd1b 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -67,8 +67,10 @@ spec: # type: RuntimeDefault containers: - command: - - /manager + - /oran-o2ims args: + - start + - controller-manager - --leader-elect image: controller:latest name: manager diff --git a/go.mod b/go.mod index c5ea0577..78548f3c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/PaesslerAG/jsonpath v0.1.1 github.com/coreos/go-semver v0.3.1 - github.com/go-logr/logr v1.2.4 + github.com/go-logr/logr v1.4.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.1 diff --git a/go.sum b/go.sum index d5f6fc94..bca688b1 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= diff --git a/internal/cmd/operator/start_controller_manager.go b/internal/cmd/operator/start_controller_manager.go new file mode 100644 index 00000000..f0b32863 --- /dev/null +++ b/internal/cmd/operator/start_controller_manager.go @@ -0,0 +1,185 @@ +/* +Copyright 2024 Red Hat Inc. + +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 operator + +import ( + "log/slog" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/klog/v2" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/healthz" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + "github.com/go-logr/logr" + oranv1alpha1 "github.com/openshift-kni/oran-o2ims/api/v1alpha1" + "github.com/openshift-kni/oran-o2ims/internal" + "github.com/openshift-kni/oran-o2ims/internal/controllers" + "github.com/spf13/cobra" +) + +// ControllerManager creates and returns the `start controller-manager` command. +func ControllerManager() *cobra.Command { + c := NewControllerManager() + result := &cobra.Command{ + Use: "controller-manager", + Short: "Starts the controller manager", + Args: cobra.NoArgs, + RunE: c.run, + } + flags := result.Flags() + flags.StringVar( + &c.metricsAddr, + "metrics-bind-address", + ":8080", + "The address the metric endpoint binds to.", + ) + flags.StringVar( + &c.probeAddr, + "health-probe-bind-address", + ":8081", + "The address the probe endpoint binds to.", + ) + flags.BoolVar( + &c.enableLeaderElection, + "leader-elect", + false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.", + ) + return result +} + +// ControllerManagerCommand contains the data and logic needed to run the `start controller-manager` +// command. +type ControllerManagerCommand struct { + metricsAddr string + enableLeaderElection bool + probeAddr string +} + +// NewControllerManager creates a new runner that knows how to execute the `start +// controller-manager` command. +func NewControllerManager() *ControllerManagerCommand { + return &ControllerManagerCommand{} +} + +var ( + scheme = runtime.NewScheme() +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(oranv1alpha1.AddToScheme(scheme)) +} + +// run executes the `start controller-manager` command. +func (c *ControllerManagerCommand) run(cmd *cobra.Command, argv []string) error { + // Get the context: + ctx := cmd.Context() + + // Get the dependencies from the context: + logger := internal.LoggerFromContext(ctx) + + // Configure the controller runtime library to use our logger: + adapter := logr.FromSlogHandler(logger.Handler()) + ctrl.SetLogger(adapter) + klog.SetLogger(adapter) + + // Restrict to the following namespaces - subject to change. + namespaces := [...]string{"default", "oran", "o2ims", "oran-o2ims"} // List of Namespaces + defaultNamespaces := make(map[string]cache.Config) + + for _, ns := range namespaces { + defaultNamespaces[ns] = cache.Config{} + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{BindAddress: c.metricsAddr}, + HealthProbeBindAddress: c.probeAddr, + LeaderElection: c.enableLeaderElection, + LeaderElectionID: "a73bc4d2.openshift.io", + Cache: cache.Options{ + DefaultNamespaces: defaultNamespaces, + }, + + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + logger.Error( + "Unable to start manager", + slog.String("error", err.Error()), + ) + os.Exit(1) + } + + if err = (&controllers.ORANO2IMSReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName("ORAN-O2IMS"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + logger.Error( + "Unable to create controller", + slog.String("controller", "ORANO2IMS"), + slog.String("error", err.Error()), + ) + os.Exit(1) + } + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + logger.Error( + "Unable to set up health check", + slog.String("error", err.Error()), + ) + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + logger.Error( + "Unable to set up ready check", + slog.String("error", err.Error()), + ) + os.Exit(1) + } + + logger.Info("Starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + logger.Error( + "Problem running manager", + slog.String("error", err.Error()), + ) + os.Exit(1) + } + + return nil +} diff --git a/internal/cmd/start_cmd.go b/internal/cmd/start_cmd.go index 0aa6a1e3..c0721e18 100644 --- a/internal/cmd/start_cmd.go +++ b/internal/cmd/start_cmd.go @@ -17,6 +17,7 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/openshift-kni/oran-o2ims/internal/cmd/operator" "github.com/openshift-kni/oran-o2ims/internal/cmd/server" ) @@ -32,5 +33,6 @@ func Start() *cobra.Command { result.AddCommand(server.ResourceServer()) result.AddCommand(server.AlarmServer()) result.AddCommand(server.AlarmSubscriptionServer()) + result.AddCommand(operator.ControllerManager()) return result }