Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion upup/pkg/fi/cloudup/template_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ func (tf *TemplateFunctions) APIServerNodeRole() string {
// HasHighlyAvailableControlPlane returns true of the cluster has more than one control plane node. False otherwise.
func (tf *TemplateFunctions) HasHighlyAvailableControlPlane() bool {
cp := 0
for _, ig := range tf.InstanceGroups {
for _, ig := range tf.AllInstanceGroups {
if ig.Spec.Role == kops.InstanceGroupRoleControlPlane {
cp++
if cp > 1 {
Expand Down
128 changes: 128 additions & 0 deletions upup/pkg/fi/cloudup/template_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"reflect"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/upup/pkg/fi"
Expand Down Expand Up @@ -313,3 +314,130 @@ func TestKopsFeatureEnabled(t *testing.T) {
})
}
}

func TestHasHighlyAvailableControlPlane(t *testing.T) {
tests := []struct {
name string
allInstanceGroups []*kops.InstanceGroup
instanceGroups []*kops.InstanceGroup
expectedHA bool
}{
{
name: "Single control plane node",
allInstanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1a"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
instanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
expectedHA: false,
},
{
name: "Multiple control plane nodes",
allInstanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1a"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1b"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
instanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
expectedHA: true,
},
{
name: "Multiple control plane nodes with filtered instance groups (regression test)",
allInstanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1a"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1b"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1c"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
instanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "nodes"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleNode},
},
},
expectedHA: true,
},
{
name: "Three control plane nodes",
allInstanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1a"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1b"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1c"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
},
instanceGroups: []*kops.InstanceGroup{
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1a"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1b"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "master-us-east-1c"},
Spec: kops.InstanceGroupSpec{Role: kops.InstanceGroupRoleControlPlane},
},
},
expectedHA: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tf := &TemplateFunctions{}
tf.AllInstanceGroups = tc.allInstanceGroups
tf.InstanceGroups = tc.instanceGroups

actual := tf.HasHighlyAvailableControlPlane()
if actual != tc.expectedHA {
t.Errorf("expected HA to be %t, got %t", tc.expectedHA, actual)
}
})
}
}
Loading