This repository has been archived by the owner on Apr 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CreateNodePool and ScaleOut actions for Cassandra
* These become the only changes supported by the Cassandra controller. * ScaleIn and CassandraUpgrade actions will be implemented in followup branches. * Some initial documentation on supported configuration changes. Fixes: #253
- Loading branch information
Showing
15 changed files
with
687 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package actions | ||
|
||
import ( | ||
corev1 "k8s.io/api/core/v1" | ||
k8sErrors "k8s.io/apimachinery/pkg/api/errors" | ||
|
||
"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1" | ||
"github.com/jetstack/navigator/pkg/controllers" | ||
"github.com/jetstack/navigator/pkg/controllers/cassandra/nodepool" | ||
) | ||
|
||
type CreateNodePool struct { | ||
Cluster *v1alpha1.CassandraCluster | ||
NodePool *v1alpha1.CassandraClusterNodePool | ||
} | ||
|
||
var _ controllers.Action = &CreateNodePool{} | ||
|
||
func (a *CreateNodePool) Name() string { | ||
return "CreateNodePool" | ||
} | ||
|
||
func (a *CreateNodePool) Execute(s *controllers.State) error { | ||
ss := nodepool.StatefulSetForCluster(a.Cluster, a.NodePool) | ||
_, err := s.Clientset.AppsV1beta1().StatefulSets(ss.Namespace).Create(ss) | ||
if k8sErrors.IsAlreadyExists(err) { | ||
return nil | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
s.Recorder.Eventf( | ||
a.Cluster, | ||
corev1.EventTypeNormal, | ||
a.Name(), | ||
"CreateNodePool: Name=%q", a.NodePool.Name, | ||
) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
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 TestCreateNodePool(t *testing.T) { | ||
type testT struct { | ||
kubeObjects []runtime.Object | ||
cluster generate.CassandraClusterConfig | ||
nodePool generate.CassandraClusterNodePoolConfig | ||
expectedStatefulSet *generate.StatefulSetConfig | ||
expectedErr bool | ||
} | ||
tests := map[string]testT{ | ||
"A statefulset is created if one does not already exist": { | ||
cluster: generate.CassandraClusterConfig{ | ||
Name: "cluster1", | ||
Namespace: "ns1", | ||
}, | ||
nodePool: generate.CassandraClusterNodePoolConfig{ | ||
Name: "pool1", | ||
}, | ||
expectedStatefulSet: &generate.StatefulSetConfig{ | ||
Name: "cass-cluster1-pool1", | ||
Namespace: "ns1", | ||
}, | ||
}, | ||
"Idempotent: CreateNodePool can be executed again without error": { | ||
kubeObjects: []runtime.Object{ | ||
generate.StatefulSet( | ||
generate.StatefulSetConfig{ | ||
Name: "cass-cluster1-pool1", | ||
Namespace: "ns1", | ||
}, | ||
), | ||
}, | ||
cluster: generate.CassandraClusterConfig{Name: "cluster1", Namespace: "ns1"}, | ||
nodePool: generate.CassandraClusterNodePoolConfig{ | ||
Name: "pool1", | ||
}, | ||
expectedStatefulSet: &generate.StatefulSetConfig{ | ||
Name: "cass-cluster1-pool1", | ||
Namespace: "ns1", | ||
}, | ||
expectedErr: false, | ||
}, | ||
} | ||
|
||
for name, test := range tests { | ||
t.Run( | ||
name, | ||
func(t *testing.T) { | ||
fixture := &framework.StateFixture{ | ||
T: t, | ||
KubeObjects: test.kubeObjects, | ||
} | ||
fixture.Start() | ||
defer fixture.Stop() | ||
state := fixture.State() | ||
a := &actions.CreateNodePool{ | ||
Cluster: generate.CassandraCluster(test.cluster), | ||
NodePool: generate.CassandraClusterNodePool(test.nodePool), | ||
} | ||
err := a.Execute(state) | ||
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 { | ||
_, 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) | ||
} | ||
} | ||
}, | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package actions | ||
|
||
import ( | ||
corev1 "k8s.io/api/core/v1" | ||
|
||
"github.com/golang/glog" | ||
|
||
"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/util/ptr" | ||
) | ||
|
||
type ScaleOut struct { | ||
Cluster *v1alpha1.CassandraCluster | ||
NodePool *v1alpha1.CassandraClusterNodePool | ||
} | ||
|
||
var _ controllers.Action = &ScaleOut{} | ||
|
||
func (a *ScaleOut) Name() string { | ||
return "ScaleOut" | ||
} | ||
|
||
func (a *ScaleOut) Execute(s *controllers.State) error { | ||
baseSet := nodepool.StatefulSetForCluster(a.Cluster, a.NodePool) | ||
existingSet, err := s.StatefulSetLister. | ||
StatefulSets(baseSet.Namespace).Get(baseSet.Name) | ||
if err != nil { | ||
return err | ||
} | ||
newSet := existingSet.DeepCopy() | ||
if *existingSet.Spec.Replicas == a.NodePool.Replicas { | ||
return nil | ||
} | ||
if *existingSet.Spec.Replicas > a.NodePool.Replicas { | ||
glog.Errorf( | ||
"ScaleOut error:"+ | ||
"The StatefulSet.Spec.Replicas value (%d) "+ | ||
"is greater than the desired value (%d)", | ||
*existingSet.Spec.Replicas, a.NodePool.Replicas, | ||
) | ||
return nil | ||
} | ||
newSet.Spec.Replicas = ptr.Int32(*newSet.Spec.Replicas + 1) | ||
_, err = s.Clientset.AppsV1beta1(). | ||
StatefulSets(newSet.Namespace).Update(newSet) | ||
if err != nil { | ||
return err | ||
} | ||
s.Recorder.Eventf( | ||
a.Cluster, | ||
corev1.EventTypeNormal, | ||
a.Name(), | ||
"ScaleOut: NodePool=%q, ReplicaCount=%d, TargetReplicaCount=%d", | ||
a.NodePool.Name, *newSet.Spec.Replicas, a.NodePool.Replicas, | ||
) | ||
return nil | ||
} |
Oops, something went wrong.