Skip to content

Commit

Permalink
Update asoctl clean command to clean beta CRDs
Browse files Browse the repository at this point in the history
This command will no longer work on alpha relases because we changed how
the CRD listing is done (now uses label, which alpha doesn't have), but
as per our metrics alpha has no more usage, and older asoctl versions will
still work to clean alpha.
  • Loading branch information
matthchr committed Oct 13, 2023
1 parent 823a0be commit f617389
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 42 deletions.
1 change: 1 addition & 0 deletions v2/cmd/asoctl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/hbollon/go-edlib v1.6.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions v2/cmd/asoctl/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hbollon/go-edlib v1.6.0 h1:ga7AwwVIvP8mHm9GsPueC0d71cfRU/52hmPJ7Tprv4E=
github.com/hbollon/go-edlib v1.6.0/go.mod h1:wnt6o6EIVEzUfgbUZY7BerzQ2uvzp354qmS2xaLkrhM=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand Down
43 changes: 31 additions & 12 deletions v2/cmd/asoctl/internal/crd/cleaner.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/Azure/azure-service-operator/v2/internal/crdmanagement"
)

type Cleaner struct {
Expand Down Expand Up @@ -60,25 +64,40 @@ func (c *Cleaner) Run(ctx context.Context) error {
c.log.Info("Starting update")
}

list, err := c.apiExtensionsClient.List(ctx, v1.ListOptions{})
appLabelRequirement, err := labels.NewRequirement(crdmanagement.ServiceOperatorAppLabel, selection.Equals, []string{crdmanagement.ServiceOperatorAppValue})
if err != nil {
return err
}
selector := labels.NewSelector()
selector = selector.Add(*appLabelRequirement)
crdsWithNewLabel, err := c.apiExtensionsClient.List(ctx, v1.ListOptions{LabelSelector: selector.String()})
if err != nil {
return errors.Wrap(err, "failed to list CRDs")
}

versionLabelRequirement, err := labels.NewRequirement(crdmanagement.ServiceOperatorVersionLabelOld, selection.Exists, []string{})
if err != nil {
return err
}
selector = labels.NewSelector()
selector = selector.Add(*versionLabelRequirement)
crdsWithOldLabel, err := c.apiExtensionsClient.List(ctx, v1.ListOptions{LabelSelector: selector.String()})
if err != nil {
return errors.Wrap(err, "failed to list CRDs")
}

var crds []apiextensions.CustomResourceDefinition
crds = append(crds, crdsWithNewLabel.Items...)
crds = append(crds, crdsWithOldLabel.Items...)

var updated int
var asoCrdsSeen int
crdRegexp := regexp.MustCompile(`.*\.azure\.com`)
deprecatedVersionRegexp := regexp.MustCompile(`v1alpha1api\d{8}(preview)?(storage)?`)
var asoCRDsSeen int
deprecatedVersionRegexp := regexp.MustCompile(`(v1alpha1api|v1beta)\d{8}(preview)?(storage)?`)

for _, crd := range list.Items {
for _, crd := range crds {
crd := crd

if !crdRegexp.MatchString(crd.Name) {
c.log.V(1).Info("Skipping CRD", "crd-name", crd.Name)
continue
}

asoCrdsSeen++
asoCRDsSeen++
newStoredVersions, deprecatedVersion := removeMatchingStoredVersions(crd.Status.StoredVersions, deprecatedVersionRegexp)

// If there is no new version found other than the matched version, we short circuit here, as there is no updated version found in the CRDs
Expand Down Expand Up @@ -119,7 +138,7 @@ func (c *Cleaner) Run(ctx context.Context) error {
updated++
}

if asoCrdsSeen <= 0 {
if asoCRDsSeen <= 0 {
return errors.New("found no Azure Service Operator CRDs, make sure you have ASO installed.")
}

Expand Down
63 changes: 33 additions & 30 deletions v2/cmd/asoctl/internal/crd/cleaner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
fake2 "sigs.k8s.io/controller-runtime/pkg/client/fake"

"github.com/Azure/azure-service-operator/v2/api"
resources "github.com/Azure/azure-service-operator/v2/api/resources/v1beta20200601"
resources "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601"
"github.com/Azure/azure-service-operator/v2/internal/util/to"
)

Expand All @@ -49,17 +49,17 @@ func makeClientSets() *clientSet {
}
}

func Test_CleanDeprecatedCRDVersions_CleansAlphaVersion_IfExists(t *testing.T) {
func Test_CleanDeprecatedCRDVersions_CleansBetaVersion_IfExists(t *testing.T) {
t.Parallel()

c := makeClientSets()

g := NewGomegaWithT(t)

alphaVersion := "v1alpha1api20200601"
betaVersion := "v1beta20200601"
gaVersion := "v1api20200601"

definition := newCRDWithStoredVersions("v1alpha1api20200601", "v1beta20200601")
definition := newCRDWithStoredVersions(betaVersion, gaVersion)

_, err := c.fakeApiExtClient.CustomResourceDefinitions().Create(context.TODO(), definition, metav1.CreateOptions{})
g.Expect(err).To(BeNil())
Expand All @@ -72,24 +72,24 @@ func Test_CleanDeprecatedCRDVersions_CleansAlphaVersion_IfExists(t *testing.T) {

g.Expect(crd.Status.StoredVersions).ToNot(BeNil())
g.Expect(crd.Status.StoredVersions).ToNot(BeEquivalentTo(definition.Status.StoredVersions))
g.Expect(crd.Status.StoredVersions).ToNot(ContainElement(alphaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
g.Expect(crd.Status.StoredVersions).ToNot(ContainElement(betaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(gaVersion))
}

func Test_MigrateDeprecatedCRDResources_DoesNotMigrateAlphaVersion_IfStorage(t *testing.T) {
func Test_MigrateDeprecatedCRDResources_DoesNotMigrateBetaVersion_IfStorage(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

c := makeClientSets()

// This test does not include beta non-storage version, as that would never be possible. Always the latest version would be set to storage
alphaVersion := "v1alpha1api20200601"
// This test does not include GA non-storage version, as that would never be possible. Always the latest version would be set to storage
betaVersion := "v1beta20200601"

// create CRD
definition := newCRDWithStoredVersions(alphaVersion)
definition := newCRDWithStoredVersions(betaVersion)
definition.Spec.Versions = []v1.CustomResourceDefinitionVersion{
{
Name: alphaVersion,
Name: betaVersion,
Storage: true,
},
}
Expand Down Expand Up @@ -120,26 +120,26 @@ func Test_MigrateDeprecatedCRDResources_DoesNotMigrateAlphaVersion_IfStorage(t *
g.Expect(updatedRG.ResourceVersion).To(BeEquivalentTo(rg.ResourceVersion))

g.Expect(crd.Status.StoredVersions).ToNot(BeNil())
g.Expect(crd.Status.StoredVersions).To(ContainElement(alphaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
}

func Test_MigrateDeprecatedCRDResources_MigratesAlpha_IfNotStorage(t *testing.T) {
func Test_MigrateDeprecatedCRDResources_MigratesBeta_IfNotStorage(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

c := makeClientSets()

alphaVersion := "v1alpha1api20200601"
betaVersion := "v1beta20200601"
gaVersion := "v1api20200601"

// create CRD
definition := newCRDWithStoredVersions(alphaVersion, betaVersion)
definition := newCRDWithStoredVersions(betaVersion, gaVersion)
definition.Spec.Versions = []v1.CustomResourceDefinitionVersion{
{
Name: alphaVersion,
Name: betaVersion,
},
{
Name: betaVersion,
Name: gaVersion,
Storage: true,
},
}
Expand Down Expand Up @@ -171,17 +171,17 @@ func Test_MigrateDeprecatedCRDResources_MigratesAlpha_IfNotStorage(t *testing.T)

g.Expect(crd.Status.StoredVersions).ToNot(BeNil())
g.Expect(crd.Status.StoredVersions).ToNot(BeEquivalentTo(definition.Status.StoredVersions))
g.Expect(crd.Status.StoredVersions).ToNot(ContainElement(alphaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
g.Expect(crd.Status.StoredVersions).ToNot(ContainElement(betaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(gaVersion))
}

func Test_CleanDeprecatedCRDVersions_DoesNothing_IfAlphaVersionDoesNotExist(t *testing.T) {
func Test_CleanDeprecatedCRDVersions_DoesNothing_IfBetaVersionDoesNotExist(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

c := makeClientSets()

betaVersion := "v1beta20230101storage"
betaVersion := "v1api20230101storage"

definition := newCRDWithStoredVersions(betaVersion)

Expand All @@ -201,15 +201,15 @@ func Test_CleanDeprecatedCRDVersions_DoesNothing_IfAlphaVersionDoesNotExist(t *t
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
}

func Test_CleanDeprecatedCRDVersions_ReturnsError_IfBetaVersionDoesNotExist(t *testing.T) {
func Test_CleanDeprecatedCRDVersions_ReturnsError_IfGAVersionDoesNotExist(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

c := makeClientSets()

alphaVersion := "v1alpha1api20230101storage"
betaVersion := "v1beta20230101storage"

definition := newCRDWithStoredVersions(alphaVersion)
definition := newCRDWithStoredVersions(betaVersion)

_, err := c.fakeApiExtClient.CustomResourceDefinitions().Create(context.TODO(), definition, metav1.CreateOptions{})
if err != nil {
Expand All @@ -224,7 +224,7 @@ func Test_CleanDeprecatedCRDVersions_ReturnsError_IfBetaVersionDoesNotExist(t *t

g.Expect(crd.Status.StoredVersions).ToNot(BeNil())
g.Expect(crd.Status.StoredVersions).To(HaveLen(1))
g.Expect(crd.Status.StoredVersions).To(ContainElement(alphaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
}

func Test_MigrateAndCleanDeprecatedCRDResources_DryRun_NoAction(t *testing.T) {
Expand All @@ -239,18 +239,18 @@ func Test_MigrateAndCleanDeprecatedCRDResources_DryRun_NoAction(t *testing.T) {
true, // dry-run
logr.Discard())

alphaVersion := "v1alpha1api20200601"
betaVersion := "v1beta20200601"
gaVersion := "v1api20200601"

// create CRD
definition := newCRDWithStoredVersions(alphaVersion, betaVersion)
definition := newCRDWithStoredVersions(betaVersion, gaVersion)
definition.Spec.Versions = []v1.CustomResourceDefinitionVersion{
{
Name: alphaVersion,
Name: betaVersion,
Storage: true,
},
{
Name: betaVersion,
Name: gaVersion,
},
}

Expand Down Expand Up @@ -281,8 +281,8 @@ func Test_MigrateAndCleanDeprecatedCRDResources_DryRun_NoAction(t *testing.T) {

g.Expect(crd.Status.StoredVersions).ToNot(BeNil())
g.Expect(definition.Status.StoredVersions).To(BeEquivalentTo(crd.Status.StoredVersions))
g.Expect(crd.Status.StoredVersions).To(ContainElement(alphaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(betaVersion))
g.Expect(crd.Status.StoredVersions).To(ContainElement(gaVersion))
}

func newNamespace(name string) *corev1.Namespace {
Expand Down Expand Up @@ -311,6 +311,9 @@ func newCRDWithStoredVersions(versions ...string) *v1.CustomResourceDefinition {
definition := &v1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "resourcegroups.resources.azure.com",
Labels: map[string]string{
"app.kubernetes.io/name": "azure-service-operator",
},
},
Spec: v1.CustomResourceDefinitionSpec{
Group: "resources.azure.com",
Expand Down

0 comments on commit f617389

Please sign in to comment.