1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

Splitting operator in two parts

This commit is contained in:
Ewout Prangsma 2018-03-19 11:09:20 +01:00
parent fd7b559324
commit 550ace82ec
No known key found for this signature in database
GPG key ID: 4DBAD380D93D0698
16 changed files with 454 additions and 207 deletions

View file

@ -40,9 +40,11 @@ else
IMAGESUFFIX := :dev
endif
ifndef MANIFESTPATH
MANIFESTPATH := manifests/arango-operator-dev.yaml
ifndef MANIFESTSUFFIX
MANIFESTSUFFIX := -dev
endif
MANIFESTPATHDEPLOYMENT := manifests/arango-deployment$(MANIFESTSUFFIX).yaml
MANIFESTPATHSTORAGE := manifests/arango-storage$(MANIFESTSUFFIX).yaml
ifndef DEPLOYMENTNAMESPACE
DEPLOYMENTNAMESPACE := default
endif
@ -189,7 +191,7 @@ endif
.PHONY: manifests
manifests: $(GOBUILDDIR)
GOPATH=$(GOBUILDDIR) go run $(ROOTDIR)/tools/manifests/manifest_builder.go \
--output=$(MANIFESTPATH) \
--output-suffix=$(MANIFESTSUFFIX) \
--image=$(OPERATORIMAGE) \
--image-sha256=$(IMAGESHA256) \
--namespace=$(DEPLOYMENTNAMESPACE)
@ -240,7 +242,8 @@ ifneq ($(DEPLOYMENTNAMESPACE), default)
$(ROOTDIR)/scripts/kube_delete_namespace.sh $(DEPLOYMENTNAMESPACE)
kubectl create namespace $(DEPLOYMENTNAMESPACE)
endif
kubectl apply -f $(MANIFESTPATH)
kubectl apply -f $(MANIFESTPATHSTORAGE)
kubectl apply -f $(MANIFESTPATHDEPLOYMENT)
$(ROOTDIR)/scripts/kube_create_storage.sh $(DEPLOYMENTNAMESPACE)
kubectl --namespace $(DEPLOYMENTNAMESPACE) \
run arangodb-operator-test -i --rm --quiet --restart=Never \
@ -308,9 +311,11 @@ minikube-start:
.PHONY: delete-operator
delete-operator:
kubectl delete -f $(MANIFESTPATH) --ignore-not-found
kubectl delete -f $(MANIFESTPATHDEPLOYMENT) --ignore-not-found
kubectl delete -f $(MANIFESTPATHSTORAGE) --ignore-not-found
.PHONY: redeploy-operator
redeploy-operator: delete-operator manifests
kubectl apply -f $(MANIFESTPATH)
kubectl apply -f $(MANIFESTPATHSTORAGE)
kubectl apply -f $(MANIFESTPATHDEPLOYMENT)
kubectl get pods

View file

@ -11,5 +11,7 @@ State: In heavy development. DO NOT USE FOR ANY PRODUCTION LIKE PURPOSE! THINGS
```bash
DOCKERNAMESPACE=<your dockerhub account> make
kubectl apply -f manifests/arango-operator-dev.yaml
kubectl apply -f manifests/arango-deployment-dev.yaml
# To use `ArangoLocalStorage`, also run
kubectl apply -f manifests/arango-storage-dev.yaml
```

View file

@ -6,7 +6,13 @@ The ArangoDB operator needs to be installed in your Kubernetes
cluster first. To do so, clone this repository and run:
```bash
kubectl apply -f manifests/arango-operator.yaml
kubectl apply -f manifests/arango-deployment.yaml
```
To use `ArangoLocalStorage`, also run:
```bash
kubectl apply -f manifests/arango-storage.yaml
```
## Cluster creation
@ -37,5 +43,7 @@ To remove the entire ArangoDB operator, remove all
clusters first and then remove the operator by running:
```bash
kubectl delete -f manifests/arango-operator.yaml
kubectl delete -f manifests/arango-deployment.yaml
# If `ArangoLocalStorage` is installed
kubectl delete -f manifests/arango-storage.yaml
```

82
main.go
View file

