2018-05-18 09:54:53 +00:00
//
// DISCLAIMER
//
2022-01-10 11:35:49 +00:00
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
2018-05-18 09:54:53 +00:00
//
// 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 operator
import (
kwatch "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
2022-07-11 11:49:47 +00:00
replication2 "github.com/arangodb/kube-arangodb/pkg/apis/replication"
2019-11-04 07:49:24 +00:00
api "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1"
2018-05-18 09:54:53 +00:00
"github.com/arangodb/kube-arangodb/pkg/metrics"
"github.com/arangodb/kube-arangodb/pkg/replication"
2022-07-11 11:49:47 +00:00
"github.com/arangodb/kube-arangodb/pkg/util/errors"
2018-05-18 09:54:53 +00:00
"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 (
2022-02-28 18:53:01 +00:00
o . Dependencies . Client . Arango ( ) . ReplicationV1 ( ) . RESTClient ( ) ,
2019-11-04 07:49:24 +00:00
replication2 . ArangoDeploymentReplicationResourcePlural ,
2018-05-18 09:54:53 +00:00
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 )
2022-06-14 07:26:07 +00:00
o . log .
2018-05-18 09:54:53 +00:00
Str ( "name" , apiObject . GetObjectMeta ( ) . GetName ( ) ) .
2022-06-14 07:26:07 +00:00
Debug ( "ArangoDeploymentReplication added" )
2018-05-18 09:54:53 +00:00
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 )
2022-06-14 07:26:07 +00:00
o . log .
2018-05-18 09:54:53 +00:00
Str ( "name" , apiObject . GetObjectMeta ( ) . GetName ( ) ) .
2022-06-14 07:26:07 +00:00
Debug ( "ArangoDeploymentReplication updated" )
2018-05-18 09:54:53 +00:00
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 {
2022-06-14 07:26:07 +00:00
log . Interface ( "event-object" , obj ) . Error ( "unknown object from ArangoDeploymentReplication delete event" )
2018-05-18 09:54:53 +00:00
return
}
apiObject , ok = tombstone . Obj . ( * api . ArangoDeploymentReplication )
if ! ok {
2022-06-14 07:26:07 +00:00
log . Interface ( "event-object" , obj ) . Error ( "Tombstone contained object that is not an ArangoDeploymentReplication" )
2018-05-18 09:54:53 +00:00
return
}
}
2022-06-14 07:26:07 +00:00
log .
2018-05-18 09:54:53 +00:00
Str ( "name" , apiObject . GetObjectMeta ( ) . GetName ( ) ) .
2022-06-14 07:26:07 +00:00
Debug ( "ArangoDeploymentReplication deleted" )
2018-05-18 09:54:53 +00:00
ev := & Event {
2019-01-01 13:39:43 +00:00
Type : kwatch . Deleted ,
2018-05-18 09:54:53 +00:00
DeploymentReplication : apiObject ,
}
// pt.start()
err := o . handleDeploymentReplicationEvent ( ev )
if err != nil {
2022-06-14 07:26:07 +00:00
log . Err ( err ) . Warn ( "Failed to handle event" )
2018-05-18 09:54:53 +00:00
}
//pt.stop()
}
// syncArangoDeploymentReplication synchronized the given deployment replication.
func ( o * Operator ) syncArangoDeploymentReplication ( apiObject * api . ArangoDeploymentReplication ) {
ev := & Event {
2019-01-01 13:39:43 +00:00
Type : kwatch . Added ,
2018-05-18 09:54:53 +00:00
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
2018-05-18 14:31:31 +00:00
if _ , ok := o . deploymentReplications [ apiObject . Name ] ; ok {
2018-05-18 09:54:53 +00:00
ev . Type = kwatch . Modified
}
//pt.start()
2018-05-18 14:31:31 +00:00
err := o . handleDeploymentReplicationEvent ( ev )
2018-05-18 09:54:53 +00:00
if err != nil {
2022-06-14 07:26:07 +00:00
o . log . Err ( err ) . Warn ( "Failed to handle event" )
2018-05-18 09:54:53 +00:00
}
//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
}
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Newf ( "ignore failed deployment replication (%s). Please delete its CR" , apiObject . Name ) )
2018-05-18 09:54:53 +00:00
}
switch event . Type {
case kwatch . Added :
if _ , ok := o . deploymentReplications [ apiObject . Name ] ; ok {
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Newf ( "unsafe state. deployment replication (%s) was created before but we received event (%s)" , apiObject . Name , event . Type ) )
2018-05-18 09:54:53 +00:00
}
// Fill in defaults
apiObject . Spec . SetDefaults ( )
// Validate deployment spec
if err := apiObject . Spec . Validate ( ) ; err != nil {
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Wrapf ( err , "invalid deployment replication spec. please fix the following problem with the deployment replication spec: %v" , err ) )
2018-05-18 09:54:53 +00:00
}
2022-06-14 07:26:07 +00:00
cfg , deps := o . makeDeploymentReplicationConfigAndDeps ( )
2018-05-18 09:54:53 +00:00
nc , err := replication . New ( cfg , deps , apiObject )
if err != nil {
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Newf ( "failed to create deployment: %s" , err ) )
2018-05-18 09:54:53 +00:00
}
o . deploymentReplications [ apiObject . Name ] = nc
deploymentReplicationsCreated . Inc ( )
deploymentReplicationsCurrent . Set ( float64 ( len ( o . deploymentReplications ) ) )
case kwatch . Modified :
repl , ok := o . deploymentReplications [ apiObject . Name ]
if ! ok {
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Newf ( "unsafe state. deployment replication (%s) was never created but we received event (%s)" , apiObject . Name , event . Type ) )
2018-05-18 09:54:53 +00:00
}
repl . Update ( apiObject )
deploymentReplicationsModified . Inc ( )
case kwatch . Deleted :
repl , ok := o . deploymentReplications [ apiObject . Name ]
if ! ok {
2021-01-08 14:35:38 +00:00
return errors . WithStack ( errors . Newf ( "unsafe state. deployment replication (%s) was never created but we received event (%s)" , apiObject . Name , event . Type ) )
2018-05-18 09:54:53 +00:00
}
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.
2022-06-14 07:26:07 +00:00
func ( o * Operator ) makeDeploymentReplicationConfigAndDeps ( ) ( replication . Config , replication . Dependencies ) {
2018-05-18 09:54:53 +00:00
cfg := replication . Config {
Namespace : o . Config . Namespace ,
}
deps := replication . Dependencies {
2022-02-28 18:53:01 +00:00
Client : o . Client ,
2018-06-18 09:55:42 +00:00
EventRecorder : o . Dependencies . EventRecorder ,
2018-05-18 09:54:53 +00:00
}
2022-06-14 07:26:07 +00:00
2018-05-18 09:54:53 +00:00
return cfg , deps
}