From 1407bca08fc47efbc02c5756620a6242e7b6dec5 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Thu, 15 Mar 2018 22:53:58 +0000 Subject: [PATCH 1/9] Add decommissioning flags to api --- pkg/apis/navigator/types.go | 21 +++++++- pkg/apis/navigator/v1alpha1/types.go | 29 +++++++++++ .../v1alpha1/zz_generated.conversion.go | 48 +++++++++++++++++ .../v1alpha1/zz_generated.deepcopy.go | 52 ++++++++++++++++++- pkg/apis/navigator/zz_generated.deepcopy.go | 52 ++++++++++++++++++- pkg/controllers/cassandra/util/util.go | 12 +++++ pkg/pilot/cassandra/v3/pilot.go | 13 +++-- 7 files changed, 219 insertions(+), 8 deletions(-) diff --git a/pkg/apis/navigator/types.go b/pkg/apis/navigator/types.go index 107095b01..c0df810ca 100644 --- a/pkg/apis/navigator/types.go +++ b/pkg/apis/navigator/types.go @@ -177,6 +177,24 @@ type PilotList struct { } type PilotSpec struct { + Elasticsearch *PilotElasticsearchSpec + Cassandra *PilotCassandraSpec +} + +type PilotPhase string + +const ( + PilotPhasePreStart PilotPhase = "PreStart" + PilotPhasePostStart PilotPhase = "PostStart" + PilotPhasePreStop PilotPhase = "PreStop" + PilotPhasePostStop PilotPhase = "PostStop" +) + +type PilotElasticsearchSpec struct { +} + +type PilotCassandraSpec struct { + Decommissioned bool } type PilotStatus struct { @@ -196,7 +214,8 @@ type ElasticsearchPilotStatus struct { } type CassandraPilotStatus struct { - Version *version.Version + Version *version.Version + Decommissioned bool } // PilotCondition contains condition information for a Pilot. diff --git a/pkg/apis/navigator/v1alpha1/types.go b/pkg/apis/navigator/v1alpha1/types.go index 11ffd3cc6..9da5994eb 100644 --- a/pkg/apis/navigator/v1alpha1/types.go +++ b/pkg/apis/navigator/v1alpha1/types.go @@ -329,6 +329,32 @@ type PilotList struct { } type PilotSpec struct { + Elasticsearch *PilotElasticsearchSpec `json:"elasticsearch"` + Cassandra *PilotCassandraSpec `json:"cassandra"` +} + +type PilotPhase string + +const ( + // PreStart occurs before the Pilot's subprocess has been started. + PilotPhasePreStart PilotPhase = "PreStart" + // PostStart occurs immediately after the Pilot's subprocess has been + // started. + PilotPhasePostStart PilotPhase = "PostStart" + // PreStop occurs just before the Pilot's subprocess is sent a graceful + // termination signal. These hooks will block termination of the process. + PilotPhasePreStop PilotPhase = "PreStop" + // PostStop occurs after the Pilot's has stopped. These can be used to + // clean up, or whatever other action that may need to be performed. + PilotPhasePostStop PilotPhase = "PostStop" +) + +type PilotElasticsearchSpec struct { +} + +type PilotCassandraSpec struct { + // Decommissioned should be set to true if we want to decommission this node + Decommissioned bool `json:"decommissioned"` } type PilotStatus struct { @@ -363,6 +389,9 @@ type CassandraPilotStatus struct { // This field may be nil if the version number is not currently known. // +optional Version *version.Version `json:"version,omitempty"` + + // Decommissioned is true if we think we have successfully decommissioned this node + Decommissioned bool `json:"decommissioned"` } // PilotCondition contains condition information for a Pilot. diff --git a/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go b/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go index 9cabdb11e..22f83665d 100644 --- a/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go @@ -76,8 +76,12 @@ func RegisterConversions(scheme *runtime.Scheme) error { Convert_navigator_PersistenceConfig_To_v1alpha1_PersistenceConfig, Convert_v1alpha1_Pilot_To_navigator_Pilot, Convert_navigator_Pilot_To_v1alpha1_Pilot, + Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec, + Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec, Convert_v1alpha1_PilotCondition_To_navigator_PilotCondition, Convert_navigator_PilotCondition_To_v1alpha1_PilotCondition, + Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec, + Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec, Convert_v1alpha1_PilotList_To_navigator_PilotList, Convert_navigator_PilotList_To_v1alpha1_PilotList, Convert_v1alpha1_PilotSpec_To_navigator_PilotSpec, @@ -267,6 +271,7 @@ func Convert_navigator_CassandraClusterStatus_To_v1alpha1_CassandraClusterStatus func autoConvert_v1alpha1_CassandraPilotStatus_To_navigator_CassandraPilotStatus(in *CassandraPilotStatus, out *navigator.CassandraPilotStatus, s conversion.Scope) error { out.Version = (*version.Version)(unsafe.Pointer(in.Version)) + out.Decommissioned = in.Decommissioned return nil } @@ -277,6 +282,7 @@ func Convert_v1alpha1_CassandraPilotStatus_To_navigator_CassandraPilotStatus(in func autoConvert_navigator_CassandraPilotStatus_To_v1alpha1_CassandraPilotStatus(in *navigator.CassandraPilotStatus, out *CassandraPilotStatus, s conversion.Scope) error { out.Version = (*version.Version)(unsafe.Pointer(in.Version)) + out.Decommissioned = in.Decommissioned return nil } @@ -617,6 +623,26 @@ func Convert_navigator_Pilot_To_v1alpha1_Pilot(in *navigator.Pilot, out *Pilot, return autoConvert_navigator_Pilot_To_v1alpha1_Pilot(in, out, s) } +func autoConvert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in *PilotCassandraSpec, out *navigator.PilotCassandraSpec, s conversion.Scope) error { + out.Decommissioned = in.Decommissioned + return nil +} + +// Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec is an autogenerated conversion function. +func Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in *PilotCassandraSpec, out *navigator.PilotCassandraSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in, out, s) +} + +func autoConvert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in *navigator.PilotCassandraSpec, out *PilotCassandraSpec, s conversion.Scope) error { + out.Decommissioned = in.Decommissioned + return nil +} + +// Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec is an autogenerated conversion function. +func Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in *navigator.PilotCassandraSpec, out *PilotCassandraSpec, s conversion.Scope) error { + return autoConvert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in, out, s) +} + func autoConvert_v1alpha1_PilotCondition_To_navigator_PilotCondition(in *PilotCondition, out *navigator.PilotCondition, s conversion.Scope) error { out.Type = navigator.PilotConditionType(in.Type) out.Status = navigator.ConditionStatus(in.Status) @@ -645,6 +671,24 @@ func Convert_navigator_PilotCondition_To_v1alpha1_PilotCondition(in *navigator.P return autoConvert_navigator_PilotCondition_To_v1alpha1_PilotCondition(in, out, s) } +func autoConvert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in *PilotElasticsearchSpec, out *navigator.PilotElasticsearchSpec, s conversion.Scope) error { + return nil +} + +// Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec is an autogenerated conversion function. +func Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in *PilotElasticsearchSpec, out *navigator.PilotElasticsearchSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in, out, s) +} + +func autoConvert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in *navigator.PilotElasticsearchSpec, out *PilotElasticsearchSpec, s conversion.Scope) error { + return nil +} + +// Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec is an autogenerated conversion function. +func Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in *navigator.PilotElasticsearchSpec, out *PilotElasticsearchSpec, s conversion.Scope) error { + return autoConvert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in, out, s) +} + func autoConvert_v1alpha1_PilotList_To_navigator_PilotList(in *PilotList, out *navigator.PilotList, s conversion.Scope) error { out.ListMeta = in.ListMeta out.Items = *(*[]navigator.Pilot)(unsafe.Pointer(&in.Items)) @@ -668,6 +712,8 @@ func Convert_navigator_PilotList_To_v1alpha1_PilotList(in *navigator.PilotList, } func autoConvert_v1alpha1_PilotSpec_To_navigator_PilotSpec(in *PilotSpec, out *navigator.PilotSpec, s conversion.Scope) error { + out.Elasticsearch = (*navigator.PilotElasticsearchSpec)(unsafe.Pointer(in.Elasticsearch)) + out.Cassandra = (*navigator.PilotCassandraSpec)(unsafe.Pointer(in.Cassandra)) return nil } @@ -677,6 +723,8 @@ func Convert_v1alpha1_PilotSpec_To_navigator_PilotSpec(in *PilotSpec, out *navig } func autoConvert_navigator_PilotSpec_To_v1alpha1_PilotSpec(in *navigator.PilotSpec, out *PilotSpec, s conversion.Scope) error { + out.Elasticsearch = (*PilotElasticsearchSpec)(unsafe.Pointer(in.Elasticsearch)) + out.Cassandra = (*PilotCassandraSpec)(unsafe.Pointer(in.Cassandra)) return nil } diff --git a/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go index f57b2d88c..7591c5e9c 100644 --- a/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go @@ -577,7 +577,7 @@ func (in *Pilot) DeepCopyInto(out *Pilot) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } @@ -601,6 +601,22 @@ func (in *Pilot) DeepCopyObject() runtime.Object { } } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PilotCassandraSpec) DeepCopyInto(out *PilotCassandraSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotCassandraSpec. +func (in *PilotCassandraSpec) DeepCopy() *PilotCassandraSpec { + if in == nil { + return nil + } + out := new(PilotCassandraSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotCondition) DeepCopyInto(out *PilotCondition) { *out = *in @@ -618,6 +634,22 @@ func (in *PilotCondition) DeepCopy() *PilotCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PilotElasticsearchSpec) DeepCopyInto(out *PilotElasticsearchSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotElasticsearchSpec. +func (in *PilotElasticsearchSpec) DeepCopy() *PilotElasticsearchSpec { + if in == nil { + return nil + } + out := new(PilotElasticsearchSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotList) DeepCopyInto(out *PilotList) { *out = *in @@ -655,6 +687,24 @@ func (in *PilotList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { *out = *in + if in.Elasticsearch != nil { + in, out := &in.Elasticsearch, &out.Elasticsearch + if *in == nil { + *out = nil + } else { + *out = new(PilotElasticsearchSpec) + **out = **in + } + } + if in.Cassandra != nil { + in, out := &in.Cassandra, &out.Cassandra + if *in == nil { + *out = nil + } else { + *out = new(PilotCassandraSpec) + **out = **in + } + } return } diff --git a/pkg/apis/navigator/zz_generated.deepcopy.go b/pkg/apis/navigator/zz_generated.deepcopy.go index 6a90f2e70..4a26fb3ef 100644 --- a/pkg/apis/navigator/zz_generated.deepcopy.go +++ b/pkg/apis/navigator/zz_generated.deepcopy.go @@ -577,7 +577,7 @@ func (in *Pilot) DeepCopyInto(out *Pilot) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } @@ -601,6 +601,22 @@ func (in *Pilot) DeepCopyObject() runtime.Object { } } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PilotCassandraSpec) DeepCopyInto(out *PilotCassandraSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotCassandraSpec. +func (in *PilotCassandraSpec) DeepCopy() *PilotCassandraSpec { + if in == nil { + return nil + } + out := new(PilotCassandraSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotCondition) DeepCopyInto(out *PilotCondition) { *out = *in @@ -618,6 +634,22 @@ func (in *PilotCondition) DeepCopy() *PilotCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PilotElasticsearchSpec) DeepCopyInto(out *PilotElasticsearchSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotElasticsearchSpec. +func (in *PilotElasticsearchSpec) DeepCopy() *PilotElasticsearchSpec { + if in == nil { + return nil + } + out := new(PilotElasticsearchSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotList) DeepCopyInto(out *PilotList) { *out = *in @@ -655,6 +687,24 @@ func (in *PilotList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { *out = *in + if in.Elasticsearch != nil { + in, out := &in.Elasticsearch, &out.Elasticsearch + if *in == nil { + *out = nil + } else { + *out = new(PilotElasticsearchSpec) + **out = **in + } + } + if in.Cassandra != nil { + in, out := &in.Cassandra, &out.Cassandra + if *in == nil { + *out = nil + } else { + *out = new(PilotCassandraSpec) + **out = **in + } + } return } diff --git a/pkg/controllers/cassandra/util/util.go b/pkg/controllers/cassandra/util/util.go index 3e3436452..1ee8786ec 100644 --- a/pkg/controllers/cassandra/util/util.go +++ b/pkg/controllers/cassandra/util/util.go @@ -66,6 +66,18 @@ func SelectorForCluster(c *v1alpha1.CassandraCluster) (labels.Selector, error) { return labels.NewSelector().Add(*clusterNameReq), nil } +func SelectorForNodePool(c *v1alpha1.CassandraCluster, poolName string) (labels.Selector, error) { + nodePoolNameReq, err := labels.NewRequirement(v1alpha1.CassandraNodePoolNameLabel, selection.Equals, []string{poolName}) + if err != nil { + return nil, err + } + clusterSelector, err := SelectorForCluster(c) + if err != nil { + return nil, err + } + return clusterSelector.Add(*nodePoolNameReq), nil +} + func NodePoolLabels( c *v1alpha1.CassandraCluster, poolName string, diff --git a/pkg/pilot/cassandra/v3/pilot.go b/pkg/pilot/cassandra/v3/pilot.go index 817d9c0e9..a9634bf7f 100644 --- a/pkg/pilot/cassandra/v3/pilot.go +++ b/pkg/pilot/cassandra/v3/pilot.go @@ -30,17 +30,20 @@ type Pilot struct { // a reference to the GenericPilot for this Pilot genericPilot *genericpilot.GenericPilot nodeTool nodetool.Interface + + decommissionInProgress bool } func NewPilot(opts *PilotOptions) (*Pilot, error) { pilotInformer := opts.sharedInformerFactory.Navigator().V1alpha1().Pilots() p := &Pilot{ - Options: opts, - navigatorClient: opts.navigatorClientset, - pilotLister: pilotInformer.Lister(), - pilotInformerSynced: pilotInformer.Informer().HasSynced, - nodeTool: opts.nodeTool, + Options: opts, + navigatorClient: opts.navigatorClientset, + pilotLister: pilotInformer.Lister(), + pilotInformerSynced: pilotInformer.Informer().HasSynced, + nodeTool: opts.nodeTool, + decommissionInProgress: false, } // hack to test the seedprovider, this should use whatever pattern is decided upon here: From ef31e77506cd0d39bee107d8eb0128acdc90db74 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Fri, 16 Mar 2018 09:46:34 +0000 Subject: [PATCH 2/9] First pass at scaleIn action --- pkg/controllers/cassandra/actions/scalein.go | 140 ++++++++++++++++ .../cassandra/actions/scalein_test.go | 158 ++++++++++++++++++ pkg/controllers/cassandra/cluster_control.go | 7 + pkg/pilot/cassandra/v3/pilot.go | 42 ++++- 4 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 pkg/controllers/cassandra/actions/scalein.go create mode 100644 pkg/controllers/cassandra/actions/scalein_test.go diff --git a/pkg/controllers/cassandra/actions/scalein.go b/pkg/controllers/cassandra/actions/scalein.go new file mode 100644 index 000000000..a290fefe6 --- /dev/null +++ b/pkg/controllers/cassandra/actions/scalein.go @@ -0,0 +1,140 @@ +package actions + +import ( + "fmt" + + apps "k8s.io/api/apps/v1beta1" + corev1 "k8s.io/api/core/v1" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilerror "k8s.io/apimachinery/pkg/util/errors" + + "github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1" + "github.com/jetstack/navigator/pkg/controllers" + "github.com/jetstack/navigator/pkg/controllers/cassandra/nodepool" + "github.com/jetstack/navigator/pkg/controllers/cassandra/util" +) + +type ScaleIn struct { + Cluster *v1alpha1.CassandraCluster + NodePool *v1alpha1.CassandraClusterNodePool +} + +var _ controllers.Action = &ScaleIn{} + +func (a *ScaleIn) Name() string { + return "ScaleIn" +} + +func (a *ScaleIn) Execute(s *controllers.State) error { + ss := nodepool.StatefulSetForCluster(a.Cluster, a.NodePool) + ss, err := s.StatefulSetLister.StatefulSets(ss.Namespace).Get(ss.Name) + if err != nil { + return err + } + ss = ss.DeepCopy() + if *ss.Spec.Replicas > a.NodePool.Replicas { + pilots, err := pilotsForStatefulSet(s, a.Cluster, a.NodePool, ss) + if err != nil { + return err + } + + allDecommissioned := true + + nPilotsToRemove := int(*ss.Spec.Replicas - a.NodePool.Replicas) + for i := 0; i < nPilotsToRemove; i++ { + p := pilots[len(pilots)-i].DeepCopy() + if p.Spec.Cassandra == nil { + p.Spec.Cassandra = &v1alpha1.PilotCassandraSpec{} + } + + if !p.Spec.Cassandra.Decommissioned { + p.Spec.Cassandra.Decommissioned = true + _, err := s.NavigatorClientset.NavigatorV1alpha1().Pilots(p.Namespace).Update(p) + if err == nil { + s.Recorder.Eventf( + p, + corev1.EventTypeNormal, + a.Name(), + "Marked cassandra pilot %s for decommission", p.Name, + ) + } + } + + if p.Status.Cassandra == nil { + p.Status.Cassandra = &v1alpha1.CassandraPilotStatus{} + } + + if !p.Status.Cassandra.Decommissioned { + allDecommissioned = false + } + } + + if allDecommissioned { + ss.Spec.Replicas = &a.NodePool.Replicas + _, err = s.Clientset.AppsV1beta1().StatefulSets(ss.Namespace).Update(ss) + if err == nil { + s.Recorder.Eventf( + a.Cluster, + corev1.EventTypeNormal, + a.Name(), + "All cassandra nodes decommissioned, scaling cluster to size %d", a.NodePool.Replicas, + ) + } + } + } + if *ss.Spec.Replicas < a.NodePool.Replicas { + return fmt.Errorf( + "the NodePool.Replicas value (%d) "+ + "is greater than the existing StatefulSet.Replicas value (%d)", + a.NodePool.Replicas, *ss.Spec.Replicas, + ) + } + return nil +} + +func pilotNameForStatefulSetReplica(setName string, replica int32) string { + return fmt.Sprintf("%s-%d", setName, replica) +} + +func pilotsForStatefulSet(state *controllers.State, cluster *v1alpha1.CassandraCluster, nodePool *v1alpha1.CassandraClusterNodePool, statefulSet *apps.StatefulSet) ([]*v1alpha1.Pilot, error) { + replicasPtr := statefulSet.Spec.Replicas + if replicasPtr == nil { + return nil, fmt.Errorf("statefulset.spec.replicas cannot be nil") + } + replicas := *replicasPtr + // TODO: read the cluster name and node pool name from the statefulset + // metadata instead of the Scale structure so we can make this a package + // function. For now, this way is safest until we are sure these + // labels are going to remain stable + selector, err := util.SelectorForNodePool(cluster, nodePool.Name) + if err != nil { + return nil, err + } + pilots, err := state.PilotLister.Pilots(cluster.Namespace).List(selector) + if err != nil { + return nil, err + } + var errs []error + var output []*v1alpha1.Pilot +Outer: + for i := int32(0); i < replicas; i++ { + pilotName := pilotNameForStatefulSetReplica(statefulSet.Name, i) + for _, p := range pilots { + if p.Name == pilotName { + output = append(output, p) + continue Outer + } + } + errs = append(errs, fmt.Errorf("pilot %q not found", pilotName)) + } + if len(errs) > 0 { + return nil, &k8sErrors.StatusError{ + ErrStatus: metav1.Status{ + Message: utilerror.NewAggregate(errs).Error(), + Reason: metav1.StatusReasonNotFound, + }, + } + } + return output, nil +} diff --git a/pkg/controllers/cassandra/actions/scalein_test.go b/pkg/controllers/cassandra/actions/scalein_test.go new file mode 100644 index 000000000..c27798a41 --- /dev/null +++ b/pkg/controllers/cassandra/actions/scalein_test.go @@ -0,0 +1,158 @@ +package actions_test + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/jetstack/navigator/internal/test/unit/framework" + "github.com/jetstack/navigator/internal/test/util/generate" + "github.com/jetstack/navigator/pkg/controllers/cassandra/actions" +) + +func TestScaleIn(t *testing.T) { + type testT struct { + kubeObjects []runtime.Object + navObjects []runtime.Object + cluster generate.CassandraClusterConfig + nodePool generate.CassandraClusterNodePoolConfig + expectedStatefulSet *generate.StatefulSetConfig + expectedErr bool + mutator func(*framework.StateFixture) + } + tests := map[string]testT{ + "Error if StatefulSet not listed": { + cluster: generate.CassandraClusterConfig{ + Name: "cluster1", + Namespace: "ns1", + }, + nodePool: generate.CassandraClusterNodePoolConfig{ + Name: "pool1", + Replicas: 123, + }, + expectedErr: true, + }, + "Error if clientset.Update fails (e.g. listed but not found)": { + kubeObjects: []runtime.Object{ + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: int32Ptr(122), + }, + ), + }, + cluster: generate.CassandraClusterConfig{ + Name: "cluster1", + Namespace: "ns1", + }, + nodePool: generate.CassandraClusterNodePoolConfig{ + Name: "pool1", + Replicas: 123, + }, + expectedErr: true, + mutator: func(f *framework.StateFixture) { + err := f.KubeClient(). + AppsV1beta1(). + StatefulSets("ns1"). + Delete("cass-cluster1-pool1", &metav1.DeleteOptions{}) + if err != nil { + f.T.Fatal(err) + } + }, + }, + "Idempotent: No error if ReplicaCount already matches the actual ReplicaCount": { + kubeObjects: []runtime.Object{ + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: int32Ptr(124), + }, + ), + }, + cluster: generate.CassandraClusterConfig{ + Name: "cluster1", + Namespace: "ns1", + }, + nodePool: generate.CassandraClusterNodePoolConfig{ + Name: "pool1", + Replicas: 124, + }, + expectedStatefulSet: &generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: int32Ptr(124), + }, + expectedErr: false, + }, + "The replicas count is decremented": { + kubeObjects: []runtime.Object{ + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: int32Ptr(125), + }, + ), + }, + cluster: generate.CassandraClusterConfig{ + Name: "cluster1", + Namespace: "ns1", + }, + nodePool: generate.CassandraClusterNodePoolConfig{ + Name: "pool1", + Replicas: 120, + }, + expectedStatefulSet: &generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: int32Ptr(120), + }, + }, + } + + for name, test := range tests { + t.Run( + name, + func(t *testing.T) { + fixture := &framework.StateFixture{ + T: t, + KubeObjects: test.kubeObjects, + NavigatorObjects: test.navObjects, + } + fixture.Start() + defer fixture.Stop() + state := fixture.State() + if test.mutator != nil { + test.mutator(fixture) + } + a := &actions.ScaleIn{ + Cluster: generate.CassandraCluster(test.cluster), + NodePool: generate.CassandraClusterNodePool(test.nodePool), + } + err := a.Execute(state) + if err != nil { + t.Logf("The error returned by Execute was: %s", err) + } + if !test.expectedErr && err != nil { + t.Errorf("Unexpected error: %s", err) + } + if test.expectedErr && err == nil { + t.Errorf("Expected an error") + } + if test.expectedStatefulSet != nil { + actualStatefulSet, err := fixture.KubeClient(). + AppsV1beta1(). + StatefulSets(test.expectedStatefulSet.Namespace). + Get(test.expectedStatefulSet.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Unexpected error retrieving statefulset: %v", err) + } + generate.AssertStatefulSetMatches(t, *test.expectedStatefulSet, actualStatefulSet) + } + }, + ) + } +} diff --git a/pkg/controllers/cassandra/cluster_control.go b/pkg/controllers/cassandra/cluster_control.go index a3ec9ad78..ba7497bf9 100644 --- a/pkg/controllers/cassandra/cluster_control.go +++ b/pkg/controllers/cassandra/cluster_control.go @@ -212,6 +212,13 @@ func NextAction(c *v1alpha1.CassandraCluster) controllers.Action { NodePool: &np, } } + + if np.Replicas < nps.ReadyReplicas { + return &actions.ScaleIn{ + Cluster: c, + NodePool: &np, + } + } } return nil } diff --git a/pkg/pilot/cassandra/v3/pilot.go b/pkg/pilot/cassandra/v3/pilot.go index a9634bf7f..07f919ebf 100644 --- a/pkg/pilot/cassandra/v3/pilot.go +++ b/pkg/pilot/cassandra/v3/pilot.go @@ -89,6 +89,18 @@ func (p *Pilot) syncFunc(pilot *v1alpha1.Pilot) error { pilot.Status.Cassandra = &v1alpha1.CassandraPilotStatus{} } + if pilot.Spec.Cassandra != nil { + if pilot.Spec.Cassandra.Decommissioned { + p.decommissionInProgress = true + err := p.decommission() + if err != nil { + glog.Errorf("error while decommissioning cassandra node: %s", err) + } else { + pilot.Status.Cassandra.Decommissioned = true + } + } + } + version, err := p.nodeTool.Version() if err != nil { pilot.Status.Cassandra.Version = nil @@ -98,6 +110,30 @@ func (p *Pilot) syncFunc(pilot *v1alpha1.Pilot) error { return nil } +func run(args ...string) error { + cmd := exec.Command(args[0], args[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + os.Unsetenv("JVM_OPTS") + return cmd.Run() +} + +func (p *Pilot) decommission() error { + nodes, err := p.nodeTool.Status() + if err != nil { + return err + } + localNode := nodes.LocalNode() + + // if node is operational and working normally, decommission node + if localNode.State == nodetool.NodeStateNormal { + glog.Info("about to decomission node") + return run("nodetool", "decommission") + } + + return nil +} + func localNodeUpAndNormal(nodeTool nodetool.Interface) error { nodes, err := nodeTool.Status() if err != nil { @@ -110,7 +146,7 @@ func localNodeUpAndNormal(nodeTool nodetool.Interface) error { if localNode.Status != nodetool.NodeStatusUp { return fmt.Errorf("Unexpected local node status: %v", localNode.Status) } - if localNode.State != nodetool.NodeStateNormal { + if localNode.State != nodetool.NodeStateNormal && localNode.State != nodetool.NodeStateLeaving { return fmt.Errorf("Unexpected local node state: %v", localNode.State) } return nil @@ -129,6 +165,10 @@ func (p *Pilot) ReadinessCheck() error { } func (p *Pilot) LivenessCheck() error { + if p.decommissionInProgress || true { + glog.Info("decommission in progress, reporting success for liveness") + return nil + } _, err := p.nodeTool.Status() return err } From b19d79212e9128af6a26478ef60469c837d07eaf Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Tue, 20 Mar 2018 17:49:47 +0000 Subject: [PATCH 3/9] Add pilot informer --- pkg/controllers/cassandra/cassandra.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/controllers/cassandra/cassandra.go b/pkg/controllers/cassandra/cassandra.go index 43d177644..873fc8488 100644 --- a/pkg/controllers/cassandra/cassandra.go +++ b/pkg/controllers/cassandra/cassandra.go @@ -95,6 +95,14 @@ func NewCassandra( WorkFunc: cc.handleObject, }, ) + + // An event handler to trigger status updates when pilots change + pilots.Informer().AddEventHandler( + &controllers.BlockingEventHandler{ + WorkFunc: cc.handleObject, + }, + ) + cc.cassLister = cassClusters.Lister() cc.statefulSetLister = statefulSets.Lister() cc.cassListerSynced = cassClusters.Informer().HasSynced From b81c229d4dfd51675c491d4a55e2885926242aa0 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Tue, 20 Mar 2018 17:50:58 +0000 Subject: [PATCH 4/9] Perform scalein based on statefulset size --- pkg/controllers/cassandra/cassandra.go | 8 ++++--- pkg/controllers/cassandra/cluster_control.go | 25 ++++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/pkg/controllers/cassandra/cassandra.go b/pkg/controllers/cassandra/cassandra.go index 873fc8488..e5ecf4853 100644 --- a/pkg/controllers/cassandra/cassandra.go +++ b/pkg/controllers/cassandra/cassandra.go @@ -161,9 +161,11 @@ func NewCassandra( ), recorder, &controllers.State{ - Clientset: kubeClient, - StatefulSetLister: statefulSets.Lister(), - Recorder: recorder, + Clientset: kubeClient, + NavigatorClientset: naviClient, + StatefulSetLister: statefulSets.Lister(), + PilotLister: pilots.Lister(), + Recorder: recorder, }, ) cc.recorder = recorder diff --git a/pkg/controllers/cassandra/cluster_control.go b/pkg/controllers/cassandra/cluster_control.go index ba7497bf9..64418b078 100644 --- a/pkg/controllers/cassandra/cluster_control.go +++ b/pkg/controllers/cassandra/cluster_control.go @@ -3,6 +3,7 @@ package cassandra import ( "github.com/golang/glog" apiv1 "k8s.io/api/core/v1" + "k8s.io/client-go/listers/apps/v1beta1" "k8s.io/client-go/tools/record" v1alpha1 "github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1" @@ -15,6 +16,7 @@ import ( "github.com/jetstack/navigator/pkg/controllers/cassandra/seedlabeller" "github.com/jetstack/navigator/pkg/controllers/cassandra/service" "github.com/jetstack/navigator/pkg/controllers/cassandra/serviceaccount" + "github.com/jetstack/navigator/pkg/controllers/cassandra/util" ) const ( @@ -170,7 +172,10 @@ func (e *defaultCassandraClusterControl) Sync(c *v1alpha1.CassandraCluster) erro return err } - a := NextAction(c) + a, err := NextAction(c, e.state.StatefulSetLister) + if err != nil { + return c.Status, err + } if a != nil { err = a.Execute(e.state) if err != nil { @@ -194,14 +199,14 @@ func (e *defaultCassandraClusterControl) Sync(c *v1alpha1.CassandraCluster) erro return nil } -func NextAction(c *v1alpha1.CassandraCluster) controllers.Action { +func NextAction(c *v1alpha1.CassandraCluster, statefulSetLister v1beta1.StatefulSetLister) (controllers.Action, error) { for _, np := range c.Spec.NodePools { _, found := c.Status.NodePools[np.Name] if !found { return &actions.CreateNodePool{ Cluster: c, NodePool: &np, - } + }, nil } } for _, np := range c.Spec.NodePools { @@ -210,15 +215,21 @@ func NextAction(c *v1alpha1.CassandraCluster) controllers.Action { return &actions.ScaleOut{ Cluster: c, NodePool: &np, - } + }, nil + } + + statefulSetName := util.NodePoolResourceName(c, &np) + ss, err := statefulSetLister.StatefulSets(c.Namespace).Get(statefulSetName) + if err != nil { + return nil, err } - if np.Replicas < nps.ReadyReplicas { + if np.Replicas < *ss.Spec.Replicas { return &actions.ScaleIn{ Cluster: c, NodePool: &np, - } + }, nil } } - return nil + return nil, nil } From fa9a1833c57a57a1ac276196a21ddeabe7c1973d Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Tue, 20 Mar 2018 17:52:21 +0000 Subject: [PATCH 5/9] Fix pilot selection logic --- pkg/controllers/cassandra/actions/scalein.go | 25 +++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/pkg/controllers/cassandra/actions/scalein.go b/pkg/controllers/cassandra/actions/scalein.go index a290fefe6..654a6a5b3 100644 --- a/pkg/controllers/cassandra/actions/scalein.go +++ b/pkg/controllers/cassandra/actions/scalein.go @@ -39,10 +39,17 @@ func (a *ScaleIn) Execute(s *controllers.State) error { return err } + if len(pilots) <= 1 { + return fmt.Errorf( + "Not enough pilots to scale down: %d", + len(pilots), + ) + } + allDecommissioned := true nPilotsToRemove := int(*ss.Spec.Replicas - a.NodePool.Replicas) - for i := 0; i < nPilotsToRemove; i++ { + for i := 1; i <= nPilotsToRemove; i++ { p := pilots[len(pilots)-i].DeepCopy() if p.Spec.Cassandra == nil { p.Spec.Cassandra = &v1alpha1.PilotCassandraSpec{} @@ -51,14 +58,16 @@ func (a *ScaleIn) Execute(s *controllers.State) error { if !p.Spec.Cassandra.Decommissioned { p.Spec.Cassandra.Decommissioned = true _, err := s.NavigatorClientset.NavigatorV1alpha1().Pilots(p.Namespace).Update(p) - if err == nil { - s.Recorder.Eventf( - p, - corev1.EventTypeNormal, - a.Name(), - "Marked cassandra pilot %s for decommission", p.Name, - ) + if err != nil { + return err } + + s.Recorder.Eventf( + p, + corev1.EventTypeNormal, + a.Name(), + "Marked cassandra pilot %s for decommission", p.Name, + ) } if p.Status.Cassandra == nil { From 22461c6f5c0fa940ca904f85867293bb2cf90705 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Wed, 9 May 2018 13:14:21 +0100 Subject: [PATCH 6/9] Update changed types --- pkg/controllers/cassandra/actions/scalein.go | 8 +++---- .../cassandra/actions/scalein_test.go | 22 ++++++++++++++----- pkg/controllers/cassandra/cluster_control.go | 4 ++-- .../cassandra/cluster_control_test.go | 5 ++++- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/pkg/controllers/cassandra/actions/scalein.go b/pkg/controllers/cassandra/actions/scalein.go index 654a6a5b3..078743119 100644 --- a/pkg/controllers/cassandra/actions/scalein.go +++ b/pkg/controllers/cassandra/actions/scalein.go @@ -33,7 +33,7 @@ func (a *ScaleIn) Execute(s *controllers.State) error { return err } ss = ss.DeepCopy() - if *ss.Spec.Replicas > a.NodePool.Replicas { + if *ss.Spec.Replicas > *a.NodePool.Replicas { pilots, err := pilotsForStatefulSet(s, a.Cluster, a.NodePool, ss) if err != nil { return err @@ -48,7 +48,7 @@ func (a *ScaleIn) Execute(s *controllers.State) error { allDecommissioned := true - nPilotsToRemove := int(*ss.Spec.Replicas - a.NodePool.Replicas) + nPilotsToRemove := int(*ss.Spec.Replicas - *a.NodePool.Replicas) for i := 1; i <= nPilotsToRemove; i++ { p := pilots[len(pilots)-i].DeepCopy() if p.Spec.Cassandra == nil { @@ -80,7 +80,7 @@ func (a *ScaleIn) Execute(s *controllers.State) error { } if allDecommissioned { - ss.Spec.Replicas = &a.NodePool.Replicas + ss.Spec.Replicas = a.NodePool.Replicas _, err = s.Clientset.AppsV1beta1().StatefulSets(ss.Namespace).Update(ss) if err == nil { s.Recorder.Eventf( @@ -92,7 +92,7 @@ func (a *ScaleIn) Execute(s *controllers.State) error { } } } - if *ss.Spec.Replicas < a.NodePool.Replicas { + if *ss.Spec.Replicas < *a.NodePool.Replicas { return fmt.Errorf( "the NodePool.Replicas value (%d) "+ "is greater than the existing StatefulSet.Replicas value (%d)", diff --git a/pkg/controllers/cassandra/actions/scalein_test.go b/pkg/controllers/cassandra/actions/scalein_test.go index c27798a41..2072cf51d 100644 --- a/pkg/controllers/cassandra/actions/scalein_test.go +++ b/pkg/controllers/cassandra/actions/scalein_test.go @@ -3,6 +3,8 @@ package actions_test import ( "testing" + "github.com/jetstack/navigator/pkg/util/ptr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -39,7 +41,7 @@ func TestScaleIn(t *testing.T) { generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: int32Ptr(122), + Replicas: ptr.Int32(122), }, ), }, @@ -68,7 +70,7 @@ func TestScaleIn(t *testing.T) { generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: int32Ptr(124), + Replicas: ptr.Int32(124), }, ), }, @@ -83,7 +85,7 @@ func TestScaleIn(t *testing.T) { expectedStatefulSet: &generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: int32Ptr(124), + Replicas: ptr.Int32(124), }, expectedErr: false, }, @@ -93,7 +95,7 @@ func TestScaleIn(t *testing.T) { generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: int32Ptr(125), + Replicas: ptr.Int32(125), }, ), }, @@ -108,7 +110,7 @@ func TestScaleIn(t *testing.T) { expectedStatefulSet: &generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: int32Ptr(120), + Replicas: ptr.Int32(120), }, }, } @@ -150,7 +152,15 @@ func TestScaleIn(t *testing.T) { if err != nil { t.Fatalf("Unexpected error retrieving statefulset: %v", err) } - generate.AssertStatefulSetMatches(t, *test.expectedStatefulSet, actualStatefulSet) + if err != nil { + t.Fatalf("Unexpected error retrieving statefulset: %v", err) + } + if *test.expectedStatefulSet.Replicas != *actualStatefulSet.Spec.Replicas { + t.Errorf( + "Unexpected replica count. Expected: %d. Actual: %d", + *test.expectedStatefulSet.Replicas, *actualStatefulSet.Spec.Replicas, + ) + } } }, ) diff --git a/pkg/controllers/cassandra/cluster_control.go b/pkg/controllers/cassandra/cluster_control.go index 64418b078..780419cf0 100644 --- a/pkg/controllers/cassandra/cluster_control.go +++ b/pkg/controllers/cassandra/cluster_control.go @@ -174,7 +174,7 @@ func (e *defaultCassandraClusterControl) Sync(c *v1alpha1.CassandraCluster) erro a, err := NextAction(c, e.state.StatefulSetLister) if err != nil { - return c.Status, err + return err } if a != nil { err = a.Execute(e.state) @@ -224,7 +224,7 @@ func NextAction(c *v1alpha1.CassandraCluster, statefulSetLister v1beta1.Stateful return nil, err } - if np.Replicas < *ss.Spec.Replicas { + if *np.Replicas < *ss.Spec.Replicas { return &actions.ScaleIn{ Cluster: c, NodePool: &np, diff --git a/pkg/controllers/cassandra/cluster_control_test.go b/pkg/controllers/cassandra/cluster_control_test.go index f44ca542c..70eb0c809 100644 --- a/pkg/controllers/cassandra/cluster_control_test.go +++ b/pkg/controllers/cassandra/cluster_control_test.go @@ -49,7 +49,10 @@ func CassandraClusterStatusSummary(c *v1alpha1.CassandraCluster) string { func TestNextAction(t *testing.T) { f := func(c *v1alpha1.CassandraCluster) bool { t.Log(CassandraClusterSummary(c)) - a := cassandra.NextAction(c) + a, err := cassandra.NextAction(c) + if err != nil { + t.Errorf("error calculating next action: %v", err) + } if a != nil { t.Log("Action:", a.Name()) } else { From 51df0d19d9338de932bb05cccf63d0b15bc92c2f Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Wed, 9 May 2018 17:16:32 +0100 Subject: [PATCH 7/9] Fix scalein_test --- internal/test/util/generate/generate.go | 43 +++++++++-- .../cassandra/actions/scalein_test.go | 71 +++++++++++++++++-- .../cassandra/cluster_control_test.go | 24 ++++++- .../elasticsearch/actions/scale_test.go | 28 ++++---- .../actions/update_version_test.go | 36 +++++----- 5 files changed, 160 insertions(+), 42 deletions(-) diff --git a/internal/test/util/generate/generate.go b/internal/test/util/generate/generate.go index 2723e51ff..66f334728 100644 --- a/internal/test/util/generate/generate.go +++ b/internal/test/util/generate/generate.go @@ -11,13 +11,15 @@ import ( ) type PilotConfig struct { - Name, Namespace string - Cluster, NodePool string - Documents *int64 - Version string + Name, Namespace string + Cluster, NodePool string + Documents *int64 + Version string + Decommissioned bool + DecommissionedStatus bool } -func Pilot(c PilotConfig) *v1alpha1.Pilot { +func EsPilot(c PilotConfig) *v1alpha1.Pilot { if c.Namespace == "" { c.Namespace = "default" } @@ -43,6 +45,37 @@ func Pilot(c PilotConfig) *v1alpha1.Pilot { } } +func CassPilot(c PilotConfig) *v1alpha1.Pilot { + if c.Namespace == "" { + c.Namespace = "default" + } + labels := map[string]string{} + labels[v1alpha1.CassandraClusterNameLabel] = c.Cluster + labels[v1alpha1.CassandraNodePoolNameLabel] = c.NodePool + var v *version.Version + if c.Version != "" { + v = version.New(c.Version) + } + return &v1alpha1.Pilot{ + ObjectMeta: metav1.ObjectMeta{ + Name: c.Name, + Namespace: c.Namespace, + Labels: labels, + }, + Spec: v1alpha1.PilotSpec{ + Cassandra: &v1alpha1.PilotCassandraSpec{ + Decommissioned: c.Decommissioned, + }, + }, + Status: v1alpha1.PilotStatus{ + Cassandra: &v1alpha1.CassandraPilotStatus{ + Version: v, + Decommissioned: c.DecommissionedStatus, + }, + }, + } +} + type ClusterConfig struct { Name, Namespace string NodePools []v1alpha1.ElasticsearchClusterNodePool diff --git a/pkg/controllers/cassandra/actions/scalein_test.go b/pkg/controllers/cassandra/actions/scalein_test.go index 2072cf51d..789fc9760 100644 --- a/pkg/controllers/cassandra/actions/scalein_test.go +++ b/pkg/controllers/cassandra/actions/scalein_test.go @@ -89,13 +89,75 @@ func TestScaleIn(t *testing.T) { }, expectedErr: false, }, - "The replicas count is decremented": { + "The replicas count is decremented without successfully decommissioned pilots": { kubeObjects: []runtime.Object{ generate.StatefulSet( generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: ptr.Int32(125), + Replicas: ptr.Int32(2), + }, + ), + }, + navObjects: []runtime.Object{ + generate.CassPilot( + generate.PilotConfig{ + Name: "cass-cluster1-pool1-0", + Namespace: "ns1", + NodePool: "pool1", + Cluster: "cluster1", + }, + ), + generate.CassPilot( + generate.PilotConfig{ + Name: "cass-cluster1-pool1-1", + Namespace: "ns1", + NodePool: "pool1", + Cluster: "cluster1", + }, + ), + }, + cluster: generate.CassandraClusterConfig{ + Name: "cluster1", + Namespace: "ns1", + }, + nodePool: generate.CassandraClusterNodePoolConfig{ + Name: "pool1", + Replicas: 1, + }, + expectedStatefulSet: &generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: ptr.Int32(2), + }, + }, + "The replicas count is decremented with successfully decommissioned pilots": { + kubeObjects: []runtime.Object{ + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: ptr.Int32(2), + }, + ), + }, + navObjects: []runtime.Object{ + generate.CassPilot( + generate.PilotConfig{ + Name: "cass-cluster1-pool1-0", + Namespace: "ns1", + NodePool: "pool1", + Cluster: "cluster1", + }, + ), + generate.CassPilot( + generate.PilotConfig{ + Name: "cass-cluster1-pool1-1", + Namespace: "ns1", + NodePool: "pool1", + Cluster: "cluster1", + DecommissionedStatus: true, + Decommissioned: true, }, ), }, @@ -105,12 +167,12 @@ func TestScaleIn(t *testing.T) { }, nodePool: generate.CassandraClusterNodePoolConfig{ Name: "pool1", - Replicas: 120, + Replicas: 1, }, expectedStatefulSet: &generate.StatefulSetConfig{ Name: "cass-cluster1-pool1", Namespace: "ns1", - Replicas: ptr.Int32(120), + Replicas: ptr.Int32(1), }, }, } @@ -130,6 +192,7 @@ func TestScaleIn(t *testing.T) { if test.mutator != nil { test.mutator(fixture) } + a := &actions.ScaleIn{ Cluster: generate.CassandraCluster(test.cluster), NodePool: generate.CassandraClusterNodePool(test.nodePool), diff --git a/pkg/controllers/cassandra/cluster_control_test.go b/pkg/controllers/cassandra/cluster_control_test.go index 70eb0c809..d6946e171 100644 --- a/pkg/controllers/cassandra/cluster_control_test.go +++ b/pkg/controllers/cassandra/cluster_control_test.go @@ -8,10 +8,15 @@ import ( "testing" "testing/quick" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/jetstack/navigator/internal/test/unit/framework" + "github.com/jetstack/navigator/internal/test/util/generate" v1alpha1 "github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1" "github.com/jetstack/navigator/pkg/controllers/cassandra" "github.com/jetstack/navigator/pkg/controllers/cassandra/actions" casstesting "github.com/jetstack/navigator/pkg/controllers/cassandra/testing" + "github.com/jetstack/navigator/pkg/util/ptr" ) func CassandraClusterSummary(c *v1alpha1.CassandraCluster) string { @@ -49,7 +54,24 @@ func CassandraClusterStatusSummary(c *v1alpha1.CassandraCluster) string { func TestNextAction(t *testing.T) { f := func(c *v1alpha1.CassandraCluster) bool { t.Log(CassandraClusterSummary(c)) - a, err := cassandra.NextAction(c) + + fixture := &framework.StateFixture{ + T: t, + KubeObjects: []runtime.Object{ + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-pool1", + Namespace: "ns1", + Replicas: ptr.Int32(8), + }, + ), + }, + } + fixture.Start() + defer fixture.Stop() + state := fixture.State() + + a, err := cassandra.NextAction(c, state.StatefulSetLister) if err != nil { t.Errorf("error calculating next action: %v", err) } diff --git a/pkg/controllers/elasticsearch/actions/scale_test.go b/pkg/controllers/elasticsearch/actions/scale_test.go index 8914cf462..f4aa17ee3 100644 --- a/pkg/controllers/elasticsearch/actions/scale_test.go +++ b/pkg/controllers/elasticsearch/actions/scale_test.go @@ -35,9 +35,9 @@ func TestScale(t *testing.T) { generate.StatefulSet(generate.StatefulSetConfig{Name: "es-test-data", Replicas: ptr.Int32(3)}), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(2)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(2)}), }, cluster: clusterWithNodePools("test", nodePoolWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData)), nodePool: nodePoolPtrWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData), @@ -51,9 +51,9 @@ func TestScale(t *testing.T) { generate.StatefulSet(generate.StatefulSetConfig{Name: "es-test-data", Replicas: ptr.Int32(3)}), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(1)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(1)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(1)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(1)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), }, cluster: clusterWithNodePools("test", nodePoolWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData)), nodePool: nodePoolPtrWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData), @@ -67,8 +67,8 @@ func TestScale(t *testing.T) { generate.StatefulSet(generate.StatefulSetConfig{Name: "es-test-data", Replicas: ptr.Int32(3)}), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), }, cluster: clusterWithNodePools("test", nodePoolWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData)), nodePool: nodePoolPtrWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData), @@ -80,9 +80,9 @@ func TestScale(t *testing.T) { "should not error if statefulset doesn't exist": { kubeObjects: []runtime.Object{}, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), }, cluster: clusterWithNodePools("test", nodePoolWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData)), nodePool: nodePoolPtrWithNameReplicasRoles("data", 2, v1alpha1.ElasticsearchRoleData), @@ -96,9 +96,9 @@ func TestScale(t *testing.T) { generate.StatefulSet(generate.StatefulSetConfig{Name: "es-test-data", Replicas: ptr.Int32(3)}), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Documents: ptr.Int64(0)}), }, cluster: clusterWithNodePools("test", nodePoolWithNameReplicasRoles("data", 3, v1alpha1.ElasticsearchRoleData)), nodePool: nodePoolPtrWithNameReplicasRoles("data", 3, v1alpha1.ElasticsearchRoleData), diff --git a/pkg/controllers/elasticsearch/actions/update_version_test.go b/pkg/controllers/elasticsearch/actions/update_version_test.go index 6d2d9d10e..4f4ac4ceb 100644 --- a/pkg/controllers/elasticsearch/actions/update_version_test.go +++ b/pkg/controllers/elasticsearch/actions/update_version_test.go @@ -43,9 +43,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", @@ -84,9 +84,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", @@ -123,9 +123,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", @@ -151,9 +151,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.1"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", @@ -182,9 +182,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.2"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.2"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.2"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.2"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", @@ -223,9 +223,9 @@ func TestUpdateVersion(t *testing.T) { }), }, navObjects: []runtime.Object{ - generate.Pilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), - generate.Pilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-0", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-1", Cluster: "test", NodePool: "data", Version: "6.1.1"}), + generate.EsPilot(generate.PilotConfig{Name: "es-test-data-2", Cluster: "test", NodePool: "data", Version: "6.1.2"}), }, cluster: generate.Cluster(generate.ClusterConfig{ Name: "test", From 7fdbe4ebe31f1fc730a3a8dccbcc4d12f9b75765 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Wed, 9 May 2018 17:33:40 +0100 Subject: [PATCH 8/9] Fix action fuzzing test --- .../cassandra/cluster_control_test.go | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/controllers/cassandra/cluster_control_test.go b/pkg/controllers/cassandra/cluster_control_test.go index d6946e171..c96cb51cd 100644 --- a/pkg/controllers/cassandra/cluster_control_test.go +++ b/pkg/controllers/cassandra/cluster_control_test.go @@ -60,7 +60,35 @@ func TestNextAction(t *testing.T) { KubeObjects: []runtime.Object{ generate.StatefulSet( generate.StatefulSetConfig{ - Name: "cass-cluster1-pool1", + Name: "cass-cluster1-np0", + Namespace: "ns1", + Replicas: ptr.Int32(8), + }, + ), + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-np1", + Namespace: "ns1", + Replicas: ptr.Int32(8), + }, + ), + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-np2", + Namespace: "ns1", + Replicas: ptr.Int32(8), + }, + ), + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-np3", + Namespace: "ns1", + Replicas: ptr.Int32(8), + }, + ), + generate.StatefulSet( + generate.StatefulSetConfig{ + Name: "cass-cluster1-np4", Namespace: "ns1", Replicas: ptr.Int32(8), }, From c162d8d4c44672d85c9f8a17f88268e09a8b6924 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Wed, 9 May 2018 17:49:54 +0100 Subject: [PATCH 9/9] Rename PilotCassandraSpec -> CassandraPilotSpec --- internal/test/util/generate/generate.go | 2 +- pkg/apis/navigator/types.go | 8 +- pkg/apis/navigator/v1alpha1/types.go | 8 +- .../v1alpha1/zz_generated.conversion.go | 92 +++++++++---------- .../v1alpha1/zz_generated.deepcopy.go | 68 +++++++------- pkg/apis/navigator/zz_generated.deepcopy.go | 68 +++++++------- pkg/controllers/cassandra/actions/scalein.go | 2 +- 7 files changed, 124 insertions(+), 124 deletions(-) diff --git a/internal/test/util/generate/generate.go b/internal/test/util/generate/generate.go index 66f334728..72a257426 100644 --- a/internal/test/util/generate/generate.go +++ b/internal/test/util/generate/generate.go @@ -63,7 +63,7 @@ func CassPilot(c PilotConfig) *v1alpha1.Pilot { Labels: labels, }, Spec: v1alpha1.PilotSpec{ - Cassandra: &v1alpha1.PilotCassandraSpec{ + Cassandra: &v1alpha1.CassandraPilotSpec{ Decommissioned: c.Decommissioned, }, }, diff --git a/pkg/apis/navigator/types.go b/pkg/apis/navigator/types.go index c0df810ca..e3d5be622 100644 --- a/pkg/apis/navigator/types.go +++ b/pkg/apis/navigator/types.go @@ -177,8 +177,8 @@ type PilotList struct { } type PilotSpec struct { - Elasticsearch *PilotElasticsearchSpec - Cassandra *PilotCassandraSpec + Elasticsearch *ElasticsearchPilotSpec + Cassandra *CassandraPilotSpec } type PilotPhase string @@ -190,10 +190,10 @@ const ( PilotPhasePostStop PilotPhase = "PostStop" ) -type PilotElasticsearchSpec struct { +type ElasticsearchPilotSpec struct { } -type PilotCassandraSpec struct { +type CassandraPilotSpec struct { Decommissioned bool } diff --git a/pkg/apis/navigator/v1alpha1/types.go b/pkg/apis/navigator/v1alpha1/types.go index 9da5994eb..a1d86b1cd 100644 --- a/pkg/apis/navigator/v1alpha1/types.go +++ b/pkg/apis/navigator/v1alpha1/types.go @@ -329,8 +329,8 @@ type PilotList struct { } type PilotSpec struct { - Elasticsearch *PilotElasticsearchSpec `json:"elasticsearch"` - Cassandra *PilotCassandraSpec `json:"cassandra"` + Elasticsearch *ElasticsearchPilotSpec `json:"elasticsearch"` + Cassandra *CassandraPilotSpec `json:"cassandra"` } type PilotPhase string @@ -349,10 +349,10 @@ const ( PilotPhasePostStop PilotPhase = "PostStop" ) -type PilotElasticsearchSpec struct { +type ElasticsearchPilotSpec struct { } -type PilotCassandraSpec struct { +type CassandraPilotSpec struct { // Decommissioned should be set to true if we want to decommission this node Decommissioned bool `json:"decommissioned"` } diff --git a/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go b/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go index 22f83665d..d989014c1 100644 --- a/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/navigator/v1alpha1/zz_generated.conversion.go @@ -50,6 +50,8 @@ func RegisterConversions(scheme *runtime.Scheme) error { Convert_navigator_CassandraClusterSpec_To_v1alpha1_CassandraClusterSpec, Convert_v1alpha1_CassandraClusterStatus_To_navigator_CassandraClusterStatus, Convert_navigator_CassandraClusterStatus_To_v1alpha1_CassandraClusterStatus, + Convert_v1alpha1_CassandraPilotSpec_To_navigator_CassandraPilotSpec, + Convert_navigator_CassandraPilotSpec_To_v1alpha1_CassandraPilotSpec, Convert_v1alpha1_CassandraPilotStatus_To_navigator_CassandraPilotStatus, Convert_navigator_CassandraPilotStatus_To_v1alpha1_CassandraPilotStatus, Convert_v1alpha1_ElasticsearchCluster_To_navigator_ElasticsearchCluster, @@ -64,6 +66,8 @@ func RegisterConversions(scheme *runtime.Scheme) error { Convert_navigator_ElasticsearchClusterSpec_To_v1alpha1_ElasticsearchClusterSpec, Convert_v1alpha1_ElasticsearchClusterStatus_To_navigator_ElasticsearchClusterStatus, Convert_navigator_ElasticsearchClusterStatus_To_v1alpha1_ElasticsearchClusterStatus, + Convert_v1alpha1_ElasticsearchPilotSpec_To_navigator_ElasticsearchPilotSpec, + Convert_navigator_ElasticsearchPilotSpec_To_v1alpha1_ElasticsearchPilotSpec, Convert_v1alpha1_ElasticsearchPilotStatus_To_navigator_ElasticsearchPilotStatus, Convert_navigator_ElasticsearchPilotStatus_To_v1alpha1_ElasticsearchPilotStatus, Convert_v1alpha1_ImageSpec_To_navigator_ImageSpec, @@ -76,12 +80,8 @@ func RegisterConversions(scheme *runtime.Scheme) error { Convert_navigator_PersistenceConfig_To_v1alpha1_PersistenceConfig, Convert_v1alpha1_Pilot_To_navigator_Pilot, Convert_navigator_Pilot_To_v1alpha1_Pilot, - Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec, - Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec, Convert_v1alpha1_PilotCondition_To_navigator_PilotCondition, Convert_navigator_PilotCondition_To_v1alpha1_PilotCondition, - Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec, - Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec, Convert_v1alpha1_PilotList_To_navigator_PilotList, Convert_navigator_PilotList_To_v1alpha1_PilotList, Convert_v1alpha1_PilotSpec_To_navigator_PilotSpec, @@ -269,6 +269,26 @@ func Convert_navigator_CassandraClusterStatus_To_v1alpha1_CassandraClusterStatus return autoConvert_navigator_CassandraClusterStatus_To_v1alpha1_CassandraClusterStatus(in, out, s) } +func autoConvert_v1alpha1_CassandraPilotSpec_To_navigator_CassandraPilotSpec(in *CassandraPilotSpec, out *navigator.CassandraPilotSpec, s conversion.Scope) error { + out.Decommissioned = in.Decommissioned + return nil +} + +// Convert_v1alpha1_CassandraPilotSpec_To_navigator_CassandraPilotSpec is an autogenerated conversion function. +func Convert_v1alpha1_CassandraPilotSpec_To_navigator_CassandraPilotSpec(in *CassandraPilotSpec, out *navigator.CassandraPilotSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_CassandraPilotSpec_To_navigator_CassandraPilotSpec(in, out, s) +} + +func autoConvert_navigator_CassandraPilotSpec_To_v1alpha1_CassandraPilotSpec(in *navigator.CassandraPilotSpec, out *CassandraPilotSpec, s conversion.Scope) error { + out.Decommissioned = in.Decommissioned + return nil +} + +// Convert_navigator_CassandraPilotSpec_To_v1alpha1_CassandraPilotSpec is an autogenerated conversion function. +func Convert_navigator_CassandraPilotSpec_To_v1alpha1_CassandraPilotSpec(in *navigator.CassandraPilotSpec, out *CassandraPilotSpec, s conversion.Scope) error { + return autoConvert_navigator_CassandraPilotSpec_To_v1alpha1_CassandraPilotSpec(in, out, s) +} + func autoConvert_v1alpha1_CassandraPilotStatus_To_navigator_CassandraPilotStatus(in *CassandraPilotStatus, out *navigator.CassandraPilotStatus, s conversion.Scope) error { out.Version = (*version.Version)(unsafe.Pointer(in.Version)) out.Decommissioned = in.Decommissioned @@ -473,6 +493,24 @@ func Convert_navigator_ElasticsearchClusterStatus_To_v1alpha1_ElasticsearchClust return autoConvert_navigator_ElasticsearchClusterStatus_To_v1alpha1_ElasticsearchClusterStatus(in, out, s) } +func autoConvert_v1alpha1_ElasticsearchPilotSpec_To_navigator_ElasticsearchPilotSpec(in *ElasticsearchPilotSpec, out *navigator.ElasticsearchPilotSpec, s conversion.Scope) error { + return nil +} + +// Convert_v1alpha1_ElasticsearchPilotSpec_To_navigator_ElasticsearchPilotSpec is an autogenerated conversion function. +func Convert_v1alpha1_ElasticsearchPilotSpec_To_navigator_ElasticsearchPilotSpec(in *ElasticsearchPilotSpec, out *navigator.ElasticsearchPilotSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_ElasticsearchPilotSpec_To_navigator_ElasticsearchPilotSpec(in, out, s) +} + +func autoConvert_navigator_ElasticsearchPilotSpec_To_v1alpha1_ElasticsearchPilotSpec(in *navigator.ElasticsearchPilotSpec, out *ElasticsearchPilotSpec, s conversion.Scope) error { + return nil +} + +// Convert_navigator_ElasticsearchPilotSpec_To_v1alpha1_ElasticsearchPilotSpec is an autogenerated conversion function. +func Convert_navigator_ElasticsearchPilotSpec_To_v1alpha1_ElasticsearchPilotSpec(in *navigator.ElasticsearchPilotSpec, out *ElasticsearchPilotSpec, s conversion.Scope) error { + return autoConvert_navigator_ElasticsearchPilotSpec_To_v1alpha1_ElasticsearchPilotSpec(in, out, s) +} + func autoConvert_v1alpha1_ElasticsearchPilotStatus_To_navigator_ElasticsearchPilotStatus(in *ElasticsearchPilotStatus, out *navigator.ElasticsearchPilotStatus, s conversion.Scope) error { out.Documents = (*int64)(unsafe.Pointer(in.Documents)) out.Version = (*semver.Version)(unsafe.Pointer(in.Version)) @@ -623,26 +661,6 @@ func Convert_navigator_Pilot_To_v1alpha1_Pilot(in *navigator.Pilot, out *Pilot, return autoConvert_navigator_Pilot_To_v1alpha1_Pilot(in, out, s) } -func autoConvert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in *PilotCassandraSpec, out *navigator.PilotCassandraSpec, s conversion.Scope) error { - out.Decommissioned = in.Decommissioned - return nil -} - -// Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec is an autogenerated conversion function. -func Convert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in *PilotCassandraSpec, out *navigator.PilotCassandraSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PilotCassandraSpec_To_navigator_PilotCassandraSpec(in, out, s) -} - -func autoConvert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in *navigator.PilotCassandraSpec, out *PilotCassandraSpec, s conversion.Scope) error { - out.Decommissioned = in.Decommissioned - return nil -} - -// Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec is an autogenerated conversion function. -func Convert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in *navigator.PilotCassandraSpec, out *PilotCassandraSpec, s conversion.Scope) error { - return autoConvert_navigator_PilotCassandraSpec_To_v1alpha1_PilotCassandraSpec(in, out, s) -} - func autoConvert_v1alpha1_PilotCondition_To_navigator_PilotCondition(in *PilotCondition, out *navigator.PilotCondition, s conversion.Scope) error { out.Type = navigator.PilotConditionType(in.Type) out.Status = navigator.ConditionStatus(in.Status) @@ -671,24 +689,6 @@ func Convert_navigator_PilotCondition_To_v1alpha1_PilotCondition(in *navigator.P return autoConvert_navigator_PilotCondition_To_v1alpha1_PilotCondition(in, out, s) } -func autoConvert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in *PilotElasticsearchSpec, out *navigator.PilotElasticsearchSpec, s conversion.Scope) error { - return nil -} - -// Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec is an autogenerated conversion function. -func Convert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in *PilotElasticsearchSpec, out *navigator.PilotElasticsearchSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PilotElasticsearchSpec_To_navigator_PilotElasticsearchSpec(in, out, s) -} - -func autoConvert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in *navigator.PilotElasticsearchSpec, out *PilotElasticsearchSpec, s conversion.Scope) error { - return nil -} - -// Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec is an autogenerated conversion function. -func Convert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in *navigator.PilotElasticsearchSpec, out *PilotElasticsearchSpec, s conversion.Scope) error { - return autoConvert_navigator_PilotElasticsearchSpec_To_v1alpha1_PilotElasticsearchSpec(in, out, s) -} - func autoConvert_v1alpha1_PilotList_To_navigator_PilotList(in *PilotList, out *navigator.PilotList, s conversion.Scope) error { out.ListMeta = in.ListMeta out.Items = *(*[]navigator.Pilot)(unsafe.Pointer(&in.Items)) @@ -712,8 +712,8 @@ func Convert_navigator_PilotList_To_v1alpha1_PilotList(in *navigator.PilotList, } func autoConvert_v1alpha1_PilotSpec_To_navigator_PilotSpec(in *PilotSpec, out *navigator.PilotSpec, s conversion.Scope) error { - out.Elasticsearch = (*navigator.PilotElasticsearchSpec)(unsafe.Pointer(in.Elasticsearch)) - out.Cassandra = (*navigator.PilotCassandraSpec)(unsafe.Pointer(in.Cassandra)) + out.Elasticsearch = (*navigator.ElasticsearchPilotSpec)(unsafe.Pointer(in.Elasticsearch)) + out.Cassandra = (*navigator.CassandraPilotSpec)(unsafe.Pointer(in.Cassandra)) return nil } @@ -723,8 +723,8 @@ func Convert_v1alpha1_PilotSpec_To_navigator_PilotSpec(in *PilotSpec, out *navig } func autoConvert_navigator_PilotSpec_To_v1alpha1_PilotSpec(in *navigator.PilotSpec, out *PilotSpec, s conversion.Scope) error { - out.Elasticsearch = (*PilotElasticsearchSpec)(unsafe.Pointer(in.Elasticsearch)) - out.Cassandra = (*PilotCassandraSpec)(unsafe.Pointer(in.Cassandra)) + out.Elasticsearch = (*ElasticsearchPilotSpec)(unsafe.Pointer(in.Elasticsearch)) + out.Cassandra = (*CassandraPilotSpec)(unsafe.Pointer(in.Cassandra)) return nil } diff --git a/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go index 7591c5e9c..b10d62957 100644 --- a/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go @@ -222,6 +222,22 @@ func (in *CassandraClusterStatus) DeepCopy() *CassandraClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CassandraPilotSpec) DeepCopyInto(out *CassandraPilotSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CassandraPilotSpec. +func (in *CassandraPilotSpec) DeepCopy() *CassandraPilotSpec { + if in == nil { + return nil + } + out := new(CassandraPilotSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CassandraPilotStatus) DeepCopyInto(out *CassandraPilotStatus) { *out = *in @@ -453,6 +469,22 @@ func (in *ElasticsearchClusterStatus) DeepCopy() *ElasticsearchClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ElasticsearchPilotSpec) DeepCopyInto(out *ElasticsearchPilotSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ElasticsearchPilotSpec. +func (in *ElasticsearchPilotSpec) DeepCopy() *ElasticsearchPilotSpec { + if in == nil { + return nil + } + out := new(ElasticsearchPilotSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ElasticsearchPilotStatus) DeepCopyInto(out *ElasticsearchPilotStatus) { *out = *in @@ -601,22 +633,6 @@ func (in *Pilot) DeepCopyObject() runtime.Object { } } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PilotCassandraSpec) DeepCopyInto(out *PilotCassandraSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotCassandraSpec. -func (in *PilotCassandraSpec) DeepCopy() *PilotCassandraSpec { - if in == nil { - return nil - } - out := new(PilotCassandraSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotCondition) DeepCopyInto(out *PilotCondition) { *out = *in @@ -634,22 +650,6 @@ func (in *PilotCondition) DeepCopy() *PilotCondition { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PilotElasticsearchSpec) DeepCopyInto(out *PilotElasticsearchSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotElasticsearchSpec. -func (in *PilotElasticsearchSpec) DeepCopy() *PilotElasticsearchSpec { - if in == nil { - return nil - } - out := new(PilotElasticsearchSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotList) DeepCopyInto(out *PilotList) { *out = *in @@ -692,7 +692,7 @@ func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { if *in == nil { *out = nil } else { - *out = new(PilotElasticsearchSpec) + *out = new(ElasticsearchPilotSpec) **out = **in } } @@ -701,7 +701,7 @@ func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { if *in == nil { *out = nil } else { - *out = new(PilotCassandraSpec) + *out = new(CassandraPilotSpec) **out = **in } } diff --git a/pkg/apis/navigator/zz_generated.deepcopy.go b/pkg/apis/navigator/zz_generated.deepcopy.go index 4a26fb3ef..d42389771 100644 --- a/pkg/apis/navigator/zz_generated.deepcopy.go +++ b/pkg/apis/navigator/zz_generated.deepcopy.go @@ -222,6 +222,22 @@ func (in *CassandraClusterStatus) DeepCopy() *CassandraClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CassandraPilotSpec) DeepCopyInto(out *CassandraPilotSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CassandraPilotSpec. +func (in *CassandraPilotSpec) DeepCopy() *CassandraPilotSpec { + if in == nil { + return nil + } + out := new(CassandraPilotSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CassandraPilotStatus) DeepCopyInto(out *CassandraPilotStatus) { *out = *in @@ -453,6 +469,22 @@ func (in *ElasticsearchClusterStatus) DeepCopy() *ElasticsearchClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ElasticsearchPilotSpec) DeepCopyInto(out *ElasticsearchPilotSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ElasticsearchPilotSpec. +func (in *ElasticsearchPilotSpec) DeepCopy() *ElasticsearchPilotSpec { + if in == nil { + return nil + } + out := new(ElasticsearchPilotSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ElasticsearchPilotStatus) DeepCopyInto(out *ElasticsearchPilotStatus) { *out = *in @@ -601,22 +633,6 @@ func (in *Pilot) DeepCopyObject() runtime.Object { } } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PilotCassandraSpec) DeepCopyInto(out *PilotCassandraSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotCassandraSpec. -func (in *PilotCassandraSpec) DeepCopy() *PilotCassandraSpec { - if in == nil { - return nil - } - out := new(PilotCassandraSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotCondition) DeepCopyInto(out *PilotCondition) { *out = *in @@ -634,22 +650,6 @@ func (in *PilotCondition) DeepCopy() *PilotCondition { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PilotElasticsearchSpec) DeepCopyInto(out *PilotElasticsearchSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotElasticsearchSpec. -func (in *PilotElasticsearchSpec) DeepCopy() *PilotElasticsearchSpec { - if in == nil { - return nil - } - out := new(PilotElasticsearchSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PilotList) DeepCopyInto(out *PilotList) { *out = *in @@ -692,7 +692,7 @@ func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { if *in == nil { *out = nil } else { - *out = new(PilotElasticsearchSpec) + *out = new(ElasticsearchPilotSpec) **out = **in } } @@ -701,7 +701,7 @@ func (in *PilotSpec) DeepCopyInto(out *PilotSpec) { if *in == nil { *out = nil } else { - *out = new(PilotCassandraSpec) + *out = new(CassandraPilotSpec) **out = **in } } diff --git a/pkg/controllers/cassandra/actions/scalein.go b/pkg/controllers/cassandra/actions/scalein.go index 078743119..6dd65c91a 100644 --- a/pkg/controllers/cassandra/actions/scalein.go +++ b/pkg/controllers/cassandra/actions/scalein.go @@ -52,7 +52,7 @@ func (a *ScaleIn) Execute(s *controllers.State) error { for i := 1; i <= nPilotsToRemove; i++ { p := pilots[len(pilots)-i].DeepCopy() if p.Spec.Cassandra == nil { - p.Spec.Cassandra = &v1alpha1.PilotCassandraSpec{} + p.Spec.Cassandra = &v1alpha1.CassandraPilotSpec{} } if !p.Spec.Cassandra.Decommissioned {