Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement operator logic #25

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 48 additions & 45 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,34 @@ import (
"context"
"flag"
"fmt"
"os"
"runtime"

"github.com/openshift-kni/performance-addon-operators/pkg/apis"
"github.com/openshift-kni/performance-addon-operators/pkg/controller"
"github.com/openshift-kni/performance-addon-operators/pkg/controller/performanceprofile/components"
"github.com/openshift-kni/performance-addon-operators/version"

configv1 "github.com/openshift/api/config/v1"
tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1"
mcov1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
kubemetrics "github.com/operator-framework/operator-sdk/pkg/kube-metrics"
"github.com/operator-framework/operator-sdk/pkg/log/zap"
"github.com/operator-framework/operator-sdk/pkg/metrics"
"github.com/operator-framework/operator-sdk/pkg/restmapper"
sdkVersion "github.com/operator-framework/operator-sdk/version"
"github.com/spf13/pflag"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/klog"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"

"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client/config"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
)
Expand All @@ -38,53 +42,48 @@ var (
metricsPort int32 = 8383
operatorMetricsPort int32 = 8686
)
var log = logf.Log.WithName("cmd")

func printVersion() {
log.Info(fmt.Sprintf("Operator Version: %s", version.Version))
log.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
log.Info(fmt.Sprintf("Version of operator-sdk: %v", sdkVersion.Version))
klog.Infof("Operator Version: %s", version.Version)
klog.Infof("Go Version: %s", runtime.Version())
klog.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)
klog.Infof("Version of operator-sdk: %v", sdkVersion.Version)
}

func main() {
// Add the zap logger flag set to the CLI. The flag set must
// be added before calling pflag.Parse().
pflag.CommandLine.AddFlagSet(zap.FlagSet())
// Add klog flags
klog.InitFlags(nil)

// Add flags registered by imported packages (e.g. glog and
// controller-runtime)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

pflag.Parse()

// Use a zap logr.Logger implementation. If none of the zap
// flags are configured (or if the zap flag set is not being
// used), this defaults to a production zap logger.
//
// The logger instantiated here can be changed to any logger
// implementing the logr.Logger interface. This logger will
// be propagated through the whole operator, generating
// uniform and structured logs.
logf.SetLogger(zap.Logger())

printVersion()

namespace, err := k8sutil.GetWatchNamespace()
if err != nil {
log.Error(err, "Failed to get watch namespace")
os.Exit(1)
klog.Exit(err.Error())
}

// we have two namespaces that we need to watch
// 1. tuned namespace - for tuned resources
// 2. None namespace - for cluster wide resources
namespaces := []string{
components.NamespaceNodeTuningOperator,
metav1.NamespaceNone,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a one-line comment to remind our future selves what "None namespace" means in this context? (e.g. watch all the namespaces, even though IIRC this is not the case)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

// Get a config to talk to the apiserver
cfg, err := config.GetConfig()
if err != nil {
log.Error(err, "")
os.Exit(1)
klog.Exit(err.Error())
}

// Create a new Cmd to provide shared dependencies and start components
mgr, err := manager.New(cfg, manager.Options{
NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
LeaderElection: true,
LeaderElectionID: "performance-addon-operators",
LeaderElectionNamespace: namespace,
Expand All @@ -93,26 +92,35 @@ func main() {
MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
})
if err != nil {
log.Error(err, "")
os.Exit(1)
klog.Exit(err.Error())
}

log.Info("Registering Components.")
klog.Info("Registering Components.")

// Setup Scheme for all resources
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
log.Error(err, "")
os.Exit(1)
klog.Exit(err.Error())
}

if err := configv1.AddToScheme(mgr.GetScheme()); err != nil {
klog.Exit(err.Error())
}

if err := mcov1.AddToScheme(mgr.GetScheme()); err != nil {
klog.Exit(err.Error())
}

if err := tunedv1.AddToScheme(mgr.GetScheme()); err != nil {
klog.Exit(err.Error())
}

// Setup all Controllers
if err := controller.AddToManager(mgr); err != nil {
log.Error(err, "")
os.Exit(1)
klog.Exit(err.Error())
}

if err = serveCRMetrics(cfg); err != nil {
log.Info("Could not generate and serve custom resource metrics", "error", err.Error())
klog.Errorf("Could not generate and serve custom resource metrics: %v", err)
}

// Add to the below struct any other metrics ports you want to expose.
Expand All @@ -123,28 +131,27 @@ func main() {
// Create Service object to expose the metrics port(s).
service, err := metrics.CreateMetricsService(context.TODO(), cfg, servicePorts)
if err != nil {
log.Info("Could not create metrics Service", "error", err.Error())
klog.Errorf("Could not create metrics Service: %v", err)
}

// CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources
// necessary to configure Prometheus to scrape metrics from this operator.
services := []*v1.Service{service}
_, err = metrics.CreateServiceMonitors(cfg, namespace, services)
if err != nil {
log.Info("Could not create ServiceMonitor object", "error", err.Error())
klog.Errorf("Could not create ServiceMonitor object: %v", err)
// If this operator is deployed to a cluster without the prometheus-operator running, it will return
// ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation.
if err == metrics.ErrServiceMonitorNotPresent {
log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error())
klog.Errorf("Install prometheus-operator in your cluster to create ServiceMonitor objects: %v", err)
}
}

log.Info("Starting the Cmd.")
klog.Info("Starting the Cmd.")

// Start the Cmd
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
log.Error(err, "Manager exited non-zero")
os.Exit(1)
klog.Exitf("Manager exited with non-zero code: %v", err)
}
}

