mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
Merged in master
This commit is contained in:
commit
6ae89d09f3
32 changed files with 652 additions and 511 deletions
31
Makefile
31
Makefile
|
@ -40,18 +40,20 @@ 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
|
||||
|
||||
ifndef OPERATORIMAGE
|
||||
OPERATORIMAGE := $(DOCKERNAMESPACE)/arangodb-operator$(IMAGESUFFIX)
|
||||
OPERATORIMAGE := $(DOCKERNAMESPACE)/kube-arangodb$(IMAGESUFFIX)
|
||||
endif
|
||||
ifndef TESTIMAGE
|
||||
TESTIMAGE := $(DOCKERNAMESPACE)/arangodb-operator-test$(IMAGESUFFIX)
|
||||
TESTIMAGE := $(DOCKERNAMESPACE)/kube-arangodb-test$(IMAGESUFFIX)
|
||||
endif
|
||||
ifndef ENTERPRISEIMAGE
|
||||
ENTERPRISEIMAGE := $(DEFAULTENTERPRISEIMAGE)
|
||||
|
@ -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,15 +242,11 @@ ifneq ($(DEPLOYMENTNAMESPACE), default)
|
|||
$(ROOTDIR)/scripts/kube_delete_namespace.sh $(DEPLOYMENTNAMESPACE)
|
||||
kubectl create namespace $(DEPLOYMENTNAMESPACE)
|
||||
endif
|
||||
kubectl apply -f $(MANIFESTPATH)
|
||||
kubectl apply -f manifests/crd.yaml
|
||||
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 \
|
||||
--image=$(TESTIMAGE) \
|
||||
--env="ENTERPRISEIMAGE=$(ENTERPRISEIMAGE)" \
|
||||
--env="TEST_NAMESPACE=$(DEPLOYMENTNAMESPACE)" \
|
||||
-- \
|
||||
-test.v -test.timeout $(TESTTIMEOUT) $(TESTLENGTHOPTIONS)
|
||||
$(ROOTDIR)/scripts/kube_run_tests.sh $(DEPLOYMENTNAMESPACE) $(TESTIMAGE) "$(ENTERPRISEIMAGE)" $(TESTTIMEOUT) $(TESTLENGTHOPTIONS)
|
||||
ifneq ($(DEPLOYMENTNAMESPACE), default)
|
||||
kubectl delete namespace $(DEPLOYMENTNAMESPACE) --ignore-not-found --now
|
||||
endif
|
||||
|
@ -308,9 +306,12 @@ 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 manifests/crd.yaml
|
||||
kubectl apply -f $(MANIFESTPATHSTORAGE)
|
||||
kubectl apply -f $(MANIFESTPATHDEPLOYMENT)
|
||||
kubectl get pods
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
"Starter for Kubernetes"
|
||||
|
||||
State: In development
|
||||
State: In heavy development. DO NOT USE FOR ANY PRODUCTION LIKE PURPOSE! THINGS WILL CHANGE.
|
||||
|
||||
- [User manual](./docs/user/README.md)
|
||||
- [Design documents](./docs/design/README.md)
|
||||
|
@ -11,5 +11,8 @@ State: In development
|
|||
|
||||
```bash
|
||||
DOCKERNAMESPACE=<your dockerhub account> make
|
||||
kubectl apply -f manifests/arango-operator-dev.yaml
|
||||
kubectl apply -f manifests/crd.yaml
|
||||
kubectl apply -f manifests/arango-deployment-dev.yaml
|
||||
# To use `ArangoLocalStorage`, also run
|
||||
kubectl apply -f manifests/arango-storage-dev.yaml
|
||||
```
|
||||
|
|
|
@ -142,7 +142,8 @@ and restarting it.
|
|||
This setting specifies the name of a kubernetes `Secret` that contains
|
||||
a standard CA certificate + private key used to sign certificates for individual
|
||||
ArangoDB servers.
|
||||
The default value is empty. TBD
|
||||
When no name is specified, it defaults to `<deployment-name>-ca`.
|
||||
To disable authentication, set this value to `None`.
|
||||
|
||||
If you specify a name of a `Secret` that does not exist, a self-signed CA certificate + key is created
|
||||
and stored in a `Secret` with given name.
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# TLS
|
||||
|
||||
The ArangoDB operator allows you to create ArangoDB deployments that use
|
||||
The ArangoDB operator will by default create ArangoDB deployments that use
|
||||
secure TLS connections.
|
||||
|
||||
It uses a single CA certificate (stored in a Kubernetes secret) and
|
||||
one certificate per ArangoDB server (stored in a Kubernetes secret per server).
|
||||
|
||||
To disable TLS, set `spec.tls.caSecretName` to `None`.
|
||||
|
||||
## Install CA certificate
|
||||
|
||||
If the CA certificate is self-signed, it will not be trusted by browsers,
|
||||
|
|
|
@ -6,7 +6,14 @@ 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/crd.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 +44,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
|
||||
```
|
||||
|
|
8
examples/simple-cluster-no-tls.yaml
Normal file
8
examples/simple-cluster-no-tls.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
apiVersion: "database.arangodb.com/v1alpha"
|
||||
kind: "ArangoDeployment"
|
||||
metadata:
|
||||
name: "example-simple-cluster-no-tls"
|
||||
spec:
|
||||
mode: cluster
|
||||
tls:
|
||||
caSecretName: None
|
|
@ -1,9 +0,0 @@
|
|||
apiVersion: "database.arangodb.com/v1alpha"
|
||||
kind: "ArangoDeployment"
|
||||
metadata:
|
||||
name: "example-simple-cluster-tls"
|
||||
spec:
|
||||
mode: cluster
|
||||
tls:
|
||||
caSecretName: example-simple-cluster-tls
|
||||
altNames: ["kube-01", "kube-02", "kube-03"]
|
66
main.go
66
main.go
|
@ -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
|
||||
}
|
||||
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{
|
||||
ID: id,
|
||||
Namespace: namespace,
|
||||
PodName: name,
|
||||
ServiceAccount: serviceAccount,
|
||||
CreateCRD: createCRD,
|
||||
EnableDeployment: operatorOptions.enableDeployment,
|
||||
EnableStorage: operatorOptions.enableStorage,
|
||||
CreateCRD: operatorOptions.createCRD,
|
||||
}
|
||||
deps := operator.Dependencies{
|
||||
LogService: logService,
|
||||
KubeCli: kubecli,
|
||||
KubeExtCli: kubeExtCli,
|
||||
CRCli: crCli,
|
||||
EventRecorder: eventRecorder,
|
||||
}
|
||||
|
||||
return cfg, deps, nil
|
||||
|
|
3
manifests/.gitignore
vendored
3
manifests/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
arango-operator-dev.yaml
|
||||
arango-deployment-dev.yaml
|
||||
arango-storage-dev.yaml
|
|
@ -1,95 +0,0 @@
|
|||
## rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: arango-operator
|
||||
rules:
|
||||
- apiGroups:
|
||||
- database.arangodb.com
|
||||
resources:
|
||||
- arangodeployments
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- storage.arangodb.com
|
||||
resources:
|
||||
- arangolocalstorages
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- apiextensions.k8s.io
|
||||
resources:
|
||||
- customresourcedefinitions
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- services
|
||||
- endpoints
|
||||
- persistentvolumes
|
||||
- persistentvolumeclaims
|
||||
- events
|
||||
- secrets
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- deployments
|
||||
- daemonsets
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- storage.k8s.io
|
||||
resources:
|
||||
- storageclasses
|
||||
verbs:
|
||||
- "*"
|
||||
|
||||
---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: arango-operator
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: arango-operator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
|
||||
---
|
||||
|
||||
## deployment.yaml
|
||||
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: arango-operator
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: arango-operator
|
||||
spec:
|
||||
containers:
|
||||
- name: arangodb-operator
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: arangodb/arangodb-operator@sha256:90663ccc4cc71562ec06b7e2ad189762aaa38e922e0c70b3cc12f2afa51bf50c
|
||||
env:
|
||||
- name: MY_POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: MY_POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
|
34
manifests/crd.yaml
Normal file
34
manifests/crd.yaml
Normal file
|
@ -0,0 +1,34 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: arangodeployments.database.arangodb.com
|
||||
spec:
|
||||
group: database.arangodb.com
|
||||
names:
|
||||
kind: ArangoDeployment
|
||||
listKind: ArangoDeploymentList
|
||||
plural: arangodeployments
|
||||
shortNames:
|
||||
- arangodb
|
||||
- arango
|
||||
singular: arangodeployment
|
||||
scope: Namespaced
|
||||
version: v1alpha
|
||||
|
||||
---
|
||||
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: arangolocalstorages.storage.arangodb.com
|
||||
spec:
|
||||
group: storage.arangodb.com
|
||||
names:
|
||||
kind: ArangoLocalStorage
|
||||
listKind: ArangoLocalStorageList
|
||||
plural: arangolocalstorages
|
||||
shortNames:
|
||||
- arangostorage
|
||||
singular: arangolocalstorage
|
||||
scope: Namespaced
|
||||
version: v1alpha
|
28
manifests/templates/deployment/deployment.yaml
Normal file
28
manifests/templates/deployment/deployment.yaml
Normal 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
|
|
@ -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,25 +10,18 @@ rules:
|
|||
- arangodeployments
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- storage.arangodb.com
|
||||
resources:
|
||||
- arangolocalstorages
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- apiextensions.k8s.io
|
||||
resources:
|
||||
- customresourcedefinitions
|
||||
verbs:
|
||||
- "*"
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- 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 -}}
|
|
@ -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:
|
56
manifests/templates/storage/rbac.yaml
Normal file
56
manifests/templates/storage/rbac.yaml
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
{{- if .RBAC -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ .Storage.ClusterRoleName }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- storage.arangodb.com
|
||||
resources:
|
||||
- arangolocalstorages
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- apiextensions.k8s.io
|
||||
resources:
|
||||
- customresourcedefinitions
|
||||
verbs:
|
||||
- get
|
||||
- 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: {{ .Storage.ClusterRoleBindingName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ .Storage.ClusterRoleName }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: {{ .Storage.Namespace }}
|
||||
|
||||
{{- end -}}
|
|
@ -113,7 +113,7 @@ func (s *DeploymentSpec) SetDefaults(deploymentName string) {
|
|||
}
|
||||
s.RocksDB.SetDefaults()
|
||||
s.Authentication.SetDefaults(deploymentName + "-jwt")
|
||||
s.TLS.SetDefaults("")
|
||||
s.TLS.SetDefaults(deploymentName + "-ca")
|
||||
s.Sync.SetDefaults(s.Image, s.ImagePullPolicy, deploymentName+"-sync-jwt", deploymentName+"-sync-ca")
|
||||
s.Single.SetDefaults(ServerGroupSingle, s.Mode.HasSingleServers(), s.Mode)
|
||||
s.Agents.SetDefaults(ServerGroupAgents, s.Mode.HasAgents(), s.Mode)
|
||||
|
|
|
@ -42,9 +42,14 @@ type TLSSpec struct {
|
|||
TTL time.Duration `json:"ttl,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// CASecretNameDisabled is the value of CASecretName to use for disabling authentication.
|
||||
CASecretNameDisabled = "None"
|
||||
)
|
||||
|
||||
// IsSecure returns true when a CA secret has been set, false otherwise.
|
||||
func (s TLSSpec) IsSecure() bool {
|
||||
return s.CASecretName != ""
|
||||
return s.CASecretName != CASecretNameDisabled
|
||||
}
|
||||
|
||||
// GetAltNames splits the list of AltNames into DNS names, IP addresses & email addresses.
|
||||
|
|
|
@ -43,8 +43,9 @@ func TestTLSSpecValidate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTLSSpecIsSecure(t *testing.T) {
|
||||
assert.False(t, TLSSpec{CASecretName: ""}.IsSecure())
|
||||
assert.True(t, TLSSpec{CASecretName: ""}.IsSecure())
|
||||
assert.True(t, TLSSpec{CASecretName: "foo"}.IsSecure())
|
||||
assert.False(t, TLSSpec{CASecretName: "None"}.IsSecure())
|
||||
}
|
||||
|
||||
func TestTLSSpecSetDefaults(t *testing.T) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
|
||||
)
|
||||
|
@ -39,10 +40,17 @@ func TestCreatePlanSingleScale(t *testing.T) {
|
|||
Mode: api.DeploymentModeSingle,
|
||||
}
|
||||
spec.SetDefaults("test")
|
||||
depl := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test_depl",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
|
||||
// Test with empty status
|
||||
var status api.DeploymentStatus
|
||||
newPlan, changed := createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed := createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
assert.Len(t, newPlan, 0) // Single mode does not scale
|
||||
|
||||
|
@ -53,7 +61,7 @@ func TestCreatePlanSingleScale(t *testing.T) {
|
|||
PodName: "something",
|
||||
},
|
||||
}
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
assert.Len(t, newPlan, 0) // Single mode does not scale
|
||||
|
||||
|
@ -68,7 +76,7 @@ func TestCreatePlanSingleScale(t *testing.T) {
|
|||
PodName: "something1",
|
||||
},
|
||||
}
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
assert.Len(t, newPlan, 0) // Single mode does not scale
|
||||
}
|
||||
|
@ -81,10 +89,17 @@ func TestCreatePlanResilientSingleScale(t *testing.T) {
|
|||
}
|
||||
spec.SetDefaults("test")
|
||||
spec.Single.Count = 2
|
||||
depl := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test_depl",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
|
||||
// Test with empty status
|
||||
var status api.DeploymentStatus
|
||||
newPlan, changed := createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed := createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 2)
|
||||
assert.Equal(t, api.ActionTypeAddMember, newPlan[0].Type)
|
||||
|
@ -97,7 +112,7 @@ func TestCreatePlanResilientSingleScale(t *testing.T) {
|
|||
PodName: "something",
|
||||
},
|
||||
}
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 1)
|
||||
assert.Equal(t, api.ActionTypeAddMember, newPlan[0].Type)
|
||||
|
@ -122,7 +137,7 @@ func TestCreatePlanResilientSingleScale(t *testing.T) {
|
|||
PodName: "something4",
|
||||
},
|
||||
}
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 2) // Note: Downscaling is only down 1 at a time
|
||||
assert.Equal(t, api.ActionTypeShutdownMember, newPlan[0].Type)
|
||||
|
@ -138,10 +153,17 @@ func TestCreatePlanClusterScale(t *testing.T) {
|
|||
Mode: api.DeploymentModeCluster,
|
||||
}
|
||||
spec.SetDefaults("test")
|
||||
depl := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test_depl",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
|
||||
// Test with empty status
|
||||
var status api.DeploymentStatus
|
||||
newPlan, changed := createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed := createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 6) // Adding 3 dbservers & 3 coordinators (note: agents do not scale now)
|
||||
assert.Equal(t, api.ActionTypeAddMember, newPlan[0].Type)
|
||||
|
@ -174,7 +196,7 @@ func TestCreatePlanClusterScale(t *testing.T) {
|
|||
PodName: "coordinator1",
|
||||
},
|
||||
}
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 3)
|
||||
assert.Equal(t, api.ActionTypeAddMember, newPlan[0].Type)
|
||||
|
@ -211,7 +233,7 @@ func TestCreatePlanClusterScale(t *testing.T) {
|
|||
}
|
||||
spec.DBServers.Count = 1
|
||||
spec.Coordinators.Count = 1
|
||||
newPlan, changed = createPlan(log, nil, spec, status, nil)
|
||||
newPlan, changed = createPlan(log, depl, nil, spec, status, nil)
|
||||
assert.True(t, changed)
|
||||
require.Len(t, newPlan, 5) // Note: Downscaling is done 1 at a time
|
||||
assert.Equal(t, api.ActionTypeCleanOutMember, newPlan[0].Type)
|
||||
|
|
|
@ -55,9 +55,9 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
[]string{
|
||||
"--agency.activate=true",
|
||||
"--agency.disaster-recovery-id=a1",
|
||||
"--agency.endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--agency.size=3",
|
||||
"--agency.supervision=true",
|
||||
"--database.directory=/data",
|
||||
|
@ -65,16 +65,18 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=false",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// Default+TLS deployment
|
||||
// Default+TLS disabled deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -84,7 +86,7 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeCluster,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "test-ca",
|
||||
CASecretName: "None",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -99,9 +101,9 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
[]string{
|
||||
"--agency.activate=true",
|
||||
"--agency.disaster-recovery-id=a1",
|
||||
"--agency.endpoint=ssl://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=ssl://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=tcp://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=tcp://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=tcp://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--agency.size=3",
|
||||
"--agency.supervision=true",
|
||||
"--database.directory=/data",
|
||||
|
@ -109,12 +111,10 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=false",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -144,9 +144,9 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
[]string{
|
||||
"--agency.activate=true",
|
||||
"--agency.disaster-recovery-id=a1",
|
||||
"--agency.endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--agency.size=3",
|
||||
"--agency.supervision=true",
|
||||
"--database.directory=/data",
|
||||
|
@ -154,9 +154,11 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=false",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.statistics=false",
|
||||
"--server.storage-engine=mmfiles",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -185,9 +187,9 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
[]string{
|
||||
"--agency.activate=true",
|
||||
"--agency.disaster-recovery-id=a1",
|
||||
"--agency.endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--agency.endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--agency.my-address=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--agency.size=3",
|
||||
"--agency.supervision=true",
|
||||
"--database.directory=/data",
|
||||
|
@ -195,10 +197,12 @@ func TestCreateArangodArgsAgent(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=false",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
"--foo1",
|
||||
"--foo2",
|
||||
},
|
||||
|
|
|
@ -53,52 +53,10 @@ func TestCreateArangodArgsCoordinator(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupCoordinators, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-crdn-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=COORDINATOR",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// Default+TLS deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeCluster,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "test-ca",
|
||||
},
|
||||
},
|
||||
}
|
||||
apiObject.Spec.SetDefaults("test")
|
||||
agents := api.MemberStatusList{
|
||||
api.MemberStatus{ID: "a1"},
|
||||
api.MemberStatus{ID: "a2"},
|
||||
api.MemberStatus{ID: "a3"},
|
||||
}
|
||||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupCoordinators, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-crdn-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-coordinator-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=COORDINATOR",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
|
@ -116,6 +74,48 @@ func TestCreateArangodArgsCoordinator(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
// Default+TLS disabled deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeCluster,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "None",
|
||||
},
|
||||
},
|
||||
}
|
||||
apiObject.Spec.SetDefaults("test")
|
||||
agents := api.MemberStatusList{
|
||||
api.MemberStatus{ID: "a1"},
|
||||
api.MemberStatus{ID: "a2"},
|
||||
api.MemberStatus{ID: "a3"},
|
||||
}
|
||||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupCoordinators, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-coordinator-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=COORDINATOR",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// No authentication
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
|
@ -137,19 +137,21 @@ func TestCreateArangodArgsCoordinator(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupCoordinators, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-crdn-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-coordinator-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=COORDINATOR",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=false",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -177,20 +179,22 @@ func TestCreateArangodArgsCoordinator(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupCoordinators, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-crdn-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-coordinator-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=COORDINATOR",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=mmfiles",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
"--foo1",
|
||||
"--foo2",
|
||||
},
|
||||
|
|
|
@ -53,52 +53,10 @@ func TestCreateArangodArgsDBServer(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupDBServers, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-prmr-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=PRIMARY",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=false",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// Default+TLS deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeCluster,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "test-ca",
|
||||
},
|
||||
},
|
||||
}
|
||||
apiObject.Spec.SetDefaults("test")
|
||||
agents := api.MemberStatusList{
|
||||
api.MemberStatus{ID: "a1"},
|
||||
api.MemberStatus{ID: "a2"},
|
||||
api.MemberStatus{ID: "a3"},
|
||||
}
|
||||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupDBServers, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-prmr-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-dbserver-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=PRIMARY",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=false",
|
||||
|
@ -116,6 +74,48 @@ func TestCreateArangodArgsDBServer(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
// Default+TLS disabled deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeCluster,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "None",
|
||||
},
|
||||
},
|
||||
}
|
||||
apiObject.Spec.SetDefaults("test")
|
||||
agents := api.MemberStatusList{
|
||||
api.MemberStatus{ID: "a1"},
|
||||
api.MemberStatus{ID: "a2"},
|
||||
api.MemberStatus{ID: "a3"},
|
||||
}
|
||||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupDBServers, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-dbserver-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=PRIMARY",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=false",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// No authentication
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
|
@ -137,19 +137,21 @@ func TestCreateArangodArgsDBServer(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupDBServers, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-prmr-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-dbserver-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=PRIMARY",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=false",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=false",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -177,20 +179,22 @@ func TestCreateArangodArgsDBServer(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupDBServers, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-prmr-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-dbserver-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=PRIMARY",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=false",
|
||||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=mmfiles",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
"--foo1",
|
||||
"--foo2",
|
||||
},
|
||||
|
|
|
@ -49,22 +49,24 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
}
|
||||
|
||||
// Default+TLS deployment
|
||||
// Default+TLS disabled deployment
|
||||
{
|
||||
apiObject := &api.ArangoDeployment{
|
||||
Spec: api.DeploymentSpec{
|
||||
Mode: api.DeploymentModeSingle,
|
||||
TLS: api.TLSSpec{
|
||||
CASecretName: "test-ca",
|
||||
CASecretName: "None",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -77,12 +79,10 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -105,10 +105,12 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=mmfiles",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -131,9 +133,11 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=false",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
@ -156,10 +160,12 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.level=INFO",
|
||||
"--log.output=+",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
"--foo1",
|
||||
"--foo2",
|
||||
},
|
||||
|
@ -187,10 +193,10 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
cmdline := createArangodArgs(apiObject, apiObject.Spec, api.ServerGroupSingle, agents, "id1")
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=tcp://name-agnt-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=tcp://name-sngl-id1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a2.name-int.ns.svc:8529",
|
||||
"--cluster.agency-endpoint=ssl://name-agent-a3.name-int.ns.svc:8529",
|
||||
"--cluster.my-address=ssl://name-single-id1.name-int.ns.svc:8529",
|
||||
"--cluster.my-role=SINGLE",
|
||||
"--database.directory=/data",
|
||||
"--foxx.queues=true",
|
||||
|
@ -198,10 +204,12 @@ func TestCreateArangodArgsSingle(t *testing.T) {
|
|||
"--log.output=+",
|
||||
"--replication.automatic-failover=true",
|
||||
"--server.authentication=true",
|
||||
"--server.endpoint=tcp://[::]:8529",
|
||||
"--server.endpoint=ssl://[::]:8529",
|
||||
"--server.jwt-secret=$(ARANGOD_JWT_SECRET)",
|
||||
"--server.statistics=true",
|
||||
"--server.storage-engine=rocksdb",
|
||||
"--ssl.ecdh-curve=",
|
||||
"--ssl.keyfile=/secrets/tls/tls.keyfile",
|
||||
},
|
||||
cmdline,
|
||||
)
|
||||
|
|
|
@ -23,46 +23,29 @@
|
|||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
deplapi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
|
||||
lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/crd"
|
||||
)
|
||||
|
||||
// initResourceIfNeeded initializes the custom resource definition when
|
||||
// instructed to do so by the config.
|
||||
func (o *Operator) initResourceIfNeeded() error {
|
||||
if o.Config.CreateCRD {
|
||||
if err := o.initCRD(); err != nil {
|
||||
return maskAny(fmt.Errorf("Failed to initialize Custom Resource Definition: %v", err))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// initCRD creates the CustomResourceDefinition and waits for it to be ready.
|
||||
func (o *Operator) initCRD() error {
|
||||
// waitForCRD waits for the CustomResourceDefinition (created externally)
|
||||
// to be ready.
|
||||
func (o *Operator) waitForCRD(enableDeployment, enableStorage bool) error {
|
||||
log := o.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))
|
||||
}
|
||||
if enableDeployment {
|
||||
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))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -26,9 +26,12 @@ import (
|
|||
"context"
|
||||
"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"
|
||||
|
@ -36,7 +39,6 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned"
|
||||
"github.com/arangodb/kube-arangodb/pkg/logging"
|
||||
"github.com/arangodb/kube-arangodb/pkg/storage"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -59,9 +61,12 @@ type Operator struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
ID string
|
||||
Namespace string
|
||||
PodName string
|
||||
ServiceAccount string
|
||||
EnableDeployment bool
|
||||
EnableStorage bool
|
||||
CreateCRD bool
|
||||
}
|
||||
|
||||
|
@ -70,6 +75,7 @@ type Dependencies struct {
|
|||
KubeCli kubernetes.Interface
|
||||
KubeExtCli apiextensionsclient.Interface
|
||||
CRCli versioned.Interface
|
||||
EventRecorder record.EventRecorder
|
||||
}
|
||||
|
||||
// NewOperator instantiates a new operator from given config & dependencies.
|
||||
|
@ -84,12 +90,22 @@ func NewOperator(config Config, deps Dependencies) (*Operator, error) {
|
|||
return o, nil
|
||||
}
|
||||
|
||||
// Start the operator
|
||||
func (o *Operator) Start() error {
|
||||
log := o.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.waitForCRD(true, false); err == nil {
|
||||
break
|
||||
} else {
|
||||
log.Error().Err(err).Msg("Resource initialization failed")
|
||||
|
@ -97,23 +113,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.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.waitForCRD(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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
60
pkg/operator/operator_leader.go
Normal file
60
pkg/operator/operator_leader.go
Normal 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.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")
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -24,6 +24,7 @@ package arangod
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
nhttp "net/http"
|
||||
|
@ -70,6 +71,19 @@ var (
|
|||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
sharedHTTPSTransport = &nhttp.Transport{
|
||||
Proxy: nhttp.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
)
|
||||
|
||||
// CreateArangodClient creates a go-driver client for a specific member in the given group.
|
||||
|
@ -97,11 +111,16 @@ func CreateArangodDatabaseClient(ctx context.Context, cli corev1.CoreV1Interface
|
|||
// CreateArangodClientForDNSName creates a go-driver client for a given DNS name.
|
||||
func createArangodClientForDNSName(ctx context.Context, cli corev1.CoreV1Interface, apiObject *api.ArangoDeployment, dnsName string) (driver.Client, error) {
|
||||
scheme := "http"
|
||||
transport := sharedHTTPTransport
|
||||
if apiObject.Spec.IsSecure() {
|
||||
scheme = "https"
|
||||
transport = sharedHTTPSTransport
|
||||
}
|
||||
connConfig := http.ConnectionConfig{
|
||||
Endpoints: []string{scheme + "://" + net.JoinHostPort(dnsName, strconv.Itoa(k8sutil.ArangoPort))},
|
||||
Transport: sharedHTTPTransport,
|
||||
Transport: transport,
|
||||
}
|
||||
// TODO deal with TLS
|
||||
// TODO deal with TLS with proper CA checking
|
||||
conn, err := http.NewConnection(connConfig)
|
||||
if err != nil {
|
||||
return nil, maskAny(err)
|
||||
|
|
|
@ -26,42 +26,13 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/retry"
|
||||
)
|
||||
|
||||
// CreateCRD creates a custom resouce definition.
|
||||
func CreateCRD(clientset apiextensionsclient.Interface, groupVersion schema.GroupVersion, crdName, rkind, rplural string, shortName ...string) error {
|
||||
crd := &apiextensionsv1beta1.CustomResourceDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: crdName,
|
||||
},
|
||||
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: groupVersion.Group,
|
||||
Version: groupVersion.Version,
|
||||
Scope: apiextensionsv1beta1.NamespaceScoped,
|
||||
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
|
||||
Plural: rplural,
|
||||
Kind: rkind,
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(shortName) != 0 {
|
||||
crd.Spec.Names.ShortNames = shortName
|
||||
}
|
||||
_, err := clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
|
||||
if err != nil && !k8sutil.IsAlreadyExists(err) {
|
||||
return 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 {
|
||||
|
|
19
scripts/kube_run_tests.sh
Executable file
19
scripts/kube_run_tests.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Run kubectl run to run the integration tests.
|
||||
|
||||
DEPLOYMENTNAMESPACE=$1
|
||||
TESTIMAGE=$2
|
||||
ENTERPRISEIMAGE=$3
|
||||
TESTTIMEOUT=$4
|
||||
TESTLENGTHOPTIONS=$5
|
||||
|
||||
IMAGEID=$(docker inspect ${TESTIMAGE} '--format={{index .RepoDigests 0}}')
|
||||
|
||||
kubectl --namespace ${DEPLOYMENTNAMESPACE} \
|
||||
run arangodb-operator-test -i --rm --quiet --restart=Never \
|
||||
--image=${IMAGEID} \
|
||||
--env="ENTERPRISEIMAGE=${ENTERPRISEIMAGE}" \
|
||||
--env="TEST_NAMESPACE=${DEPLOYMENTNAMESPACE}" \
|
||||
-- \
|
||||
-test.v -test.timeout $TESTTIMEOUT $TESTLENGTHOPTIONS $TESTOPTIONS
|
|
@ -38,40 +38,58 @@ import (
|
|||
|
||||
var (
|
||||
options struct {
|
||||
OutputFile string
|
||||
OutputSuffix string
|
||||
TemplatesDir string
|
||||
|
||||
Namespace string
|
||||
Image string
|
||||
ImagePullPolicy string
|
||||
ImageSHA256 bool
|
||||
OperatorName string
|
||||
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,40 +113,47 @@ 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,
|
||||
// Prepare templates to include
|
||||
templateNameSet := map[string][]string{
|
||||
"deployment": deploymentTemplateNames,
|
||||
"storage": storageTemplateNames,
|
||||
}
|
||||
|
||||
// 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",
|
||||
},
|
||||
}
|
||||
for group, templateNames := range templateNameSet {
|
||||
output := &bytes.Buffer{}
|
||||
for i, name := range templateNames {
|
||||
t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, name))
|
||||
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\n", name))
|
||||
output.WriteString(fmt.Sprintf("## %s/%s\n", group, name))
|
||||
t.Execute(output, templateOptions)
|
||||
output.WriteString("\n")
|
||||
}
|
||||
|
||||
// Save output
|
||||
outputPath, err := filepath.Abs(options.OutputFile)
|
||||
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)
|
||||
}
|
||||
|
@ -138,4 +163,5 @@ func main() {
|
|||
if err := ioutil.WriteFile(outputPath, output.Bytes(), 0644); err != nil {
|
||||
log.Fatalf("Failed to write output file: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue