Skip to content

Commit

Permalink
Add a new test case to cover preexisting CRD case
Browse files Browse the repository at this point in the history
Signed-off-by: Vu Dinh <[email protected]>
  • Loading branch information
dinhxuanvu committed Jun 19, 2019
1 parent 24c59dc commit 930163c
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 57 deletions.
50 changes: 25 additions & 25 deletions pkg/controller/operators/catalog/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,18 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo

// Allocate the new instance of an Operator.
op := &Operator{
Operator: queueOperator,
logger: logger,
clock: clock,
opClient: opClient,
client: crClient,
lister: lister,
namespace: operatorNamespace,
sources: make(map[resolver.CatalogKey]resolver.SourceRef),
resolver: resolver.NewOperatorsV1alpha1Resolver(lister),
catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(),
subQueueSet: queueinformer.NewEmptyResourceQueueSet(),
Operator: queueOperator,
logger: logger,
clock: clock,
opClient: opClient,
client: crClient,
lister: lister,
namespace: operatorNamespace,
sources: make(map[resolver.CatalogKey]resolver.SourceRef),
resolver: resolver.NewOperatorsV1alpha1Resolver(lister),
catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(),
subQueueSet: queueinformer.NewEmptyResourceQueueSet(),
csvProvidedAPIsIndexer: map[string]cache.Indexer{},
}
op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now)

Expand Down Expand Up @@ -253,19 +254,18 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
}

// Register CustomResourceDefinition QueueInformer
customResourceDefinitionInformer := extinf.NewSharedInformerFactory(op.OpClient.ApiextensionsV1beta1Interface(), wakeupInterval).Apiextensions().V1beta1().CustomResourceDefinitions()
op.RegisterQueueInformer(queueinformer.NewInformer(
workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "customresourcedefinitions"),
customResourceDefinitionInformer.Informer(),
op.syncObject,
&cache.ResourceEventHandlerFuncs{
DeleteFunc: op.handleDeletion,
},
"customresourcedefinitions",
metrics.NewMetricsNil(),
logger,
))
op.lister.APIExtensionsV1beta1().RegisterCustomResourceDefinitionLister(customResourceDefinitionInformer.Lister())
crdInformer := extinf.NewSharedInformerFactory(op.opClient.ApiextensionsV1beta1Interface(), resyncPeriod).Apiextensions().V1beta1().CustomResourceDefinitions()
op.lister.APIExtensionsV1beta1().RegisterCustomResourceDefinitionLister(crdInformer.Lister())
crdQueueInformer, err := queueinformer.NewQueueInformer(
ctx,
queueinformer.WithLogger(op.logger),
queueinformer.WithInformer(crdInformer.Informer()),
queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion)),
)
if err != nil {
return nil, err
}
op.RegisterQueueInformer(crdQueueInformer)

