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 until ScaleIn and CassandraUpgrade actions are implemented in followup branches. Fixes: #253
- Loading branch information
Showing
19 changed files
with
834 additions
and
126 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,70 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"fmt" | ||
"math/rand" | ||
"reflect" | ||
"testing/quick" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func (_ CassandraCluster) Generate(rand *rand.Rand, size int) reflect.Value { | ||
o := CassandraCluster{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: fmt.Sprintf("cluster%d", rand.Intn(10)), | ||
Namespace: "", | ||
}, | ||
} | ||
v, ok := quick.Value(reflect.TypeOf(CassandraClusterSpec{}), rand) | ||
if ok { | ||
o.Spec = v.Interface().(CassandraClusterSpec) | ||
} | ||
v, ok = quick.Value(reflect.TypeOf(CassandraClusterStatus{}), rand) | ||
if ok { | ||
o.Status = v.Interface().(CassandraClusterStatus) | ||
} | ||
return reflect.ValueOf(o) | ||
} | ||
|
||
func (_ CassandraClusterSpec) Generate(rand *rand.Rand, size int) reflect.Value { | ||
nodepools := make([]CassandraClusterNodePool, rand.Intn(10)) | ||
for i := range nodepools { | ||
v, ok := quick.Value(reflect.TypeOf(CassandraClusterNodePool{}), rand) | ||
if ok { | ||
nodepools[i] = v.Interface().(CassandraClusterNodePool) | ||
} | ||
} | ||
o := CassandraClusterSpec{ | ||
CqlPort: rand.Int31n(10), | ||
NodePools: nodepools, | ||
} | ||
return reflect.ValueOf(o) | ||
} | ||
|
||
func (_ CassandraClusterNodePool) Generate(rand *rand.Rand, size int) reflect.Value { | ||
o := CassandraClusterNodePool{ | ||
Name: fmt.Sprintf("np%d", rand.Intn(10)), | ||
Replicas: rand.Int31n(10), | ||
} | ||
return reflect.ValueOf(o) | ||
} | ||
|
||
func (_ CassandraClusterStatus) Generate(rand *rand.Rand, size int) reflect.Value { | ||
o := CassandraClusterStatus{ | ||
NodePools: map[string]CassandraClusterNodePoolStatus{}, | ||
} | ||
nodepools := make([]CassandraClusterNodePool, rand.Intn(10)) | ||
for i := range nodepools { | ||
v, ok := quick.Value(reflect.TypeOf(CassandraClusterNodePool{}), rand) | ||
if ok { | ||
nodepools[i] = v.Interface().(CassandraClusterNodePool) | ||
} | ||
} | ||
for _, np := range nodepools { | ||
o.NodePools[np.Name] = CassandraClusterNodePoolStatus{ | ||
ReadyReplicas: np.Replicas, | ||
} | ||
} | ||
return reflect.ValueOf(o) | ||
} |
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,30 @@ | ||
package actions | ||
|
||
import ( | ||
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) | ||
// XXX: Should this be idempotent? | ||
if k8sErrors.IsAlreadyExists(err) { | ||
return nil | ||
} | ||
return 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,95 @@ | ||
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 | ||
navObjects []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", | ||
Replicas: int32Ptr(0), | ||
}, | ||
}, | ||
"Idempotent: CreateNodePool can be executed again without error": { | ||
kubeObjects: []runtime.Object{ | ||
generate.StatefulSet( | ||
generate.StatefulSetConfig{ | ||
Name: "cass-cluster1-pool1", | ||
Namespace: "ns1", | ||
Replicas: int32Ptr(10), | ||
}, | ||
), | ||
}, | ||
cluster: generate.CassandraClusterConfig{Name: "cluster1", Namespace: "ns1"}, | ||
nodePool: generate.CassandraClusterNodePoolConfig{ | ||
Name: "pool1", | ||
}, | ||
expectedStatefulSet: generate.StatefulSetConfig{ | ||
Name: "cass-cluster1-pool1", | ||
Namespace: "ns1", | ||
Replicas: int32Ptr(10), | ||
}, | ||
expectedErr: false, | ||
}, | ||
} | ||
|
||
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() | ||
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") | ||
} | ||
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) | ||
}, | ||
) | ||
} | ||
} |
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,42 @@ | ||
package actions | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1" | ||
"github.com/jetstack/navigator/pkg/controllers" | ||
"github.com/jetstack/navigator/pkg/controllers/cassandra/nodepool" | ||
) | ||
|
||
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 { | ||
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 == nil || *ss.Spec.Replicas < a.NodePool.Replicas { | ||
ss.Spec.Replicas = &a.NodePool.Replicas | ||
_, err = s.Clientset.AppsV1beta1().StatefulSets(ss.Namespace).Update(ss) | ||
return err | ||
} | ||
if *ss.Spec.Replicas > a.NodePool.Replicas { | ||
return fmt.Errorf( | ||
"the NodePool.Replicas value (%d) "+ | ||
"is less than the existing StatefulSet.Replicas value (%d)", | ||
a.NodePool.Replicas, *ss.Spec.Replicas, | ||
) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.