Add support for suspending image scans.
Co-authored-by: Michael Bridgen <mikeb@squaremobius.net>
This commit is contained in:
parent
0882b33903
commit
4c0f6d69be
|
@ -33,6 +33,11 @@ type ImageRepositorySpec struct {
|
|||
// scans of the image repository.
|
||||
// +optional
|
||||
ScanInterval *metav1.Duration `json:"scanInterval,omitempty"`
|
||||
|
||||
// This flag tells the controller to suspend subsequent image scans.
|
||||
// It does not apply to already started scans. Defaults to false.
|
||||
// +optional
|
||||
Suspend bool `json:"suspend,omitempty"`
|
||||
}
|
||||
|
||||
type ScanResult struct {
|
||||
|
|
|
@ -51,6 +51,11 @@ spec:
|
|||
description: ScanInterval is the (minimum) length of time to wait
|
||||
between scans of the image repository.
|
||||
type: string
|
||||
suspend:
|
||||
description: This flag tells the controller to suspend
|
||||
scanning of the image repository.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
type: object
|
||||
status:
|
||||
description: ImageRepositoryStatus defines the observed state of ImageRepository
|
||||
|
|
|
@ -77,6 +77,22 @@ func (r *ImageRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er
|
|||
|
||||
log := r.Log.WithValues("controller", strings.ToLower(imagev1alpha1.ImageRepositoryKind), "request", req.NamespacedName)
|
||||
|
||||
if imageRepo.Spec.Suspend {
|
||||
msg := "ImageRepository is suspended, skipping reconciliation"
|
||||
status := imagev1alpha1.SetImageRepositoryReadiness(
|
||||
imageRepo,
|
||||
corev1.ConditionFalse,
|
||||
imagev1alpha1.SuspendedReason,
|
||||
msg,
|
||||
)
|
||||
if err := r.Status().Update(ctx, &status); err != nil {
|
||||
log.Error(err, "unable to update status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
log.Info(msg)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(imageRepo.Spec.Image)
|
||||
if err != nil {
|
||||
status := imagev1alpha1.SetImageRepositoryReadiness(
|
||||
|
|
|
@ -36,17 +36,24 @@ import (
|
|||
// has an example of loading a test registry with a random image.
|
||||
|
||||
var _ = Describe("ImageRepository controller", func() {
|
||||
const imageName = "alpine-image"
|
||||
var repo imagev1alpha1.ImageRepository
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(k8sClient.Delete(context.Background(), &repo)).To(Succeed())
|
||||
})
|
||||
|
||||
It("expands the canonical image name", func() {
|
||||
// would be good to test this without needing to do the scanning, since
|
||||
// 1. better to not rely on external services being available
|
||||
// 2. probably going to want to have several test cases
|
||||
repo := imagev1alpha1.ImageRepository{
|
||||
repo = imagev1alpha1.ImageRepository{
|
||||
Spec: imagev1alpha1.ImageRepositorySpec{
|
||||
Image: "alpine",
|
||||
},
|
||||
}
|
||||
imageRepoName := types.NamespacedName{
|
||||
Name: "alpine-image",
|
||||
Name: imageName,
|
||||
Namespace: "default",
|
||||
}
|
||||
|
||||
|
@ -65,7 +72,7 @@ var _ = Describe("ImageRepository controller", func() {
|
|||
err := r.Get(context.Background(), imageRepoName, &repoAfter)
|
||||
return err == nil && repoAfter.Status.CanonicalImageName != ""
|
||||
}, timeout, interval).Should(BeTrue())
|
||||
Expect(repoAfter.Name).To(Equal("alpine-image"))
|
||||
Expect(repoAfter.Name).To(Equal(imageName))
|
||||
Expect(repoAfter.Namespace).To(Equal("default"))
|
||||
Expect(repoAfter.Status.CanonicalImageName).To(Equal("index.docker.io/library/alpine"))
|
||||
})
|
||||
|
@ -74,7 +81,7 @@ var _ = Describe("ImageRepository controller", func() {
|
|||
versions := []string{"0.1.0", "0.1.1", "0.2.0", "1.0.0", "1.0.1", "1.0.2", "1.1.0-alpha"}
|
||||
imgRepo := loadImages("test-fetch", versions)
|
||||
|
||||
repo := imagev1alpha1.ImageRepository{
|
||||
repo = imagev1alpha1.ImageRepository{
|
||||
Spec: imagev1alpha1.ImageRepositorySpec{
|
||||
Image: imgRepo,
|
||||
},
|
||||
|
@ -101,6 +108,45 @@ var _ = Describe("ImageRepository controller", func() {
|
|||
Expect(repoAfter.Status.CanonicalImageName).To(Equal(imgRepo))
|
||||
Expect(repoAfter.Status.LastScanResult.TagCount).To(Equal(len(versions)))
|
||||
})
|
||||
|
||||
Context("when the ImageRepository is suspended", func() {
|
||||
It("does not process the image", func() {
|
||||
repo = imagev1alpha1.ImageRepository{
|
||||
Spec: imagev1alpha1.ImageRepositorySpec{
|
||||
Image: "alpine",
|
||||
Suspend: true,
|
||||
},
|
||||
}
|
||||
imageRepoName := types.NamespacedName{
|
||||
Name: imageName,
|
||||
Namespace: "default",
|
||||
}
|
||||
|
||||
repo.Name = imageRepoName.Name
|
||||
repo.Namespace = imageRepoName.Namespace
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
r := imageRepoReconciler
|
||||
|
||||
err := r.Create(ctx, &repo)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
var repoAfter imagev1alpha1.ImageRepository
|
||||
Eventually(func() bool {
|
||||
err := r.Get(ctx, imageRepoName, &repoAfter)
|
||||
return err == nil && len(repoAfter.Status.Conditions) > 0
|
||||
}, timeout, interval).Should(BeTrue())
|
||||
Expect(repoAfter.Status.CanonicalImageName).To(Equal(""))
|
||||
cond := repoAfter.Status.Conditions[0]
|
||||
Expect(cond.Message).To(
|
||||
Equal("ImageRepository is suspended, skipping reconciliation"))
|
||||
Expect(cond.Reason).To(
|
||||
Equal(imagev1alpha1.SuspendedReason))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// loadImages uploads images to the local registry, and returns the
|
||||
|
|
Loading…
Reference in New Issue