// Namespace sync for resolving subscriptions
namespaceInformer := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), resyncPeriod).Core().V1().Namespaces()
Expand Down Expand Up @@ -1070,7 +1070,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
if len(matchedCSV) == 1 {
// Attempt to update CRD
crd.SetResourceVersion(currentCRD.GetResourceVersion())
_, err = o.OpClient.ApiextensionsV1beta1Interface().ApiextensionsV1beta1().CustomResourceDefinitions().Update(&crd)
_, err = o.opClient.ApiextensionsV1beta1Interface().ApiextensionsV1beta1().CustomResourceDefinitions().Update(&crd)
if err != nil {
return errorwrap.Wrapf(err, "error update CRD: %s", step.Resource.Name)
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/lib/index/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ func CRDProviderNames(indexers map[string]cache.Indexer, crd v1beta1ext.CustomRe
crdSpec[fmt.Sprintf("%s/%s/%s", crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Kind)] = struct{}{}
}
for _, indexer := range indexers {
for key, _ := range crdSpec {
for key := range crdSpec {
csvs, err := indexer.ByIndex(ProvidedAPIsIndexFuncKey, key)
if err != nil {
return nil, err
}
for _, csv := range csvs {
csv, ok := csv.(*v1alpha1.ClusterServiceVersion)
for _, item := range csvs {
csv, ok := item.(*v1alpha1.ClusterServiceVersion)
if !ok {
continue
}
Expand Down
214 changes: 185 additions & 29 deletions test/e2e/installplan_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,15 +647,15 @@ func TestUpdateInstallPlan(t *testing.T) {
t.Run("UpdateSingleExistingCRDOwner", func(t *testing.T) {
defer cleaner.NotifyTestComplete(t, true)

mainPackageName := genName("nginx-")
mainPackageName := genName("nginx-update-")

mainPackageStable := fmt.Sprintf("%s-stable", mainPackageName)

stableChannel := "stable"

mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), nil, nil)

crdPlural := genName("ins-")
crdPlural := genName("ins-update-")
crdName := crdPlural + ".cluster.com"
mainCRD := apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -708,16 +708,6 @@ func TestUpdateInstallPlan(t *testing.T) {
},
}

expectedCRDVersions := map[v1beta1.CustomResourceDefinitionVersion]struct{}{}
for _, version := range updatedCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
expectedCRDVersions[key] = struct{}{}
}

mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, mainNamedStrategy)

c := newKubeClient(t)
Expand All @@ -726,7 +716,7 @@ func TestUpdateInstallPlan(t *testing.T) {
require.NoError(t, crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}))
}()

mainCatalogName := genName("mock-ocs-main-")
mainCatalogName := genName("mock-ocs-main-update-")

// Create separate manifests for each CatalogSource
mainManifests := []registry.PackageManifest{
Expand All @@ -746,7 +736,7 @@ func TestUpdateInstallPlan(t *testing.T) {
_, err := fetchCatalogSource(t, crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced)
require.NoError(t, err)

subscriptionName := genName("sub-nginx-")
subscriptionName := genName("sub-nginx-update-")
subscriptionCleanup := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic)
defer subscriptionCleanup()

Expand Down Expand Up @@ -775,47 +765,213 @@ func TestUpdateInstallPlan(t *testing.T) {
_, err = awaitCSV(t, crc, testNamespace, mainCSV.GetName(), csvAnyChecker)
require.NoError(t, err)

// Create new CSV to replace the one CSV
updatedCSV := newCSV(mainPackageStable+"-v2", testNamespace, mainPackageStable, semver.MustParse("0.1.1"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, mainNamedStrategy)
updateInternalCatalog(t, c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{updatedCRD}, []v1alpha1.ClusterServiceVersion{mainCSV}, mainManifests)

// Update the subscription resource
err = crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(metav1.NewDeleteOptions(0), metav1.ListOptions{})
require.NoError(t, err)

// existing cleanup should remove this
createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic)

// Wait for subscription to update
updatedSubscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker)
require.NoError(t, err)

// Verify installplan created and installed
fetchedUpdatedInstallPlan, err := fetchInstallPlan(t, crc, updatedSubscription.Status.InstallPlanRef.Name, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
require.NoError(t, err)
require.NotEqual(t, fetchedInstallPlan.GetName(), fetchedUpdatedInstallPlan.GetName())

// Wait for csv to update
_, err = awaitCSV(t, crc, testNamespace, mainCSV.GetName(), csvAnyChecker)
require.NoError(t, err)

// Get the CRD to see if it is updated
fetchedCRD, err := c.ApiextensionsV1beta1Interface().ApiextensionsV1beta1().CustomResourceDefinitions().Get(crdName, metav1.GetOptions{})
require.NoError(t, err)
require.Equal(t, len(fetchedCRD.Spec.Versions), len(updatedCRD.Spec.Versions), "The CRD versions counts don't match")

fetchedCRDVersions := map[v1beta1.CustomResourceDefinitionVersion]struct{}{}
for _, version := range fetchedCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
fetchedCRDVersions[key] = struct{}{}
}

for _, version := range updatedCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
_, ok := fetchedCRDVersions[key]
require.True(t, ok, "couldn't find %v in fetched CRD versions: %#v", key, fetchedCRDVersions)
}
})

t.Run("UpdatePreexistingCRDFailed", func(t *testing.T) {
defer cleaner.NotifyTestComplete(t, true)

c := newKubeClient(t)
crc := newCRClient(t)
defer func() {
require.NoError(t, crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}))
}()

mainPackageName := genName("nginx-update2-")

mainPackageStable := fmt.Sprintf("%s-stable", mainPackageName)

stableChannel := "stable"

mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), nil, nil)

crdPlural := genName("ins-update2-")
crdName := crdPlural + ".cluster.com"
mainCRD := apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: crdName,
},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "cluster.com",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "v1alpha1",
Served: true,
Storage: true,
},
},
Names: apiextensions.CustomResourceDefinitionNames{
Plural: crdPlural,
Singular: crdPlural,
Kind: crdPlural,
ListKind: "list" + crdPlural,
},
Scope: "Namespaced",
},
}

