-
Notifications
You must be signed in to change notification settings - Fork 65
🌱 fix TestClusterExtensionInstallReResolvesWhenNewCataloge2e test #1008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,8 +124,11 @@ E2E_REGISTRY_NAME := docker-registry | |
E2E_REGISTRY_NAMESPACE := operator-controller-e2e | ||
|
||
export REG_PKG_NAME := registry-operator | ||
export REGISTRY_ROOT := $(E2E_REGISTRY_NAME).$(E2E_REGISTRY_NAMESPACE).svc:5000 | ||
export CATALOG_IMG := $(REGISTRY_ROOT)/e2e/test-catalog:e2e | ||
export LOCAL_REGISTRY_HOST := $(E2E_REGISTRY_NAME).$(E2E_REGISTRY_NAMESPACE).svc:5000 | ||
export CLUSTER_REGISTRY_HOST := localhost:30000 | ||
export E2E_TEST_CATALOG_V1 := e2e/test-catalog:v1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm seeing a lot of os.Getenvs in the e2es. Could we (if it's not there already), group the env vars that the e2e expects and add a comment? I know we'll find out relatively quickly if we deleted something we shouldn't, but I just want to avoid the CI run for that if we can. |
||
export E2E_TEST_CATALOG_V2 := e2e/test-catalog:v2 | ||
export CATALOG_IMG := $(LOCAL_REGISTRY_HOST)/$(E2E_TEST_CATALOG_V1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
.PHONY: test-ext-dev-e2e | ||
test-ext-dev-e2e: $(OPERATOR_SDK) $(KUSTOMIZE) $(KIND) #HELP Run extension create, upgrade and delete tests. | ||
test/extension-developer-e2e/setup.sh $(OPERATOR_SDK) $(CONTAINER_RUNTIME) $(KUSTOMIZE) $(KIND) $(KIND_CLUSTER_NAME) $(E2E_REGISTRY_NAMESPACE) | ||
|
@@ -141,7 +144,8 @@ image-registry: ## Setup in-cluster image registry | |
./test/tools/image-registry.sh $(E2E_REGISTRY_NAMESPACE) $(E2E_REGISTRY_NAME) | ||
|
||
build-push-e2e-catalog: ## Build the testdata catalog used for e2e tests and push it to the image registry | ||
./test/tools/build-push-e2e-catalog.sh $(E2E_REGISTRY_NAMESPACE) $(CATALOG_IMG) | ||
./test/tools/build-push-e2e-catalog.sh $(E2E_REGISTRY_NAMESPACE) $(LOCAL_REGISTRY_HOST)/$(E2E_TEST_CATALOG_V1) | ||
./test/tools/build-push-e2e-catalog.sh $(E2E_REGISTRY_NAMESPACE) $(LOCAL_REGISTRY_HOST)/$(E2E_TEST_CATALOG_V2) | ||
|
||
# When running the e2e suite, you can set the ARTIFACT_PATH variable to the absolute path | ||
# of the directory for the operator-controller e2e tests to store the artifacts, which | ||
|
@@ -202,10 +206,10 @@ kind-clean: $(KIND) #EXHELP Delete the kind cluster. | |
$(KIND) delete cluster --name $(KIND_CLUSTER_NAME) | ||
|
||
registry-load-bundles: ## Load selected e2e testdata container images created in kind-load-bundles into registry | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(REGISTRY_ROOT)/bundles/registry-v1/prometheus-operator:v1.0.0 prometheus-operator.v1.0.0 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(REGISTRY_ROOT)/bundles/registry-v1/prometheus-operator:v1.0.1 prometheus-operator.v1.0.1 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(REGISTRY_ROOT)/bundles/registry-v1/prometheus-operator:v1.2.0 prometheus-operator.v1.2.0 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(REGISTRY_ROOT)/bundles/registry-v1/prometheus-operator:v2.0.0 prometheus-operator.v2.0.0 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(LOCAL_REGISTRY_HOST)/bundles/registry-v1/prometheus-operator:v1.0.0 prometheus-operator.v1.0.0 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(LOCAL_REGISTRY_HOST)/bundles/registry-v1/prometheus-operator:v1.0.1 prometheus-operator.v1.0.1 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(LOCAL_REGISTRY_HOST)/bundles/registry-v1/prometheus-operator:v1.2.0 prometheus-operator.v1.2.0 prometheus-operator.v1.0.0 | ||
testdata/bundles/registry-v1/build-push-e2e-bundle.sh ${E2E_REGISTRY_NAMESPACE} $(LOCAL_REGISTRY_HOST)/bundles/registry-v1/prometheus-operator:v2.0.0 prometheus-operator.v2.0.0 prometheus-operator.v1.0.0 | ||
|
||
#SECTION Build | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import ( | |
"testing" | ||
"time" | ||
|
||
"github.com/google/go-containerregistry/pkg/crane" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"gopkg.in/yaml.v2" | ||
|
@@ -94,7 +95,7 @@ func TestClusterExtensionInstallRegistry(t *testing.T) { | |
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) | ||
assert.Contains(ct, cond.Message, "resolved to") | ||
assert.Equal(ct, &ocv1alpha1.BundleMetadata{Name: "prometheus-operator.2.0.0", Version: "2.0.0"}, clusterExtension.Status.ResolvedBundle) | ||
assert.Equal(ct, &ocv1alpha1.BundleMetadata{Name: "prometheus-operator.1.2.0", Version: "1.2.0"}, clusterExtension.Status.ResolvedBundle) | ||
}, pollDuration, pollInterval) | ||
|
||
t.Log("By eventually reporting a successful unpacked") | ||
|
@@ -123,75 +124,6 @@ func TestClusterExtensionInstallRegistry(t *testing.T) { | |
}, pollDuration, pollInterval) | ||
} | ||
|
||
func TestClusterExtensionInstallReResolvesWhenNewCatalog(t *testing.T) { | ||
t.Log("When a cluster extension is installed from a catalog") | ||
t.Log("It resolves again when a new catalog is available") | ||
|
||
clusterExtension, extensionCatalog := testInit(t) | ||
defer testCleanup(t, extensionCatalog, clusterExtension) | ||
defer getArtifactsOutput(t) | ||
|
||
pkgName := "prometheus" | ||
clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ | ||
PackageName: pkgName, | ||
InstallNamespace: "default", | ||
ServiceAccount: ocv1alpha1.ServiceAccountReference{ | ||
Name: "default", | ||
}, | ||
} | ||
|
||
t.Log("By deleting the catalog first") | ||
require.NoError(t, c.Delete(context.Background(), extensionCatalog)) | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
err := c.Get(context.Background(), types.NamespacedName{Name: extensionCatalog.Name}, &catalogd.ClusterCatalog{}) | ||
assert.True(ct, errors.IsNotFound(err)) | ||
}, pollDuration, pollInterval) | ||
|
||
t.Log("By creating the ClusterExtension resource") | ||
require.NoError(t, c.Create(context.Background(), clusterExtension)) | ||
|
||
// TODO: this isn't a good precondition because a missing package results in | ||
// exponential backoff retries. So we can't be sure that the re-reconcile is a result of | ||
// the catalog becoming available because it could also be a retry of the initial failed | ||
// resolution. | ||
t.Log("By failing to find ClusterExtension during resolution") | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) | ||
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionFalse, cond.Status) | ||
assert.Equal(ct, ocv1alpha1.ReasonResolutionFailed, cond.Reason) | ||
assert.Contains(ct, cond.Message, fmt.Sprintf("no package %q found", pkgName)) | ||
}, pollDuration, pollInterval) | ||
|
||
t.Log("By creating an ClusterExtension catalog with the desired package") | ||
var err error | ||
extensionCatalog, err = createTestCatalog(context.Background(), testCatalogName, os.Getenv(testCatalogRefEnvVar)) | ||
require.NoError(t, err) | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: extensionCatalog.Name}, extensionCatalog)) | ||
cond := apimeta.FindStatusCondition(extensionCatalog.Status.Conditions, catalogd.TypeUnpacked) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, catalogd.ReasonUnpackSuccessful, cond.Reason) | ||
}, pollDuration, pollInterval) | ||
|
||
t.Log("By eventually resolving the package successfully") | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) | ||
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) | ||
}, pollDuration, pollInterval) | ||
} | ||
|
||
func TestClusterExtensionBlockInstallNonSuccessorVersion(t *testing.T) { | ||
t.Log("When a cluster extension is installed from a catalog") | ||
t.Log("When resolving upgrade edges") | ||
|
@@ -337,6 +269,84 @@ func TestClusterExtensionInstallSuccessorVersion(t *testing.T) { | |
}, pollDuration, pollInterval) | ||
} | ||
|
||
func TestClusterExtensionInstallReResolvesWhenNewCatalog(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @joelanford I wonder if we should rethink the e2es to flow from each other some how and where possible. What I mean is, do we want (just about) every test to start with install a CE then wait? I'm wondering if instead we could 1) install something 2) upgrade that something 3) swap the catalog 4) bring it down, etc. I want to avoid as much as possible the 2h e2e test runtime (if possible). I know there's some pros and cons here. So, just wondering if there's another strategy that we can adopt that keep the resource usage lower while still giving us a strong signal. |
||
t.Log("When a cluster extension is installed from a catalog") | ||
t.Log("It resolves again when a new catalog is available") | ||
|
||
// Tag the image with the new tag | ||
var err error | ||
v1Image := fmt.Sprintf("%s/%s", os.Getenv("CLUSTER_REGISTRY_HOST"), os.Getenv("E2E_TEST_CATALOG_V1")) | ||
err = crane.Tag(v1Image, latestImageTag, crane.Insecure) | ||
require.NoError(t, err) | ||
|
||
// create a test-catalog with latest image tag | ||
latestCatalogImage := fmt.Sprintf("%s/e2e/test-catalog:latest", os.Getenv("LOCAL_REGISTRY_HOST")) | ||
extensionCatalog, err := createTestCatalog(context.Background(), testCatalogName, latestCatalogImage) | ||
require.NoError(t, err) | ||
clusterExtensionName := fmt.Sprintf("clusterextension-%s", rand.String(8)) | ||
clusterExtension := &ocv1alpha1.ClusterExtension{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: clusterExtensionName, | ||
}, | ||
} | ||
defer testCleanup(t, extensionCatalog, clusterExtension) | ||
defer getArtifactsOutput(t) | ||
|
||
clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ | ||
PackageName: "prometheus", | ||
InstallNamespace: "default", | ||
ServiceAccount: ocv1alpha1.ServiceAccountReference{ | ||
Name: "default", | ||
}, | ||
} | ||
t.Log("It resolves the specified package with correct bundle path") | ||
t.Log("By creating the ClusterExtension resource") | ||
require.NoError(t, c.Create(context.Background(), clusterExtension)) | ||
|
||
t.Log("By reporting a successful resolution and bundle path") | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) | ||
assert.Len(ct, clusterExtension.Status.Conditions, len(conditionsets.ConditionTypes)) | ||
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) | ||
assert.Contains(ct, cond.Message, "resolved to") | ||
assert.Equal(ct, &ocv1alpha1.BundleMetadata{Name: "prometheus-operator.1.2.0", Version: "1.2.0"}, clusterExtension.Status.ResolvedBundle) | ||
}, pollDuration, pollInterval) | ||
|
||
// update tag on test-catalog image with v2 image | ||
t.Log("By updating the catalog tag to point to the v2 catalog") | ||
v2Image := fmt.Sprintf("%s/%s", os.Getenv("CLUSTER_REGISTRY_HOST"), os.Getenv("E2E_TEST_CATALOG_V2")) | ||
err = crane.Tag(v2Image, latestImageTag, crane.Insecure) | ||
require.NoError(t, err) | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: extensionCatalog.Name}, extensionCatalog)) | ||
cond := apimeta.FindStatusCondition(extensionCatalog.Status.Conditions, catalogd.TypeUnpacked) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, catalogd.ReasonUnpackSuccessful, cond.Reason) | ||
}, pollDuration, pollInterval) | ||
|
||
t.Log("By eventually reporting a successful resolution and bundle path") | ||
require.EventuallyWithT(t, func(ct *assert.CollectT) { | ||
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) | ||
assert.Len(ct, clusterExtension.Status.Conditions, len(conditionsets.ConditionTypes)) | ||
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) | ||
if !assert.NotNil(ct, cond) { | ||
return | ||
} | ||
assert.Equal(ct, metav1.ConditionTrue, cond.Status) | ||
assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) | ||
assert.Contains(ct, cond.Message, "resolved to") | ||
assert.Equal(ct, &ocv1alpha1.BundleMetadata{Name: "prometheus-operator.2.0.0", Version: "2.0.0"}, clusterExtension.Status.ResolvedBundle) | ||
}, pollDuration, pollInterval) | ||
} | ||
|
||
// getArtifactsOutput gets all the artifacts from the test run and saves them to the artifact path. | ||
// Currently it saves: | ||
// - clusterextensions | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
FROM scratch | ||
ADD test-catalog-v2 /configs | ||
|
||
# Set DC-specific label for the location of the DC root directory | ||
# in the image | ||
LABEL operators.operatorframework.io.index.configs.v1=/configs |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/expected_all.json | ||
..* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
schema: olm.package | ||
name: prometheus | ||
defaultChannel: beta | ||
--- | ||
schema: olm.channel | ||
name: beta | ||
package: prometheus | ||
entries: | ||
- name: prometheus-operator.2.0.0 | ||
replaces: prometheus-operator.1.2.0 | ||
--- | ||
schema: olm.bundle | ||
name: prometheus-operator.2.0.0 | ||
package: prometheus | ||
image: docker-registry.operator-controller-e2e.svc.cluster.local:5000/bundles/registry-v1/prometheus-operator:v2.0.0 | ||
properties: | ||
- type: olm.package | ||
value: | ||
packageName: prometheus | ||
version: 2.0.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what others think, but to me it is more logical to flip these. LOCAL for
localhost
, CLUSTER for the service-based name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't call
localhost
a host, this is theENDPOINT
into the the cluster. It's really theexternal
callable address. Spitballing, because names are hard, but maybeCLUSTER_REGISTRY_INGRESS
?I agree the
svc:5000
address should be calledCLUSTER
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to address this before merging? Looks like we should...?