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

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

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

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

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