From 19aa4477f9d3677242a0cefc4a42c49b6b983ba7 Mon Sep 17 00:00:00 2001 From: Ewout Prangsma Date: Fri, 18 May 2018 11:54:53 +0200 Subject: [PATCH] Adding structure for ArangoDeploymentReplication operator --- Makefile | 6 +- main.go | 51 +-- .../arango-deployment-replication-dev.yaml | 130 ++++++ .../deployment-replication.yaml | 52 +++ .../deployment-replication/rbac.yaml | 75 ++++ pkg/apis/replication/v1alpha/doc.go | 25 ++ pkg/apis/replication/v1alpha/errors.go | 37 ++ pkg/apis/replication/v1alpha/register.go | 59 +++ pkg/apis/replication/v1alpha/replication.go | 63 +++ .../replication/v1alpha/replication_phase.go | 42 ++ .../replication/v1alpha/replication_spec.go | 57 +++ .../replication/v1alpha/replication_state.go | 32 ++ .../v1alpha/zz_generated.deepcopy.go | 122 ++++++ .../clientset/versioned/clientset.go | 26 +- .../versioned/fake/clientset_generated.go | 12 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../v1alpha/arangodeploymentreplication.go | 175 ++++++++ .../typed/replication/v1alpha/doc.go | 21 + .../typed/replication/v1alpha/fake/doc.go | 21 + .../fake/fake_arangodeploymentreplication.go | 141 +++++++ .../v1alpha/fake/fake_replication_client.go | 41 ++ .../v1alpha/generated_expansion.go | 22 + .../replication/v1alpha/replication_client.go | 91 +++++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 5 + .../externalversions/replication/interface.go | 50 +++ .../v1alpha/arangodeploymentreplication.go | 93 +++++ .../replication/v1alpha/interface.go | 49 +++ .../v1alpha/arangodeploymentreplication.go | 98 +++++ .../v1alpha/expansion_generated.go | 31 ++ pkg/operator/crd.go | 10 +- pkg/operator/operator.go | 82 ++-- .../operator_deployment_relication.go | 215 ++++++++++ pkg/replication/deployment_replication.go | 380 ++++++++++++++++++ pkg/replication/errors.go | 29 ++ tools/manifests/manifest_builder.go | 57 ++- 37 files changed, 2337 insertions(+), 73 deletions(-) create mode 100644 manifests/arango-deployment-replication-dev.yaml create mode 100644 manifests/templates/deployment-replication/deployment-replication.yaml create mode 100644 manifests/templates/deployment-replication/rbac.yaml create mode 100644 pkg/apis/replication/v1alpha/doc.go create mode 100644 pkg/apis/replication/v1alpha/errors.go create mode 100644 pkg/apis/replication/v1alpha/register.go create mode 100644 pkg/apis/replication/v1alpha/replication.go create mode 100644 pkg/apis/replication/v1alpha/replication_phase.go create mode 100644 pkg/apis/replication/v1alpha/replication_spec.go create mode 100644 pkg/apis/replication/v1alpha/replication_state.go create mode 100644 pkg/apis/replication/v1alpha/zz_generated.deepcopy.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/arangodeploymentreplication.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/doc.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/doc.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_arangodeploymentreplication.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_replication_client.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/generated_expansion.go create mode 100644 pkg/generated/clientset/versioned/typed/replication/v1alpha/replication_client.go create mode 100644 pkg/generated/informers/externalversions/replication/interface.go create mode 100644 pkg/generated/informers/externalversions/replication/v1alpha/arangodeploymentreplication.go create mode 100644 pkg/generated/informers/externalversions/replication/v1alpha/interface.go create mode 100644 pkg/generated/listers/replication/v1alpha/arangodeploymentreplication.go create mode 100644 pkg/generated/listers/replication/v1alpha/expansion_generated.go create mode 100644 pkg/operator/operator_deployment_relication.go create mode 100644 pkg/replication/deployment_replication.go create mode 100644 pkg/replication/errors.go diff --git a/Makefile b/Makefile index dde514010..4c008e2c2 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ ifndef MANIFESTSUFFIX endif endif MANIFESTPATHDEPLOYMENT := manifests/arango-deployment$(MANIFESTSUFFIX).yaml +MANIFESTPATHDEPLOYMENTREPLICATION := manifests/arango-deployment-replication$(MANIFESTSUFFIX).yaml MANIFESTPATHSTORAGE := manifests/arango-storage$(MANIFESTSUFFIX).yaml MANIFESTPATHTEST := manifests/arango-test$(MANIFESTSUFFIX).yaml ifndef DEPLOYMENTNAMESPACE @@ -172,7 +173,7 @@ update-generated: $(GOBUILDDIR) "all" \ "github.com/arangodb/kube-arangodb/pkg/generated" \ "github.com/arangodb/kube-arangodb/pkg/apis" \ - "deployment:v1alpha storage:v1alpha" \ + "deployment:v1alpha replication:v1alpha storage:v1alpha" \ --go-header-file "./tools/codegen/boilerplate.go.txt" \ $(VERIFYARGS) @@ -270,6 +271,7 @@ endif kubectl apply -f manifests/crd.yaml kubectl apply -f $(MANIFESTPATHSTORAGE) kubectl apply -f $(MANIFESTPATHDEPLOYMENT) + kubectl apply -f $(MANIFESTPATHDEPLOYMENTREPLICATION) kubectl apply -f $(MANIFESTPATHTEST) $(ROOTDIR)/scripts/kube_create_storage.sh $(DEPLOYMENTNAMESPACE) $(ROOTDIR)/scripts/kube_run_tests.sh $(DEPLOYMENTNAMESPACE) $(TESTIMAGE) "$(ENTERPRISEIMAGE)" $(TESTTIMEOUT) $(TESTLENGTHOPTIONS) @@ -345,6 +347,7 @@ minikube-start: delete-operator: kubectl delete -f $(MANIFESTPATHTEST) --ignore-not-found kubectl delete -f $(MANIFESTPATHDEPLOYMENT) --ignore-not-found + kubectl delete -f $(MANIFESTPATHDEPLOYMENTREPLICATION) --ignore-not-found kubectl delete -f $(MANIFESTPATHSTORAGE) --ignore-not-found .PHONY: redeploy-operator @@ -352,5 +355,6 @@ redeploy-operator: delete-operator manifests kubectl apply -f manifests/crd.yaml kubectl apply -f $(MANIFESTPATHSTORAGE) kubectl apply -f $(MANIFESTPATHDEPLOYMENT) + kubectl apply -f $(MANIFESTPATHDEPLOYMENTREPLICATION) kubectl apply -f $(MANIFESTPATHTEST) kubectl get pods diff --git a/main.go b/main.go index 5f83ac185..56b276fb7 100644 --- a/main.go +++ b/main.go @@ -79,15 +79,17 @@ var ( tlsSecretName string } operatorOptions struct { - enableDeployment bool // Run deployment operator - enableStorage bool // Run deployment operator + enableDeployment bool // Run deployment operator + enableDeploymentReplication bool // Run deployment-replication operator + enableStorage bool // Run local-storage operator } chaosOptions struct { allowed bool } - livenessProbe probe.LivenessProbe - deploymentProbe probe.ReadyProbe - storageProbe probe.ReadyProbe + livenessProbe probe.LivenessProbe + deploymentProbe probe.ReadyProbe + deploymentReplicationProbe probe.ReadyProbe + storageProbe probe.ReadyProbe ) func init() { @@ -97,6 +99,7 @@ func init() { f.StringVar(&serverOptions.tlsSecretName, "server.tls-secret-name", "", "Name of secret containing tls.crt & tls.key for HTTPS server (if empty, self-signed certificate is used)") f.StringVar(&logLevel, "log.level", defaultLogLevel, "Set initial log level") f.BoolVar(&operatorOptions.enableDeployment, "operator.deployment", false, "Enable to run the ArangoDeployment operator") + f.BoolVar(&operatorOptions.enableDeploymentReplication, "operator.deployment-replication", false, "Enable to run the ArangoDeploymentReplication operator") f.BoolVar(&operatorOptions.enableStorage, "operator.storage", false, "Enable to run the ArangoLocalStorage operator") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") } @@ -121,8 +124,8 @@ func cmdMainRun(cmd *cobra.Command, args []string) { } // Check operating mode - if !operatorOptions.enableDeployment && !operatorOptions.enableStorage { - cliLog.Fatal().Err(err).Msg("Turn on --operator.deployment or --operator.storage or both") + if !operatorOptions.enableDeployment && !operatorOptions.enableDeploymentReplication && !operatorOptions.enableStorage { + cliLog.Fatal().Err(err).Msg("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage or any combination of these") } // Log version @@ -209,24 +212,26 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper eventRecorder := createRecorder(cliLog, kubecli, name, namespace) cfg := operator.Config{ - ID: id, - Namespace: namespace, - PodName: name, - ServiceAccount: serviceAccount, - LifecycleImage: image, - EnableDeployment: operatorOptions.enableDeployment, - EnableStorage: operatorOptions.enableStorage, - AllowChaos: chaosOptions.allowed, + ID: id, + Namespace: namespace, + PodName: name, + ServiceAccount: serviceAccount, + LifecycleImage: image, + EnableDeployment: operatorOptions.enableDeployment, + EnableDeploymentReplication: operatorOptions.enableDeploymentReplication, + EnableStorage: operatorOptions.enableStorage, + AllowChaos: chaosOptions.allowed, } deps := operator.Dependencies{ - LogService: logService, - KubeCli: kubecli, - KubeExtCli: kubeExtCli, - CRCli: crCli, - EventRecorder: eventRecorder, - LivenessProbe: &livenessProbe, - DeploymentProbe: &deploymentProbe, - StorageProbe: &storageProbe, + LogService: logService, + KubeCli: kubecli, + KubeExtCli: kubeExtCli, + CRCli: crCli, + EventRecorder: eventRecorder, + LivenessProbe: &livenessProbe, + DeploymentProbe: &deploymentProbe, + DeploymentReplicationProbe: &deploymentReplicationProbe, + StorageProbe: &storageProbe, } return cfg, deps, nil diff --git a/manifests/arango-deployment-replication-dev.yaml b/manifests/arango-deployment-replication-dev.yaml new file mode 100644 index 000000000..a95878fb8 --- /dev/null +++ b/manifests/arango-deployment-replication-dev.yaml @@ -0,0 +1,130 @@ +## deployment-replication/rbac.yaml +## Cluster role granting access to ArangoDeploymentReplication resources. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: arango-deployment-replications +rules: +- apiGroups: ["replication.database.arangodb.com"] + resources: ["arangodeploymentreplications"] + verbs: ["*"] + +--- + +## Cluster role granting access to all resources needed by the ArangoDeploymentReplication operator. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: arango-deployment-replication-operator +rules: +- apiGroups: ["replication.database.arangodb.com"] + resources: ["arangodeploymentreplications"] + verbs: ["*"] +- apiGroups: ["database.arangodb.com"] + resources: ["arangodeployments"] + verbs: ["get"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "services", "endpoints", "persistentvolumeclaims", "events", "secrets"] + verbs: ["*"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["*"] + +--- + +## Bind the cluster role granting access to ArangoDeploymentReplication resources +## to the default service account of the configured namespace. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: arango-deployment-replications + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: arango-deployment-replications +subjects: +- kind: ServiceAccount + name: default + namespace: default + +--- + +## Bind the cluster role granting access to all resources needed by +## the ArangoDeploymentReplication operator to the default service account +## the is being used to run the operator deployment. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: arango-deployment-replication-operator-default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: arango-deployment-replication-operator +subjects: +- kind: ServiceAccount + name: default + namespace: default + +--- + +## deployment-replication/deployment-replication.yaml + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: arango-deployment-replication-operator + namespace: default +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + name: arango-deployment-replication-operator + app: arango-deployment-replication-operator + spec: + containers: + - name: operator + imagePullPolicy: IfNotPresent + image: ewoutp/kube-arangodb@sha256:ee3c19a789b7ac9e4e606617da643a7a54a2dc6d398db7a573f2120d77a45258 + args: + - --operator.deployment-replication + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + ports: + - name: metrics + containerPort: 8528 + livenessProbe: + httpGet: + path: /health + port: 8528 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /ready/deploymentReplication + port: 8528 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 10 + diff --git a/manifests/templates/deployment-replication/deployment-replication.yaml b/manifests/templates/deployment-replication/deployment-replication.yaml new file mode 100644 index 000000000..debb91d3d --- /dev/null +++ b/manifests/templates/deployment-replication/deployment-replication.yaml @@ -0,0 +1,52 @@ + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ .DeploymentReplication.OperatorDeploymentName }} + namespace: {{ .DeploymentReplication.Operator.Namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + name: {{ .DeploymentReplication.OperatorDeploymentName }} + app: arango-deployment-replication-operator + spec: + containers: + - name: operator + imagePullPolicy: {{ .ImagePullPolicy }} + image: {{ .Image }} + args: + - --operator.deployment-replication + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + ports: + - name: metrics + containerPort: 8528 + livenessProbe: + httpGet: + path: /health + port: 8528 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /ready/deploymentReplication + port: 8528 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/manifests/templates/deployment-replication/rbac.yaml b/manifests/templates/deployment-replication/rbac.yaml new file mode 100644 index 000000000..90df2baf4 --- /dev/null +++ b/manifests/templates/deployment-replication/rbac.yaml @@ -0,0 +1,75 @@ +{{- if .RBAC -}} +## Cluster role granting access to ArangoDeploymentReplication resources. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: {{ .DeploymentReplication.User.RoleName }} +rules: +- apiGroups: ["replication.database.arangodb.com"] + resources: ["arangodeploymentreplications"] + verbs: ["*"] + +--- + +## Cluster role granting access to all resources needed by the ArangoDeploymentReplication operator. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: {{ .DeploymentReplication.Operator.RoleName }} +rules: +- apiGroups: ["replication.database.arangodb.com"] + resources: ["arangodeploymentreplications"] + verbs: ["*"] +- apiGroups: ["database.arangodb.com"] + resources: ["arangodeployments"] + verbs: ["get"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "services", "endpoints", "persistentvolumeclaims", "events", "secrets"] + verbs: ["*"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["*"] + +--- + +## Bind the cluster role granting access to ArangoDeploymentReplication resources +## to the default service account of the configured namespace. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: {{ .DeploymentReplication.User.RoleBindingName }} + namespace: {{ .DeploymentReplication.User.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .DeploymentReplication.User.RoleName }} +subjects: +- kind: ServiceAccount + name: {{ .DeploymentReplication.User.ServiceAccountName }} + namespace: {{ .DeploymentReplication.User.Namespace }} + +--- + +## Bind the cluster role granting access to all resources needed by +## the ArangoDeploymentReplication operator to the default service account +## the is being used to run the operator deployment. +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: {{ .DeploymentReplication.Operator.RoleBindingName }}-{{ .DeploymentReplication.Operator.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .DeploymentReplication.Operator.RoleName }} +subjects: +- kind: ServiceAccount + name: {{ .DeploymentReplication.Operator.ServiceAccountName }} + namespace: {{ .DeploymentReplication.Operator.Namespace }} + +{{- end -}} diff --git a/pkg/apis/replication/v1alpha/doc.go b/pkg/apis/replication/v1alpha/doc.go new file mode 100644 index 000000000..a33182847 --- /dev/null +++ b/pkg/apis/replication/v1alpha/doc.go @@ -0,0 +1,25 @@ +// +// 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 +// + +// +k8s:deepcopy-gen=package +// +groupName=replication.database.arangodb.com +package v1alpha diff --git a/pkg/apis/replication/v1alpha/errors.go b/pkg/apis/replication/v1alpha/errors.go new file mode 100644 index 000000000..64f72e81c --- /dev/null +++ b/pkg/apis/replication/v1alpha/errors.go @@ -0,0 +1,37 @@ +// +// 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 v1alpha + +import "github.com/pkg/errors" + +var ( + // ValidationError indicates a validation failure + ValidationError = errors.New("validation failed") + + maskAny = errors.WithStack +) + +// IsValidation return true when the given error is or is caused by a ValidationError. +func IsValidation(err error) bool { + return errors.Cause(err) == ValidationError +} diff --git a/pkg/apis/replication/v1alpha/register.go b/pkg/apis/replication/v1alpha/register.go new file mode 100644 index 000000000..ccab2f54d --- /dev/null +++ b/pkg/apis/replication/v1alpha/register.go @@ -0,0 +1,59 @@ +// +// 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 v1alpha + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + ArangoDeploymentReplicationResourceKind = "ArangoDeploymentReplication" + ArangoDeploymentReplicationResourcePlural = "arangodeploymentreplications" + groupName = "replication.database.arangodb.com" +) + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme + + SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha"} + ArangoDeploymentReplicationCRDName = ArangoDeploymentReplicationResourcePlural + "." + groupName + ArangoDeploymentReplicationShortNames = []string{"arangorepl"} +) + +// Resource gets an ArangoCluster GroupResource for a specified resource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// addKnownTypes adds the set of types defined in this package to the supplied scheme. +func addKnownTypes(s *runtime.Scheme) error { + s.AddKnownTypes(SchemeGroupVersion, + &ArangoDeploymentReplication{}, + &ArangoDeploymentReplicationList{}, + ) + metav1.AddToGroupVersion(s, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/replication/v1alpha/replication.go b/pkg/apis/replication/v1alpha/replication.go new file mode 100644 index 000000000..4bb3be55f --- /dev/null +++ b/pkg/apis/replication/v1alpha/replication.go @@ -0,0 +1,63 @@ +// +// 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 v1alpha + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ArangoDeploymentReplicationList is a list of ArangoDB deployment replications. +type ArangoDeploymentReplicationList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata + // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata + metav1.ListMeta `json:"metadata,omitempty"` + Items []ArangoDeploymentReplication `json:"items"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ArangoDeploymentReplication contains the entire Kubernetes info for an ArangoDB +// local storage provider. +type ArangoDeploymentReplication struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec DeploymentReplicationSpec `json:"spec"` + Status DeploymentReplicationStatus `json:"status"` +} + +// AsOwner creates an OwnerReference for the given replication +func (d *ArangoDeploymentReplication) AsOwner() metav1.OwnerReference { + trueVar := true + return metav1.OwnerReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: ArangoDeploymentReplicationResourceKind, + Name: d.Name, + UID: d.UID, + Controller: &trueVar, + BlockOwnerDeletion: &trueVar, + } +} diff --git a/pkg/apis/replication/v1alpha/replication_phase.go b/pkg/apis/replication/v1alpha/replication_phase.go new file mode 100644 index 000000000..670224948 --- /dev/null +++ b/pkg/apis/replication/v1alpha/replication_phase.go @@ -0,0 +1,42 @@ +// +// 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 v1alpha + +// DeploymentReplicationPhase is a strongly typed lifetime phase of a deployment replication +type DeploymentReplicationPhase string + +const ( + // DeploymentReplicationPhaseNone indicates that the phase is not set yet + DeploymentReplicationPhaseNone DeploymentReplicationPhase = "" + // DeploymentReplicationPhaseRunning indicates that the deployment replication is under control of the + // ArangoDeploymentReplication operator. + DeploymentReplicationPhaseRunning DeploymentReplicationPhase = "Running" + // DeploymentReplicationPhaseFailed indicates that a deployment replication is in a failed state + // from which automatic recovery is impossible. Inspect `Reason` for more info. + DeploymentReplicationPhaseFailed DeploymentReplicationPhase = "Failed" +) + +// IsFailed returns true if given state is DeploymentStateFailed +func (cs DeploymentReplicationPhase) IsFailed() bool { + return cs == DeploymentReplicationPhaseFailed +} diff --git a/pkg/apis/replication/v1alpha/replication_spec.go b/pkg/apis/replication/v1alpha/replication_spec.go new file mode 100644 index 000000000..54251e22b --- /dev/null +++ b/pkg/apis/replication/v1alpha/replication_spec.go @@ -0,0 +1,57 @@ +// +// 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 v1alpha + +// DeploymentReplicationSpec contains the specification part of +// an ArangoDeploymentReplication. +type DeploymentReplicationSpec struct { +} + +// Validate the given spec, returning an error on validation +// problems or nil if all ok. +func (s DeploymentReplicationSpec) Validate() error { + /* if err := s.StorageClass.Validate(); err != nil { + return maskAny(err) + } + if len(s.LocalPath) == 0 { + return maskAny(errors.Wrapf(ValidationError, "localPath cannot be empty")) + } + for _, p := range s.LocalPath { + if len(p) == 0 { + return maskAny(errors.Wrapf(ValidationError, "localPath cannot contain empty strings")) + } + }*/ + return nil +} + +// SetDefaults fills empty field with default values. +func (s *DeploymentReplicationSpec) SetDefaults() { +} + +// ResetImmutableFields replaces all immutable fields in the given target with values from the source spec. +// It returns a list of fields that have been reset. +// Field names are relative to `spec.`. +func (s DeploymentReplicationSpec) ResetImmutableFields(target *DeploymentReplicationSpec) []string { + var result []string + return result +} diff --git a/pkg/apis/replication/v1alpha/replication_state.go b/pkg/apis/replication/v1alpha/replication_state.go new file mode 100644 index 000000000..c34b113ba --- /dev/null +++ b/pkg/apis/replication/v1alpha/replication_state.go @@ -0,0 +1,32 @@ +// +// 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 v1alpha + +// DeploymentReplicationStatus contains the status part of +// an ArangoDeploymentReplication. +type DeploymentReplicationStatus struct { + // Phase holds the current lifetime phase of the deployment replication + Phase DeploymentReplicationPhase `json:"phase"` + // Reason contains a human readable reason for reaching the current phase (can be empty) + Reason string `json:"reason,omitempty"` // Reason for current phase +} diff --git a/pkg/apis/replication/v1alpha/zz_generated.deepcopy.go b/pkg/apis/replication/v1alpha/zz_generated.deepcopy.go new file mode 100644 index 000000000..8919cdbe7 --- /dev/null +++ b/pkg/apis/replication/v1alpha/zz_generated.deepcopy.go @@ -0,0 +1,122 @@ +// +build !ignore_autogenerated + +// +// 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 +// + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package v1alpha + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArangoDeploymentReplication) DeepCopyInto(out *ArangoDeploymentReplication) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoDeploymentReplication. +func (in *ArangoDeploymentReplication) DeepCopy() *ArangoDeploymentReplication { + if in == nil { + return nil + } + out := new(ArangoDeploymentReplication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ArangoDeploymentReplication) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArangoDeploymentReplicationList) DeepCopyInto(out *ArangoDeploymentReplicationList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ArangoDeploymentReplication, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoDeploymentReplicationList. +func (in *ArangoDeploymentReplicationList) DeepCopy() *ArangoDeploymentReplicationList { + if in == nil { + return nil + } + out := new(ArangoDeploymentReplicationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ArangoDeploymentReplicationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentReplicationSpec) DeepCopyInto(out *DeploymentReplicationSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentReplicationSpec. +func (in *DeploymentReplicationSpec) DeepCopy() *DeploymentReplicationSpec { + if in == nil { + return nil + } + out := new(DeploymentReplicationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentReplicationStatus) DeepCopyInto(out *DeploymentReplicationStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentReplicationStatus. +func (in *DeploymentReplicationStatus) DeepCopy() *DeploymentReplicationStatus { + if in == nil { + return nil + } + out := new(DeploymentReplicationStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go index 6d76c9bde..44936e362 100644 --- a/pkg/generated/clientset/versioned/clientset.go +++ b/pkg/generated/clientset/versioned/clientset.go @@ -21,6 +21,7 @@ package versioned import ( databasev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/deployment/v1alpha" + replicationv1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/replication/v1alpha" storagev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/storage/v1alpha" glog "github.com/golang/glog" discovery "k8s.io/client-go/discovery" @@ -33,6 +34,9 @@ type Interface interface { DatabaseV1alpha() databasev1alpha.DatabaseV1alphaInterface // Deprecated: please explicitly pick a version if possible. Database() databasev1alpha.DatabaseV1alphaInterface + ReplicationV1alpha() replicationv1alpha.ReplicationV1alphaInterface + // Deprecated: please explicitly pick a version if possible. + Replication() replicationv1alpha.ReplicationV1alphaInterface StorageV1alpha() storagev1alpha.StorageV1alphaInterface // Deprecated: please explicitly pick a version if possible. Storage() storagev1alpha.StorageV1alphaInterface @@ -42,8 +46,9 @@ type Interface interface { // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - databaseV1alpha *databasev1alpha.DatabaseV1alphaClient - storageV1alpha *storagev1alpha.StorageV1alphaClient + databaseV1alpha *databasev1alpha.DatabaseV1alphaClient + replicationV1alpha *replicationv1alpha.ReplicationV1alphaClient + storageV1alpha *storagev1alpha.StorageV1alphaClient } // DatabaseV1alpha retrieves the DatabaseV1alphaClient @@ -57,6 +62,17 @@ func (c *Clientset) Database() databasev1alpha.DatabaseV1alphaInterface { return c.databaseV1alpha } +// ReplicationV1alpha retrieves the ReplicationV1alphaClient +func (c *Clientset) ReplicationV1alpha() replicationv1alpha.ReplicationV1alphaInterface { + return c.replicationV1alpha +} + +// Deprecated: Replication retrieves the default version of ReplicationClient. +// Please explicitly pick a version. +func (c *Clientset) Replication() replicationv1alpha.ReplicationV1alphaInterface { + return c.replicationV1alpha +} + // StorageV1alpha retrieves the StorageV1alphaClient func (c *Clientset) StorageV1alpha() storagev1alpha.StorageV1alphaInterface { return c.storageV1alpha @@ -88,6 +104,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.replicationV1alpha, err = replicationv1alpha.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.storageV1alpha, err = storagev1alpha.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -106,6 +126,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.databaseV1alpha = databasev1alpha.NewForConfigOrDie(c) + cs.replicationV1alpha = replicationv1alpha.NewForConfigOrDie(c) cs.storageV1alpha = storagev1alpha.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) @@ -116,6 +137,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { func New(c rest.Interface) *Clientset { var cs Clientset cs.databaseV1alpha = databasev1alpha.New(c) + cs.replicationV1alpha = replicationv1alpha.New(c) cs.storageV1alpha = storagev1alpha.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go index 1ca192f22..1e3cefd46 100644 --- a/pkg/generated/clientset/versioned/fake/clientset_generated.go +++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go @@ -23,6 +23,8 @@ import ( clientset "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" databasev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/deployment/v1alpha" fakedatabasev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/deployment/v1alpha/fake" + replicationv1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/replication/v1alpha" + fakereplicationv1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake" storagev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/storage/v1alpha" fakestoragev1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/storage/v1alpha/fake" "k8s.io/apimachinery/pkg/runtime" @@ -83,6 +85,16 @@ func (c *Clientset) Database() databasev1alpha.DatabaseV1alphaInterface { return &fakedatabasev1alpha.FakeDatabaseV1alpha{Fake: &c.Fake} } +// ReplicationV1alpha retrieves the ReplicationV1alphaClient +func (c *Clientset) ReplicationV1alpha() replicationv1alpha.ReplicationV1alphaInterface { + return &fakereplicationv1alpha.FakeReplicationV1alpha{Fake: &c.Fake} +} + +// Replication retrieves the ReplicationV1alphaClient +func (c *Clientset) Replication() replicationv1alpha.ReplicationV1alphaInterface { + return &fakereplicationv1alpha.FakeReplicationV1alpha{Fake: &c.Fake} +} + // StorageV1alpha retrieves the StorageV1alphaClient func (c *Clientset) StorageV1alpha() storagev1alpha.StorageV1alphaInterface { return &fakestoragev1alpha.FakeStorageV1alpha{Fake: &c.Fake} diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go index 33cdee33e..70c37b32b 100644 --- a/pkg/generated/clientset/versioned/fake/register.go +++ b/pkg/generated/clientset/versioned/fake/register.go @@ -21,6 +21,7 @@ package fake import ( databasev1alpha "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha" + replicationv1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" storagev1alpha "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -53,5 +54,6 @@ func init() { // correctly. func AddToScheme(scheme *runtime.Scheme) { databasev1alpha.AddToScheme(scheme) + replicationv1alpha.AddToScheme(scheme) storagev1alpha.AddToScheme(scheme) } diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go index 63ca2d1cd..de3b9f360 100644 --- a/pkg/generated/clientset/versioned/scheme/register.go +++ b/pkg/generated/clientset/versioned/scheme/register.go @@ -21,6 +21,7 @@ package scheme import ( databasev1alpha "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha" + replicationv1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" storagev1alpha "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -53,5 +54,6 @@ func init() { // correctly. func AddToScheme(scheme *runtime.Scheme) { databasev1alpha.AddToScheme(scheme) + replicationv1alpha.AddToScheme(scheme) storagev1alpha.AddToScheme(scheme) } diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/arangodeploymentreplication.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/arangodeploymentreplication.go new file mode 100644 index 000000000..b548a7665 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/arangodeploymentreplication.go @@ -0,0 +1,175 @@ +// +// 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 +// +package v1alpha + +import ( + v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + scheme "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// ArangoDeploymentReplicationsGetter has a method to return a ArangoDeploymentReplicationInterface. +// A group's client should implement this interface. +type ArangoDeploymentReplicationsGetter interface { + ArangoDeploymentReplications(namespace string) ArangoDeploymentReplicationInterface +} + +// ArangoDeploymentReplicationInterface has methods to work with ArangoDeploymentReplication resources. +type ArangoDeploymentReplicationInterface interface { + Create(*v1alpha.ArangoDeploymentReplication) (*v1alpha.ArangoDeploymentReplication, error) + Update(*v1alpha.ArangoDeploymentReplication) (*v1alpha.ArangoDeploymentReplication, error) + UpdateStatus(*v1alpha.ArangoDeploymentReplication) (*v1alpha.ArangoDeploymentReplication, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha.ArangoDeploymentReplication, error) + List(opts v1.ListOptions) (*v1alpha.ArangoDeploymentReplicationList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha.ArangoDeploymentReplication, err error) + ArangoDeploymentReplicationExpansion +} + +// arangoDeploymentReplications implements ArangoDeploymentReplicationInterface +type arangoDeploymentReplications struct { + client rest.Interface + ns string +} + +// newArangoDeploymentReplications returns a ArangoDeploymentReplications +func newArangoDeploymentReplications(c *ReplicationV1alphaClient, namespace string) *arangoDeploymentReplications { + return &arangoDeploymentReplications{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the arangoDeploymentReplication, and returns the corresponding arangoDeploymentReplication object, and an error if there is any. +func (c *arangoDeploymentReplications) Get(name string, options v1.GetOptions) (result *v1alpha.ArangoDeploymentReplication, err error) { + result = &v1alpha.ArangoDeploymentReplication{} + err = c.client.Get(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ArangoDeploymentReplications that match those selectors. +func (c *arangoDeploymentReplications) List(opts v1.ListOptions) (result *v1alpha.ArangoDeploymentReplicationList, err error) { + result = &v1alpha.ArangoDeploymentReplicationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested arangoDeploymentReplications. +func (c *arangoDeploymentReplications) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a arangoDeploymentReplication and creates it. Returns the server's representation of the arangoDeploymentReplication, and an error, if there is any. +func (c *arangoDeploymentReplications) Create(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (result *v1alpha.ArangoDeploymentReplication, err error) { + result = &v1alpha.ArangoDeploymentReplication{} + err = c.client.Post(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + Body(arangoDeploymentReplication). + Do(). + Into(result) + return +} + +// Update takes the representation of a arangoDeploymentReplication and updates it. Returns the server's representation of the arangoDeploymentReplication, and an error, if there is any. +func (c *arangoDeploymentReplications) Update(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (result *v1alpha.ArangoDeploymentReplication, err error) { + result = &v1alpha.ArangoDeploymentReplication{} + err = c.client.Put(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + Name(arangoDeploymentReplication.Name). + Body(arangoDeploymentReplication). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *arangoDeploymentReplications) UpdateStatus(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (result *v1alpha.ArangoDeploymentReplication, err error) { + result = &v1alpha.ArangoDeploymentReplication{} + err = c.client.Put(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + Name(arangoDeploymentReplication.Name). + SubResource("status"). + Body(arangoDeploymentReplication). + Do(). + Into(result) + return +} + +// Delete takes name of the arangoDeploymentReplication and deletes it. Returns an error if one occurs. +func (c *arangoDeploymentReplications) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *arangoDeploymentReplications) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched arangoDeploymentReplication. +func (c *arangoDeploymentReplications) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha.ArangoDeploymentReplication, err error) { + result = &v1alpha.ArangoDeploymentReplication{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("arangodeploymentreplications"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/doc.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/doc.go new file mode 100644 index 000000000..f48feba5c --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/doc.go @@ -0,0 +1,21 @@ +// +// 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 +// +// This package has the automatically generated typed clients. +package v1alpha diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/doc.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/doc.go new file mode 100644 index 000000000..6055f5176 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/doc.go @@ -0,0 +1,21 @@ +// +// 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 +// +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_arangodeploymentreplication.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_arangodeploymentreplication.go new file mode 100644 index 000000000..96c937aed --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_arangodeploymentreplication.go @@ -0,0 +1,141 @@ +// +// 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 +// +package fake + +import ( + v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeArangoDeploymentReplications implements ArangoDeploymentReplicationInterface +type FakeArangoDeploymentReplications struct { + Fake *FakeReplicationV1alpha + ns string +} + +var arangodeploymentreplicationsResource = schema.GroupVersionResource{Group: "replication.database.arangodb.com", Version: "v1alpha", Resource: "arangodeploymentreplications"} + +var arangodeploymentreplicationsKind = schema.GroupVersionKind{Group: "replication.database.arangodb.com", Version: "v1alpha", Kind: "ArangoDeploymentReplication"} + +// Get takes name of the arangoDeploymentReplication, and returns the corresponding arangoDeploymentReplication object, and an error if there is any. +func (c *FakeArangoDeploymentReplications) Get(name string, options v1.GetOptions) (result *v1alpha.ArangoDeploymentReplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(arangodeploymentreplicationsResource, c.ns, name), &v1alpha.ArangoDeploymentReplication{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha.ArangoDeploymentReplication), err +} + +// List takes label and field selectors, and returns the list of ArangoDeploymentReplications that match those selectors. +func (c *FakeArangoDeploymentReplications) List(opts v1.ListOptions) (result *v1alpha.ArangoDeploymentReplicationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(arangodeploymentreplicationsResource, arangodeploymentreplicationsKind, c.ns, opts), &v1alpha.ArangoDeploymentReplicationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha.ArangoDeploymentReplicationList{} + for _, item := range obj.(*v1alpha.ArangoDeploymentReplicationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested arangoDeploymentReplications. +func (c *FakeArangoDeploymentReplications) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(arangodeploymentreplicationsResource, c.ns, opts)) + +} + +// Create takes the representation of a arangoDeploymentReplication and creates it. Returns the server's representation of the arangoDeploymentReplication, and an error, if there is any. +func (c *FakeArangoDeploymentReplications) Create(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (result *v1alpha.ArangoDeploymentReplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(arangodeploymentreplicationsResource, c.ns, arangoDeploymentReplication), &v1alpha.ArangoDeploymentReplication{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha.ArangoDeploymentReplication), err +} + +// Update takes the representation of a arangoDeploymentReplication and updates it. Returns the server's representation of the arangoDeploymentReplication, and an error, if there is any. +func (c *FakeArangoDeploymentReplications) Update(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (result *v1alpha.ArangoDeploymentReplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(arangodeploymentreplicationsResource, c.ns, arangoDeploymentReplication), &v1alpha.ArangoDeploymentReplication{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha.ArangoDeploymentReplication), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeArangoDeploymentReplications) UpdateStatus(arangoDeploymentReplication *v1alpha.ArangoDeploymentReplication) (*v1alpha.ArangoDeploymentReplication, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(arangodeploymentreplicationsResource, "status", c.ns, arangoDeploymentReplication), &v1alpha.ArangoDeploymentReplication{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha.ArangoDeploymentReplication), err +} + +// Delete takes name of the arangoDeploymentReplication and deletes it. Returns an error if one occurs. +func (c *FakeArangoDeploymentReplications) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(arangodeploymentreplicationsResource, c.ns, name), &v1alpha.ArangoDeploymentReplication{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeArangoDeploymentReplications) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(arangodeploymentreplicationsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha.ArangoDeploymentReplicationList{}) + return err +} + +// Patch applies the patch and returns the patched arangoDeploymentReplication. +func (c *FakeArangoDeploymentReplications) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha.ArangoDeploymentReplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(arangodeploymentreplicationsResource, c.ns, name, data, subresources...), &v1alpha.ArangoDeploymentReplication{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha.ArangoDeploymentReplication), err +} diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_replication_client.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_replication_client.go new file mode 100644 index 000000000..bea672c63 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/fake/fake_replication_client.go @@ -0,0 +1,41 @@ +// +// 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 +// +package fake + +import ( + v1alpha "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/replication/v1alpha" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeReplicationV1alpha struct { + *testing.Fake +} + +func (c *FakeReplicationV1alpha) ArangoDeploymentReplications(namespace string) v1alpha.ArangoDeploymentReplicationInterface { + return &FakeArangoDeploymentReplications{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeReplicationV1alpha) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/generated_expansion.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/generated_expansion.go new file mode 100644 index 000000000..c102dfab5 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/generated_expansion.go @@ -0,0 +1,22 @@ +// +// 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 +// +package v1alpha + +type ArangoDeploymentReplicationExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/replication/v1alpha/replication_client.go b/pkg/generated/clientset/versioned/typed/replication/v1alpha/replication_client.go new file mode 100644 index 000000000..a2ae5c1c2 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/replication/v1alpha/replication_client.go @@ -0,0 +1,91 @@ +// +// 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 +// +package v1alpha + +import ( + v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type ReplicationV1alphaInterface interface { + RESTClient() rest.Interface + ArangoDeploymentReplicationsGetter +} + +// ReplicationV1alphaClient is used to interact with features provided by the replication.database.arangodb.com group. +type ReplicationV1alphaClient struct { + restClient rest.Interface +} + +func (c *ReplicationV1alphaClient) ArangoDeploymentReplications(namespace string) ArangoDeploymentReplicationInterface { + return newArangoDeploymentReplications(c, namespace) +} + +// NewForConfig creates a new ReplicationV1alphaClient for the given config. +func NewForConfig(c *rest.Config) (*ReplicationV1alphaClient, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ReplicationV1alphaClient{client}, nil +} + +// NewForConfigOrDie creates a new ReplicationV1alphaClient for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ReplicationV1alphaClient { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ReplicationV1alphaClient for the given RESTClient. +func New(c rest.Interface) *ReplicationV1alphaClient { + return &ReplicationV1alphaClient{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ReplicationV1alphaClient) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go index bb541551e..c88fc2a3f 100644 --- a/pkg/generated/informers/externalversions/factory.go +++ b/pkg/generated/informers/externalversions/factory.go @@ -30,6 +30,7 @@ import ( versioned "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" deployment "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/deployment" internalinterfaces "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/internalinterfaces" + replication "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/replication" storage "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/storage" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -129,6 +130,7 @@ type SharedInformerFactory interface { WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool Database() deployment.Interface + Replication() replication.Interface Storage() storage.Interface } @@ -136,6 +138,10 @@ func (f *sharedInformerFactory) Database() deployment.Interface { return deployment.New(f, f.namespace, f.tweakListOptions) } +func (f *sharedInformerFactory) Replication() replication.Interface { + return replication.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Storage() storage.Interface { return storage.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index e076d52f0..b169aa0ef 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -26,6 +26,7 @@ import ( "fmt" v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha" + replication_v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" storage_v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" @@ -61,6 +62,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha.SchemeGroupVersion.WithResource("arangodeployments"): return &genericInformer{resource: resource.GroupResource(), informer: f.Database().V1alpha().ArangoDeployments().Informer()}, nil + // Group=replication.database.arangodb.com, Version=v1alpha + case replication_v1alpha.SchemeGroupVersion.WithResource("arangodeploymentreplications"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Replication().V1alpha().ArangoDeploymentReplications().Informer()}, nil + // Group=storage.arangodb.com, Version=v1alpha case storage_v1alpha.SchemeGroupVersion.WithResource("arangolocalstorages"): return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1alpha().ArangoLocalStorages().Informer()}, nil diff --git a/pkg/generated/informers/externalversions/replication/interface.go b/pkg/generated/informers/externalversions/replication/interface.go new file mode 100644 index 000000000..6c7a3bcfb --- /dev/null +++ b/pkg/generated/informers/externalversions/replication/interface.go @@ -0,0 +1,50 @@ +// +// 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 +// + +// This file was automatically generated by informer-gen + +package replication + +import ( + internalinterfaces "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/replication/v1alpha" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha provides access to shared informers for resources in V1alpha. + V1alpha() v1alpha.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha returns a new v1alpha.Interface. +func (g *group) V1alpha() v1alpha.Interface { + return v1alpha.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/replication/v1alpha/arangodeploymentreplication.go b/pkg/generated/informers/externalversions/replication/v1alpha/arangodeploymentreplication.go new file mode 100644 index 000000000..2c45a1651 --- /dev/null +++ b/pkg/generated/informers/externalversions/replication/v1alpha/arangodeploymentreplication.go @@ -0,0 +1,93 @@ +// +// 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 +// + +// This file was automatically generated by informer-gen + +package v1alpha + +import ( + time "time" + + replication_v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + versioned "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" + internalinterfaces "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha "github.com/arangodb/kube-arangodb/pkg/generated/listers/replication/v1alpha" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ArangoDeploymentReplicationInformer provides access to a shared informer and lister for +// ArangoDeploymentReplications. +type ArangoDeploymentReplicationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha.ArangoDeploymentReplicationLister +} + +type arangoDeploymentReplicationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewArangoDeploymentReplicationInformer constructs a new informer for ArangoDeploymentReplication type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewArangoDeploymentReplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredArangoDeploymentReplicationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredArangoDeploymentReplicationInformer constructs a new informer for ArangoDeploymentReplication type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredArangoDeploymentReplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ReplicationV1alpha().ArangoDeploymentReplications(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ReplicationV1alpha().ArangoDeploymentReplications(namespace).Watch(options) + }, + }, + &replication_v1alpha.ArangoDeploymentReplication{}, + resyncPeriod, + indexers, + ) +} + +func (f *arangoDeploymentReplicationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredArangoDeploymentReplicationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *arangoDeploymentReplicationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&replication_v1alpha.ArangoDeploymentReplication{}, f.defaultInformer) +} + +func (f *arangoDeploymentReplicationInformer) Lister() v1alpha.ArangoDeploymentReplicationLister { + return v1alpha.NewArangoDeploymentReplicationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/replication/v1alpha/interface.go b/pkg/generated/informers/externalversions/replication/v1alpha/interface.go new file mode 100644 index 000000000..c5f378749 --- /dev/null +++ b/pkg/generated/informers/externalversions/replication/v1alpha/interface.go @@ -0,0 +1,49 @@ +// +// 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 +// + +// This file was automatically generated by informer-gen + +package v1alpha + +import ( + internalinterfaces "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ArangoDeploymentReplications returns a ArangoDeploymentReplicationInformer. + ArangoDeploymentReplications() ArangoDeploymentReplicationInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ArangoDeploymentReplications returns a ArangoDeploymentReplicationInformer. +func (v *version) ArangoDeploymentReplications() ArangoDeploymentReplicationInformer { + return &arangoDeploymentReplicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/generated/listers/replication/v1alpha/arangodeploymentreplication.go b/pkg/generated/listers/replication/v1alpha/arangodeploymentreplication.go new file mode 100644 index 000000000..09bdea528 --- /dev/null +++ b/pkg/generated/listers/replication/v1alpha/arangodeploymentreplication.go @@ -0,0 +1,98 @@ +// +// 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 +// + +// This file was automatically generated by lister-gen + +package v1alpha + +import ( + v1alpha "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ArangoDeploymentReplicationLister helps list ArangoDeploymentReplications. +type ArangoDeploymentReplicationLister interface { + // List lists all ArangoDeploymentReplications in the indexer. + List(selector labels.Selector) (ret []*v1alpha.ArangoDeploymentReplication, err error) + // ArangoDeploymentReplications returns an object that can list and get ArangoDeploymentReplications. + ArangoDeploymentReplications(namespace string) ArangoDeploymentReplicationNamespaceLister + ArangoDeploymentReplicationListerExpansion +} + +// arangoDeploymentReplicationLister implements the ArangoDeploymentReplicationLister interface. +type arangoDeploymentReplicationLister struct { + indexer cache.Indexer +} + +// NewArangoDeploymentReplicationLister returns a new ArangoDeploymentReplicationLister. +func NewArangoDeploymentReplicationLister(indexer cache.Indexer) ArangoDeploymentReplicationLister { + return &arangoDeploymentReplicationLister{indexer: indexer} +} + +// List lists all ArangoDeploymentReplications in the indexer. +func (s *arangoDeploymentReplicationLister) List(selector labels.Selector) (ret []*v1alpha.ArangoDeploymentReplication, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha.ArangoDeploymentReplication)) + }) + return ret, err +} + +// ArangoDeploymentReplications returns an object that can list and get ArangoDeploymentReplications. +func (s *arangoDeploymentReplicationLister) ArangoDeploymentReplications(namespace string) ArangoDeploymentReplicationNamespaceLister { + return arangoDeploymentReplicationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ArangoDeploymentReplicationNamespaceLister helps list and get ArangoDeploymentReplications. +type ArangoDeploymentReplicationNamespaceLister interface { + // List lists all ArangoDeploymentReplications in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha.ArangoDeploymentReplication, err error) + // Get retrieves the ArangoDeploymentReplication from the indexer for a given namespace and name. + Get(name string) (*v1alpha.ArangoDeploymentReplication, error) + ArangoDeploymentReplicationNamespaceListerExpansion +} + +// arangoDeploymentReplicationNamespaceLister implements the ArangoDeploymentReplicationNamespaceLister +// interface. +type arangoDeploymentReplicationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ArangoDeploymentReplications in the indexer for a given namespace. +func (s arangoDeploymentReplicationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha.ArangoDeploymentReplication, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha.ArangoDeploymentReplication)) + }) + return ret, err +} + +// Get retrieves the ArangoDeploymentReplication from the indexer for a given namespace and name. +func (s arangoDeploymentReplicationNamespaceLister) Get(name string) (*v1alpha.ArangoDeploymentReplication, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha.Resource("arangodeploymentreplication"), name) + } + return obj.(*v1alpha.ArangoDeploymentReplication), nil +} diff --git a/pkg/generated/listers/replication/v1alpha/expansion_generated.go b/pkg/generated/listers/replication/v1alpha/expansion_generated.go new file mode 100644 index 000000000..51d8b72b8 --- /dev/null +++ b/pkg/generated/listers/replication/v1alpha/expansion_generated.go @@ -0,0 +1,31 @@ +// +// 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 +// + +// This file was automatically generated by lister-gen + +package v1alpha + +// ArangoDeploymentReplicationListerExpansion allows custom methods to be added to +// ArangoDeploymentReplicationLister. +type ArangoDeploymentReplicationListerExpansion interface{} + +// ArangoDeploymentReplicationNamespaceListerExpansion allows custom methods to be added to +// ArangoDeploymentReplicationNamespaceLister. +type ArangoDeploymentReplicationNamespaceListerExpansion interface{} diff --git a/pkg/operator/crd.go b/pkg/operator/crd.go index 0b20f3cac..826a02405 100644 --- a/pkg/operator/crd.go +++ b/pkg/operator/crd.go @@ -24,13 +24,14 @@ package operator import ( deplapi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha" + replapi "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" "github.com/arangodb/kube-arangodb/pkg/util/crd" ) // waitForCRD waits for the CustomResourceDefinition (created externally) // to be ready. -func (o *Operator) waitForCRD(enableDeployment, enableStorage bool) error { +func (o *Operator) waitForCRD(enableDeployment, enableDeploymentReplication, enableStorage bool) error { log := o.log if enableDeployment { @@ -40,6 +41,13 @@ func (o *Operator) waitForCRD(enableDeployment, enableStorage bool) error { } } + if enableDeploymentReplication { + log.Debug().Msg("Waiting for ArangoDeploymentReplication CRD to be ready") + if err := crd.WaitCRDReady(o.KubeExtCli, replapi.ArangoDeploymentReplicationCRDName); err != nil { + return maskAny(err) + } + } + if enableStorage { log.Debug().Msg("Waiting for ArangoLocalStorage CRD to be ready") if err := crd.WaitCRDReady(o.KubeExtCli, lsapi.ArangoLocalStorageCRDName); err != nil { diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index fa0d75bd4..ba43136b4 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -34,10 +34,12 @@ import ( "k8s.io/client-go/tools/record" deplapi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha" + replapi "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha" "github.com/arangodb/kube-arangodb/pkg/deployment" "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" "github.com/arangodb/kube-arangodb/pkg/logging" + "github.com/arangodb/kube-arangodb/pkg/replication" "github.com/arangodb/kube-arangodb/pkg/storage" "github.com/arangodb/kube-arangodb/pkg/util/probe" ) @@ -47,50 +49,55 @@ const ( ) type Event struct { - Type kwatch.EventType - Deployment *deplapi.ArangoDeployment - LocalStorage *lsapi.ArangoLocalStorage + Type kwatch.EventType + Deployment *deplapi.ArangoDeployment + DeploymentReplication *replapi.ArangoDeploymentReplication + LocalStorage *lsapi.ArangoLocalStorage } type Operator struct { Config Dependencies - log zerolog.Logger - deployments map[string]*deployment.Deployment - localStorages map[string]*storage.LocalStorage + log zerolog.Logger + deployments map[string]*deployment.Deployment + deploymentReplications map[string]*replication.DeploymentReplication + localStorages map[string]*storage.LocalStorage } type Config struct { - ID string - Namespace string - PodName string - ServiceAccount string - LifecycleImage string - EnableDeployment bool - EnableStorage bool - AllowChaos bool + ID string + Namespace string + PodName string + ServiceAccount string + LifecycleImage string + EnableDeployment bool + EnableDeploymentReplication bool + EnableStorage bool + AllowChaos bool } type Dependencies struct { - LogService logging.Service - KubeCli kubernetes.Interface - KubeExtCli apiextensionsclient.Interface - CRCli versioned.Interface - EventRecorder record.EventRecorder - LivenessProbe *probe.LivenessProbe - DeploymentProbe *probe.ReadyProbe - StorageProbe *probe.ReadyProbe + LogService logging.Service + KubeCli kubernetes.Interface + KubeExtCli apiextensionsclient.Interface + CRCli versioned.Interface + EventRecorder record.EventRecorder + LivenessProbe *probe.LivenessProbe + DeploymentProbe *probe.ReadyProbe + DeploymentReplicationProbe *probe.ReadyProbe + StorageProbe *probe.ReadyProbe } // NewOperator instantiates a new operator from given config & dependencies. func NewOperator(config Config, deps Dependencies) (*Operator, error) { o := &Operator{ - Config: config, - Dependencies: deps, - log: deps.LogService.MustGetLogger("operator"), - deployments: make(map[string]*deployment.Deployment), - localStorages: make(map[string]*storage.LocalStorage), + Config: config, + Dependencies: deps, + log: deps.LogService.MustGetLogger("operator"), + deployments: make(map[string]*deployment.Deployment), + deploymentReplications: make(map[string]*replication.DeploymentReplication), + localStorages: make(map[string]*storage.LocalStorage), } return o, nil } @@ -100,6 +107,9 @@ func (o *Operator) Run() { if o.Config.EnableDeployment { go o.runLeaderElection("arango-deployment-operator", o.onStartDeployment) } + if o.Config.EnableDeploymentReplication { + go o.runLeaderElection("arango-deployment-replication-operator", o.onStartDeploymentReplication) + } if o.Config.EnableStorage { go o.runLeaderElection("arango-storage-operator", o.onStartStorage) } @@ -110,7 +120,7 @@ func (o *Operator) Run() { // onStartDeployment starts the deployment operator and run till given channel is closed. func (o *Operator) onStartDeployment(stop <-chan struct{}) { for { - if err := o.waitForCRD(true, false); err == nil { + if err := o.waitForCRD(true, false, false); err == nil { break } else { log.Error().Err(err).Msg("Resource initialization failed") @@ -121,10 +131,24 @@ func (o *Operator) onStartDeployment(stop <-chan struct{}) { o.runDeployments(stop) } +// onStartDeploymentReplication starts the deployment replication operator and run till given channel is closed. +func (o *Operator) onStartDeploymentReplication(stop <-chan struct{}) { + for { + if err := o.waitForCRD(false, true, false); err == nil { + break + } else { + log.Error().Err(err).Msg("Resource initialization failed") + log.Info().Msgf("Retrying in %s...", initRetryWaitTime) + time.Sleep(initRetryWaitTime) + } + } + o.runDeploymentReplications(stop) +} + // 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 { + if err := o.waitForCRD(false, false, true); err == nil { break } else { log.Error().Err(err).Msg("Resource initialization failed") diff --git a/pkg/operator/operator_deployment_relication.go b/pkg/operator/operator_deployment_relication.go new file mode 100644 index 000000000..fef7bfc3e --- /dev/null +++ b/pkg/operator/operator_deployment_relication.go @@ -0,0 +1,215 @@ +// +// 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 ( + "fmt" + + "github.com/pkg/errors" + kwatch "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" + + api "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + "github.com/arangodb/kube-arangodb/pkg/metrics" + "github.com/arangodb/kube-arangodb/pkg/replication" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" +) + +var ( + deploymentReplicationsCreated = metrics.MustRegisterCounter("controller", "deployment_replications_created", "Number of deployment replications that have been created") + deploymentReplicationsDeleted = metrics.MustRegisterCounter("controller", "deployment_replications_deleted", "Number of deployment replications that have been deleted") + deploymentReplicationsFailed = metrics.MustRegisterCounter("controller", "deployment_replications_failed", "Number of deployment replications that have failed") + deploymentReplicationsModified = metrics.MustRegisterCounter("controller", "deployment_replications_modified", "Number of deployment replication modifications") + deploymentReplicationsCurrent = metrics.MustRegisterGauge("controller", "deployment_replications", "Number of deployment replications currently being managed") +) + +// run the deployment replications part of the operator. +// This registers a listener and waits until the process stops. +func (o *Operator) runDeploymentReplications(stop <-chan struct{}) { + rw := k8sutil.NewResourceWatcher( + o.log, + o.Dependencies.CRCli.ReplicationV1alpha().RESTClient(), + api.ArangoDeploymentReplicationResourcePlural, + o.Config.Namespace, + &api.ArangoDeploymentReplication{}, + cache.ResourceEventHandlerFuncs{ + AddFunc: o.onAddArangoDeploymentReplication, + UpdateFunc: o.onUpdateArangoDeploymentReplication, + DeleteFunc: o.onDeleteArangoDeploymentReplication, + }) + + o.Dependencies.DeploymentReplicationProbe.SetReady() + rw.Run(stop) +} + +// onAddArangoDeploymentReplication deployment replication addition callback +func (o *Operator) onAddArangoDeploymentReplication(obj interface{}) { + o.Dependencies.LivenessProbe.Lock() + defer o.Dependencies.LivenessProbe.Unlock() + + apiObject := obj.(*api.ArangoDeploymentReplication) + o.log.Debug(). + Str("name", apiObject.GetObjectMeta().GetName()). + Msg("ArangoDeploymentReplication added") + o.syncArangoDeploymentReplication(apiObject) +} + +// onUpdateArangoDeploymentReplication deployment replication update callback +func (o *Operator) onUpdateArangoDeploymentReplication(oldObj, newObj interface{}) { + o.Dependencies.LivenessProbe.Lock() + defer o.Dependencies.LivenessProbe.Unlock() + + apiObject := newObj.(*api.ArangoDeploymentReplication) + o.log.Debug(). + Str("name", apiObject.GetObjectMeta().GetName()). + Msg("ArangoDeploymentReplication updated") + o.syncArangoDeploymentReplication(apiObject) +} + +// onDeleteArangoDeploymentReplication deployment replication delete callback +func (o *Operator) onDeleteArangoDeploymentReplication(obj interface{}) { + o.Dependencies.LivenessProbe.Lock() + defer o.Dependencies.LivenessProbe.Unlock() + + log := o.log + apiObject, ok := obj.(*api.ArangoDeploymentReplication) + if !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + log.Error().Interface("event-object", obj).Msg("unknown object from ArangoDeploymentReplication delete event") + return + } + apiObject, ok = tombstone.Obj.(*api.ArangoDeploymentReplication) + if !ok { + log.Error().Interface("event-object", obj).Msg("Tombstone contained object that is not an ArangoDeploymentReplication") + return + } + } + log.Debug(). + Str("name", apiObject.GetObjectMeta().GetName()). + Msg("ArangoDeploymentReplication deleted") + ev := &Event{ + Type: kwatch.Deleted, + DeploymentReplication: apiObject, + } + + // pt.start() + err := o.handleDeploymentReplicationEvent(ev) + if err != nil { + log.Warn().Err(err).Msg("Failed to handle event") + } + //pt.stop() +} + +// syncArangoDeploymentReplication synchronized the given deployment replication. +func (o *Operator) syncArangoDeploymentReplication(apiObject *api.ArangoDeploymentReplication) { + ev := &Event{ + Type: kwatch.Added, + DeploymentReplication: apiObject, + } + // re-watch or restart could give ADD event. + // If for an ADD event the cluster spec is invalid then it is not added to the local cache + // so modifying that deployment will result in another ADD event + if _, ok := o.deployments[apiObject.Name]; ok { + ev.Type = kwatch.Modified + } + + //pt.start() + err := o.handleDeploymentEvent(ev) + if err != nil { + o.log.Warn().Err(err).Msg("Failed to handle event") + } + //pt.stop() +} + +// handleDeploymentReplicationEvent processed the given event. +func (o *Operator) handleDeploymentReplicationEvent(event *Event) error { + apiObject := event.DeploymentReplication + + if apiObject.Status.Phase.IsFailed() { + deploymentReplicationsFailed.Inc() + if event.Type == kwatch.Deleted { + delete(o.deploymentReplications, apiObject.Name) + return nil + } + return maskAny(fmt.Errorf("ignore failed deployment replication (%s). Please delete its CR", apiObject.Name)) + } + + switch event.Type { + case kwatch.Added: + if _, ok := o.deploymentReplications[apiObject.Name]; ok { + return maskAny(fmt.Errorf("unsafe state. deployment replication (%s) was created before but we received event (%s)", apiObject.Name, event.Type)) + } + + // Fill in defaults + apiObject.Spec.SetDefaults() + // Validate deployment spec + if err := apiObject.Spec.Validate(); err != nil { + return maskAny(errors.Wrapf(err, "invalid deployment replication spec. please fix the following problem with the deployment replication spec: %v", err)) + } + + cfg, deps := o.makeDeploymentReplicationConfigAndDeps(apiObject) + nc, err := replication.New(cfg, deps, apiObject) + if err != nil { + return maskAny(fmt.Errorf("failed to create deployment: %s", err)) + } + o.deploymentReplications[apiObject.Name] = nc + + deploymentReplicationsCreated.Inc() + deploymentReplicationsCurrent.Set(float64(len(o.deploymentReplications))) + + case kwatch.Modified: + repl, ok := o.deploymentReplications[apiObject.Name] + if !ok { + return maskAny(fmt.Errorf("unsafe state. deployment replication (%s) was never created but we received event (%s)", apiObject.Name, event.Type)) + } + repl.Update(apiObject) + deploymentReplicationsModified.Inc() + + case kwatch.Deleted: + repl, ok := o.deploymentReplications[apiObject.Name] + if !ok { + return maskAny(fmt.Errorf("unsafe state. deployment replication (%s) was never created but we received event (%s)", apiObject.Name, event.Type)) + } + repl.Delete() + delete(o.deploymentReplications, apiObject.Name) + deploymentReplicationsDeleted.Inc() + deploymentReplicationsCurrent.Set(float64(len(o.deploymentReplications))) + } + return nil +} + +// makeDeploymentReplicationConfigAndDeps creates a Config & Dependencies object for a new DeploymentReplication. +func (o *Operator) makeDeploymentReplicationConfigAndDeps(apiObject *api.ArangoDeploymentReplication) (replication.Config, replication.Dependencies) { + cfg := replication.Config{ + Namespace: o.Config.Namespace, + } + deps := replication.Dependencies{ + Log: o.Dependencies.LogService.MustGetLogger("deployment-replication").With(). + Str("deployment-replication", apiObject.GetName()). + Logger(), + KubeCli: o.Dependencies.KubeCli, + CRCli: o.Dependencies.CRCli, + } + return cfg, deps +} diff --git a/pkg/replication/deployment_replication.go b/pkg/replication/deployment_replication.go new file mode 100644 index 000000000..f2697c83e --- /dev/null +++ b/pkg/replication/deployment_replication.go @@ -0,0 +1,380 @@ +// +// 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 replication + +import ( + "fmt" + "reflect" + "sync/atomic" + "time" + + "github.com/rs/zerolog" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" + + api "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha" + "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" + "github.com/arangodb/kube-arangodb/pkg/util/retry" + "github.com/arangodb/kube-arangodb/pkg/util/trigger" +) + +// Config holds configuration settings for a DeploymentReplication +type Config struct { + Namespace string + // PodName string + // ServiceAccount string +} + +// Dependencies holds dependent services for a DeploymentReplication +type Dependencies struct { + Log zerolog.Logger + KubeCli kubernetes.Interface + CRCli versioned.Interface +} + +// deploymentReplicationEvent strongly typed type of event +type deploymentReplicationEventType string + +const ( + eventArangoDeploymentReplicationUpdated deploymentReplicationEventType = "DeploymentReplicationUpdated" +) + +// seploymentReplicationEvent holds an event passed from the controller to the deployment replication. +type deploymentReplicationEvent struct { + Type deploymentReplicationEventType + DeploymentReplication *api.ArangoDeploymentReplication +} + +const ( + deploymentReplicationEventQueueSize = 100 + minInspectionInterval = time.Second // Ensure we inspect the generated resources no less than with this interval + maxInspectionInterval = time.Minute // Ensure we inspect the generated resources no less than with this interval +) + +// DeploymentReplication is the in process state of an ArangoDeploymentReplication. +type DeploymentReplication struct { + apiObject *api.ArangoDeploymentReplication // API object + status api.DeploymentReplicationStatus // Internal status of the CR + config Config + deps Dependencies + + eventCh chan *deploymentReplicationEvent + stopCh chan struct{} + stopped int32 + + eventsCli corev1.EventInterface + + inspectTrigger trigger.Trigger +} + +// New creates a new DeploymentReplication from the given API object. +func New(config Config, deps Dependencies, apiObject *api.ArangoDeploymentReplication) (*DeploymentReplication, error) { + if err := apiObject.Spec.Validate(); err != nil { + return nil, maskAny(err) + } + dr := &DeploymentReplication{ + apiObject: apiObject, + status: *(apiObject.Status.DeepCopy()), + config: config, + deps: deps, + eventCh: make(chan *deploymentReplicationEvent, deploymentReplicationEventQueueSize), + stopCh: make(chan struct{}), + eventsCli: deps.KubeCli.Core().Events(apiObject.GetNamespace()), + } + + go dr.run() + + return dr, nil +} + +// Update the deployment replication. +// This sends an update event in the event queue. +func (dr *DeploymentReplication) Update(apiObject *api.ArangoDeploymentReplication) { + dr.send(&deploymentReplicationEvent{ + Type: eventArangoDeploymentReplicationUpdated, + DeploymentReplication: apiObject, + }) +} + +// Delete the deployment replication. +// Called when the local storage was deleted by the user. +func (dr *DeploymentReplication) Delete() { + dr.deps.Log.Info().Msg("deployment replication is deleted by user") + if atomic.CompareAndSwapInt32(&dr.stopped, 0, 1) { + close(dr.stopCh) + } +} + +// send given event into the deployment replication event queue. +func (dr *DeploymentReplication) send(ev *deploymentReplicationEvent) { + select { + case dr.eventCh <- ev: + l, ecap := len(dr.eventCh), cap(dr.eventCh) + if l > int(float64(ecap)*0.8) { + dr.deps.Log.Warn(). + Int("used", l). + Int("capacity", ecap). + Msg("event queue buffer is almost full") + } + case <-dr.stopCh: + } +} + +// run is the core the core worker. +// It processes the event queue and polls the state of generated +// resource on a regular basis. +func (dr *DeploymentReplication) run() { + //log := dr.deps.Log + + inspectionInterval := maxInspectionInterval + recentInspectionErrors := 0 + for { + select { + case <-dr.stopCh: + // We're being stopped. + return + + case event := <-dr.eventCh: + // Got event from event queue + switch event.Type { + case eventArangoDeploymentReplicationUpdated: + if err := dr.handleArangoDeploymentReplicationUpdatedEvent(event); err != nil { + dr.failOnError(err, "Failed to handle deployment replication update") + return + } + default: + panic("unknown event type" + event.Type) + } + + case <-dr.inspectTrigger.Done(): + hasError := false + if hasError { + if recentInspectionErrors == 0 { + inspectionInterval = minInspectionInterval + recentInspectionErrors++ + } + } else { + recentInspectionErrors = 0 + } + + case <-time.After(inspectionInterval): + // Trigger inspection + dr.inspectTrigger.Trigger() + // Backoff with next interval + inspectionInterval = time.Duration(float64(inspectionInterval) * 1.5) + if inspectionInterval > maxInspectionInterval { + inspectionInterval = maxInspectionInterval + } + } + } +} + +// handleArangoDeploymentReplicationUpdatedEvent is called when the deployment replication is updated by the user. +func (dr *DeploymentReplication) handleArangoDeploymentReplicationUpdatedEvent(event *deploymentReplicationEvent) error { + log := dr.deps.Log.With().Str("deployoment-replication", event.DeploymentReplication.GetName()).Logger() + repls := dr.deps.CRCli.ReplicationV1alpha().ArangoDeploymentReplications(dr.apiObject.GetNamespace()) + + // Get the most recent version of the deployment replication from the API server + current, err := repls.Get(dr.apiObject.GetName(), metav1.GetOptions{}) + if err != nil { + log.Debug().Err(err).Msg("Failed to get current version of deployment replication from API server") + if k8sutil.IsNotFound(err) { + return nil + } + return maskAny(err) + } + + newAPIObject := current.DeepCopy() + newAPIObject.Spec.SetDefaults() + newAPIObject.Status = dr.status + resetFields := dr.apiObject.Spec.ResetImmutableFields(&newAPIObject.Spec) + if len(resetFields) > 0 { + log.Debug().Strs("fields", resetFields).Msg("Found modified immutable fields") + } + if err := newAPIObject.Spec.Validate(); err != nil { + dr.createEvent(k8sutil.NewErrorEvent("Validation failed", err, dr.apiObject)) + // Try to reset object + if err := dr.updateCRSpec(dr.apiObject.Spec); err != nil { + log.Error().Err(err).Msg("Restore original spec failed") + dr.createEvent(k8sutil.NewErrorEvent("Restore original failed", err, dr.apiObject)) + } + return nil + } + if len(resetFields) > 0 { + for _, fieldName := range resetFields { + log.Debug().Str("field", fieldName).Msg("Reset immutable field") + dr.createEvent(k8sutil.NewImmutableFieldEvent(fieldName, dr.apiObject)) + } + } + + // Save updated spec + if err := dr.updateCRSpec(newAPIObject.Spec); err != nil { + return maskAny(fmt.Errorf("failed to update ArangoDeploymentReplication spec: %v", err)) + } + + // Trigger inspect + dr.inspectTrigger.Trigger() + + return nil +} + +// createEvent creates a given event. +// On error, the error is logged. +func (dr *DeploymentReplication) createEvent(evt *v1.Event) { + if _, err := dr.eventsCli.Create(evt); err != nil { + dr.deps.Log.Error().Err(err).Interface("event", *evt).Msg("Failed to record event") + } +} + +// Update the status of the API object from the internal status +func (dr *DeploymentReplication) updateCRStatus() error { + if reflect.DeepEqual(dr.apiObject.Status, dr.status) { + // Nothing has changed + return nil + } + + // Send update to API server + log := dr.deps.Log + repls := dr.deps.CRCli.ReplicationV1alpha().ArangoDeploymentReplications(dr.apiObject.GetNamespace()) + update := dr.apiObject.DeepCopy() + attempt := 0 + for { + attempt++ + update.Status = dr.status + newAPIObject, err := repls.Update(update) + if err == nil { + // Update internal object + dr.apiObject = newAPIObject + return nil + } + if attempt < 10 && k8sutil.IsConflict(err) { + // API object may have been changed already, + // Reload api object and try again + var current *api.ArangoDeploymentReplication + current, err = repls.Get(update.GetName(), metav1.GetOptions{}) + if err == nil { + update = current.DeepCopy() + continue + } + } + if err != nil { + log.Debug().Err(err).Msg("failed to patch ArangoDeploymentReplication status") + return maskAny(fmt.Errorf("failed to patch ArangoDeploymentReplication status: %v", err)) + } + } +} + +// Update the spec part of the API object (d.apiObject) +// to the given object, while preserving the status. +// On success, d.apiObject is updated. +func (dr *DeploymentReplication) updateCRSpec(newSpec api.DeploymentReplicationSpec) error { + log := dr.deps.Log + repls := dr.deps.CRCli.ReplicationV1alpha().ArangoDeploymentReplications(dr.apiObject.GetNamespace()) + + // Send update to API server + update := dr.apiObject.DeepCopy() + attempt := 0 + for { + attempt++ + update.Spec = newSpec + update.Status = dr.status + newAPIObject, err := repls.Update(update) + if err == nil { + // Update internal object + dr.apiObject = newAPIObject + return nil + } + if attempt < 10 && k8sutil.IsConflict(err) { + // API object may have been changed already, + // Reload api object and try again + var current *api.ArangoDeploymentReplication + current, err = repls.Get(update.GetName(), metav1.GetOptions{}) + if err == nil { + update = current.DeepCopy() + continue + } + } + if err != nil { + log.Debug().Err(err).Msg("failed to patch ArangoDeploymentReplication spec") + return maskAny(fmt.Errorf("failed to patch ArangoDeploymentReplication spec: %v", err)) + } + } +} + +// failOnError reports the given error and sets the deployment replication status to failed. +func (dr *DeploymentReplication) failOnError(err error, msg string) { + log := dr.deps.Log + log.Error().Err(err).Msg(msg) + dr.status.Reason = err.Error() + dr.reportFailedStatus() +} + +// reportFailedStatus sets the status of the deployment replication to Failed and keeps trying to forward +// that to the API server. +func (dr *DeploymentReplication) reportFailedStatus() { + log := dr.deps.Log + log.Info().Msg("local storage failed. Reporting failed reason...") + repls := dr.deps.CRCli.ReplicationV1alpha().ArangoDeploymentReplications(dr.apiObject.GetNamespace()) + + op := func() error { + dr.status.Phase = api.DeploymentReplicationPhaseFailed + err := dr.updateCRStatus() + if err == nil || k8sutil.IsNotFound(err) { + // Status has been updated + return nil + } + + if !k8sutil.IsConflict(err) { + log.Warn().Err(err).Msg("retry report status: fail to update") + return maskAny(err) + } + + depl, err := repls.Get(dr.apiObject.Name, metav1.GetOptions{}) + if err != nil { + // Update (PUT) will return conflict even if object is deleted since we have UID set in object. + // Because it will check UID first and return something like: + // "Precondition failed: UID in precondition: 0xc42712c0f0, UID in object meta: ". + if k8sutil.IsNotFound(err) { + return nil + } + log.Warn().Err(err).Msg("retry report status: fail to get latest version") + return maskAny(err) + } + dr.apiObject = depl + return maskAny(fmt.Errorf("retry needed")) + } + + retry.Retry(op, time.Hour*24*365) +} + +// isOwnerOf returns true if the given object belong to this local storage. +func (dr *DeploymentReplication) isOwnerOf(obj metav1.Object) bool { + ownerRefs := obj.GetOwnerReferences() + if len(ownerRefs) < 1 { + return false + } + return ownerRefs[0].UID == dr.apiObject.UID +} diff --git a/pkg/replication/errors.go b/pkg/replication/errors.go new file mode 100644 index 000000000..e48fb52d3 --- /dev/null +++ b/pkg/replication/errors.go @@ -0,0 +1,29 @@ +// +// 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 replication + +import "github.com/pkg/errors" + +var ( + maskAny = errors.WithStack +) diff --git a/tools/manifests/manifest_builder.go b/tools/manifests/manifest_builder.go index 06c40f010..1a1c5467c 100644 --- a/tools/manifests/manifest_builder.go +++ b/tools/manifests/manifest_builder.go @@ -41,19 +41,24 @@ var ( OutputSuffix string TemplatesDir string - Namespace string - Image string - ImagePullPolicy string - ImageSHA256 bool - DeploymentOperatorName string - StorageOperatorName string - RBAC bool - AllowChaos bool + Namespace string + Image string + ImagePullPolicy string + ImageSHA256 bool + DeploymentOperatorName string + DeploymentReplicationOperatorName string + StorageOperatorName string + RBAC bool + AllowChaos bool } deploymentTemplateNames = []string{ "rbac.yaml", "deployment.yaml", } + deploymentReplicationTemplateNames = []string{ + "rbac.yaml", + "deployment-replication.yaml", + } storageTemplateNames = []string{ "rbac.yaml", "deployment.yaml", @@ -71,6 +76,7 @@ func init() { 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.DeploymentOperatorName, "deployment-operator-name", "arango-deployment-operator", "Name of the ArangoDeployment operator deployment") + pflag.StringVar(&options.DeploymentReplicationOperatorName, "deployment-replication-operator-name", "arango-deployment-replication-operator", "Name of the ArangoDeploymentReplication 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.BoolVar(&options.AllowChaos, "allow-chaos", false, "If set, allows chaos in deployments") @@ -79,12 +85,13 @@ func init() { } type TemplateOptions struct { - Image string - ImagePullPolicy string - RBAC bool - Deployment ResourceOptions - Storage ResourceOptions - Test CommonOptions + Image string + ImagePullPolicy string + RBAC bool + Deployment ResourceOptions + DeploymentReplication ResourceOptions + Storage ResourceOptions + Test CommonOptions } type CommonOptions struct { @@ -128,9 +135,10 @@ func main() { // Prepare templates to include templateNameSet := map[string][]string{ - "deployment": deploymentTemplateNames, - "storage": storageTemplateNames, - "test": testTemplateNames, + "deployment": deploymentTemplateNames, + "deployment-replication": deploymentReplicationTemplateNames, + "storage": storageTemplateNames, + "test": testTemplateNames, } // Process templates @@ -154,6 +162,21 @@ func main() { OperatorDeploymentName: "arango-deployment-operator", AllowChaos: options.AllowChaos, }, + DeploymentReplication: ResourceOptions{ + User: CommonOptions{ + Namespace: options.Namespace, + RoleName: "arango-deployment-replications", + RoleBindingName: "arango-deployment-replications", + ServiceAccountName: "default", + }, + Operator: CommonOptions{ + Namespace: options.Namespace, + RoleName: "arango-deployment-replication-operator", + RoleBindingName: "arango-deployment-replication-operator", + ServiceAccountName: "default", + }, + OperatorDeploymentName: "arango-deployment-replication-operator", + }, Storage: ResourceOptions{ User: CommonOptions{ Namespace: options.Namespace,