Skip to content

Commit befc645

Browse files
committed
Automate OCP-70203: ICSP and IDMS/ITMS can coexist in cluster
1 parent 355916d commit befc645

1 file changed

Lines changed: 305 additions & 0 deletions

File tree

test/extended/node/node_e2e/node.go

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
g "github.com/onsi/ginkgo/v2"
1111
o "github.com/onsi/gomega"
1212

13+
ote "github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo"
1314
configv1 "github.com/openshift/api/config/v1"
15+
operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
1416
"github.com/openshift/origin/test/extended/imagepolicy"
1517
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1618
utilrand "k8s.io/apimachinery/pkg/util/rand"
@@ -309,4 +311,307 @@ var _ = g.Describe("[sig-node][Suite:openshift/disruptive-longrunning][Disruptiv
309311
o.Expect(registriesConf).To(o.ContainSubstring("location = \"registry.redhat.io/rhel8\"\n blocked = true"),
310312
"registry.redhat.io/rhel8 should be blocked (NeverContactSource)")
311313
})
314+
315+
//author: asahay@redhat.com
316+
g.It("[OTP] ICSP and IDMS/ITMS can coexist in cluster [OCP-70203]", ote.Informing(), func() {
317+
configClient := oc.AdminConfigClient().ConfigV1()
318+
operatorClient := oc.AdminOperatorClient().OperatorV1alpha1()
319+
suffix := utilrand.String(5)
320+
icspName1 := fmt.Sprintf("ubi8repo-%s", suffix)
321+
idmsName := fmt.Sprintf("digest-mirror-%s", suffix)
322+
itmsName := fmt.Sprintf("tag-mirror-%s", suffix)
323+
icspName2 := fmt.Sprintf("ubi9repo-%s", suffix)
324+
325+
g.By("Pre-flight: Verify both MCPs are in a stable Updated state before proceeding")
326+
for _, pool := range []string{"worker", "master"} {
327+
updatedStatus, mcpErr := oc.AsAdmin().WithoutNamespace().Run("get").
328+
Args("mcp", pool, "-o=jsonpath={.status.conditions[?(@.type=='Updated')].status}").Output()
329+
o.Expect(mcpErr).NotTo(o.HaveOccurred())
330+
specName, specErr := oc.AsAdmin().WithoutNamespace().Run("get").
331+
Args("mcp", pool, "-o=jsonpath={.spec.configuration.name}").Output()
332+
o.Expect(specErr).NotTo(o.HaveOccurred())
333+
statusName, statusErr := oc.AsAdmin().WithoutNamespace().Run("get").
334+
Args("mcp", pool, "-o=jsonpath={.status.configuration.name}").Output()
335+
o.Expect(statusErr).NotTo(o.HaveOccurred())
336+
o.Expect(updatedStatus).To(o.Equal("True"),
337+
"MCP %s must be in Updated=True state before running this test (spec=%s, status=%s)", pool, specName, statusName)
338+
o.Expect(specName).To(o.Equal(statusName),
339+
"MCP %s spec and status configuration names must match before running this test", pool)
340+
}
341+
342+
g.By("Step 1: Create ICSP with digest mirrors for ubi8/ubi-minimal and openshift5")
343+
icsp1 := &operatorv1alpha1.ImageContentSourcePolicy{
344+
ObjectMeta: metav1.ObjectMeta{
345+
Name: icspName1,
346+
Labels: map[string]string{"e2e-test": "ocp-70203"},
347+
},
348+
Spec: operatorv1alpha1.ImageContentSourcePolicySpec{
349+
RepositoryDigestMirrors: []operatorv1alpha1.RepositoryDigestMirrors{
350+
{
351+
Source: "registry.access.redhat.com/ubi8/ubi-minimal",
352+
Mirrors: []string{
353+
"example.io/example/ubi-minimal",
354+
"example.com/example/ubi-minimal",
355+
},
356+
},
357+
{
358+
Source: "registry.redhat.io/openshift5",
359+
Mirrors: []string{
360+
"mirror.example.com/redhat",
361+
},
362+
},
363+
},
364+
},
365+
}
366+
367+
initialWorkerSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
368+
initialMasterSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
369+
370+
_, err := operatorClient.ImageContentSourcePolicies().Create(ctx, icsp1, metav1.CreateOptions{})
371+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create ICSP %s", icspName1)
372+
e2e.Logf("ICSP %s created successfully", icspName1)
373+
374+
g.DeferCleanup(func() {
375+
g.By("Cleanup: Delete any remaining test resources and wait for MCP to settle")
376+
cleanupWorkerSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
377+
cleanupMasterSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
378+
toDelete := false
379+
380+
for _, name := range []string{icspName1, icspName2} {
381+
if _, getErr := operatorClient.ImageContentSourcePolicies().Get(ctx, name, metav1.GetOptions{}); getErr == nil {
382+
if delErr := operatorClient.ImageContentSourcePolicies().Delete(ctx, name, metav1.DeleteOptions{}); delErr == nil {
383+
e2e.Logf("Cleanup: deleted ICSP %s", name)
384+
toDelete = true
385+
} else {
386+
e2e.Logf("Cleanup: warning - failed to delete ICSP %s: %v", name, delErr)
387+
}
388+
}
389+
}
390+
if _, getErr := configClient.ImageTagMirrorSets().Get(ctx, itmsName, metav1.GetOptions{}); getErr == nil {
391+
if delErr := configClient.ImageTagMirrorSets().Delete(ctx, itmsName, metav1.DeleteOptions{}); delErr == nil {
392+
e2e.Logf("Cleanup: deleted ITMS %s", itmsName)
393+
toDelete = true
394+
} else {
395+
e2e.Logf("Cleanup: warning - failed to delete ITMS %s: %v", itmsName, delErr)
396+
}
397+
}
398+
if _, getErr := configClient.ImageDigestMirrorSets().Get(ctx, idmsName, metav1.GetOptions{}); getErr == nil {
399+
if delErr := configClient.ImageDigestMirrorSets().Delete(ctx, idmsName, metav1.DeleteOptions{}); delErr == nil {
400+
e2e.Logf("Cleanup: deleted IDMS %s", idmsName)
401+
toDelete = true
402+
} else {
403+
e2e.Logf("Cleanup: warning - failed to delete IDMS %s: %v", idmsName, delErr)
404+
}
405+
}
406+
407+
if toDelete {
408+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "worker", cleanupWorkerSpec)
409+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "master", cleanupMasterSpec)
410+
}
411+
})
412+
413+
g.By("Step 2: Wait for MCP rollout after ICSP creation and verify registries.conf")
414+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "worker", initialWorkerSpec)
415+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "master", initialMasterSpec)
416+
e2e.Logf("MCP rollout complete after ICSP creation")
417+
418+
workerNode := nodeutils.GetFirstReadyWorkerNode(oc)
419+
o.Expect(workerNode).NotTo(o.BeEmpty(), "no ready worker node found")
420+
421+
registriesConf, err := nodeutils.ExecOnNodeWithChroot(oc, workerNode, "cat", "/etc/containers/registries.conf")
422+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read registries.conf from node %s", workerNode)
423+
e2e.Logf("registries.conf after ICSP creation: read %d bytes, asserting expected entries", len(registriesConf))
424+
425+
o.Expect(registriesConf).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi8/ubi-minimal"`),
426+
"registries.conf should contain ICSP source for ubi8/ubi-minimal")
427+
o.Expect(registriesConf).To(o.ContainSubstring(`location = "example.io/example/ubi-minimal"`),
428+
"registries.conf should contain ICSP mirror example.io/example/ubi-minimal")
429+
o.Expect(registriesConf).To(o.ContainSubstring(`location = "example.com/example/ubi-minimal"`),
430+
"registries.conf should contain ICSP mirror example.com/example/ubi-minimal")
431+
o.Expect(registriesConf).To(o.ContainSubstring(`location = "registry.redhat.io/openshift5"`),
432+
"registries.conf should contain ICSP source for openshift5")
433+
o.Expect(registriesConf).To(o.ContainSubstring(`location = "mirror.example.com/redhat"`),
434+
"registries.conf should contain ICSP mirror mirror.example.com/redhat")
435+
o.Expect(registriesConf).To(o.ContainSubstring(`pull-from-mirror = "digest-only"`),
436+
"registries.conf should have pull-from-mirror = digest-only for ICSP entries")
437+
438+
g.By("Step 3: Create IDMS with same registry/mirror config as ICSP (AllowContactingSource) - should succeed without triggering new MC")
439+
specBeforeIDMS := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
440+
masterSpecBeforeIDMS := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
441+
idms := &configv1.ImageDigestMirrorSet{
442+
ObjectMeta: metav1.ObjectMeta{
443+
Name: idmsName,
444+
Labels: map[string]string{"e2e-test": "ocp-70203"},
445+
},
446+
Spec: configv1.ImageDigestMirrorSetSpec{
447+
ImageDigestMirrors: []configv1.ImageDigestMirrors{
448+
{
449+
Source: "registry.access.redhat.com/ubi8/ubi-minimal",
450+
Mirrors: []configv1.ImageMirror{
451+
"example.io/example/ubi-minimal",
452+
"example.com/example/ubi-minimal",
453+
},
454+
MirrorSourcePolicy: configv1.AllowContactingSource,
455+
},
456+
{
457+
Source: "registry.redhat.io/openshift5",
458+
Mirrors: []configv1.ImageMirror{
459+
"mirror.example.com/redhat",
460+
},
461+
MirrorSourcePolicy: configv1.AllowContactingSource,
462+
},
463+
},
464+
},
465+
}
466+
_, err = configClient.ImageDigestMirrorSets().Create(ctx, idms, metav1.CreateOptions{})
467+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create IDMS %s", idmsName)
468+
e2e.Logf("IDMS %s created successfully", idmsName)
469+
470+
g.By("Step 3 (verify): Confirm no new MC was generated after IDMS creation with same config as ICSP")
471+
noRolloutDeadline := time.Now().Add(2 * time.Minute)
472+
for time.Now().Before(noRolloutDeadline) {
473+
o.Expect(imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")).To(o.Equal(specBeforeIDMS),
474+
"worker MCP spec changed unexpectedly after IDMS creation with same config as ICSP")
475+
o.Expect(imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")).To(o.Equal(masterSpecBeforeIDMS),
476+
"master MCP spec changed unexpectedly after IDMS creation with same config as ICSP")
477+
time.Sleep(15 * time.Second)
478+
}
479+
e2e.Logf("Confirmed: no new MC generated after IDMS creation (worker and master polled for 2 minutes)")
480+
481+
g.By("Step 4.1: Delete ICSP - should succeed without triggering a new MC (IDMS covers the same config)")
482+
specBeforeICSPDelete := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
483+
masterSpecBeforeICSPDelete := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
484+
err = operatorClient.ImageContentSourcePolicies().Delete(ctx, icspName1, metav1.DeleteOptions{})
485+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete ICSP %s", icspName1)
486+
e2e.Logf("ICSP %s deleted successfully", icspName1)
487+
488+
g.By("Step 4.2: Confirm no new MC was generated after ICSP deletion (IDMS still covers the same config)")
489+
noRolloutDeadline = time.Now().Add(2 * time.Minute)
490+
for time.Now().Before(noRolloutDeadline) {
491+
o.Expect(imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")).To(o.Equal(specBeforeICSPDelete),
492+
"worker MCP spec changed unexpectedly after ICSP deletion")
493+
o.Expect(imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")).To(o.Equal(masterSpecBeforeICSPDelete),
494+
"master MCP spec changed unexpectedly after ICSP deletion")
495+
time.Sleep(15 * time.Second)
496+
}
497+
e2e.Logf("Confirmed: no new MC generated after ICSP deletion (worker and master polled for 2 minutes)")
498+
499+
g.By("Step 5: Verify registries.conf is unchanged after ICSP deletion (IDMS maintains same mirror config)")
500+
registriesConfAfterICSPDelete, err := nodeutils.ExecOnNodeWithChroot(oc, workerNode, "cat", "/etc/containers/registries.conf")
501+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read registries.conf from node %s", workerNode)
502+
o.Expect(registriesConfAfterICSPDelete).To(o.Equal(registriesConf),
503+
"registries.conf should be unchanged after ICSP deletion when IDMS covers the same mirror config")
504+
e2e.Logf("Confirmed: registries.conf unchanged after ICSP deletion")
505+
506+
g.By("Step 6: Create ITMS with different registry/mirror config from IDMS - should trigger MCP rollout")
507+
itmsWorkerSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
508+
itmsMasterSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
509+
itms := &configv1.ImageTagMirrorSet{
510+
ObjectMeta: metav1.ObjectMeta{
511+
Name: itmsName,
512+
Labels: map[string]string{"e2e-test": "ocp-70203"},
513+
},
514+
Spec: configv1.ImageTagMirrorSetSpec{
515+
ImageTagMirrors: []configv1.ImageTagMirrors{
516+
{
517+
Source: "registry.access.redhat.com/ubi9/ubi-minimal",
518+
Mirrors: []configv1.ImageMirror{
519+
"example.io/example/ubi-minimal-1",
520+
"example.com/example/ubi-minimal-1",
521+
},
522+
MirrorSourcePolicy: configv1.AllowContactingSource,
523+
},
524+
},
525+
},
526+
}
527+
_, err = configClient.ImageTagMirrorSets().Create(ctx, itms, metav1.CreateOptions{})
528+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create ITMS %s", itmsName)
529+
e2e.Logf("ITMS %s created successfully", itmsName)
530+
531+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "worker", itmsWorkerSpec)
532+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "master", itmsMasterSpec)
533+
e2e.Logf("MCP rollout complete after ITMS creation")
534+
535+
g.By("Step 7: Verify registries.conf updated with new ITMS tag-only mirror entries")
536+
registriesConfAfterITMS, err := nodeutils.ExecOnNodeWithChroot(oc, workerNode, "cat", "/etc/containers/registries.conf")
537+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read registries.conf from node %s", workerNode)
538+
e2e.Logf("registries.conf after ITMS creation: read %d bytes, asserting expected entries", len(registriesConfAfterITMS))
539+
540+
o.Expect(registriesConfAfterITMS).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi9/ubi-minimal"`),
541+
"registries.conf should contain the ITMS source")
542+
o.Expect(registriesConfAfterITMS).To(o.ContainSubstring(`location = "example.io/example/ubi-minimal-1"`),
543+
"registries.conf should contain ITMS mirror example.io/example/ubi-minimal-1")
544+
o.Expect(registriesConfAfterITMS).To(o.ContainSubstring(`location = "example.com/example/ubi-minimal-1"`),
545+
"registries.conf should contain ITMS mirror example.com/example/ubi-minimal-1")
546+
o.Expect(registriesConfAfterITMS).To(o.ContainSubstring(`pull-from-mirror = "tag-only"`),
547+
"registries.conf should have pull-from-mirror = tag-only for ITMS entries")
548+
o.Expect(registriesConfAfterITMS).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi8/ubi-minimal"`),
549+
"registries.conf should still contain IDMS entries for ubi8/ubi-minimal")
550+
551+
g.By("Step 8: Create second ICSP with different registry/mirror config from both ITMS and IDMS - should trigger MCP rollout")
552+
icsp2WorkerSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
553+
icsp2MasterSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
554+
icsp2 := &operatorv1alpha1.ImageContentSourcePolicy{
555+
ObjectMeta: metav1.ObjectMeta{
556+
Name: icspName2,
557+
Labels: map[string]string{"e2e-test": "ocp-70203"},
558+
},
559+
Spec: operatorv1alpha1.ImageContentSourcePolicySpec{
560+
RepositoryDigestMirrors: []operatorv1alpha1.RepositoryDigestMirrors{
561+
{
562+
Source: "registry.example.com/example/myimage",
563+
Mirrors: []string{
564+
"mirror.example.net/image",
565+
},
566+
},
567+
},
568+
},
569+
}
570+
_, err = operatorClient.ImageContentSourcePolicies().Create(ctx, icsp2, metav1.CreateOptions{})
571+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create ICSP %s", icspName2)
572+
e2e.Logf("ICSP %s created successfully", icspName2)
573+
574+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "worker", icsp2WorkerSpec)
575+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "master", icsp2MasterSpec)
576+
e2e.Logf("MCP rollout complete after second ICSP creation")
577+
578+
g.By("Step 9: Verify registries.conf updated with new ICSP2 digest-only entries alongside existing IDMS and ITMS entries")
579+
registriesConfAfterICSP2, err := nodeutils.ExecOnNodeWithChroot(oc, workerNode, "cat", "/etc/containers/registries.conf")
580+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read registries.conf from node %s", workerNode)
581+
e2e.Logf("registries.conf after second ICSP creation: read %d bytes, asserting expected entries", len(registriesConfAfterICSP2))
582+
583+
o.Expect(registriesConfAfterICSP2).To(o.ContainSubstring(`location = "registry.example.com/example/myimage"`),
584+
"registries.conf should contain the ICSP2 source")
585+
o.Expect(registriesConfAfterICSP2).To(o.ContainSubstring(`location = "mirror.example.net/image"`),
586+
"registries.conf should contain the ICSP2 mirror")
587+
o.Expect(registriesConfAfterICSP2).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi8/ubi-minimal"`),
588+
"registries.conf should still contain IDMS entries for ubi8/ubi-minimal")
589+
o.Expect(registriesConfAfterICSP2).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi9/ubi-minimal"`),
590+
"registries.conf should still contain ITMS entries for ubi9/ubi-minimal")
591+
592+
g.By("Step 10: Delete IDMS and wait for MCP rollout")
593+
idmsDeleteWorkerSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "worker")
594+
idmsDeleteMasterSpec := imagepolicy.GetMCPCurrentSpecConfigName(oc, "master")
595+
err = configClient.ImageDigestMirrorSets().Delete(ctx, idmsName, metav1.DeleteOptions{})
596+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete IDMS %s", idmsName)
597+
e2e.Logf("IDMS %s deleted successfully", idmsName)
598+
599+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "worker", idmsDeleteWorkerSpec)
600+
imagepolicy.WaitForMCPConfigSpecChangeAndUpdated(oc, "master", idmsDeleteMasterSpec)
601+
e2e.Logf("MCP rollout complete after IDMS deletion")
602+
603+
g.By("Step 11: Verify registries.conf updated after IDMS deletion - IDMS entries removed, ITMS and ICSP2 entries remain")
604+
registriesConfAfterIDMSDelete, err := nodeutils.ExecOnNodeWithChroot(oc, workerNode, "cat", "/etc/containers/registries.conf")
605+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read registries.conf from node %s", workerNode)
606+
e2e.Logf("registries.conf after IDMS deletion: read %d bytes, asserting expected entries", len(registriesConfAfterIDMSDelete))
607+
608+
o.Expect(registriesConfAfterIDMSDelete).NotTo(o.ContainSubstring(`location = "registry.access.redhat.com/ubi8/ubi-minimal"`),
609+
"registries.conf should not contain IDMS source registry.access.redhat.com/ubi8/ubi-minimal after IDMS deletion")
610+
o.Expect(registriesConfAfterIDMSDelete).NotTo(o.ContainSubstring(`location = "registry.redhat.io/openshift5"`),
611+
"registries.conf should not contain IDMS source registry.redhat.io/openshift5 after IDMS deletion")
612+
o.Expect(registriesConfAfterIDMSDelete).To(o.ContainSubstring(`location = "registry.access.redhat.com/ubi9/ubi-minimal"`),
613+
"registries.conf should still contain ITMS entries for ubi9/ubi-minimal")
614+
o.Expect(registriesConfAfterIDMSDelete).To(o.ContainSubstring(`location = "registry.example.com/example/myimage"`),
615+
"registries.conf should still contain ICSP2 entries for registry.example.com/example/myimage")
616+
})
312617
})

0 commit comments

Comments
 (0)