Expand All @@ -157,13 +164,9 @@ func serveCRMetrics(cfg *rest.Config) error {
if err != nil {
return err
}
// Get the namespace the operator is currently deployed in.
operatorNs, err := k8sutil.GetOperatorNamespace()
if err != nil {
return err
}

// To generate metrics in other namespaces, add the values below.
ns := []string{operatorNs}
ns := []string{metav1.NamespaceNone}
// Generate and serve custom resource specific metrics.
err = kubemetrics.GenerateAndServeCRMetrics(cfg, ns, filteredGVK, metricsHost, operatorMetricsPort)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
listKind: PerformanceProfileList
plural: performanceprofiles
singular: performanceprofile
scope: Namespaced
scope: Cluster
subresources:
status: {}
validation:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,16 @@ kind: PerformanceProfile
metadata:
name: example-performanceprofile
spec:
# Add fields here
size: 3
cpu:
isolated: "2-3"
nonIsolated: "0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify the state of CPU 1? how could it be neither isolated nor nonIsolated?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe even add a validation hook on that later on ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is just example that will be injected under the CSV and does not the real case
regarding validation webhook I left TODO -

// TODO: we need to check if all under performance profiles values != nil

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, good enough for me now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO examples should be easy to understand, people will see and copy/paste this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@slintes this CR example injected into CSV, so I do not add some comments to it(unsure regarding parsing), what example do you prefer?

reserved: "0-1"
hugepages:
defaultHugepagesSize: "1G"
pages:
- size: "1G"
count: 2
realTimeKernel:
repoURL: "http://download-node-02.eng.bos.redhat.com/rhel-8/nightly/RHEL-8/latest-RHEL-8.1.1/compose/RT/x86_64/os"
nodeSelector:
node-role.kubernetes.io/performance: ""
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,84 @@ apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
annotations:
alm-examples: '[]'
alm-examples: |-
[
{
"apiVersion": "performance.openshift.io/v1alpha1",
"kind": "PerformanceProfile",
"metadata": {
"name": "example-performanceprofile"
},
"spec": {
"cpu": {
"isolated": "2-3",
"nonIsolated": "0",
"reserved": "0-1"
},
"hugepages": {
"defaultHugepagesSize": "1G",
"pages": [
{
"count": 2,
"size": "1G"
}
]
},
"nodeSelector": {
"node-role.kubernetes.io/performance": ""
},
"realTimeKernel": {
"repoURL": "http://download-node-02.eng.bos.redhat.com/rhel-8/nightly/RHEL-8/latest-RHEL-8.1.1/compose/RT/x86_64/os"
}
}
}
]
capabilities: Basic Install
name: performance-addon-operators.v0.0.1
namespace: placeholder
spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
- description: CPUPerformanceProfile is the Schema for the cpuperformanceprofiles
API
displayName: placeholder
kind: CPUPerformanceProfile
name: cpuperformanceprofiles.performance.openshift.io
- description: PerformanceProfile is the Schema for the performanceprofiles API.
kind: PerformanceProfile
name: performanceprofiles.performance.openshift.io
version: v1alpha1
displayName: placeholder
description: Placeholder description
displayName: Performance Addon Operators
install:
spec:
clusterPermissions:
- rules:
- apiGroups:
- performance.openshift.io
resources:
- performanceprofiles
- performanceprofiles/finalizers
verbs:
- '*'
- apiGroups:
- config.openshift.io
resources:
- featuregates
verbs:
- '*'
- apiGroups:
- machineconfiguration.openshift.io
resources:
- machineconfigs
- machineconfigpools
- kubeletconfigs
verbs:
- '*'
- apiGroups:
- tuned.openshift.io
resources:
- tuneds
verbs:
- '*'
serviceAccountName: performance-operator
deployments:
- name: performance-operator
spec:
Expand Down Expand Up @@ -61,11 +120,8 @@ spec:
- pods
- services
- services/finalizers
- endpoints
- persistentvolumeclaims
- events
- configmaps
- secrets
- events
verbs:
- '*'
- apiGroups:
Expand All @@ -77,13 +133,6 @@ spec:
- statefulsets
verbs:
- '*'
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
verbs:
- get
- create
- apiGroups:
- apps
resourceNames:
Expand All @@ -93,31 +142,11 @@ spec:
verbs:
- update
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- apps
- monitoring.coreos.com
resources:
- replicasets
- deployments
- servicemonitors
verbs:
- get
- apiGroups:
- performance.openshift.io
resources:
- '*'
- performanceprofiles
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
serviceAccountName: performance-operator
strategy: deployment
installModes:
Expand Down
Loading