@ -41,8 +41,6 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"k8s.io/client-go/tools/record"
"github.com/arangodb/kube-arangodb/pkg/client"
@ -77,7 +75,11 @@ var (
host string
port int
}
createCRD bool
operatorOptions struct {
enableDeployment bool // Run deployment operator
enableStorage bool // Run deployment operator
createCRD bool
}
)
func init() {
@ -85,7 +87,9 @@ func init() {
f.StringVar(&server.host, "server.host", defaultServerHost, "Host to listen on")
f.IntVar(&server.port, "server.port", defaultServerPort, "Port to listen on")
f.StringVar(&logLevel, "log.level", defaultLogLevel, "Set initial log level")
f.BoolVar(&createCRD, "operator.create-crd", true, "Disable to avoid create the custom resource definition")
f.BoolVar(&operatorOptions.enableDeployment, "operator.deployment", false, "Enable to run the ArangoDeployment operator")
f.BoolVar(&operatorOptions.enableStorage, "operator.storage", false, "Enable to run the ArangoLocalStorage operator")
f.BoolVar(&operatorOptions.createCRD, "operator.create-crd", true, "Disable to avoid create the custom resource definition")
}
func main() {
@ -107,6 +111,11 @@ func cmdMainRun(cmd *cobra.Command, args []string) {
cliLog.Fatal().Err(err).Msg("Failed to initialize log service")
}
// Check operating mode
if !operatorOptions.enableDeployment && !operatorOptions.enableStorage {
cliLog.Fatal().Err(err).Msg("Turn on --operator.deployment or --operator.storage or both")
}
// Log version
cliLog.Info().Msgf("Starting arangodb-operator, version %s build %s", projectVersion, projectBuild)
@ -126,48 +135,12 @@ func cmdMainRun(cmd *cobra.Command, args []string) {
cliLog.Fatal().Err(err).Msg("Failed to get hostname")
}
// Create k8s client
kubecli, err := k8sutil.NewKubeClient()
if err != nil {
cliLog.Fatal().Err(err).Msg("Failed to create kubernetes client")
}
//http.HandleFunc(probe.HTTPReadyzEndpoint, probe.ReadyzHandler)
http.Handle("/metrics", prometheus.Handler())
listenAddr := net.JoinHostPort(server.host, strconv.Itoa(server.port))
go http.ListenAndServe(listenAddr, nil)
rl, err := resourcelock.New(resourcelock.EndpointsResourceLock,
namespace,
"arangodb-operator",
kubecli.CoreV1(),
resourcelock.ResourceLockConfig{
Identity: id,
EventRecorder: createRecorder(cliLog, kubecli, name, namespace),
})
if err != nil {
cliLog.Fatal().Err(err).Msg("Failed to create resource lock")
}
leaderelection.RunOrDie(leaderelection.LeaderElectionConfig{
Lock: rl,
LeaseDuration: 15 * time.Second,
RenewDeadline: 10 * time.Second,
RetryPeriod: 2 * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: func(stop <-chan struct{}) {
run(stop, namespace, name)
},
OnStoppedLeading: func() {
cliLog.Fatal().Msg("Leader election lost")
},
},
})
}
// run the operator
func run(stop <-chan struct{}, namespace, name string) {
cfg, deps, err := newOperatorConfigAndDeps(namespace, name)
cfg, deps, err := newOperatorConfigAndDeps(id+"-"+name, namespace, name)
if err != nil {
cliLog.Fatal().Err(err).Msg("Failed to create operator config & deps")
}
@ -178,13 +151,11 @@ func run(stop <-chan struct{}, namespace, name string) {
if err != nil {
cliLog.Fatal().Err(err).Msg("Failed to create operator")
}
if err := o.Start(); err != nil {
cliLog.Fatal().Err(err).Msg("Failed to start operator")
}
o.Run()
}
// newOperatorConfigAndDeps creates operator config & dependencies.
func newOperatorConfigAndDeps(namespace, name string) (operator.Config, operator.Dependencies, error) {
func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, operator.Dependencies, error) {
kubecli, err := k8sutil.NewKubeClient()
if err != nil {
return operator.Config{}, operator.Dependencies{}, maskAny(err)
@ -203,18 +174,23 @@ func newOperatorConfigAndDeps(namespace, name string) (operator.Config, operator
if err != nil {
return operator.Config{}, operator.Dependencies{}, maskAny(fmt.Errorf("Failed to created versioned client: %s", err))
}
eventRecorder := createRecorder(cliLog, kubecli, name, namespace)
cfg := operator.Config{
Namespace: namespace,
PodName: name,
ServiceAccount: serviceAccount,
CreateCRD: createCRD,
ID: id,
Namespace: namespace,
PodName: name,
ServiceAccount: serviceAccount,
EnableDeployment: operatorOptions.enableDeployment,
EnableStorage: operatorOptions.enableStorage,
CreateCRD: operatorOptions.createCRD,
}
deps := operator.Dependencies{
Log: logService.MustGetLogger("operator"),
KubeCli: kubecli,
KubeExtCli: kubeExtCli,
CRCli: crCli,
Log: logService.MustGetLogger("operator"),
KubeCli: kubecli,
KubeExtCli: kubeExtCli,
CRCli: crCli,
EventRecorder: eventRecorder,
}
return cfg, deps, nil

View file

@ -1,8 +1,8 @@
## rbac.yaml
## deployment/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: arango-operator
name: arango-deployment-operator
rules:
- apiGroups:
- database.arangodb.com
@ -10,12 +10,6 @@ rules:
- arangodeployments
verbs:
- "*"
- apiGroups:
- storage.arangodb.com
resources:
- arangolocalstorages
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
@ -28,7 +22,6 @@ rules:
- pods
- services
- endpoints
- persistentvolumes
- persistentvolumeclaims
- events
- secrets
@ -38,7 +31,6 @@ rules:
- apps
resources:
- deployments
- daemonsets
verbs:
- "*"
- apiGroups:
@ -46,18 +38,19 @@ rules:
resources:
- storageclasses
verbs:
- "*"
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: arango-operator
name: arango-deployment-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: arango-operator
name: arango-deployment-operator
subjects:
- kind: ServiceAccount
name: default
@ -65,24 +58,26 @@ subjects:
---
## deployment.yaml
## deployment/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: arango-operator
name: arango-deployment-operator
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
name: arango-operator
name: arango-deployment-operator
spec:
containers:
- name: arangodb-operator
- name: operator
imagePullPolicy: IfNotPresent
image: arangodb/arangodb-operator@sha256:90663ccc4cc71562ec06b7e2ad189762aaa38e922e0c70b3cc12f2afa51bf50c
image: ewoutp/arangodb-operator@sha256:51a122f8b36cb26f181dd1ffdddae6cb3fb5a4def4709c3ea123744a557cbe08
args:
- --operator.deployment
env:
- name: MY_POD_NAMESPACE
valueFrom:

View file

@ -0,0 +1,86 @@
## storage/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: arango-deployment-operator
rules:
- apiGroups:
- storage.arangodb.com
resources:
- arangolocalstorages
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- "*"
- apiGroups:
- ""
resources:
- persistentvolumes
- persistentvolumeclaims
- events
verbs:
- "*"
- apiGroups:
- apps
resources:
- daemonsets
verbs:
- "*"
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: arango-deployment-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: arango-deployment-operator
subjects:
- kind: ServiceAccount
name: default
namespace: default
---
## storage/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: arango-storage-operator
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
name: arango-storage-operator
spec:
containers:
- name: operator
imagePullPolicy: IfNotPresent
image: ewoutp/arangodb-operator@sha256:51a122f8b36cb26f181dd1ffdddae6cb3fb5a4def4709c3ea123744a557cbe08
args:
- --operator.storage
env:
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name

View file

@ -0,0 +1,28 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .Deployment.OperatorName }}
namespace: {{ .Deployment.Namespace }}
spec:
replicas: 1
template:
metadata:
labels:
name: {{ .Deployment.OperatorName }}
spec:
containers:
- name: operator
imagePullPolicy: {{ .ImagePullPolicy }}
image: {{ .Image }}
args:
- --operator.deployment
env:
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name

View file

@ -1,9 +1,8 @@
{{- if .RBAC -}}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: {{ .ClusterRoleName }}
name: {{ .Deployment.ClusterRoleName }}
rules:
- apiGroups:
- database.arangodb.com
@ -11,12 +10,6 @@ rules:
- arangodeployments
verbs:
- "*"
- apiGroups:
- storage.arangodb.com
resources:
- arangolocalstorages
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
@ -29,7 +22,6 @@ rules:
- pods
- services
- endpoints
- persistentvolumes
- persistentvolumeclaims
- events
- secrets
@ -39,7 +31,6 @@ rules:
- apps
resources:
- deployments
- daemonsets
verbs:
- "*"
- apiGroups:
@ -47,21 +38,22 @@ rules:
resources:
- storageclasses
verbs:
- "*"
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: {{ .ClusterRoleBindingName }}
name: {{ .Deployment.ClusterRoleBindingName }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ .ClusterRoleName }}
name: {{ .Deployment.ClusterRoleName }}
subjects:
- kind: ServiceAccount
name: default
namespace: {{ .Namespace }}
namespace: {{ .Deployment.Namespace }}
{{- end -}}

View file

@ -2,19 +2,21 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .OperatorName }}
namespace: {{ .Namespace }}
name: {{ .Storage.OperatorName }}
namespace: {{ .Storage.Namespace }}
spec:
replicas: 1
template:
metadata:
labels:
name: {{ .OperatorName }}
name: {{ .Storage.OperatorName }}
spec:
containers:
- name: arangodb-operator
- name: operator
imagePullPolicy: {{ .ImagePullPolicy }}
image: {{ .OperatorImage }}
image: {{ .Image }}
args:
- --operator.storage
env:
- name: MY_POD_NAMESPACE
valueFrom:

