Repository: operator-framework/operator-lifecycle-manager
Pull request #1591 (2020-06-23 19:20:25)

Bug 1850237: Delete subscription metric when an operator is uninstalled
**Description of the change:**

When an operator was subscribed to using a Subscription Object,
the subscription_sync_total metric was emitted whenever the Subscription
Object was created/updated/deleted. This PR updates that behaviour to emit
the metric only when the Subscription object is created/updated, and deletes
the time series for that particular subscription when the subscription object
is deleted.

**Motivation for the change:**

**Reviewer Checklist**
- [ ] Implementation matches the proposed design, or proposal is updated to match implementation
- [ ] Sufficient unit test coverage 
- [ ] Sufficient end-to-end test coverage
- [ ] Docs updated or added to `/docs` 
- [ ] Commit messages sensible and descriptive



openshift-ci-robot: @anik120: This pull request references [Bugzilla bug 1850237](https://bugzilla.redhat.com/show_bug.cgi?id=1850237), which is invalid:
 - expected the bug to target the "4.5.0" release, but it targets "4.5.z" instead

Comment <code>/bugzilla refresh</code> to re-evaluate validity if changes to the Bugzilla bug are made, or edit the title of this pull request to link to a different bug.

<details>

In response to [this](https://github.com/operator-framework/operator-lifecycle-manager/pull/1591):

>Bug 1850237: Delete subscription metric when an operator is uninstalled


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/operator-framework/operator-lifecycle-manager/pull/1591#" title="Author self-approved">anik120</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **njhale**
You can assign the PR to them by writing `/assign @njhale` in a comment when ready.

The full list of commands accepted by this bot can be found [here](?repo=operator-framework%2Foperator-lifecycle-manager).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/operator-framework/operator-lifecycle-manager/blob/release-4.5/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["njhale"]} -->
anik120: /bugzilla refresh 
openshift-ci-robot: @anik120: This pull request references [Bugzilla bug 1850237](https://bugzilla.redhat.com/show_bug.cgi?id=1850237), which is valid. The bug has been moved to the POST state. The bug has been updated to refer to the pull request using the external bug tracker.

<details><summary>6 validation(s) were run on this bug</summary>

* bug is open, matching expected state (open)
* bug target release (4.5.0) matches configured target release for branch (4.5.0)
* bug is in the state NEW, which is one of the valid states (NEW, ASSIGNED, ON_DEV, POST, POST)
* dependent bug [Bugzilla bug 1822396](https://bugzilla.redhat.com/show_bug.cgi?id=1822396) is in the state ON_QA, which is one of the valid states (MODIFIED, ON_QA, VERIFIED)
* dependent [Bugzilla bug 1822396](https://bugzilla.redhat.com/show_bug.cgi?id=1822396) targets the "4.6.0" release, which is one of the valid target releases: 4.6.0, 4.6.z
* bug has dependents</details>

<details>

In response to [this](https://github.com/operator-framework/operator-lifecycle-manager/pull/1591#issuecomment-648370527):

>/bugzilla refresh 


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 82d5d060f2ef289bd9f3ef01041c7e2dc96f3826 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1275509039509278720) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anik120: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 82d5d060f2ef289bd9f3ef01041c7e2dc96f3826 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1275509039509278720) | `/test e2e-aws-olm`
ci/prow/e2e-aws-console-olm | 82d5d060f2ef289bd9f3ef01041c7e2dc96f3826 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-console-olm/1275509039475724288) | `/test e2e-aws-console-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anik120: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-console-olm | 82d5d060f2ef289bd9f3ef01041c7e2dc96f3826 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-console-olm/1275509039475724288) | `/test e2e-aws-console-olm`
ci/prow/e2e-aws-olm | 9f4b9a8dd0a5c679f20371c7d4cdcc65c8c859ee | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1276028083014471680) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anik120: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 9f4b9a8dd0a5c679f20371c7d4cdcc65c8c859ee | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1276028083014471680) | `/test e2e-aws-olm`
ci/prow/e2e-gcp | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-gcp/1276047445830144000) | `/test e2e-gcp`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anik120: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-gcp | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-gcp/1276047445830144000) | `/test e2e-gcp`
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1276047436334239744) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1276179862662418432) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /test e2e-aws-olm
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1276286166588461056) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
njhale: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1277622446769311744) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1277641165121785856) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1278361896616988672) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1280135157918994432) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest
openshift-ci-robot: @anik120: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-aws-olm | 5e006a9753facbc77840612c1b48452017068153 | [link](https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/operator-framework_operator-lifecycle-manager/1591/pull-ci-operator-framework-operator-lifecycle-manager-release-4.5-e2e-aws-olm/1280209365252444160) | `/test e2e-aws-olm`

[Full PR test history](https://prow.svc.ci.openshift.org/pr-history?org=operator-framework&repo=operator-lifecycle-manager&pr=1591). [Your PR dashboard](https://prow.svc.ci.openshift.org/pr?query=is:pr+state:open+author:anik120). Please help us cut down on flakes by [linking to](https://github.com/kubernetes/community/blob/master/contributors/devel/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/operator-framework/operator-lifecycle-manager/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
anik120: /retest

Patch:
diff --git a/pkg/controller/bundle/bundle_unpacker.go b/pkg/controller/bundle/bundle_unpacker.go
index bfca2f92d..a76427a03 100644
--- a/pkg/controller/bundle/bundle_unpacker.go
+++ b/pkg/controller/bundle/bundle_unpacker.go
@@ -34,27 +34,6 @@ func (b *BundleUnpackResult) Bundle() *api.Bundle {
 	return b.bundle
 }
 
-func (b *BundleUnpackResult) Name() string {
-	return b.name
-}
-
-// SetCondition replaces the existing BundleLookupCondition of the same type, or adds it if it was not found.
-func (b *BundleUnpackResult) SetCondition(cond operatorsv1alpha1.BundleLookupCondition) operatorsv1alpha1.BundleLookupCondition {
-	for i, existing := range b.Conditions {
-		if existing.Type != cond.Type {
-			continue
-		}
-		if existing.Status == cond.Status && existing.Reason == cond.Reason {
-			cond.LastTransitionTime = existing.LastTransitionTime
-		}
-		b.Conditions[i] = cond
-		return cond
-	}
-	b.Conditions = append(b.Conditions, cond)
-
-	return cond
-}
-
 var catalogSourceGVK = operatorsv1alpha1.SchemeGroupVersion.WithKind(operatorsv1alpha1.CatalogSourceKind)
 
 func newBundleUnpackResult(lookup *operatorsv1alpha1.BundleLookup) *BundleUnpackResult {
@@ -272,26 +251,16 @@ const (
 	CatalogSourceMissingMessage = "referenced catalogsource not found"
 	JobIncompleteReason         = "JobIncomplete"
 	JobIncompleteMessage        = "unpack job not completed"
-	JobNotStartedReason         = "JobNotStarted"
-	JobNotStartedMessage        = "unpack job not yet started"
-	NotUnpackedReason           = "BundleNotUnpacked"
-	NotUnpackedMessage          = "bundle contents have not yet been persisted to installplan status"
 )
 
 func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup) (result *BundleUnpackResult, err error) {
 	result = newBundleUnpackResult(lookup)
-
-	// if pending condition is missing, bundle has already been unpacked
 	cond := result.GetCondition(operatorsv1alpha1.BundleLookupPending)
-	if cond.Status == corev1.ConditionUnknown {
-		return result, nil
-	}
-
 	now := c.now()
 
 	var cs *operatorsv1alpha1.CatalogSource
 	if cs, err = c.csLister.CatalogSources(result.CatalogSourceRef.Namespace).Get(result.CatalogSourceRef.Name); err != nil {
-		if apierrors.IsNotFound(err) && cond.Reason != CatalogSourceMissingReason {
+		if apierrors.IsNotFound(err) && cond.Status != corev1.ConditionTrue && cond.Reason != CatalogSourceMissingReason {
 			cond.Status = corev1.ConditionTrue
 			cond.Reason = CatalogSourceMissingReason
 			cond.Message = CatalogSourceMissingMessage
@@ -335,7 +304,7 @@ func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup)
 		return
 	}
 
-	if !jobConditionTrue(job, batchv1.JobComplete) && (cond.Status != corev1.ConditionTrue || cond.Reason != JobIncompleteReason) {
+	if !jobConditionTrue(job, batchv1.JobComplete) && cond.Status != corev1.ConditionTrue && cond.Reason != JobIncompleteReason {
 		cond.Status = corev1.ConditionTrue
 		cond.Reason = JobIncompleteReason
 		cond.Message = JobIncompleteMessage
@@ -350,10 +319,6 @@ func (c *ConfigMapUnpacker) UnpackBundle(lookup *operatorsv1alpha1.BundleLookup)
 		return
 	}
 
-	if result.Bundle() == nil || len(result.Bundle().GetObject()) == 0 {
-		return
-	}
-
 	// A successful load should remove the pending condition
 	result.RemoveCondition(operatorsv1alpha1.BundleLookupPending)
 
diff --git a/pkg/controller/operators/catalog/manifests.go b/pkg/controller/operators/catalog/manifests.go
deleted file mode 100644
index d3b4e03b2..000000000
--- a/pkg/controller/operators/catalog/manifests.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package catalog
-
-import (
-	"encoding/json"
-	"fmt"
-
-	"github.com/operator-framework/api/pkg/operators/v1alpha1"
-	"github.com/operator-framework/operator-registry/pkg/configmap"
-	errorwrap "github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
-	v1 "k8s.io/client-go/listers/core/v1"
-
-	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
-)
-
-// ManifestResolver can dereference a manifest for a step. Steps may embed manifests directly or reference content
-// in configmaps
-type ManifestResolver interface {
-	ManifestForStep(step *v1alpha1.Step) (string, error)
-}
-
-// manifestResolver caches manifest from unpacked bundles (via configmaps)
-type manifestResolver struct {
-	configMapLister v1.ConfigMapLister
-	unpackedSteps   map[string][]v1alpha1.StepResource
-	namespace       string
-	logger          logrus.FieldLogger
-}
-
-func newManifestResolver(namespace string, configMapLister v1.ConfigMapLister, logger logrus.FieldLogger) *manifestResolver {
-	return &manifestResolver{
-		namespace:       namespace,
-		configMapLister: configMapLister,
-		unpackedSteps:   map[string][]v1alpha1.StepResource{},
-		logger:          logger,
-	}
-}
-
-// ManifestForStep always returns the manifest that should be applied to the cluster for a given step
-// the manifest field in the installplan status can contain a reference to a configmap instead
-func (r *manifestResolver) ManifestForStep(step *v1alpha1.Step) (string, error) {
-	manifest := step.Resource.Manifest
-	ref := refForStep(step, r.logger)
-	if ref == nil {
-		return manifest, nil
-	}
-
-	log := r.logger.WithFields(logrus.Fields{"resolving": step.Resolving, "step": step.Resource.Name})
-	log.WithField("ref", ref).Debug("step is a reference to configmap")
-
-	usteps, err := r.unpackedStepsForBundle(step.Resolving, ref)
-	if err != nil  {
-		return "", err
-	}
-
-	log.Debugf("checking cache for unpacked step")
-	// need to find the real manifest from the unpacked steps
-	for _, u := range usteps {
-		if u.Name == step.Resource.Name &&
-			u.Kind == step.Resource.Kind &&
-			u.Version == step.Resource.Version &&
-			u.Group == step.Resource.Group {
-			manifest = u.Manifest
-			log.WithField("manifest", manifest).Debug("step replaced with unpacked value")
-			break
-		}
-	}
-	if manifest == step.Resource.Manifest {
-		return "", fmt.Errorf("couldn't find unpacked step for %v", step)
-	}
-	return manifest, nil
-}
-
-func (r *manifestResolver) unpackedStepsForBundle(bundleName string, ref *UnpackedBundleReference) ([]v1alpha1.StepResource, error) {
-	usteps, ok := r.unpackedSteps[bundleName]
-	if ok {
-		return usteps, nil
-	}
-	cm, err := r.configMapLister.ConfigMaps(ref.Namespace).Get(ref.Name)
-	if err != nil {
-		return nil, errorwrap.Wrapf(err, "error finding unpacked bundle configmap for ref %v", *ref)
-	}
-	loader := configmap.NewBundleLoader()
-	bundle, err := loader.Load(cm)
-	if err != nil {
-		return nil, errorwrap.Wrapf(err, "error loading unpacked bundle configmap for ref %v", *ref)
-	}
-	steps, err := resolver.NewStepResourceFromBundle(bundle, r.namespace, ref.Replaces, ref.CatalogSourceName, ref.CatalogSourceNamespace)
-	if err != nil {
-		return nil, errorwrap.Wrapf(err, "error calculating steps for ref %v", *ref)
-	}
-	r.unpackedSteps[bundleName] = steps
-	return steps, nil
-}
-
-func refForStep(step *v1alpha1.Step, log logrus.FieldLogger) *UnpackedBundleReference {
-	log = log.WithFields(logrus.Fields{"resolving": step.Resolving, "step": step.Resource.Name})
-	var ref UnpackedBundleReference
-	if err := json.Unmarshal([]byte(step.Resource.Manifest), &ref); err != nil {
-		log.Debug("step is not a reference to an unpacked bundle (this is not an error if the step is a manifest)")
-		return nil
-	}
-	log = log.WithField("ref", ref)
-	if ref.Kind != "ConfigMap" || ref.Name == "" || ref.Namespace == "" || ref.CatalogSourceName == "" || ref.CatalogSourceNamespace == "" {
-		log.Debug("step is not a reference to an unpacked bundle (this is not an error if the step is a manifest)")
-		return nil
-	}
-	return &ref
-}
diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go
index c2d5ea533..dedbef13b 100644
--- a/pkg/controller/operators/catalog/operator.go
+++ b/pkg/controller/operators/catalog/operator.go
@@ -1105,16 +1105,6 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
 	return reference.GetReference(res)
 }
 
-type UnpackedBundleReference struct {
-	Kind                   string `json:"kind"`
-	Name                   string `json:"name"`
-	Namespace              string `json:"namespace"`
-	CatalogSourceName      string `json:"catalogSourceName"`
-	CatalogSourceNamespace string `json:"catalogSourceNamespace"`
-	Replaces               string `json:"replaces"`
-}
-
-// unpackBundles makes one walk through the bundlelookups and attempts to progress them
 func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.InstallPlan, error) {
 	out := plan.DeepCopy()
 	unpacked := true
@@ -1127,53 +1117,32 @@ func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.In
 			errs = append(errs, err)
 			continue
 		}
-		out.Status.BundleLookups[i] = *res.BundleLookup
 
-		// if pending condition is present, still waiting for the job to unpack to configmap
-		if res.GetCondition(v1alpha1.BundleLookupPending).Status == corev1.ConditionTrue {
+		if res == nil {
 			unpacked = false
 			continue
 		}
 
-		// if packed condition is missing, bundle has already been unpacked into steps, continue
-		if res.GetCondition(resolver.BundleLookupConditionPacked).Status == corev1.ConditionUnknown {
+		out.Status.BundleLookups[i] = *res.BundleLookup
+		if res.Bundle() == nil || len(res.Bundle().GetObject()) == 0 {
+			unpacked = false
 			continue
 		}
 
-		// Ensure that bundle can be applied by the current version of OLM by converting to steps
 		steps, err := resolver.NewStepsFromBundle(res.Bundle(), out.GetNamespace(), res.Replaces, res.CatalogSourceRef.Name, res.CatalogSourceRef.Namespace)
 		if err != nil {
-			errs = append(errs, fmt.Errorf("failed to turn bundle into steps: %v", err))
+			errs = append(errs, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()))
 			unpacked = false
 			continue
 		}
 
-		// step manifests are replaced with references to the configmap containing them
-		for i, s := range steps {
-			ref := UnpackedBundleReference{
-				Kind:                   "ConfigMap",
-				Namespace:              res.CatalogSourceRef.Namespace,
-				Name:                   res.Name(),
-				CatalogSourceName:      res.CatalogSourceRef.Name,
-				CatalogSourceNamespace: res.CatalogSourceRef.Namespace,
-				Replaces:               res.Replaces,
-			}
-			r, err := json.Marshal(&ref)
-			if err != nil {
-				errs = append(errs, fmt.Errorf("failed to generate reference for configmap: %v", err))
-				unpacked = false
-				continue
-			}
-			s.Resource.Manifest = string(r)
-			steps[i] = s
-		}
-		res.RemoveCondition(resolver.BundleLookupConditionPacked)
-		out.Status.BundleLookups[i] = *res.BundleLookup
+		// Add steps and remove resolved bundle lookup
 		out.Status.Plan = append(out.Status.Plan, steps...)
+		out.Status.BundleLookups = append(out.Status.BundleLookups[:i], out.Status.BundleLookups[i+1:]...)
+		i--
 	}
 
 	if err := utilerrors.NewAggregate(errs); err != nil {
-		o.logger.Debugf("failed to unpack bundles: %v", err)
 		return false, nil, err
 	}
 
@@ -1447,8 +1416,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 	}
 
 	ensurer := newStepEnsurer(kubeclient, crclient, dynamicClient)
-	r := newManifestResolver(plan.GetNamespace(), o.lister.CoreV1().ConfigMapLister(), o.logger)
-	b := newBuilder(kubeclient, dynamicClient, o.csvProvidedAPIsIndexer, r, o.logger)
+	b := newBuilder(kubeclient, dynamicClient, o.csvProvidedAPIsIndexer, o.logger)
 
 	for i, step := range plan.Status.Plan {
 		doStep := true
@@ -1475,16 +1443,12 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 		case v1alpha1.StepStatusPresent, v1alpha1.StepStatusCreated, v1alpha1.StepStatusWaitingForAPI:
 			continue
 		case v1alpha1.StepStatusUnknown, v1alpha1.StepStatusNotPresent:
-			manifest, err := r.ManifestForStep(step)
-			if err != nil {
-				return err
-			}
 			o.logger.WithFields(logrus.Fields{"kind": step.Resource.Kind, "name": step.Resource.Name}).Debug("execute resource")
 			switch step.Resource.Kind {
 			case v1alpha1.ClusterServiceVersionKind:
 				// Marshal the manifest into a CSV instance.
 				var csv v1alpha1.ClusterServiceVersion
-				err := json.Unmarshal([]byte(manifest), &csv)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &csv)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1517,7 +1481,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case v1alpha1.SubscriptionKind:
 				// Marshal the manifest into a subscription instance.
 				var sub v1alpha1.Subscription
-				err := json.Unmarshal([]byte(manifest), &sub)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &sub)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1541,7 +1505,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 
 			case resolver.BundleSecretKind:
 				var s corev1.Secret
-				err := json.Unmarshal([]byte(manifest), &s)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &s)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1580,7 +1544,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case clusterRoleKind:
 				// Marshal the manifest into a ClusterRole instance.
 				var cr rbacv1.ClusterRole
-				err := json.Unmarshal([]byte(manifest), &cr)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &cr)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1595,7 +1559,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case clusterRoleBindingKind:
 				// Marshal the manifest into a RoleBinding instance.
 				var rb rbacv1.ClusterRoleBinding
-				err := json.Unmarshal([]byte(manifest), &rb)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &rb)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1610,7 +1574,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case roleKind:
 				// Marshal the manifest into a Role instance.
 				var r rbacv1.Role
-				err := json.Unmarshal([]byte(manifest), &r)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &r)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1633,7 +1597,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case roleBindingKind:
 				// Marshal the manifest into a RoleBinding instance.
 				var rb rbacv1.RoleBinding
-				err := json.Unmarshal([]byte(manifest), &rb)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &rb)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1656,7 +1620,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case serviceAccountKind:
 				// Marshal the manifest into a ServiceAccount instance.
 				var sa corev1.ServiceAccount
-				err := json.Unmarshal([]byte(manifest), &sa)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &sa)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1679,7 +1643,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 			case serviceKind:
 				// Marshal the manifest into a Service instance
 				var s corev1.Service
-				err := json.Unmarshal([]byte(manifest), &s)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &s)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1709,7 +1673,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 
 			case configMapKind:
 				var cfg corev1.ConfigMap
-				err := json.Unmarshal([]byte(manifest), &cfg)
+				err := json.Unmarshal([]byte(step.Resource.Manifest), &cfg)
 				if err != nil {
 					return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name)
 				}
@@ -1745,7 +1709,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
 				}
 
 				// Marshal the manifest into an unstructured object
-				dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(manifest), 10)
+				dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(step.Resource.Manifest), 10)
 				unstructuredObject := &unstructured.Unstructured{}
 				if err := dec.Decode(unstructuredObject); err != nil {
 					return errorwrap.Wrapf(err, "error decoding %s object to an unstructured object", step.Resource.Name)
diff --git a/pkg/controller/operators/catalog/step.go b/pkg/controller/operators/catalog/step.go
index 99e2910e7..958db78fa 100644
--- a/pkg/controller/operators/catalog/step.go
+++ b/pkg/controller/operators/catalog/step.go
@@ -38,17 +38,15 @@ func (s StepperFunc) Status() (v1alpha1.StepStatus, error) {
 type builder struct {
 	opclient          operatorclient.ClientInterface
 	dynamicClient     dynamic.Interface
-	manifestResolver  ManifestResolver
 	csvToProvidedAPIs map[string]cache.Indexer
 	logger            logger.FieldLogger
 }
 
 func newBuilder(opclient operatorclient.ClientInterface, dynamicClient dynamic.Interface, csvToProvidedAPIs map[string]cache.Indexer,
-	manifestResolver ManifestResolver, logger logger.FieldLogger) *builder {
+	logger logger.FieldLogger) *builder {
 	return &builder{
 		opclient:          opclient,
 		dynamicClient:     dynamicClient,
-		manifestResolver:  manifestResolver,
 		csvToProvidedAPIs: csvToProvidedAPIs,
 		logger:            logger,
 	}
@@ -64,15 +62,9 @@ func (n notSupportedStepperErr) Error() string {
 
 // step is a factory that creates StepperFuncs based on the install plan step Kind.
 func (b *builder) create(step *v1alpha1.Step) (Stepper, error) {
-	manifest, err := b.manifestResolver.ManifestForStep(step)
-	if err != nil {
-		return nil, err
-	}
-	step.Resource.Manifest = manifest
-
 	switch step.Resource.Kind {
 	case crdKind:
-		version, err := crdlib.Version(&manifest)
+		version, err := crdlib.Version(&step.Resource.Manifest)
 		if err != nil {
 			return nil, err
 		}
diff --git a/pkg/controller/operators/catalog/subscription/syncer.go b/pkg/controller/operators/catalog/subscription/syncer.go
index bccd50726..da88ced25 100644
--- a/pkg/controller/operators/catalog/subscription/syncer.go
+++ b/pkg/controller/operators/catalog/subscription/syncer.go
@@ -50,7 +50,7 @@ func (s *subscriptionSyncer) Sync(ctx context.Context, event kubestate.ResourceE
 		return err
 	}
 
-	s.recordMetrics(res)
+	metrics.EmitSubMetric(res)
 
 	logger := s.logger.WithFields(logrus.Fields{
 		"reconciling": fmt.Sprintf("%T", res),
@@ -68,8 +68,10 @@ func (s *subscriptionSyncer) Sync(ctx context.Context, event kubestate.ResourceE
 		initial = initial.Add()
 	case kubestate.ResourceUpdated:
 		initial = initial.Update()
+		metrics.UpdateSubsSyncCounterStorage(res)
 	case kubestate.ResourceDeleted:
 		initial = initial.Delete()
+		metrics.DeleteSubsMetric(res)
 	}
 
 	reconciled, err := s.reconcilers.Reconcile(ctx, initial)
@@ -85,15 +87,6 @@ func (s *subscriptionSyncer) Sync(ctx context.Context, event kubestate.ResourceE
 	return nil
 }
 
-func (s *subscriptionSyncer) recordMetrics(sub *v1alpha1.Subscription) {
-	// sub.Spec is not a required field.
-	if sub.Spec == nil {
-		return
-	}
-
-	metrics.CounterForSubscription(sub.GetName(), sub.Status.InstalledCSV, sub.Spec.Channel, sub.Spec.Package).Inc()
-}
-
 func (s *subscriptionSyncer) Notify(event kubestate.ResourceEvent) {
 	s.notify(event)
 }
diff --git a/pkg/controller/registry/registry_client.go b/pkg/controller/registry/registry_client.go
index 170f887db..9fe3ef9bc 100644
--- a/pkg/controller/registry/registry_client.go
+++ b/pkg/controller/registry/registry_client.go
@@ -86,9 +86,9 @@ func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, ki
 	if err != nil {
 		return nil, err
 	}
-	entry := rc.filterChannelEntries(ctx, it, excludedPkgName)
+	entry := rc.filterChannelEntries(it, excludedPkgName)
 	if entry == nil {
-		return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s's default channel", excludedPkgName)
+		return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s", excludedPkgName)
 	}
 	bundle, err := rc.Client.Registry.GetBundle(ctx, &registryapi.GetBundleRequest{PkgName: entry.PackageName, ChannelName: entry.ChannelName, CsvName: entry.BundleName})
 	if err != nil {
@@ -97,53 +97,25 @@ func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, ki
 	return bundle, nil
 }
 
-// FilterChannelEntries filters out channel entries that provide the requested
+// FilterChannelEntries filters out a channel entries that provide the requested
 // API and come from the same package with original operator and returns the
-// first entry on the list from the default channel of that package
-func (rc *Client) filterChannelEntries(ctx context.Context, it *ChannelEntryIterator, excludedPkgName string) *opregistry.ChannelEntry {
-	defChannels := make(map[string]string, 0)
-
+// first entry on the list
+func (rc *Client) filterChannelEntries(it *ChannelEntryIterator, excludedPkgName string) *opregistry.ChannelEntry {
 	var entries []*opregistry.ChannelEntry
 	for e := it.Next(); e != nil; e = it.Next() {
 		if e.PackageName != excludedPkgName {
-			// keep track of the default channel for each package
-			if _, ok := defChannels[e.PackageName]; !ok {
-				defChannel, err := rc.getDefaultPackageChannel(ctx, e.PackageName)
-				if err != nil {
-					continue
-				}
-				defChannels[e.PackageName] = defChannel
-			}
-
-			// only add entry to the list if the entry is in the default channel
-			if e.ChannelName == defChannels[e.PackageName] {
-				entry := &opregistry.ChannelEntry{
-					PackageName: e.PackageName,
-					ChannelName: e.ChannelName,
-					BundleName:  e.BundleName,
-					Replaces:    e.Replaces,
-				}
-				entries = append(entries, entry)
+			entry := &opregistry.ChannelEntry{
+				PackageName: e.PackageName,
+				ChannelName: e.ChannelName,
+				BundleName:  e.BundleName,
+				Replaces:    e.Replaces,
 			}
+			entries = append(entries, entry)
 		}
 	}
 
-	if len(entries) > 0 {
+	if entries != nil {
 		return entries[0]
 	}
 	return nil
 }
-
-// GetDefaultPackageChannel uses registry client to get the default
-// channel name for a given package name
-func (rc *Client) getDefaultPackageChannel(ctx context.Context, pkgName string) (string, error) {
-	pkg, err := rc.Client.Registry.GetPackage(ctx, &registryapi.GetPackageRequest{Name: pkgName})
-	if err != nil {
-		return "", err
-	}
-	if pkg == nil {
-		return "", fmt.Errorf("package %s not found in registry", pkgName)
-	}
-
-	return pkg.DefaultChannelName, nil
-}
diff --git a/pkg/controller/registry/resolver/rbac.go b/pkg/controller/registry/resolver/rbac.go
index d29c80a09..957626235 100644
--- a/pkg/controller/registry/resolver/rbac.go
+++ b/pkg/controller/registry/resolver/rbac.go
@@ -2,30 +2,19 @@ package resolver
 
 import (
 	"fmt"
-	"hash/fnv"
 
 	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	utilrand "k8s.io/apimachinery/pkg/util/rand"
+	"k8s.io/apiserver/pkg/storage/names"
 
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
-	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
 )
 
-const maxNameLength = 63
-
-func generateName(base string, o interface{}) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, o)
-	hash := utilrand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
-	if len(base)+len(hash) > maxNameLength {
-		base = base[:maxNameLength - len(hash) - 1]
-	}
-
-	return fmt.Sprintf("%s-%s", base, hash)
+var generateName = func(base string) string {
+	return names.SimpleNameGenerator.GenerateName(base + "-")
 }
 
 type OperatorPermissions struct {
@@ -93,7 +82,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		// Create Role
 		role := &rbacv1.Role{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:            generateName(csv.GetName(), permission.Rules),
+				Name:            generateName(csv.GetName()),
 				Namespace:       csv.GetNamespace(),
 				OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
 				Labels:          ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
@@ -105,7 +94,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		// Create RoleBinding
 		roleBinding := &rbacv1.RoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:     		 generateName(role.GetName(), role),
+				Name:            generateName(fmt.Sprintf("%s-%s", role.GetName(), permission.ServiceAccountName)),
 				Namespace:       csv.GetNamespace(),
 				OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
 				Labels:          ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
@@ -137,7 +126,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		// Create ClusterRole
 		role := &rbacv1.ClusterRole{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:   generateName(csv.GetName(), permission.Rules),
+				Name:   generateName(csv.GetName()),
 				Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
 			},
 			Rules: permission.Rules,
@@ -147,7 +136,7 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		// Create ClusterRoleBinding
 		roleBinding := &rbacv1.ClusterRoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      generateName(role.GetName(), role),
+				Name:      generateName(fmt.Sprintf("%s-%s", role.GetName(), permission.ServiceAccountName)),
 				Namespace: csv.GetNamespace(),
 				Labels:    ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
 			},
diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go
index 0f70de9c6..ea551ee25 100644
--- a/pkg/controller/registry/resolver/resolver.go
+++ b/pkg/controller/registry/resolver/resolver.go
@@ -16,14 +16,9 @@ import (
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
 	v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
-	controllerbundle "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
 )
 
-const (
-	BundleLookupConditionPacked v1alpha1.BundleLookupConditionType = "BundleLookupNotPersisted"
-)
-
 var timeNow = func() metav1.Time { return metav1.NewTime(time.Now().UTC()) }
 
 type Resolver interface {
@@ -122,20 +117,6 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier
 						Namespace: op.SourceInfo().Catalog.Namespace,
 						Name:      op.SourceInfo().Catalog.Name,
 					},
-					Conditions: []v1alpha1.BundleLookupCondition{
-						{
-							Type:    BundleLookupConditionPacked,
-							Status:  corev1.ConditionTrue,
-							Reason:  controllerbundle.NotUnpackedReason,
-							Message: controllerbundle.NotUnpackedMessage,
-						},
-						{
-							Type:    v1alpha1.BundleLookupPending,
-							Status:  corev1.ConditionTrue,
-							Reason:  controllerbundle.JobNotStartedReason,
-							Message: controllerbundle.JobNotStartedMessage,
-						},
-					},
 				})
 			}
 
diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go
index 4a52946fb..e82586735 100644
--- a/pkg/metrics/metrics.go
+++ b/pkg/metrics/metrics.go
@@ -2,6 +2,7 @@ package metrics
 
 import (
 	"context"
+
 	"github.com/prometheus/client_golang/prometheus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
@@ -168,8 +169,19 @@ var (
 		},
 		[]string{NAMESPACE_LABEL, NAME_LABEL, VERSION_LABEL, PHASE_LABEL, REASON_LABEL},
 	)
+
+	// subscriptionSyncCounters keeps a record of the promethues counters emitted by
+	// Subscription objects. The key of a record is the Subscription name, while the value
+	//  is struct containing label values used in the counter
+	subscriptionSyncCounters = make(map[string]subscriptionSyncLabelValues)
 )
 
+type subscriptionSyncLabelValues struct {
+	installedCSV string
+	pkg          string
+	channel      string
+}
+
 func RegisterOLM() {
 	prometheus.MustRegister(csvCount)
 	prometheus.MustRegister(csvSucceeded)
@@ -217,3 +229,45 @@ func EmitCSVMetric(oldCSV *olmv1alpha1.ClusterServiceVersion, newCSV *olmv1alpha
 		csvAbnormal.WithLabelValues(newCSV.Namespace, newCSV.Name, newCSV.Spec.Version.String(), string(newCSV.Status.Phase), string(newCSV.Status.Reason)).Set(1)
 	}
 }
+
+func EmitSubMetric(sub *olmv1alpha1.Subscription) {
+	if sub.Spec == nil {
+		return
+	}
+	SubscriptionSyncCount.WithLabelValues(sub.GetName(), sub.Status.InstalledCSV, sub.Spec.Channel, sub.Spec.Package).Inc()
+	if _, present := subscriptionSyncCounters[sub.GetName()]; !present {
+		subscriptionSyncCounters[sub.GetName()] = subscriptionSyncLabelValues{
+			installedCSV: sub.Status.InstalledCSV,
+			pkg:          sub.Spec.Package,
+			channel:      sub.Spec.Channel,
+		}
+	}
+}
+
+func DeleteSubsMetric(sub *olmv1alpha1.Subscription) {
+	if sub.Spec == nil {
+		return
+	}
+	SubscriptionSyncCount.DeleteLabelValues(sub.GetName(), sub.Status.InstalledCSV, sub.Spec.Channel, sub.Spec.Package)
+}
+
+func UpdateSubsSyncCounterStorage(sub *olmv1alpha1.Subscription) {
+	if sub.Spec == nil {
+		return
+	}
+	counterValues := subscriptionSyncCounters[sub.GetName()]
+
+	if sub.Spec.Channel != counterValues.channel ||
+		sub.Spec.Package != counterValues.pkg ||
+		sub.Status.InstalledCSV != counterValues.installedCSV {
+
+		// Delete metric will label values of old Subscription first
+		SubscriptionSyncCount.DeleteLabelValues(sub.GetName(), counterValues.installedCSV, counterValues.channel, counterValues.pkg)
+
+		counterValues.installedCSV = sub.Status.InstalledCSV
+		counterValues.pkg = sub.Spec.Package
+		counterValues.channel = sub.Spec.Channel
+
+		subscriptionSyncCounters[sub.GetName()] = counterValues
+	}
+}


Test patch:
diff --git a/pkg/controller/bundle/bundle_unpacker_test.go b/pkg/controller/bundle/bundle_unpacker_test.go
index e81653182..f0643ef92 100644
--- a/pkg/controller/bundle/bundle_unpacker_test.go
+++ b/pkg/controller/bundle/bundle_unpacker_test.go
@@ -71,14 +71,6 @@ func TestConfigMapUnpacker(t *testing.T) {
 						Namespace: "ns-a",
 						Name:      "src-a",
 					},
-					Conditions: []operatorsv1alpha1.BundleLookupCondition{
-						{
-							Type:    operatorsv1alpha1.BundleLookupPending,
-							Status:  corev1.ConditionTrue,
-							Reason:  JobNotStartedReason,
-							Message: JobNotStartedMessage,
-						},
-					},
 				},
 			},
 			expected: expected{
@@ -124,14 +116,6 @@ func TestConfigMapUnpacker(t *testing.T) {
 						Namespace: "ns-a",
 						Name:      "src-a",
 					},
-					Conditions: []operatorsv1alpha1.BundleLookupCondition{
-						{
-							Type:    operatorsv1alpha1.BundleLookupPending,
-							Status:  corev1.ConditionTrue,
-							Reason:  JobNotStartedReason,
-							Message: JobNotStartedMessage,
-						},
-					},
 				},
 			},
 			expected: expected{
diff --git a/pkg/controller/operators/catalog/operator_test.go b/pkg/controller/operators/catalog/operator_test.go
index 7902572a7..ee883c508 100644
--- a/pkg/controller/operators/catalog/operator_test.go
+++ b/pkg/controller/operators/catalog/operator_test.go
@@ -269,13 +269,13 @@ func TestExecutePlan(t *testing.T) {
 							Version:                "v1",
 							Kind:                   "ConfigMap",
 							Name:                   "cfg",
-							Manifest:               toManifest(t, configMap("cfg", namespace)),
+							Manifest:               toManifest(t, configmap("cfg", namespace)),
 						},
 						Status: v1alpha1.StepStatusUnknown,
 					},
 				},
 			),
-			want: []runtime.Object{configMap("cfg", namespace)},
+			want: []runtime.Object{configmap("cfg", namespace)},
 			err:  nil,
 		},
 		{
@@ -1307,7 +1307,7 @@ func serviceAccount(name, namespace, generateName string, secretRef *corev1.Obje
 	}
 }
 
-func configMap(name, namespace string) *corev1.ConfigMap {
+func configmap(name, namespace string) *corev1.ConfigMap {
 	return &corev1.ConfigMap{
 		TypeMeta:   metav1.TypeMeta{Kind: configMapKind},
 		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace},
diff --git a/pkg/controller/operators/catalog/subscription/syncer_test.go b/pkg/controller/operators/catalog/subscription/syncer_test.go
index a8ed1002a..9ce669dc5 100644
--- a/pkg/controller/operators/catalog/subscription/syncer_test.go
+++ b/pkg/controller/operators/catalog/subscription/syncer_test.go
@@ -6,11 +6,19 @@ import (
 
 	"github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/require"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubestate"
 )
 
+const (
+	name             = "test-subscription"
+	packageName      = "test-package"
+	channel          = "test-channel"
+	installedCSVName = "test-csv"
+)
+
 func TestSync(t *testing.T) {
 	type fields struct {
 		syncer kubestate.Syncer
@@ -39,7 +47,22 @@ func TestSync(t *testing.T) {
 			args: args{
 				event: kubestate.NewResourceEvent(
 					kubestate.ResourceAdded,
-					&v1alpha1.Subscription{},
+					&v1alpha1.Subscription{
+						TypeMeta: metav1.TypeMeta{
+							Kind:       v1alpha1.SubscriptionKind,
+							APIVersion: v1alpha1.SubscriptionCRDAPIVersion,
+						},
+						ObjectMeta: metav1.ObjectMeta{
+							Name: name,
+						},
+						Spec: &v1alpha1.SubscriptionSpec{
+							Package: packageName,
+							Channel: channel,
+						},
+						Status: v1alpha1.SubscriptionStatus{
+							InstalledCSV: installedCSVName,
+						},
+					},
 				),
 			},
 			want: want{
diff --git a/pkg/controller/registry/resolver/rbac_test.go b/pkg/controller/registry/resolver/rbac_test.go
deleted file mode 100644
index 060f99d75..000000000
--- a/pkg/controller/registry/resolver/rbac_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package resolver
-
-import (
-	"github.com/stretchr/testify/require"
-	"math/rand"
-	"reflect"
-	"strings"
-	"testing"
-	"testing/quick"
-)
-
-func TestGenerateName(t *testing.T) {
-	type args struct {
-		base string
-		o    interface{}
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{
-			name: "generate",
-			args: args{
-				base: "myname",
-				o: []string{"something"},
-			},
-			want: "myname-9c895f74f",
-		},
-		{
-			name: "truncated",
-			args: args{
-				base: strings.Repeat("name", 100),
-				o: []string{"something", "else"},
-			},
-			want: "namenamenamenamenamenamenamenamenamenamenamenamename-78fd8b4d6b",
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := generateName(tt.args.base, tt.args.o)
-			require.Equal(t, tt.want, got)
-			require.LessOrEqual(t, len(got), maxNameLength)
-		})
-	}
-}
-
-var runeSet = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-")
-
-type validKubeName string
-
-func (validKubeName) Generate(rand *rand.Rand, size int) reflect.Value {
-	b := make([]rune, size)
-	for i := range b {
-		b[i] = runeSet[rand.Intn(len(runeSet))]
-	}
-	return reflect.ValueOf(validKubeName(b))
-}
-
-func TestGeneratesWithinRange(t *testing.T) {
-	f := func(base validKubeName, o string) bool {
-		return len(generateName(string(base), o)) <= maxNameLength
-	}
-	require.NoError(t, quick.Check(f, nil))
-}
diff --git a/pkg/controller/registry/resolver/resolver_test.go b/pkg/controller/registry/resolver/resolver_test.go
index df0195f09..a4d11ce6f 100644
--- a/pkg/controller/registry/resolver/resolver_test.go
+++ b/pkg/controller/registry/resolver/resolver_test.go
@@ -20,7 +20,6 @@ import (
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
-	controllerbundle "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
 )
 
@@ -127,20 +126,6 @@ func TestNamespaceResolver(t *testing.T) {
 							Namespace: catalog.Namespace,
 							Name:      catalog.Name,
 						},
-						Conditions: []v1alpha1.BundleLookupCondition{
-							{
-								Type:    BundleLookupConditionPacked,
-								Status:  corev1.ConditionTrue,
-								Reason:  controllerbundle.NotUnpackedReason,
-								Message: controllerbundle.NotUnpackedMessage,
-							},
-							{
-								Type:    v1alpha1.BundleLookupPending,
-								Status:  corev1.ConditionTrue,
-								Reason:  controllerbundle.JobNotStartedReason,
-								Message: controllerbundle.JobNotStartedMessage,
-							},
-						},
 					},
 				},
 				subs: []*v1alpha1.Subscription{
@@ -256,20 +241,6 @@ func TestNamespaceResolver(t *testing.T) {
 							Namespace: catalog.Namespace,
 							Name:      catalog.Name,
 						},
-						Conditions: []v1alpha1.BundleLookupCondition{
-							{
-								Type:    BundleLookupConditionPacked,
-								Status:  corev1.ConditionTrue,
-								Reason:  controllerbundle.NotUnpackedReason,
-								Message: controllerbundle.NotUnpackedMessage,
-							},
-							{
-								Type:    v1alpha1.BundleLookupPending,
-								Status:  corev1.ConditionTrue,
-								Reason:  controllerbundle.JobNotStartedReason,
-								Message: controllerbundle.JobNotStartedMessage,
-							},
-						},
 					},
 				},
 				subs: []*v1alpha1.Subscription{
@@ -569,6 +540,10 @@ func TestNamespaceResolver(t *testing.T) {
 }
 
 func TestNamespaceResolverRBAC(t *testing.T) {
+	generateName = func(base string) string {
+		return "a"
+	}
+
 	namespace := "catsrc-namespace"
 	catalog := CatalogKey{"catsrc", namespace}
 
diff --git a/test/e2e/metrics_e2e_test.go b/test/e2e/metrics_e2e_test.go
index e63a1dbd8..d88176d0c 100644
--- a/test/e2e/metrics_e2e_test.go
+++ b/test/e2e/metrics_e2e_test.go
@@ -6,6 +6,7 @@ import (
 	"context"
 	"fmt"
 	"regexp"
+	"time"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
@@ -15,61 +16,172 @@ import (
 	"k8s.io/apimachinery/pkg/util/net"
 
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
+	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
+	"github.com/operator-framework/operator-lifecycle-manager/pkg/metrics"
 )
 
 var _ = Describe("Metrics", func() {
-	It("endpoint", func() {
-
-		// TestMetrics tests the metrics endpoint of the OLM pod.
-
-		c := newKubeClient()
-		crc := newCRClient()
-
-		failingCSV := v1alpha1.ClusterServiceVersion{
-			TypeMeta: metav1.TypeMeta{
-				Kind:       v1alpha1.ClusterServiceVersionKind,
-				APIVersion: v1alpha1.ClusterServiceVersionAPIVersion,
-			},
-			ObjectMeta: metav1.ObjectMeta{
-				Name: genName("failing-csv-test-"),
-			},
-			Spec: v1alpha1.ClusterServiceVersionSpec{
-				InstallStrategy: v1alpha1.NamedInstallStrategy{
-					StrategyName: v1alpha1.InstallStrategyNameDeployment,
-					StrategySpec: strategy,
-				},
-			},
-		}
 
-		cleanupCSV, err := createCSV(GinkgoT(), c, crc, failingCSV, testNamespace, false, false)
-		Expect(err).ToNot(HaveOccurred())
+	var (
+		c   operatorclient.ClientInterface
+		crc versioned.Interface
+	)
 
-		_, err = fetchCSV(GinkgoT(), crc, failingCSV.Name, testNamespace, csvFailedChecker)
-		Expect(err).ToNot(HaveOccurred())
+	BeforeEach(func() {
+		c = newKubeClient()
+		crc = newCRClient()
+
+	})
+
+	Context("CSV metrics", func() {
+		It("endpoint", func() {
+
+			// TestMetrics tests the metrics endpoint of the OLM pod.
+
+			failingCSV := v1alpha1.ClusterServiceVersion{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       v1alpha1.ClusterServiceVersionKind,
+					APIVersion: v1alpha1.ClusterServiceVersionAPIVersion,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name: genName("failing-csv-test-"),
+				},
+				Spec: v1alpha1.ClusterServiceVersionSpec{
+					InstallStrategy: v1alpha1.NamedInstallStrategy{
+						StrategyName: v1alpha1.InstallStrategyNameDeployment,
+						StrategySpec: strategy,
+					},
+				},
+			}
+
+			cleanupCSV, err := createCSV(GinkgoT(), c, crc, failingCSV, testNamespace, false, false)
+			Expect(err).ToNot(HaveOccurred())
+
+			_, err = fetchCSV(GinkgoT(), crc, failingCSV.Name, testNamespace, csvFailedChecker)
+			Expect(err).ToNot(HaveOccurred())
+
+			// Verify metrics have been emitted for packageserver csv
+			Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8081")).To(And(
+				ContainSubstring("csv_abnormal"),
+				ContainSubstring(fmt.Sprintf("name=\"%s\"", failingCSV.Name)),
+				ContainSubstring("phase=\"Failed\""),
+				ContainSubstring("reason=\"UnsupportedOperatorGroup\""),
+				ContainSubstring("version=\"0.0.0\""),
+				ContainSubstring("csv_succeeded"),
+			))
+
+			cleanupCSV()
+
+			// Verify that when the csv has been deleted, it deletes the corresponding CSV metrics
+			Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8081")).ToNot(And(
+				ContainSubstring("csv_abnormal{name=\"%s\"", failingCSV.Name),
+				ContainSubstring("csv_succeeded{name=\"%s\"", failingCSV.Name),
+			))
+		})
+	})
 
-		// Verify metrics have been emitted for packageserver csv
-		Expect(getMetricsFromPod(c, getOLMPod(c), "8081")).To(And(
-			ContainSubstring("csv_abnormal"),
-			ContainSubstring(fmt.Sprintf("name=\"%s\"", failingCSV.Name)),
-			ContainSubstring("phase=\"Failed\""),
-			ContainSubstring("reason=\"UnsupportedOperatorGroup\""),
-			ContainSubstring("version=\"0.0.0\""),
-			ContainSubstring("csv_succeeded"),
-		))
-
-		cleanupCSV()
-
-		// Verify that when the csv has been deleted, it deletes the corresponding CSV metrics
-		Expect(getMetricsFromPod(c, getOLMPod(c), "8081")).ToNot(And(
-			ContainSubstring("csv_abnormal{name=\"%s\"", failingCSV.Name),
-			ContainSubstring("csv_succeeded{name=\"%s\"", failingCSV.Name),
-		))
+	Context("Subscription Metric", func() {
+		var (
+			subscriptionCleanup cleanupFunc
+			subscription        *v1alpha1.Subscription
+		)
+		When("A subscription object is created", func() {
+
+			BeforeEach(func() {
+				subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription", testPackageName, stableChannel, v1alpha1.ApprovalManual)
+			})
+
+			It("generates subscription_sync_total metric", func() {
+
+				// Verify metrics have been emitted for subscription
+				Eventually(func() string {
+					return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+				}, time.Minute, 5*time.Second).Should(And(
+					ContainSubstring("subscription_sync_total"),
+					ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.NAME_LABEL, "metric-subscription")),
+					ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, stableChannel)),
+					ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.PACKAGE_LABEL, testPackageName))))
+			})
+
+			When("The subscription object is updated", func() {
+
+				BeforeEach(func() {
+					updatedSubscription, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{})
+					Expect(err).ToNot(HaveOccurred())
+					updatedSubscription.Spec.Channel = betaChannel
+					updateSubscription(GinkgoT(), crc, updatedSubscription)
+				})
+
+				It("deletes the old Subscription metric and emits the new metric", func() {
+					Eventually(func() string {
+						return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+					}, time.Minute, 5*time.Second).ShouldNot(And(
+						ContainSubstring("subscription_sync_total{name=\"metric-subscription\""),
+						ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, stableChannel))))
+
+					Eventually(func() string {
+						return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+					}, time.Minute, 5*time.Second).Should(And(
+						ContainSubstring("subscription_sync_total"),
+						ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.NAME_LABEL, "metric-subscription")),
+						ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, betaChannel)),
+						ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.PACKAGE_LABEL, testPackageName))))
+				})
+
+				When("The Subscription object is updated again", func() {
+
+					BeforeEach(func() {
+						updatedSubscription, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{})
+						Expect(err).ToNot(HaveOccurred())
+						updatedSubscription.Spec.Channel = alphaChannel
+						updateSubscription(GinkgoT(), crc, updatedSubscription)
+					})
+
+					It("deletes the old subscription metric and emits the new metric(there is only one metric for the subscription)", func() {
+						Eventually(func() string {
+							return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+						}, time.Minute, 5*time.Second).ShouldNot(And(
+							ContainSubstring("subscription_sync_total{name=\"metric-subscription-for-update\""),
+							ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, stableChannel)),
+							ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, betaChannel))))
+
+						Eventually(func() string {
+							return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+						}, time.Minute, 5*time.Second).Should(And(
+							ContainSubstring("subscription_sync_total"),
+							ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.NAME_LABEL, "metric-subscription")),
+							ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.CHANNEL_LABEL, alphaChannel)),
+							ContainSubstring(fmt.Sprintf("%s=\"%s\"", metrics.PACKAGE_LABEL, testPackageName))))
+					})
+				})
+			})
+
+			AfterEach(func() {
+				if subscriptionCleanup != nil {
+					subscriptionCleanup()
+				}
+			})
+		})
+		When("A Subscription object is deleted", func() {
+
+			BeforeEach(func() {
+				subscriptionCleanup, _ = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-deletion", testPackageName, stableChannel, v1alpha1.ApprovalManual)
+				if subscriptionCleanup != nil {
+					subscriptionCleanup()
+				}
+			})
+			It("deletes the Subscription metric", func() {
+				Eventually(func() string {
+					return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081")
+				}, time.Minute, 5*time.Second).ShouldNot(ContainSubstring("subscription_sync_total{name=\"metric-subscription-for-deletion\""))
+			})
+		})
 	})
 })
 
-func getOLMPod(client operatorclient.ClientInterface) *corev1.Pod {
-	listOptions := metav1.ListOptions{LabelSelector: "app=olm-operator"}
+func getPodWithLabel(client operatorclient.ClientInterface, label string) *corev1.Pod {
+	listOptions := metav1.ListOptions{LabelSelector: label}
 	var podList *corev1.PodList
 	Eventually(func() (err error) {
 		podList, err = client.KubernetesInterface().CoreV1().Pods(operatorNamespace).List(context.TODO(), listOptions)
diff --git a/test/e2e/subscription_e2e_test.go b/test/e2e/subscription_e2e_test.go
index 6a2106b49..8b1c0a819 100644
--- a/test/e2e/subscription_e2e_test.go
+++ b/test/e2e/subscription_e2e_test.go
@@ -51,7 +51,7 @@ var _ = Describe("Subscription", func() {
 		}()
 		require.NoError(GinkgoT(), initCatalog(GinkgoT(), c, crc))
 
-		cleanup := createSubscription(GinkgoT(), crc, testNamespace, testSubscriptionName, testPackageName, betaChannel, v1alpha1.ApprovalAutomatic)
+		cleanup, _ := createSubscription(GinkgoT(), crc, testNamespace, testSubscriptionName, testPackageName, betaChannel, v1alpha1.ApprovalAutomatic)
 		defer cleanup()
 
 		subscription, err := fetchSubscription(crc, testNamespace, testSubscriptionName, subscriptionStateAtLatestChecker)
@@ -80,7 +80,7 @@ var _ = Describe("Subscription", func() {
 		_, err := createCSV(GinkgoT(), c, crc, stableCSV, testNamespace, false, false)
 		require.NoError(GinkgoT(), err)
 
-		subscriptionCleanup := createSubscription(GinkgoT(), crc, testNamespace, testSubscriptionName, testPackageName, alphaChannel, v1alpha1.ApprovalAutomatic)
+		subscriptionCleanup, _ := createSubscription(GinkgoT(), crc, testNamespace, testSubscriptionName, testPackageName, alphaChannel, v1alpha1.ApprovalAutomatic)
 		defer subscriptionCleanup()
 
 		subscription, err := fetchSubscription(crc, testNamespace, testSubscriptionName, subscriptionStateAtLatestChecker)
@@ -188,7 +188,7 @@ var _ = Describe("Subscription", func() {
 		}()
 		require.NoError(GinkgoT(), initCatalog(GinkgoT(), c, crc))
 
-		subscriptionCleanup := createSubscription(GinkgoT(), crc, testNamespace, "manual-subscription", testPackageName, stableChannel, v1alpha1.ApprovalManual)
+		subscriptionCleanup, _ := createSubscription(GinkgoT(), crc, testNamespace, "manual-subscription", testPackageName, stableChannel, v1alpha1.ApprovalManual)
 		defer subscriptionCleanup()
 
 		subscription, err := fetchSubscription(crc, testNamespace, "manual-subscription", subscriptionStateUpgradePendingChecker)
@@ -1348,8 +1348,6 @@ var _ = Describe("Subscription", func() {
 		csvB := newCSV("nginx-b-dep", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, depNamedStrategy)
 		// csvC provides CRD2 in the different catalogsource with csvA (apackage)
 		csvC := newCSV("nginx-c-dep", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd2}, nil, depNamedStrategy2)
-		// csvD provides CRD1 in the same catalogsource with csvA (apackage)
-		csvD := newCSV("nginx-d-dep", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, depNamedStrategy)
 
 		// Create PackageManifests 1
 		// Contain csvA, ABC and B
@@ -1365,7 +1363,6 @@ var _ = Describe("Subscription", func() {
 			{
 				PackageName: packageName2,
 				Channels: []registry.PackageChannel{
-					{Name: alphaChannel, CurrentCSVName: csvD.GetName()},
 					{Name: stableChannel, CurrentCSVName: csvB.GetName()},
 				},
 				DefaultChannelName: stableChannel,
@@ -1385,7 +1382,7 @@ var _ = Describe("Subscription", func() {
 		}
 
 		catalogSourceName := genName("catsrc")
-		catsrc, cleanup := createInternalCatalogSource(kubeClient, crClient, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd, crd2}, []v1alpha1.ClusterServiceVersion{csvA, csvABC, csvB, csvD})
+		catsrc, cleanup := createInternalCatalogSource(kubeClient, crClient, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd, crd2}, []v1alpha1.ClusterServiceVersion{csvA, csvABC, csvB})
 		defer cleanup()
 
 		// Ensure that the catalog source is resolved before we create a subscription.
@@ -1431,9 +1428,6 @@ var _ = Describe("Subscription", func() {
 		// Ensure csvABC is not installed
 		_, err = crClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), csvABC.Name, metav1.GetOptions{})
 		require.Error(GinkgoT(), err)
-		// Ensure csvD is not installed -- this implies the dependent subscription selected the default channel
-		_, err = crClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), csvD.Name, metav1.GetOptions{})
-		require.Error(GinkgoT(), err)
 	})
 })
 
@@ -1788,7 +1782,7 @@ func buildSubscriptionCleanupFunc(crc versioned.Interface, subscription *v1alpha
 	}
 }
 
-func createSubscription(t GinkgoTInterface, crc versioned.Interface, namespace, name, packageName, channel string, approval v1alpha1.Approval) cleanupFunc {
+func createSubscription(t GinkgoTInterface, crc versioned.Interface, namespace, name, packageName, channel string, approval v1alpha1.Approval) (cleanupFunc, *v1alpha1.Subscription) {
 	subscription := &v1alpha1.Subscription{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       v1alpha1.SubscriptionKind,
@@ -1808,8 +1802,13 @@ func createSubscription(t GinkgoTInterface, crc versioned.Interface, namespace,
 	}
 
 	subscription, err := crc.OperatorsV1alpha1().Subscriptions(namespace).Create(context.TODO(), subscription, metav1.CreateOptions{})
-	require.NoError(t, err)
-	return buildSubscriptionCleanupFunc(crc, subscription)
+	Expect(err).ToNot(HaveOccurred())
+	return buildSubscriptionCleanupFunc(crc, subscription), subscription
+}
+
+func updateSubscription(t GinkgoTInterface, crc versioned.Interface, subscription *v1alpha1.Subscription) {
+	_, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Update(context.TODO(), subscription, metav1.UpdateOptions{})
+	Expect(err).ToNot(HaveOccurred())
 }
 
 func createSubscriptionForCatalog(crc versioned.Interface, namespace, name, catalog, packageName, channel, startingCSV string, approval v1alpha1.Approval) cleanupFunc {