From 46759132b9a33fe986ef43e3a90e25b6e4055236 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Thu, 13 Aug 2020 12:17:40 +0000 Subject: [PATCH 1/5] Add Namespaced mode --- CHANGELOG.md | 2 +- chart/kube-arangodb/README.md | 1 + .../backup-operator/cluster-role-binding.yaml | 3 +- .../backup-operator/cluster-role.yaml | 3 + .../cluster-role-binding.yaml | 3 +- .../deployment-operator/cluster-role.yaml | 5 +- .../cluster-role-binding.yaml | 3 +- .../cluster-role.yaml | 4 +- chart/kube-arangodb/templates/deployment.yaml | 9 +- .../cluster-role-binding.yaml | 1 - .../storage-operator/cluster-role.yaml | 3 +- main.go | 6 +- pkg/deployment/context_impl.go | 16 ++-- pkg/deployment/deployment.go | 3 + pkg/deployment/reconcile/action_context.go | 6 -- pkg/deployment/reconcile/action_pvc_resize.go | 11 +-- pkg/deployment/reconcile/context.go | 2 - pkg/deployment/resources/context.go | 3 + pkg/deployment/resources/pod_termination.go | 6 +- pkg/metrics/collector.go | 86 +++++++++++++++++++ pkg/operator/crd.go | 71 +++++++++++---- pkg/operator/operator.go | 25 +----- pkg/operator/operator_deployment.go | 1 + pkg/operator/scope/scope.go | 51 +++++++++++ pkg/operator/server_discovery_api.go | 8 ++ pkg/util/crd/crd.go | 13 ++- 26 files changed, 255 insertions(+), 90 deletions(-) create mode 100644 pkg/metrics/collector.go create mode 100644 pkg/operator/scope/scope.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c767d33e6..34e54d2e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change Log ## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A) +- Add Operator Namespaced mode (Alpha) ## [1.0.5](https://github.com/arangodb/kube-arangodb/tree/1.0.5) (2020-08-05) - Add Labels and Annotations to ServiceMonitor @@ -28,7 +29,6 @@ ## [1.0.3](https://github.com/arangodb/kube-arangodb/tree/1.0.3) (2020-05-25) - Prevent deletion of not known PVC's -- Move Restore as Plan ## [1.0.2](https://github.com/arangodb/kube-arangodb/tree/1.0.2) (2020-04-16) - Added additional checks in UpToDate condition diff --git a/chart/kube-arangodb/README.md b/chart/kube-arangodb/README.md index c1623b423..ad6be3fb6 100644 --- a/chart/kube-arangodb/README.md +++ b/chart/kube-arangodb/README.md @@ -75,6 +75,7 @@ Default: `legacy` Supported modes: - `legacy` - mode with limited cluster scope access +- `namespaced` - mode with namespace access only ### `operator.service.type` diff --git a/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml index 14c60dae3..28e4a8d57 100644 --- a/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.backup -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -20,6 +21,6 @@ subjects: name: {{ template "kube-arangodb.operatorName" . }} namespace: {{ .Release.Namespace }} - +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml b/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml index 9d449b185..b1f9628bb 100644 --- a/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.backup -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -15,5 +16,7 @@ rules: - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] verbs: ["get", "list", "watch"] + +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml index 8bd0264d9..02dd431a2 100644 --- a/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.deployment -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -20,6 +21,6 @@ subjects: name: {{ template "kube-arangodb.operatorName" . }} namespace: {{ .Release.Namespace }} - +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml b/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml index 0df49ad6a..d230a0154 100644 --- a/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.deployment -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -18,9 +19,7 @@ rules: - apiGroups: [""] resources: ["namespaces", "nodes", "persistentvolumes"] verbs: ["get", "list"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list"] +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml index b0c338766..5a2e588f7 100644 --- a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.deploymentReplications -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -20,6 +21,6 @@ subjects: name: {{ template "kube-arangodb.operatorName" . }} namespace: {{ .Release.Namespace }} - +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml index d156fb4e1..509a5f354 100644 --- a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml @@ -1,4 +1,5 @@ {{ if .Values.rbac.enabled -}} +{{ if neq .Values.operator.scope "namespaced" -}} {{ if .Values.operator.features.deploymentReplications -}} apiVersion: rbac.authorization.k8s.io/v1 @@ -14,10 +15,11 @@ metadata: rules: - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] - verbs: ["get"] + verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["namespaces", "nodes"] verbs: ["get", "list"] +{{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment.yaml b/chart/kube-arangodb/templates/deployment.yaml index fab261d38..8d8ef86f7 100644 --- a/chart/kube-arangodb/templates/deployment.yaml +++ b/chart/kube-arangodb/templates/deployment.yaml @@ -1,7 +1,12 @@ {{- if eq .Values.operator.scope "legacy" -}} # Scope "legacy" selected -{{ else -}} -{{ fail (printf "Operator Scope %s is not supported!" .Values.operator.scope) }} +{{ elif eq .Values.operator.scope "namespaced" -}} +# Scope "namespaced" selected +{{- if .Values.operator.features.storage -}} +{{- fail (printf "Storage Operator not supported in %s scope!" .Values.operator.scope) -}} +{{- end -}} +{{- else -}} +{{- fail (printf "Operator Scope %s is not supported!" .Values.operator.scope) -}} {{- end -}} apiVersion: apps/v1 kind: Deployment diff --git a/chart/kube-arangodb/templates/storage-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/storage-operator/cluster-role-binding.yaml index 1a6d7cee9..cfaaff455 100644 --- a/chart/kube-arangodb/templates/storage-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/storage-operator/cluster-role-binding.yaml @@ -20,6 +20,5 @@ subjects: name: {{ template "kube-arangodb.operatorName" . }} namespace: {{ .Release.Namespace }} - {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/templates/storage-operator/cluster-role.yaml b/chart/kube-arangodb/templates/storage-operator/cluster-role.yaml index 525d5a72f..89232a0aa 100644 --- a/chart/kube-arangodb/templates/storage-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/storage-operator/cluster-role.yaml @@ -17,7 +17,7 @@ rules: verbs: ["*"] - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] - verbs: ["get"] + verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["namespaces", "nodes"] verbs: ["get", "list"] @@ -27,5 +27,6 @@ rules: - apiGroups: ["storage.arangodb.com"] resources: ["arangolocalstorages"] verbs: ["*"] + {{- end }} {{- end }} \ No newline at end of file diff --git a/main.go b/main.go index 02ec54196..7c5187dfa 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,8 @@ import ( "strings" "time" + scope2 "github.com/arangodb/kube-arangodb/pkg/operator/scope" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/rs/zerolog/log" @@ -139,7 +141,7 @@ func init() { f.StringVar(&operatorOptions.arangoImage, "operator.arango-image", ArangoImageEnv.GetOrDefault(defaultArangoImage), "Docker image used for arango by default") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") f.BoolVar(&operatorOptions.singleMode, "mode.single", false, "Enable single mode in Operator. WARNING: There should be only one replica of Operator, otherwise Operator can take unexpected actions") - f.StringVar(&operatorOptions.scope, "scope", operator.DefaultScope.String(), "Define scope on which Operator works. Legacy - pre 1.1.0 scope with limited cluster access") + f.StringVar(&operatorOptions.scope, "scope", scope2.DefaultScope.String(), "Define scope on which Operator works. Legacy - pre 1.1.0 scope with limited cluster access") features.Init(&cmdMain) } @@ -299,7 +301,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper } eventRecorder := createRecorder(cliLog, kubecli, name, namespace) - scope, ok := operator.AsScope(operatorOptions.scope) + scope, ok := scope2.AsScope(operatorOptions.scope) if !ok { return operator.Config{}, operator.Dependencies{}, maskAny(fmt.Errorf("Scope %s is not known by Operator", operatorOptions.scope)) } diff --git a/pkg/deployment/context_impl.go b/pkg/deployment/context_impl.go index 7bf20dbde..100bca312 100644 --- a/pkg/deployment/context_impl.go +++ b/pkg/deployment/context_impl.go @@ -31,6 +31,8 @@ import ( "strconv" "time" + "github.com/arangodb/kube-arangodb/pkg/operator/scope" + monitoringClient "github.com/coreos/prometheus-operator/pkg/client/versioned/typed/monitoring/v1" "github.com/arangodb/kube-arangodb/pkg/deployment/features" @@ -84,6 +86,10 @@ func (d *Deployment) GetMonitoringV1Cli() monitoringClient.MonitoringV1Interface return d.deps.KubeMonitoringCli } +func (d *Deployment) GetScope() scope.Scope { + return d.config.Scope +} + // GetLifecycleImage returns the image name containing the lifecycle helper (== name of operator image) func (d *Deployment) GetLifecycleImage() string { return d.config.LifecycleImage @@ -425,16 +431,6 @@ func (d *Deployment) UpdatePvc(pvc *v1.PersistentVolumeClaim) error { return maskAny(err) } -// GetPv returns PV info about PV with given name. -func (d *Deployment) GetPv(pvName string) (*v1.PersistentVolume, error) { - pv, err := d.GetKubeCli().CoreV1().PersistentVolumes().Get(pvName, meta.GetOptions{}) - if err == nil { - return pv, nil - } - - return nil, maskAny(err) -} - // GetOwnedPVCs returns a list of all PVCs owned by the deployment. func (d *Deployment) GetOwnedPVCs() ([]v1.PersistentVolumeClaim, error) { // Get all current PVCs diff --git a/pkg/deployment/deployment.go b/pkg/deployment/deployment.go index 5fe4a25c0..126fa0a7d 100644 --- a/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -29,6 +29,8 @@ import ( "sync/atomic" "time" + "github.com/arangodb/kube-arangodb/pkg/operator/scope" + monitoringClient "github.com/coreos/prometheus-operator/pkg/client/versioned/typed/monitoring/v1" "github.com/arangodb/kube-arangodb/pkg/util/arangod/conn" @@ -63,6 +65,7 @@ type Config struct { OperatorUUIDInitImage string MetricsExporterImage string ArangoImage string + Scope scope.Scope } // Dependencies holds dependent services for a Deployment diff --git a/pkg/deployment/reconcile/action_context.go b/pkg/deployment/reconcile/action_context.go index 00d868f73..a16b902ba 100644 --- a/pkg/deployment/reconcile/action_context.go +++ b/pkg/deployment/reconcile/action_context.go @@ -84,8 +84,6 @@ type ActionContext interface { // GetPvc returns PVC info about PVC with given name in the namespace // of the deployment. GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error) - // GetPv returns PV info about PV with given name. - GetPv(pvName string) (*v1.PersistentVolume, error) // UpdatePvc update PVC with given name in the namespace // of the deployment. UpdatePvc(pvc *v1.PersistentVolumeClaim) error @@ -187,10 +185,6 @@ func (ac *actionContext) UpdateClusterCondition(conditionType api.ConditionType, }) } -func (ac *actionContext) GetPv(pvName string) (*v1.PersistentVolume, error) { - return ac.context.GetPv(pvName) -} - func (ac *actionContext) GetAPIObject() k8sutil.APIObject { return ac.context.GetAPIObject() } diff --git a/pkg/deployment/reconcile/action_pvc_resize.go b/pkg/deployment/reconcile/action_pvc_resize.go index e993cbb18..2feaf88fa 100644 --- a/pkg/deployment/reconcile/action_pvc_resize.go +++ b/pkg/deployment/reconcile/action_pvc_resize.go @@ -129,17 +129,8 @@ func (a *actionPVCResize) CheckProgress(ctx context.Context) (bool, bool, error) return false, true, err } - pv, err := a.actionCtx.GetPv(pvc.Spec.VolumeName) - if err != nil { - if errors.IsNotFound(err) { - return true, false, nil - } - - return false, true, err - } - if requestedSize, ok := pvc.Spec.Resources.Requests[core.ResourceStorage]; ok { - if volumeSize, ok := pv.Spec.Capacity[core.ResourceStorage]; ok { + if volumeSize, ok := pvc.Status.Capacity[core.ResourceStorage]; ok { cmp := volumeSize.Cmp(requestedSize) if cmp >= 0 { return true, false, nil diff --git a/pkg/deployment/reconcile/context.go b/pkg/deployment/reconcile/context.go index 1bec5dcf8..e287bed53 100644 --- a/pkg/deployment/reconcile/context.go +++ b/pkg/deployment/reconcile/context.go @@ -83,8 +83,6 @@ type Context interface { UpdatePvc(pvc *v1.PersistentVolumeClaim) error // GetPvc gets a PVC by the given name, in the samespace of the deployment. GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error) - // GetPv returns PV info about PV with given name. - GetPv(pvName string) (*v1.PersistentVolume, error) // GetTLSKeyfile returns the keyfile encoded TLS certificate+key for // the given member. GetTLSKeyfile(group api.ServerGroup, member api.MemberStatus) (string, error) diff --git a/pkg/deployment/resources/context.go b/pkg/deployment/resources/context.go index b09bb4e43..68a53eaaa 100644 --- a/pkg/deployment/resources/context.go +++ b/pkg/deployment/resources/context.go @@ -25,6 +25,8 @@ package resources import ( "context" + "github.com/arangodb/kube-arangodb/pkg/operator/scope" + monitoringClient "github.com/coreos/prometheus-operator/pkg/client/versioned/typed/monitoring/v1" backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1" @@ -100,4 +102,5 @@ type Context interface { WithStatusUpdate(action func(s *api.DeploymentStatus) bool, force ...bool) error // GetBackup receives information about a backup resource GetBackup(backup string) (*backupApi.ArangoBackup, error) + GetScope() scope.Scope } diff --git a/pkg/deployment/resources/pod_termination.go b/pkg/deployment/resources/pod_termination.go index 21ca6a090..59dca02da 100644 --- a/pkg/deployment/resources/pod_termination.go +++ b/pkg/deployment/resources/pod_termination.go @@ -54,9 +54,9 @@ func (r *Resources) prepareAgencyPodTermination(ctx context.Context, log zerolog return nil } - // Check node the pod is scheduled on + // Check node the pod is scheduled on. Only if not in namespaced scope agentDataWillBeGone := false - if p.Spec.NodeName != "" { + if !r.context.GetScope().IsNamespaced() && p.Spec.NodeName != "" { node, err := r.context.GetKubeCli().CoreV1().Nodes().Get(p.Spec.NodeName, metav1.GetOptions{}) if k8sutil.IsNotFound(err) { log.Warn().Msg("Node not found") @@ -165,7 +165,7 @@ func (r *Resources) prepareDBServerPodTermination(ctx context.Context, log zerol // Check node the pod is scheduled on dbserverDataWillBeGone := false - if p.Spec.NodeName != "" { + if !r.context.GetScope().IsNamespaced() && p.Spec.NodeName != "" { node, err := r.context.GetKubeCli().CoreV1().Nodes().Get(p.Spec.NodeName, metav1.GetOptions{}) if k8sutil.IsNotFound(err) { log.Warn().Msg("Node not found") diff --git a/pkg/metrics/collector.go b/pkg/metrics/collector.go new file mode 100644 index 000000000..4bb7c739e --- /dev/null +++ b/pkg/metrics/collector.go @@ -0,0 +1,86 @@ +package metrics + +import ( + "net/http" + "sync" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +type Collector interface { + Collect(chan<- prometheus.Collector) +} + +type CollectorFactory interface { + Collector + CollectFactory(chan<- Collector) +} + +func WrapHttpForCollectors(collectors ...Collector) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + r := prometheus.NewRegistry() + Register(r, collectors...) + + promhttp.HandlerFor(r, promhttp.HandlerOpts{}).ServeHTTP(writer, request) + } +} + +func Register(registerer prometheus.Registerer, collectors ...Collector) { + c := make(chan prometheus.Collector) + + go func() { + defer close(c) + Collect(c, collectors...) + }() + + for m := range c { + registerer.Register(m) + } +} + +func Collect(c chan<- prometheus.Collector, collectors ...Collector) { + var wg sync.WaitGroup + + for _, collector := range collectors { + wg.Add(1) + go func() { + defer wg.Done() + collectSingle(c, collector) + }() + } + + wg.Wait() +} + +func collectSingle(c chan<- prometheus.Collector, collector Collector) { + collector.Collect(c) + + if f, ok := collector.(CollectorFactory); ok { + collectFactory(c, f) + } + +} + +func collectFactory(c chan<- prometheus.Collector, f CollectorFactory) { + collectors := make(chan Collector) + + go func() { + defer close(collectors) + f.CollectFactory(collectors) + }() + + var wg sync.WaitGroup + + for m := range collectors { + wg.Add(1) + + go func() { + defer wg.Done() + + collectSingle(c, m) + }() + } + + wg.Wait() +} diff --git a/pkg/operator/crd.go b/pkg/operator/crd.go index b466ca1b2..243f4259e 100644 --- a/pkg/operator/crd.go +++ b/pkg/operator/crd.go @@ -28,6 +28,7 @@ import ( "github.com/arangodb/kube-arangodb/pkg/apis/replication" lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" "github.com/arangodb/kube-arangodb/pkg/util/crd" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" ) // waitForCRD waits for the CustomResourceDefinition (created externally) @@ -35,31 +36,63 @@ import ( func (o *Operator) waitForCRD(enableDeployment, enableDeploymentReplication, enableStorage, enableBackup bool) error { log := o.log - if enableDeployment { - log.Debug().Msg("Waiting for ArangoDeployment CRD to be ready") - if err := crd.WaitCRDReady(o.KubeExtCli, deployment.ArangoDeploymentCRDName); err != nil { - return maskAny(err) + if o.Scope.IsNamespaced() { + if enableDeployment { + log.Debug().Msg("Waiting for ArangoDeployment CRD to be ready") + if err := crd.WaitReady(func() error { + _, err := o.CRCli.DatabaseV1().ArangoDeployments(o.Namespace).List(meta.ListOptions{}) + return err + }); err != nil { + return maskAny(err) + } } - } - if enableDeploymentReplication { - log.Debug().Msg("Waiting for ArangoDeploymentReplication CRD to be ready") - if err := crd.WaitCRDReady(o.KubeExtCli, replication.ArangoDeploymentReplicationCRDName); err != nil { - return maskAny(err) + if enableDeploymentReplication { + log.Debug().Msg("Waiting for ArangoDeploymentReplication CRD to be ready") + if err := crd.WaitReady(func() error { + _, err := o.CRCli.ReplicationV1().ArangoDeploymentReplications(o.Namespace).List(meta.ListOptions{}) + return err + }); err != nil { + return maskAny(err) + } } - } - if enableStorage { - log.Debug().Msg("Waiting for ArangoLocalStorage CRD to be ready") - if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil { - return maskAny(err) + if enableBackup { + log.Debug().Msg("Wait for ArangoBackup CRD to be ready") + if err := crd.WaitReady(func() error { + _, err := o.CRCli.BackupV1().ArangoBackups(o.Namespace).List(meta.ListOptions{}) + return err + }); err != nil { + return maskAny(err) + } + } + } else { + if enableDeployment { + log.Debug().Msg("Waiting for ArangoDeployment CRD to be ready") + if err := crd.WaitCRDReady(o.KubeExtCli, deployment.ArangoDeploymentCRDName); err != nil { + return maskAny(err) + } + } + + if enableDeploymentReplication { + log.Debug().Msg("Waiting for ArangoDeploymentReplication CRD to be ready") + if err := crd.WaitCRDReady(o.KubeExtCli, replication.ArangoDeploymentReplicationCRDName); err != nil { + return maskAny(err) + } + } + + if enableStorage { + log.Debug().Msg("Waiting for ArangoLocalStorage CRD to be ready") + if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil { + return maskAny(err) + } } - } - if enableBackup { - log.Debug().Msg("Wait for ArangoBackup CRD to be ready") - if err := crd.WaitCRDReady(o.KubeExtCli, backup.ArangoBackupCRDName); err != nil { - return maskAny(err) + if enableBackup { + log.Debug().Msg("Wait for ArangoBackup CRD to be ready") + if err := crd.WaitCRDReady(o.KubeExtCli, backup.ArangoBackupCRDName); err != nil { + return maskAny(err) + } } } diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index a8c50f08b..6276d7084 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -27,6 +27,8 @@ import ( "math/rand" "time" + "github.com/arangodb/kube-arangodb/pkg/operator/scope" + monitoringClient "github.com/coreos/prometheus-operator/pkg/client/versioned/typed/monitoring/v1" "github.com/arangodb/kube-arangodb/pkg/backup/operator/event" @@ -63,27 +65,6 @@ const ( initRetryWaitTime = 30 * time.Second ) -func AsScope(s string) (Scope, bool) { - switch s { - case LegacyScope.String(): - return LegacyScope, true - } - - return "", false -} - -type Scope string - -func (s Scope) String() string { - return string(s) -} - -const ( - LegacyScope Scope = "legacy" - - DefaultScope = LegacyScope -) - type Event struct { Type kwatch.EventType Deployment *deplapi.ArangoDeployment @@ -116,7 +97,7 @@ type Config struct { EnableBackup bool AllowChaos bool SingleMode bool - Scope Scope + Scope scope.Scope } type Dependencies struct { diff --git a/pkg/operator/operator_deployment.go b/pkg/operator/operator_deployment.go index 89bccfeea..2ba616ee4 100644 --- a/pkg/operator/operator_deployment.go +++ b/pkg/operator/operator_deployment.go @@ -210,6 +210,7 @@ func (o *Operator) makeDeploymentConfigAndDeps(apiObject *api.ArangoDeployment) MetricsExporterImage: o.MetricsExporterImage, ArangoImage: o.ArangoImage, AllowChaos: o.Config.AllowChaos, + Scope: o.Scope, } deps := deployment.Dependencies{ Log: o.Dependencies.LogService.MustGetLogger("deployment").With(). diff --git a/pkg/operator/scope/scope.go b/pkg/operator/scope/scope.go new file mode 100644 index 000000000..5c17c48e2 --- /dev/null +++ b/pkg/operator/scope/scope.go @@ -0,0 +1,51 @@ +// +// DISCLAIMER +// +// Copyright 2020 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// +// Author Adam Janikowski +// + +package scope + +func AsScope(s string) (Scope, bool) { + switch s { + case LegacyScope.String(): + return LegacyScope, true + case NamespacedScope.String(): + return NamespacedScope, true + } + + return "", false +} + +type Scope string + +func (s Scope) String() string { + return string(s) +} + +func (s Scope) IsNamespaced() bool { + return s == NamespacedScope +} + +const ( + LegacyScope Scope = "legacy" + NamespacedScope Scope = "namespaced" + + DefaultScope = LegacyScope +) diff --git a/pkg/operator/server_discovery_api.go b/pkg/operator/server_discovery_api.go index 3f63e6fe9..d65720cfe 100644 --- a/pkg/operator/server_discovery_api.go +++ b/pkg/operator/server_discovery_api.go @@ -44,6 +44,11 @@ const ( // FindOtherOperators looks up references to other operators in the same Kubernetes cluster. func (o *Operator) FindOtherOperators() []server.OperatorReference { + if o.Scope.IsNamespaced() { + // In namespaced scope nothing to do + return []server.OperatorReference{} + } + log := o.log var result []server.OperatorReference namespaces, err := o.Dependencies.KubeCli.CoreV1().Namespaces().List(metav1.ListOptions{}) @@ -94,6 +99,9 @@ func (o *Operator) findOtherOperatorsInNamespace(log zerolog.Logger, namespace s return nil } nodeFetcher := func() (v1.NodeList, error) { + if o.Scope.IsNamespaced() { + return v1.NodeList{}, nil + } result, err := o.Dependencies.KubeCli.CoreV1().Nodes().List(metav1.ListOptions{}) if err != nil { return v1.NodeList{}, maskAny(err) diff --git a/pkg/util/crd/crd.go b/pkg/util/crd/crd.go index e4632c1ca..8f68602bd 100644 --- a/pkg/util/crd/crd.go +++ b/pkg/util/crd/crd.go @@ -33,6 +33,14 @@ import ( "github.com/arangodb/kube-arangodb/pkg/util/retry" ) +// WaitReady waits for a check to be ready. +func WaitReady(check func() error) error { + if err := retry.Retry(check, time.Second*30); err != nil { + return maskAny(err) + } + return nil +} + // WaitCRDReady waits for a custom resource definition with given name to be ready. func WaitCRDReady(clientset apiextensionsclient.Interface, crdName string) error { op := func() error { @@ -54,8 +62,5 @@ func WaitCRDReady(clientset apiextensionsclient.Interface, crdName string) error } return maskAny(fmt.Errorf("Retry needed")) } - if err := retry.Retry(op, time.Second*30); err != nil { - return maskAny(err) - } - return nil + return WaitReady(op) } From ade5b644d16f66e9a458955b85a0ab8260d11d55 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Thu, 13 Aug 2020 12:40:44 +0000 Subject: [PATCH 2/5] Replace neq to not eq --- .../backup-operator/cluster-role-binding.yaml | 2 +- .../templates/backup-operator/cluster-role.yaml | 2 +- .../cluster-role-binding.yaml | 2 +- .../deployment-operator/cluster-role.yaml | 2 +- .../cluster-role-binding.yaml | 2 +- .../cluster-role.yaml | 2 +- chart/kube-arangodb/templates/deployment.yaml | 16 ++++++++-------- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml index 28e4a8d57..4f1c23cff 100644 --- a/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/backup-operator/cluster-role-binding.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.backup -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml b/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml index b1f9628bb..a1c011982 100644 --- a/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/backup-operator/cluster-role.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.backup -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml index 02dd431a2..5e3261c21 100644 --- a/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/deployment-operator/cluster-role-binding.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.deployment -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml b/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml index d230a0154..1e9222396 100644 --- a/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/deployment-operator/cluster-role.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.deployment -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml index 5a2e588f7..e526e91f3 100644 --- a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml +++ b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role-binding.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.deploymentReplications -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml index 509a5f354..cd4f9eb67 100644 --- a/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml +++ b/chart/kube-arangodb/templates/deployment-replications-operator/cluster-role.yaml @@ -1,5 +1,5 @@ {{ if .Values.rbac.enabled -}} -{{ if neq .Values.operator.scope "namespaced" -}} +{{ if not (eq .Values.operator.scope "namespaced") -}} {{ if .Values.operator.features.deploymentReplications -}} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/chart/kube-arangodb/templates/deployment.yaml b/chart/kube-arangodb/templates/deployment.yaml index 8d8ef86f7..3c48bbdbb 100644 --- a/chart/kube-arangodb/templates/deployment.yaml +++ b/chart/kube-arangodb/templates/deployment.yaml @@ -1,13 +1,13 @@ -{{- if eq .Values.operator.scope "legacy" -}} +{{ if eq .Values.operator.scope "legacy" -}} # Scope "legacy" selected -{{ elif eq .Values.operator.scope "namespaced" -}} +{{ else if eq .Values.operator.scope "namespaced" -}} # Scope "namespaced" selected -{{- if .Values.operator.features.storage -}} -{{- fail (printf "Storage Operator not supported in %s scope!" .Values.operator.scope) -}} -{{- end -}} -{{- else -}} -{{- fail (printf "Operator Scope %s is not supported!" .Values.operator.scope) -}} -{{- end -}} +{{ if .Values.operator.features.storage -}} +{{ fail (printf "Storage Operator not supported in %s scope!" .Values.operator.scope) -}} +{{ end -}} +{{ else -}} +{{ fail (printf "Operator Scope %s is not supported!" .Values.operator.scope) -}} +{{ end -}} apiVersion: apps/v1 kind: Deployment metadata: From 740c7ea0f590d51fbd70146c4a6701b0ba3505e7 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Fri, 14 Aug 2020 06:21:11 +0000 Subject: [PATCH 3/5] Add Namespaced SM --- pkg/deployment/deployment.go | 7 ++- pkg/metrics/collector.go | 86 ------------------------------------ 2 files changed, 6 insertions(+), 87 deletions(-) delete mode 100644 pkg/metrics/collector.go diff --git a/pkg/deployment/deployment.go b/pkg/deployment/deployment.go index 126fa0a7d..f55a38415 100644 --- a/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -469,7 +469,12 @@ func (d *Deployment) isOwnerOf(obj metav1.Object) bool { // once at creation time of the deployment and then always if the CRD // informer is triggered. func (d *Deployment) lookForServiceMonitorCRD() { - _, err := d.deps.KubeExtCli.ApiextensionsV1beta1().CustomResourceDefinitions().Get("servicemonitors.monitoring.coreos.com", metav1.GetOptions{}) + var err error + if d.GetScope().IsNamespaced() { + _, err = d.deps.KubeMonitoringCli.ServiceMonitors(d.GetNamespace()).List(metav1.ListOptions{}) + } else { + _, err = d.deps.KubeExtCli.ApiextensionsV1beta1().CustomResourceDefinitions().Get("servicemonitors.monitoring.coreos.com", metav1.GetOptions{}) + } log := d.deps.Log log.Debug().Msgf("Looking for ServiceMonitor CRD...") if err == nil { diff --git a/pkg/metrics/collector.go b/pkg/metrics/collector.go deleted file mode 100644 index 4bb7c739e..000000000 --- a/pkg/metrics/collector.go +++ /dev/null @@ -1,86 +0,0 @@ -package metrics - -import ( - "net/http" - "sync" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" -) - -type Collector interface { - Collect(chan<- prometheus.Collector) -} - -type CollectorFactory interface { - Collector - CollectFactory(chan<- Collector) -} - -func WrapHttpForCollectors(collectors ...Collector) http.HandlerFunc { - return func(writer http.ResponseWriter, request *http.Request) { - r := prometheus.NewRegistry() - Register(r, collectors...) - - promhttp.HandlerFor(r, promhttp.HandlerOpts{}).ServeHTTP(writer, request) - } -} - -func Register(registerer prometheus.Registerer, collectors ...Collector) { - c := make(chan prometheus.Collector) - - go func() { - defer close(c) - Collect(c, collectors...) - }() - - for m := range c { - registerer.Register(m) - } -} - -func Collect(c chan<- prometheus.Collector, collectors ...Collector) { - var wg sync.WaitGroup - - for _, collector := range collectors { - wg.Add(1) - go func() { - defer wg.Done() - collectSingle(c, collector) - }() - } - - wg.Wait() -} - -func collectSingle(c chan<- prometheus.Collector, collector Collector) { - collector.Collect(c) - - if f, ok := collector.(CollectorFactory); ok { - collectFactory(c, f) - } - -} - -func collectFactory(c chan<- prometheus.Collector, f CollectorFactory) { - collectors := make(chan Collector) - - go func() { - defer close(collectors) - f.CollectFactory(collectors) - }() - - var wg sync.WaitGroup - - for m := range collectors { - wg.Add(1) - - go func() { - defer wg.Done() - - collectSingle(c, m) - }() - } - - wg.Wait() -} From e4b235e39d69ae299fab22e3933b954e45751df4 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Fri, 14 Aug 2020 06:33:59 +0000 Subject: [PATCH 4/5] Fix changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e54d2e4..d2acd6fe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ ## [1.0.3](https://github.com/arangodb/kube-arangodb/tree/1.0.3) (2020-05-25) - Prevent deletion of not known PVC's +- Move Restore as Plan ## [1.0.2](https://github.com/arangodb/kube-arangodb/tree/1.0.2) (2020-04-16) - Added additional checks in UpToDate condition From c1dbf020f9a201def70e67d311f75ad3c4d40b40 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Fri, 14 Aug 2020 06:40:29 +0000 Subject: [PATCH 5/5] Fix IDE renaming --- main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 7c5187dfa..9ac0b3009 100644 --- a/main.go +++ b/main.go @@ -31,7 +31,7 @@ import ( "strings" "time" - scope2 "github.com/arangodb/kube-arangodb/pkg/operator/scope" + "github.com/arangodb/kube-arangodb/pkg/operator/scope" "github.com/arangodb/kube-arangodb/pkg/deployment/features" @@ -141,7 +141,7 @@ func init() { f.StringVar(&operatorOptions.arangoImage, "operator.arango-image", ArangoImageEnv.GetOrDefault(defaultArangoImage), "Docker image used for arango by default") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") f.BoolVar(&operatorOptions.singleMode, "mode.single", false, "Enable single mode in Operator. WARNING: There should be only one replica of Operator, otherwise Operator can take unexpected actions") - f.StringVar(&operatorOptions.scope, "scope", scope2.DefaultScope.String(), "Define scope on which Operator works. Legacy - pre 1.1.0 scope with limited cluster access") + f.StringVar(&operatorOptions.scope, "scope", scope.DefaultScope.String(), "Define scope on which Operator works. Legacy - pre 1.1.0 scope with limited cluster access") features.Init(&cmdMain) } @@ -301,7 +301,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper } eventRecorder := createRecorder(cliLog, kubecli, name, namespace) - scope, ok := scope2.AsScope(operatorOptions.scope) + scope, ok := scope.AsScope(operatorOptions.scope) if !ok { return operator.Config{}, operator.Dependencies{}, maskAny(fmt.Errorf("Scope %s is not known by Operator", operatorOptions.scope)) }