View file

@ -0,0 +1,56 @@
{{- if .RBAC -}}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: {{ .Deployment.ClusterRoleName }}
rules:
- apiGroups:
- storage.arangodb.com
resources:
- arangolocalstorages
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- "*"
- apiGroups:
- ""
resources:
- persistentvolumes
- persistentvolumeclaims
- events
verbs:
- "*"
- apiGroups:
- apps
resources:
- daemonsets
verbs:
- "*"
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: {{ .Deployment.ClusterRoleBindingName }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ .Deployment.ClusterRoleName }}
subjects:
- kind: ServiceAccount
name: default
namespace: {{ .Deployment.Namespace }}
{{- end -}}

View file

@ -34,9 +34,9 @@ import (
// initResourceIfNeeded initializes the custom resource definition when
// instructed to do so by the config.
func (o *Operator) initResourceIfNeeded() error {
func (o *Operator) initResourceIfNeeded(enableDeployment, enableStorage bool) error {
if o.Config.CreateCRD {
if err := o.initCRD(); err != nil {
if err := o.initCRD(enableDeployment, enableStorage); err != nil {
return maskAny(fmt.Errorf("Failed to initialize Custom Resource Definition: %v", err))
}
}
@ -44,25 +44,30 @@ func (o *Operator) initResourceIfNeeded() error {
}
// initCRD creates the CustomResourceDefinition and waits for it to be ready.
func (o *Operator) initCRD() error {
func (o *Operator) initCRD(enableDeployment, enableStorage bool) error {
log := o.Dependencies.Log
log.Debug().Msg("Creating ArangoDeployment CRD")
if err := crd.CreateCRD(o.KubeExtCli, deplapi.SchemeGroupVersion, deplapi.ArangoDeploymentCRDName, deplapi.ArangoDeploymentResourceKind, deplapi.ArangoDeploymentResourcePlural, deplapi.ArangoDeploymentShortNames...); err != nil {
return maskAny(errors.Wrapf(err, "failed to create CRD: %v", err))
}
log.Debug().Msg("Waiting for ArangoDeployment CRD to be ready")
if err := crd.WaitCRDReady(o.KubeExtCli, deplapi.ArangoDeploymentCRDName); err != nil {
return maskAny(err)
if enableDeployment {
log.Debug().Msg("Creating ArangoDeployment CRD")
if err := crd.CreateCRD(o.KubeExtCli, deplapi.SchemeGroupVersion, deplapi.ArangoDeploymentCRDName, deplapi.ArangoDeploymentResourceKind, deplapi.ArangoDeploymentResourcePlural, deplapi.ArangoDeploymentShortNames...); err != nil {
return maskAny(errors.Wrapf(err, "failed to create CRD: %v", err))
}
log.Debug().Msg("Waiting for ArangoDeployment CRD to be ready")
if err := crd.WaitCRDReady(o.KubeExtCli, deplapi.ArangoDeploymentCRDName); err != nil {
return maskAny(err)
}
}
log.Debug().Msg("Creating ArangoLocalStorage CRD")
if err := crd.CreateCRD(o.KubeExtCli, lsapi.SchemeGroupVersion, lsapi.ArangoLocalStorageCRDName, lsapi.ArangoLocalStorageResourceKind, lsapi.ArangoLocalStorageResourcePlural, lsapi.ArangoLocalStorageShortNames...); err != nil {
return maskAny(errors.Wrapf(err, "failed to create CRD: %v", err))
}
log.Debug().Msg("Waiting for ArangoLocalStorage CRD to be ready")
if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil {
return maskAny(err)
if enableStorage {
log.Debug().Msg("Creating ArangoLocalStorage CRD")
if err := crd.CreateCRD(o.KubeExtCli, lsapi.SchemeGroupVersion, lsapi.ArangoLocalStorageCRDName, lsapi.ArangoLocalStorageResourceKind, lsapi.ArangoLocalStorageResourcePlural, lsapi.ArangoLocalStorageShortNames...); err != nil {
return maskAny(errors.Wrapf(err, "failed to create CRD: %v", err))
}
log.Debug().Msg("Waiting for ArangoLocalStorage CRD to be ready")
if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil {
return maskAny(err)
}
}
return nil
}

View file

@ -27,9 +27,11 @@ import (
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
kwatch "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/record"
deplapi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha"
@ -57,17 +59,21 @@ type Operator struct {
}
type Config struct {
Namespace string
PodName string
ServiceAccount string
CreateCRD bool
ID string
Namespace string
PodName string
ServiceAccount string
EnableDeployment bool
EnableStorage bool
CreateCRD bool
}
type Dependencies struct {
Log zerolog.Logger
KubeCli kubernetes.Interface
KubeExtCli apiextensionsclient.Interface
CRCli versioned.Interface
Log zerolog.Logger
KubeCli kubernetes.Interface
KubeExtCli apiextensionsclient.Interface
CRCli versioned.Interface
EventRecorder record.EventRecorder
}
// NewOperator instantiates a new operator from given config & dependencies.
@ -81,12 +87,22 @@ func NewOperator(config Config, deps Dependencies) (*Operator, error) {
return o, nil
}
// Start the operator
func (o *Operator) Start() error {
log := o.Dependencies.Log
// Run the operator
func (o *Operator) Run() {
if o.Config.EnableDeployment {
go o.runLeaderElection("arango-deployment-operator", o.onStartDeployment)
}
if o.Config.EnableStorage {
go o.runLeaderElection("arango-storage-operator", o.onStartStorage)
}
// Wait until process terminates
<-context.TODO().Done()
}
// onStartDeployment starts the deployment operator and run till given channel is closed.
func (o *Operator) onStartDeployment(stop <-chan struct{}) {
for {
if err := o.initResourceIfNeeded(); err == nil {
if err := o.initResourceIfNeeded(true, false); err == nil {
break
} else {
log.Error().Err(err).Msg("Resource initialization failed")
@ -94,23 +110,19 @@ func (o *Operator) Start() error {
time.Sleep(initRetryWaitTime)
}
}
//probe.SetReady()
o.run()
panic("unreachable")
o.runDeployments(stop)
}
// run the operator.
// This registers a listener and waits until the process stops.
func (o *Operator) run() {
log := o.Dependencies.Log
log.Info().Msgf("Running controller in namespace '%s'", o.Config.Namespace)
go o.runDeployments()
go o.runLocalStorages()
// Wait till done
ctx := context.TODO()
<-ctx.Done()
// onStartStorage starts the storage operator and run till given channel is closed.
func (o *Operator) onStartStorage(stop <-chan struct{}) {
for {
if err := o.initResourceIfNeeded(false, true); err == nil {
break
} else {
log.Error().Err(err).Msg("Resource initialization failed")
log.Info().Msgf("Retrying in %s...", initRetryWaitTime)
time.Sleep(initRetryWaitTime)
}
}
o.runLocalStorages(stop)
}

View file

@ -23,7 +23,6 @@
package operator
import (
"context"
"fmt"
"github.com/pkg/errors"
@ -46,7 +45,7 @@ var (
// run the deployments part of the operator.
// This registers a listener and waits until the process stops.
func (o *Operator) runDeployments() {
func (o *Operator) runDeployments(stop <-chan struct{}) {
source := cache.NewListWatchFromClient(
o.Dependencies.CRCli.DatabaseV1alpha().RESTClient(),
api.ArangoDeploymentResourcePlural,
@ -59,9 +58,7 @@ func (o *Operator) runDeployments() {
DeleteFunc: o.onDeleteArangoDeployment,
}, cache.Indexers{})
ctx := context.TODO()
// TODO: use workqueue to avoid blocking
informer.Run(ctx.Done())
informer.Run(stop)
}
// onAddArangoDeployment deployment addition callback

View file

@ -0,0 +1,60 @@
//
// DISCLAIMER
//
// Copyright 2018 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 Ewout Prangsma
//
package operator
import (
"time"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)
func (o *Operator) runLeaderElection(lockName string, onStart func(stop <-chan struct{})) {
namespace := o.Config.Namespace
kubecli := o.Dependencies.KubeCli
log := o.Dependencies.Log.With().Str("lock-name", lockName).Logger()
rl, err := resourcelock.New(resourcelock.EndpointsResourceLock,
namespace,
lockName,
kubecli.CoreV1(),
resourcelock.ResourceLockConfig{
Identity: o.Config.ID,
EventRecorder: o.Dependencies.EventRecorder,
})
if err != nil {
log.Fatal().Err(err).Msg("Failed to create resource lock")
}
leaderelection.RunOrDie(leaderelection.LeaderElectionConfig{
Lock: rl,
LeaseDuration: 15 * time.Second,
RenewDeadline: 10 * time.Second,
RetryPeriod: 2 * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: onStart,
OnStoppedLeading: func() {
log.Info().Msg("Leader election lost")
},
},
})
}

View file

@ -23,7 +23,6 @@
package operator
import (
"context"
"fmt"
"github.com/pkg/errors"
@ -46,7 +45,7 @@ var (
// run the local storages part of the operator.
// This registers a listener and waits until the process stops.
func (o *Operator) runLocalStorages() {
func (o *Operator) runLocalStorages(stop <-chan struct{}) {
source := cache.NewListWatchFromClient(
o.Dependencies.CRCli.StorageV1alpha().RESTClient(),
api.ArangoLocalStorageResourcePlural,
@ -59,9 +58,7 @@ func (o *Operator) runLocalStorages() {
DeleteFunc: o.onDeleteArangoLocalStorage,
}, cache.Indexers{})
ctx := context.TODO()
// TODO: use workqueue to avoid blocking
informer.Run(ctx.Done())
informer.Run(stop)
}
// onAddArangoLocalStorage local storage addition callback

View file

@ -38,40 +38,58 @@ import (
var (
options struct {
OutputFile string
OutputSuffix string
TemplatesDir string
Namespace string
Image string
ImagePullPolicy string
ImageSHA256 bool
OperatorName string
RBAC bool
Namespace string
Image string
ImagePullPolicy string
ImageSHA256 bool
DeploymentOperatorName string
StorageOperatorName string
RBAC bool
}
templateNames = []string{
deploymentTemplateNames = []string{
"rbac.yaml",
"deployment.yaml",
}
storageTemplateNames = []string{
"rbac.yaml",
"deployment.yaml",
}
)
func init() {
pflag.StringVar(&options.OutputFile, "output", "manifests/arango-operator.yaml", "Path of the generated manifest file")
pflag.StringVar(&options.OutputSuffix, "output-suffix", "", "Suffix of the generated manifest files")
pflag.StringVar(&options.TemplatesDir, "templates-dir", "manifests/templates", "Directory containing manifest templates")
pflag.StringVar(&options.Namespace, "namespace", "default", "Namespace in which the operator will be deployed")
pflag.StringVar(&options.Image, "image", "arangodb/arangodb-operator:latest", "Fully qualified image name of the ArangoDB operator")
pflag.StringVar(&options.ImagePullPolicy, "image-pull-policy", "IfNotPresent", "Pull policy of the ArangoDB operator image")
pflag.BoolVar(&options.ImageSHA256, "image-sha256", true, "Use SHA256 syntax for image")
pflag.StringVar(&options.OperatorName, "operator-name", "arango-operator", "Name of the ArangoDB operator deployment")
pflag.StringVar(&options.DeploymentOperatorName, "deployment-operator-name", "arango-deployment-operator", "Name of the ArangoDeployment operator deployment")
pflag.StringVar(&options.StorageOperatorName, "storage-operator-name", "arango-storage-operator", "Name of the ArangoLocalStorage operator deployment")
pflag.BoolVar(&options.RBAC, "rbac", true, "Use role based access control")
pflag.Parse()
}
type TemplateOptions struct {
Image string
ImagePullPolicy string
RBAC bool
Deployment OperatorOptions
Storage OperatorOptions
}
type OperatorOptions struct {
Namespace string
OperatorName string
ClusterRoleName string
ClusterRoleBindingName string
}
func main() {
// Check options
if options.OutputFile == "" {
log.Fatal("--output not specified.")
}
if options.Namespace == "" {
log.Fatal("--namespace not specified.")
}
@ -95,47 +113,55 @@ func main() {
options.Image = strings.TrimSpace(string(result))
}
// Process templates
templateOptions := struct {
Namespace string
OperatorName string
OperatorImage string
ImagePullPolicy string
ClusterRoleName string
ClusterRoleBindingName string
RBAC bool
}{
Namespace: options.Namespace,
OperatorName: options.OperatorName,
OperatorImage: options.Image,
ImagePullPolicy: options.ImagePullPolicy,
ClusterRoleName: "arango-operator",
ClusterRoleBindingName: "arango-operator",
RBAC: options.RBAC,
}
output := &bytes.Buffer{}
for i, name := range templateNames {
t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, name))
if err != nil {
log.Fatalf("Failed to parse template %s: %v", name, err)
}
if i > 0 {
output.WriteString("\n---\n\n")
}
output.WriteString(fmt.Sprintf("## %s\n", name))
t.Execute(output, templateOptions)
output.WriteString("\n")
// Prepare templates to include
templateNameSet := map[string][]string{
"deployment": deploymentTemplateNames,
"storage": storageTemplateNames,
}
// Save output
outputPath, err := filepath.Abs(options.OutputFile)
if err != nil {
log.Fatalf("Failed to get absolute output path: %v\n", err)
// Process templates
templateOptions := TemplateOptions{
Image: options.Image,
ImagePullPolicy: options.ImagePullPolicy,
RBAC: options.RBAC,
Deployment: OperatorOptions{
Namespace: options.Namespace,
OperatorName: options.DeploymentOperatorName,
ClusterRoleName: "arango-deployment-operator",
ClusterRoleBindingName: "arango-deployment-operator",
},
Storage: OperatorOptions{
Namespace: options.Namespace,
OperatorName: options.StorageOperatorName,
ClusterRoleName: "arango-storage-operator",
ClusterRoleBindingName: "arango-storage-operator",
},
}
if err := os.MkdirAll(filepath.Base(outputPath), 0755); err != nil {
log.Fatalf("Failed to create output directory: %v\n", err)
}
if err := ioutil.WriteFile(outputPath, output.Bytes(), 0644); err != nil {
log.Fatalf("Failed to write output file: %v\n", err)
for group, templateNames := range templateNameSet {
output := &bytes.Buffer{}
for i, name := range templateNames {
t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, group, name))
if err != nil {
log.Fatalf("Failed to parse template %s: %v", name, err)
}
if i > 0 {
output.WriteString("\n---\n\n")
}
output.WriteString(fmt.Sprintf("## %s/%s\n", group, name))
t.Execute(output, templateOptions)
output.WriteString("\n")
}
// Save output
outputPath, err := filepath.Abs(filepath.Join("manifests", "arango-"+group+options.OutputSuffix+".yaml"))
if err != nil {
log.Fatalf("Failed to get absolute output path: %v\n", err)
}
if err := os.MkdirAll(filepath.Base(outputPath), 0755); err != nil {
log.Fatalf("Failed to create output directory: %v\n", err)
}
if err := ioutil.WriteFile(outputPath, output.Bytes(), 0644); err != nil {
log.Fatalf("Failed to write output file: %v\n", err)
}
}
}