updatedCRD := apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: crdName,
},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "cluster.com",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "v1alpha1",
Served: true,
Storage: true,
},
{
Name: "v1alpha2",
Served: true,
Storage: false,
},
},
Names: apiextensions.CustomResourceDefinitionNames{
Plural: crdPlural,
Singular: crdPlural,
Kind: crdPlural,
ListKind: "list" + crdPlural,
},
Scope: "Namespaced",
},
}

expectedCRDVersions := map[v1beta1.CustomResourceDefinitionVersion]struct{}{}
for _, version := range mainCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
expectedCRDVersions[key] = struct{}{}
}

// Create the initial CSV
cleanupCRD, err := createCRD(c, mainCRD)
require.NoError(t, err)
defer cleanupCRD()

mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, mainNamedStrategy)

mainCatalogName := genName("mock-ocs-main-update2-")

// Update manifest
updatedManifests := []registry.PackageManifest{
// Create separate manifests for each CatalogSource
mainManifests := []registry.PackageManifest{
{
PackageName: mainPackageName,
Channels: []registry.PackageChannel{
{Name: stableChannel, CurrentCSVName: updatedCSV.GetName()},
{Name: stableChannel, CurrentCSVName: mainPackageStable},
},
DefaultChannelName: stableChannel,
},
}

updateInternalCatalog(t, c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{updatedCRD}, []v1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests)
// Create the catalog sources
_, cleanupMainCatalogSource := createInternalCatalogSource(t, c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{updatedCRD}, []v1alpha1.ClusterServiceVersion{mainCSV})
defer cleanupMainCatalogSource()
// Attempt to get the catalog source before creating install plan
_, err = fetchCatalogSource(t, crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced)
require.NoError(t, err)

// Wait for subscription to update
updatedSubscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasCurrentCSV(updatedCSV.GetName()))
subscriptionName := genName("sub-nginx-update2-")
subscriptionCleanup := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic)
defer subscriptionCleanup()

subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker)
require.NoError(t, err)
require.NotNil(t, subscription)
require.NotNil(t, subscription.Status.InstallPlanRef)
require.Equal(t, mainCSV.GetName(), subscription.Status.CurrentCSV)

// Verify installplan created and installed
fetchedUpdatedInstallPlan, err := fetchInstallPlan(t, crc, updatedSubscription.Status.InstallPlanRef.Name, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
installPlanName := subscription.Status.InstallPlanRef.Name

// Wait for InstallPlan to be status: Complete before checking resource presence
fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
require.NoError(t, err)
require.NotEqual(t, fetchedInstallPlan.GetName(), fetchedUpdatedInstallPlan.GetName())

// Wait for csv to update
_, err = awaitCSV(t, crc, testNamespace, updatedCSV.GetName(), csvAnyChecker)
require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase)

// Fetch installplan again to check for unnecessary control loops
fetchedInstallPlan, err = fetchInstallPlan(t, crc, fetchedInstallPlan.GetName(), func(fip *v1alpha1.InstallPlan) bool {
compareResources(t, fetchedInstallPlan, fip)
return true
})
require.NoError(t, err)

// Verify CSV is created
_, err = awaitCSV(t, crc, testNamespace, mainCSV.GetName(), csvAnyChecker)
require.NoError(t, err)

// Get the CRD to see if it is updated
fetchedCRD, err := c.ApiextensionsV1beta1Interface().ApiextensionsV1beta1().CustomResourceDefinitions().Get(crdName, metav1.GetOptions{})
require.NoError(t, err)
require.Equal(t, len(fetchedCRD.Spec.Versions), len(mainCRD.Spec.Versions), "The CRD versions counts don't match")

fetchedCRDVersions := map[v1beta1.CustomResourceDefinitionVersion]struct{}{}
for _, version := range fetchedCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
_, ok := expectedCRDVersions[key]
require.True(t, ok, "couldn't find %v in expected CRD versions: %#v", key, expectedCRDVersions)
fetchedCRDVersions[key] = struct{}{}
}

for _, version := range mainCRD.Spec.Versions {
key := v1beta1.CustomResourceDefinitionVersion{
Name: version.Name,
Served: version.Served,
Storage: version.Storage,
}
_, ok := fetchedCRDVersions[key]
require.True(t, ok, "couldn't find %v in fetched CRD versions: %#v", key, fetchedCRDVersions)
}
})
}
Expand Down

0 comments on commit 930163c

Please sign in to comment.