1
0
Fork 0
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:
Ewout Prangsma 2018-03-20 08:22:28 +01:00
commit 6ae89d09f3
No known key found for this signature in database
GPG key ID: 4DBAD380D93D0698
32 changed files with 652 additions and 511 deletions

View file

@ -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

View file

@ -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
```

View file

@ -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.

View file

@ -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,

View file

@ -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
```

View 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

View file

@ -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"]

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{
LogService: logService,
KubeCli: kubecli,
KubeExtCli: kubeExtCli,
CRCli: crCli,
LogService: logService,
KubeCli: kubecli,
KubeExtCli: kubeExtCli,
CRCli: crCli,
EventRecorder: eventRecorder,
}
return cfg, deps, nil

View file

@ -1 +1,2 @@
arango-operator-dev.yaml
arango-deployment-dev.yaml
arango-storage-dev.yaml

View file

@ -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
View 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

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,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 -}}

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: {{ .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 -}}

View file

@ -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)

View file

@ -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.

View file

@ -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) {

View file

@ -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)

View file

@ -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",
},

View file

@ -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",
},

View file

@ -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",
},

View file

@ -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,
)

View file

@ -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))
}
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("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("Waiting for ArangoLocalStorage CRD to be ready")
if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil {
return maskAny(err)
}
}
return nil
}

View file

@ -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,17 +61,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 {
LogService logging.Service
KubeCli kubernetes.Interface
KubeExtCli apiextensionsclient.Interface
CRCli versioned.Interface
LogService logging.Service
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)
}

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.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

@ -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)

View file

@ -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
View 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

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)
}
}
}