github.com/verrazzano/verrazzano-monitoring-operator@v0.0.30/pkg/resources/statefulsets/plan_test.go (about) 1 // Copyright (C) 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package statefulsets 5 6 import ( 7 "github.com/stretchr/testify/assert" 8 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/config" 9 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/constants" 10 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/resources" 11 "github.com/verrazzano/verrazzano-monitoring-operator/pkg/util/logs/vzlog" 12 appsv1 "k8s.io/api/apps/v1" 13 corev1 "k8s.io/api/core/v1" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "testing" 16 ) 17 18 func createTestSTS(name string, replicas int32) *appsv1.StatefulSet { 19 return &appsv1.StatefulSet{ 20 ObjectMeta: metav1.ObjectMeta{ 21 Name: name, 22 }, 23 Spec: appsv1.StatefulSetSpec{ 24 Replicas: &replicas, 25 }, 26 Status: appsv1.StatefulSetStatus{ 27 ReadyReplicas: replicas, 28 }, 29 } 30 } 31 32 func TestCreatePlan(t *testing.T) { 33 log := vzlog.DefaultLogger() 34 var tests = []struct { 35 name string 36 existingList []*appsv1.StatefulSet 37 expectedList []*appsv1.StatefulSet 38 plan *StatefulSetPlan 39 }{ 40 { 41 "should delete nodes when expected is empty", 42 []*appsv1.StatefulSet{ 43 createTestSTS("foo", 1), 44 }, 45 []*appsv1.StatefulSet{}, 46 &StatefulSetPlan{ 47 ExistingCluster: true, 48 BounceNodes: true, 49 Delete: []*appsv1.StatefulSet{ 50 createTestSTS("foo", 1), 51 }, 52 }, 53 }, 54 { 55 "should bounce nodes when scaling up single node cluster", 56 []*appsv1.StatefulSet{ 57 createTestSTS("foo", 1), 58 }, 59 []*appsv1.StatefulSet{ 60 createTestSTS("foo", 3), 61 }, 62 &StatefulSetPlan{ 63 ExistingCluster: true, 64 BounceNodes: true, 65 Update: []*appsv1.StatefulSet{ 66 createTestSTS("foo", 3), 67 }, 68 }, 69 }, 70 { 71 "do nothing when expected and existing are the same", 72 []*appsv1.StatefulSet{ 73 createTestSTS("foo", 1), 74 createTestSTS("bar", 2), 75 }, 76 []*appsv1.StatefulSet{ 77 createTestSTS("foo", 1), 78 createTestSTS("bar", 2), 79 }, 80 &StatefulSetPlan{ExistingCluster: true}, 81 }, 82 { 83 "create when expected, but not existing", 84 nil, 85 []*appsv1.StatefulSet{ 86 createTestSTS("foo", 1), 87 createTestSTS("bar", 2), 88 }, 89 &StatefulSetPlan{ 90 ExistingCluster: false, 91 Create: []*appsv1.StatefulSet{ 92 createTestSTS("foo", 1), 93 createTestSTS("bar", 2), 94 }, 95 }, 96 }, 97 { 98 "delete when no longer expected", 99 []*appsv1.StatefulSet{ 100 createTestSTS("foo", 1), 101 createTestSTS("bar", 2), 102 }, 103 nil, 104 &StatefulSetPlan{ 105 ExistingCluster: true, 106 Delete: []*appsv1.StatefulSet{ 107 createTestSTS("foo", 1), 108 createTestSTS("bar", 2), 109 }, 110 }, 111 }, 112 { 113 "update when existing and expected are both present, and there is a change, and scaling is allowed", 114 []*appsv1.StatefulSet{ 115 createTestSTS("foo", 3), 116 }, 117 []*appsv1.StatefulSet{ 118 createTestSTS("foo", 4), 119 }, 120 &StatefulSetPlan{ 121 ExistingCluster: true, 122 Update: []*appsv1.StatefulSet{ 123 createTestSTS("foo", 4), 124 }, 125 }, 126 }, 127 { 128 "update allowed when existing cluster is down", 129 []*appsv1.StatefulSet{ 130 createTestSTS("foo", 0), 131 }, 132 []*appsv1.StatefulSet{ 133 createTestSTS("foo", 3), 134 }, 135 &StatefulSetPlan{ 136 ExistingCluster: false, 137 Update: []*appsv1.StatefulSet{ 138 createTestSTS("foo", 3), 139 }, 140 }, 141 }, 142 { 143 "don't update if the scaling would cause cluster downtime", 144 []*appsv1.StatefulSet{ 145 createTestSTS("foo", 3), 146 }, 147 []*appsv1.StatefulSet{ 148 createTestSTS("foo", 2), 149 }, 150 &StatefulSetPlan{ExistingCluster: true}, 151 }, 152 { 153 "don't delete if the scaling would cause cluster downtime", 154 []*appsv1.StatefulSet{ 155 createTestSTS("foo", 1), 156 createTestSTS("bar", 2), 157 }, 158 []*appsv1.StatefulSet{ 159 createTestSTS("foo", 1), 160 }, 161 &StatefulSetPlan{ExistingCluster: true}, 162 }, 163 { 164 "scaling should be allowed on single node clusters", 165 []*appsv1.StatefulSet{ 166 createTestSTS("foo", 1), 167 }, 168 []*appsv1.StatefulSet{ 169 createTestSTS("foo", 1), 170 }, 171 &StatefulSetPlan{ 172 BounceNodes: true, 173 ExistingCluster: true, 174 }, 175 }, 176 { 177 "changing single node cluster name is not allowed", 178 []*appsv1.StatefulSet{ 179 createTestSTS("foo", 1), 180 }, 181 []*appsv1.StatefulSet{ 182 createTestSTS("bar", 1), 183 }, 184 &StatefulSetPlan{ 185 BounceNodes: true, 186 ExistingCluster: true, 187 Create: []*appsv1.StatefulSet{ 188 createTestSTS("bar", 1), 189 }, 190 }, 191 }, 192 } 193 194 for _, tt := range tests { 195 t.Run(tt.name, func(t *testing.T) { 196 actualPlan := CreatePlan(log, tt.existingList, tt.expectedList) 197 assert.Equal(t, len(tt.plan.Create), len(actualPlan.Create)) 198 assert.Equal(t, len(tt.plan.Update), len(actualPlan.Update)) 199 assert.Equal(t, len(tt.plan.Delete), len(actualPlan.Delete)) 200 assert.Equal(t, tt.plan.ExistingCluster, actualPlan.ExistingCluster) 201 assert.Equal(t, tt.plan.BounceNodes, actualPlan.BounceNodes) 202 }) 203 } 204 } 205 206 func TestCopyFromContainers(t *testing.T) { 207 nodeRoleVar := "node.roles" 208 existing := createTestSTS("foo", 1) 209 existing.Spec = appsv1.StatefulSetSpec{ 210 VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ 211 { 212 ObjectMeta: metav1.ObjectMeta{ 213 Name: "test", 214 }, 215 }, 216 }, 217 Template: corev1.PodTemplateSpec{ 218 Spec: corev1.PodSpec{ 219 Containers: []corev1.Container{ 220 { 221 Name: config.ElasticsearchMaster.Name, 222 Env: []corev1.EnvVar{ 223 { 224 Name: constants.ClusterInitialMasterNodes, 225 Value: "z", 226 }, 227 { 228 Name: nodeRoleVar, 229 Value: "a", 230 }, 231 }, 232 }, 233 }, 234 }, 235 }, 236 } 237 expected := createTestSTS("foo", 1) 238 expected.Spec = appsv1.StatefulSetSpec{ 239 Template: corev1.PodTemplateSpec{ 240 Spec: corev1.PodSpec{ 241 Containers: []corev1.Container{ 242 { 243 Name: config.ElasticsearchMaster.Name, 244 Env: []corev1.EnvVar{ 245 { 246 Name: "x", 247 Value: "y", 248 }, 249 { 250 Name: nodeRoleVar, 251 Value: "b", 252 }, 253 }, 254 }, 255 }, 256 }, 257 }, 258 } 259 260 assert.NotEqualValues(t, existing.Spec.VolumeClaimTemplates, expected.Spec.VolumeClaimTemplates) 261 existingInitialClusterMasters := resources.GetEnvVar(&existing.Spec.Template.Spec.Containers[0], constants.ClusterInitialMasterNodes) 262 expectedInitialClusterMasters := resources.GetEnvVar(&expected.Spec.Template.Spec.Containers[0], constants.ClusterInitialMasterNodes) 263 assert.NotEqualValues(t, existingInitialClusterMasters, expectedInitialClusterMasters) 264 existingNodeRoles := resources.GetEnvVar(&existing.Spec.Template.Spec.Containers[0], nodeRoleVar) 265 expectedNodeRoles := resources.GetEnvVar(&expected.Spec.Template.Spec.Containers[0], nodeRoleVar) 266 assert.NotEqualValues(t, existingNodeRoles, expectedNodeRoles) 267 CopyFromExisting(expected, existing) 268 269 assert.EqualValues(t, existing.Spec.VolumeClaimTemplates, expected.Spec.VolumeClaimTemplates) 270 existingInitialClusterMasters = resources.GetEnvVar(&existing.Spec.Template.Spec.Containers[0], constants.ClusterInitialMasterNodes) 271 expectedInitialClusterMasters = resources.GetEnvVar(&expected.Spec.Template.Spec.Containers[0], constants.ClusterInitialMasterNodes) 272 assert.EqualValues(t, existingInitialClusterMasters, expectedInitialClusterMasters) 273 existingNodeRoles = resources.GetEnvVar(&existing.Spec.Template.Spec.Containers[0], nodeRoleVar) 274 expectedNodeRoles = resources.GetEnvVar(&expected.Spec.Template.Spec.Containers[0], nodeRoleVar) 275 assert.EqualValues(t, existingNodeRoles, expectedNodeRoles) 276 }