github.com/verrazzano/verrazzano@v1.7.0/platform-operator/namespacewatch/namespace_watcher_test.go (about) 1 // Copyright (c) 2023, 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 namespacewatch 5 6 import ( 7 "context" 8 asserts "github.com/stretchr/testify/assert" 9 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1" 10 "github.com/verrazzano/verrazzano/platform-operator/constants" 11 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/rancher" 12 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/spi" 13 "github.com/verrazzano/verrazzano/platform-operator/internal/config" 14 appsv1 "k8s.io/api/apps/v1" 15 v1 "k8s.io/api/core/v1" 16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/runtime/schema" 19 "k8s.io/apimachinery/pkg/types" 20 k8scheme "k8s.io/client-go/kubernetes/scheme" 21 "sigs.k8s.io/controller-runtime/pkg/client/fake" 22 "testing" 23 "time" 24 ) 25 26 const ( 27 reldir = "../manifests/profiles" 28 cattleSystem = "cattle-system" 29 testBomFilePath = "../controllers/verrazzano/testdata/test_bom.json" 30 ) 31 32 var period = time.Duration(10) * time.Second 33 var testScheme = runtime.NewScheme() 34 35 func init() { 36 _ = k8scheme.AddToScheme(testScheme) 37 _ = v1alpha1.AddToScheme(testScheme) 38 } 39 40 func TestStart(t *testing.T) { 41 client := fake.NewClientBuilder().WithScheme(testScheme).WithObjects().Build() 42 ctx := spi.NewFakeContext(client, nil, nil, false) 43 namespaceWatcher = NewNamespaceWatcher(ctx.Client(), period) 44 asserts.Nil(t, namespaceWatcher.shutdown) 45 namespaceWatcher.Start() 46 asserts.NotNil(t, namespaceWatcher.shutdown) 47 namespaceWatcher.Start() 48 asserts.NotNil(t, namespaceWatcher.shutdown) 49 namespaceWatcher.Pause() 50 asserts.Nil(t, namespaceWatcher.shutdown) 51 namespaceWatcher.Pause() 52 asserts.Nil(t, namespaceWatcher.shutdown) 53 } 54 55 // TestNotToMoveSystemNamespacesWhenRancherNotReady tests the following cases 56 // GIVEN that rancher component is enabled and in not ready state in Verrazzano installation 57 // OR when subcomponents are not ready 58 // THEN no operation takes place 59 func TestNotToMoveSystemNamespacesWhenRancherNotReady(t *testing.T) { 60 namespace1 := &v1.Namespace{ 61 ObjectMeta: metav1.ObjectMeta{ 62 Name: "verrazzano-system", 63 Labels: map[string]string{ 64 constants.VerrazzanoManagedKey: "verrazzano-system", 65 }, 66 }, 67 } 68 enabled := true 69 var availability v1alpha1.ComponentAvailability = "Available" 70 vzCR := &v1alpha1.Verrazzano{ 71 ObjectMeta: metav1.ObjectMeta{ 72 Namespace: "default", 73 Name: "example", 74 }, 75 Spec: v1alpha1.VerrazzanoSpec{ 76 Components: v1alpha1.ComponentSpec{ 77 Rancher: &v1alpha1.RancherComponent{ 78 Enabled: &enabled, 79 }, 80 }, 81 }, 82 Status: v1alpha1.VerrazzanoStatus{ 83 Components: v1alpha1.ComponentStatusMap{ 84 "rancher": &v1alpha1.ComponentStatusDetails{ 85 Name: "rancher", 86 State: "Ready", 87 Available: &availability, 88 }, 89 }, 90 }, 91 } 92 93 testScheme.AddKnownTypeWithName(schema.GroupVersionKind{ 94 Group: "install.verrazzano.io/v1alpha1", 95 Kind: "Verrazzano", 96 Version: "v1alpha1", 97 }, &v1alpha1.Verrazzano{}) 98 config.TestProfilesDir = reldir 99 defer func() { config.TestProfilesDir = "" }() 100 client := fake.NewClientBuilder().WithScheme(testScheme).WithObjects(vzCR, 101 newReplicaSet(cattleSystem, "rancher"), 102 newReplicaSet(cattleSystem, "rancher-webhook"), 103 newReplicaSet("cattle-fleet-system", "gitjob"), 104 newReplicaSet("cattle-fleet-system", "fleet-controller"), 105 newReplicaSet("cattle-fleet-local-system", "fleet-agent"), 106 newPod("cattle-system", "rancher"), namespace1).Build() 107 ctx := spi.NewFakeContext(client, vzCR, nil, false) 108 namespaceWatcher = NewNamespaceWatcher(ctx.Client(), period) 109 projectID := "p-47cnm" 110 err := namespaceWatcher.MoveSystemNamespacesToRancherSystemProject(projectID, "") 111 asserts.NoError(t, err) 112 ns := v1.Namespace{} 113 asserts.NoError(t, client.Get(context.Background(), types.NamespacedName{Name: "verrazzano-system"}, &ns)) 114 asserts.Equal(t, ns.Annotations[RancherProjectIDLabelKey], "") 115 } 116 117 // TestToNotMoveSystemNamespaces tests the following cases 118 // GIVEN that rancher component is enabled and in ready state in Verrazzano installation 119 // When namespaces on the cluster does not have label "verrazzano.io/namespace" 120 // THEN the namespace is ignored 121 func TestToNotMoveSystemNamespacesWhenNoSystemNSLabel(t *testing.T) { 122 oldBomPath := config.GetDefaultBOMFilePath() 123 config.SetDefaultBomFilePath(testBomFilePath) 124 defer config.SetDefaultBomFilePath(oldBomPath) 125 126 namespace1 := &v1.Namespace{ 127 ObjectMeta: metav1.ObjectMeta{ 128 Name: "verrazzano-system", 129 }, 130 } 131 enabled := true 132 var availability v1alpha1.ComponentAvailability = "Available" 133 vzCR := &v1alpha1.Verrazzano{ 134 ObjectMeta: metav1.ObjectMeta{ 135 Namespace: "default", 136 Name: "example", 137 }, 138 Spec: v1alpha1.VerrazzanoSpec{ 139 Components: v1alpha1.ComponentSpec{ 140 Rancher: &v1alpha1.RancherComponent{ 141 Enabled: &enabled, 142 }, 143 }, 144 }, 145 Status: v1alpha1.VerrazzanoStatus{ 146 Components: v1alpha1.ComponentStatusMap{ 147 "rancher": &v1alpha1.ComponentStatusDetails{ 148 Name: "rancher", 149 State: "Ready", 150 Available: &availability, 151 }, 152 }, 153 }, 154 } 155 156 testScheme.AddKnownTypeWithName(schema.GroupVersionKind{ 157 Group: "install.verrazzano.io/v1alpha1", 158 Kind: "Verrazzano", 159 Version: "v1alpha1", 160 }, &v1alpha1.Verrazzano{}) 161 config.TestProfilesDir = reldir 162 defer func() { config.TestProfilesDir = "" }() 163 client := fake.NewClientBuilder().WithScheme(testScheme).WithObjects(vzCR, 164 newReplicaSet(rancher.ComponentNamespace, "rancher"), 165 newReplicaSet(rancher.ComponentNamespace, "rancher-webhook"), 166 newReplicaSet(rancher.FleetSystemNamespace, "gitjob"), 167 newReplicaSet(rancher.FleetSystemNamespace, "fleet-controller"), 168 newReplicaSet(rancher.FleetLocalSystemNamespace, "fleet-agent"), 169 newPod(rancher.ComponentNamespace, "rancher"), 170 newPod(rancher.ComponentNamespace, "rancher-webhook"), 171 newPod(rancher.FleetSystemNamespace, "gitjob"), 172 newPod(rancher.FleetSystemNamespace, "fleet-controller"), 173 newPod(rancher.FleetLocalSystemNamespace, "fleet-agent"), 174 newReadyDeployment(rancher.ComponentNamespace, "rancher"), 175 newReadyDeploymentWithImage(rancher.ComponentNamespace, "rancher-webhook", "rancher-webhook:v0.2.6-20221005161115-fee4a23"), 176 newReadyDeployment(rancher.FleetSystemNamespace, "gitjob"), 177 newReadyDeployment(rancher.FleetSystemNamespace, "fleet-controller"), 178 newReadyDeployment(rancher.FleetLocalSystemNamespace, "fleet-agent"), namespace1).Build() 179 ctx := spi.NewFakeContext(client, vzCR, nil, false) 180 namespaceWatcher = NewNamespaceWatcher(ctx.Client(), period) 181 projectID := "p-47cnm" 182 clusterName := "local" 183 err := namespaceWatcher.MoveSystemNamespacesToRancherSystemProject(projectID, clusterName) 184 asserts.NoError(t, err) 185 ns := v1.Namespace{} 186 asserts.NoError(t, client.Get(context.Background(), types.NamespacedName{Name: "verrazzano-system"}, &ns)) 187 asserts.NotEqual(t, ns.Annotations[RancherProjectIDLabelKey], clusterName+":"+projectID) 188 } 189 190 // TestMoveSystemNamespaces tests the following cases 191 // GIVEN that rancher component is enabled and in ready state in Verrazzano installation 192 // When namespaces on the cluster has a label "verrazzano.io/namespace" 193 // And when namespaces on the cluster does not have a label management.cattle.io/system-namespace 194 // THEN the method retrieves the System project ID from the rancher 195 // And updates the namespace annotation and label with the Project ID. 196 func TestMoveSystemNamespaces(t *testing.T) { 197 oldBomPath := config.GetDefaultBOMFilePath() 198 config.SetDefaultBomFilePath(testBomFilePath) 199 defer config.SetDefaultBomFilePath(oldBomPath) 200 201 namespace1 := &v1.Namespace{ 202 ObjectMeta: metav1.ObjectMeta{ 203 Name: "verrazzano-system", 204 Labels: map[string]string{ 205 constants.VerrazzanoManagedKey: "verrazzano-system", 206 }, 207 }, 208 } 209 enabled := true 210 var availability v1alpha1.ComponentAvailability = "Available" 211 vzCR := &v1alpha1.Verrazzano{ 212 ObjectMeta: metav1.ObjectMeta{ 213 Namespace: "default", 214 Name: "example", 215 }, 216 Spec: v1alpha1.VerrazzanoSpec{ 217 Components: v1alpha1.ComponentSpec{ 218 Rancher: &v1alpha1.RancherComponent{ 219 Enabled: &enabled, 220 }, 221 }, 222 }, 223 Status: v1alpha1.VerrazzanoStatus{ 224 Components: v1alpha1.ComponentStatusMap{ 225 "rancher": &v1alpha1.ComponentStatusDetails{ 226 Name: "rancher", 227 State: "Ready", 228 Available: &availability, 229 }, 230 }, 231 }, 232 } 233 234 testScheme.AddKnownTypeWithName(schema.GroupVersionKind{ 235 Group: "install.verrazzano.io/v1alpha1", 236 Kind: "Verrazzano", 237 Version: "v1alpha1", 238 }, &v1alpha1.Verrazzano{}) 239 config.TestProfilesDir = reldir 240 defer func() { config.TestProfilesDir = "" }() 241 client := fake.NewClientBuilder().WithScheme(testScheme).WithObjects(vzCR, 242 newReplicaSet(rancher.ComponentNamespace, "rancher"), 243 newReplicaSet(rancher.ComponentNamespace, "rancher-webhook"), 244 newReplicaSet(rancher.FleetSystemNamespace, "gitjob"), 245 newReplicaSet(rancher.FleetSystemNamespace, "fleet-controller"), 246 newReplicaSet(rancher.FleetLocalSystemNamespace, "fleet-agent"), 247 newPod(rancher.ComponentNamespace, "rancher"), 248 newPod(rancher.ComponentNamespace, "rancher-webhook"), 249 newPod(rancher.FleetSystemNamespace, "gitjob"), 250 newPod(rancher.FleetSystemNamespace, "fleet-controller"), 251 newPod(rancher.FleetLocalSystemNamespace, "fleet-agent"), 252 newReadyDeployment(rancher.ComponentNamespace, "rancher"), 253 newReadyDeploymentWithImage(rancher.ComponentNamespace, "rancher-webhook", "rancher-webhook:v0.2.6-20221005161115-fee4a23"), 254 newReadyDeployment(rancher.FleetSystemNamespace, "gitjob"), 255 newReadyDeployment(rancher.FleetSystemNamespace, "fleet-controller"), 256 newReadyDeployment(rancher.FleetLocalSystemNamespace, "fleet-agent"), namespace1).Build() 257 ctx := spi.NewFakeContext(client, vzCR, nil, false) 258 namespaceWatcher = NewNamespaceWatcher(ctx.Client(), period) 259 projectID := "p-47cnm" 260 clusterName := "local" 261 err := namespaceWatcher.MoveSystemNamespacesToRancherSystemProject(projectID, clusterName) 262 asserts.NoError(t, err) 263 ns := v1.Namespace{} 264 asserts.NoError(t, client.Get(context.Background(), types.NamespacedName{Name: "verrazzano-system"}, &ns)) 265 asserts.Equal(t, ns.Annotations[RancherProjectIDLabelKey], clusterName+":"+projectID) 266 } 267 268 func newPod(namespace string, name string) *v1.Pod { 269 return &v1.Pod{ 270 ObjectMeta: metav1.ObjectMeta{ 271 Namespace: namespace, 272 Name: name, 273 Labels: map[string]string{ 274 "app": name, 275 "pod-template-hash": "95d8c5d97", 276 }, 277 }, 278 } 279 } 280 281 func newReplicaSet(namespace string, name string) *appsv1.ReplicaSet { 282 return &appsv1.ReplicaSet{ 283 ObjectMeta: metav1.ObjectMeta{ 284 Namespace: namespace, 285 Name: name + "-95d8c5d97", 286 Annotations: map[string]string{"deployment.kubernetes.io/revision": "1"}, 287 }, 288 } 289 } 290 291 // Create a new deployment object for testing 292 func newReadyDeployment(namespace string, name string) *appsv1.Deployment { 293 return &appsv1.Deployment{ 294 ObjectMeta: metav1.ObjectMeta{ 295 Namespace: namespace, 296 Name: name, 297 Labels: map[string]string{"app": name}, 298 }, 299 Spec: appsv1.DeploymentSpec{ 300 Selector: &metav1.LabelSelector{ 301 MatchLabels: map[string]string{"app": name}, 302 }, 303 }, 304 Status: appsv1.DeploymentStatus{ 305 AvailableReplicas: 1, 306 Replicas: 1, 307 UpdatedReplicas: 1, 308 }, 309 } 310 } 311 312 func newReadyDeploymentWithImage(namespace string, name string, image string) *appsv1.Deployment { 313 return &appsv1.Deployment{ 314 ObjectMeta: metav1.ObjectMeta{ 315 Namespace: namespace, 316 Name: name, 317 Labels: map[string]string{"app": name}, 318 }, 319 Spec: appsv1.DeploymentSpec{ 320 Selector: &metav1.LabelSelector{ 321 MatchLabels: map[string]string{"app": name}, 322 }, 323 Template: v1.PodTemplateSpec{ 324 Spec: v1.PodSpec{ 325 Containers: []v1.Container{{Image: image}}, 326 }, 327 }, 328 }, 329 Status: appsv1.DeploymentStatus{ 330 AvailableReplicas: 1, 331 Replicas: 1, 332 UpdatedReplicas: 1, 333 }, 334 } 335 }