Skip to content

Commit

Permalink
Move controller manager command to internal
Browse files Browse the repository at this point in the history
Currently the code of the command that starts the operator is in a
separate `main.go` file inside the `cmd` directory. This is different to
all the other commands that start things, as they are sub-commands of
the `oran-oims start` command and their code lives in the `internal/cmd`
package. In addition that operator command also uses a different logging
framework than the rest of the project. In order to improve consistency
this patch changes that command to use the same infrastructure than the
rest of the project, including logging. The command will now be
`oran-o2ims start controller-manager`.

Signed-off-by: Juan Hernandez <[email protected]>
  • Loading branch information
jhernand committed Apr 10, 2024
1 parent 3b907ce commit e375c04
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 139 deletions.
10 changes: 4 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
129 changes: 0 additions & 129 deletions cmd/main.go

This file was deleted.

4 changes: 3 additions & 1 deletion config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ spec:
# type: RuntimeDefault
containers:
- command:
- /manager
- /oran-o2ims
args:
- start
- controller-manager
- --leader-elect
image: controller:latest
name: manager
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
185 changes: 185 additions & 0 deletions internal/cmd/operator/start_controller_manager.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit e375c04

Please sign in to comment.