---
# System prepended metadata

title: Resolver Breakout
tags: [wip]

---

---
title: Resolver Breakout
authors:
  - "@tylerslaton"
  - "@jbuchananr"
reviewers:
  - TBD
approvers:
  - TBD
creation-date: 2022-04-21
last-updated: 2022-04-21
status: provisional
tags: wip
---

# [WIP] Resolver Breakout

## Release Signoff Checklist

- [ ] Enhancement is `implementable`
- [ ] Design details are appropriately documented from clear requirements
- [ ] Test plan is defined
- [ ] Graduation criteria for dev preview, tech preview, GA

## Open Questions
1. How do we make the resolver be generic and agnostic of existing OLM concepts?
2. How does this fit into Deppy work? Are they tied together or completely seperate?
3. Should the existing resolver be used or should we do a complete rewrite?
4. Should we provide users the ability to apply a new resolution? Only issue is that it may be tricky to do on any number of systems.

## Summary

## Motivation
It has become evident that the Operator Framework has a need for the Resolver package (currently residing within Operator Lifecycle Manager (OLM)) to be generic and easily accessible accross the ecosystem. How this phasing out ultimately looks like is up for debate but this document aims at tackling an initial approach to it. The end-goal is to have a Resolver that can generically resolve resources and is extensible enough for our needs.

### Goals
- Break the Resolver into its own repository for consumption by operator framework components such as Deppy (a.k.a the Input API), OLM and Depster. 
- Change API interface to be agnostic from OLM resources and thus generic.
- Make the new version of the resolver have a simple interface design for any form of arbitrary resources.

### Non-Goals
- Completely rewrite the underlying logic behind the Resolver (such as the SAT solver)
- Create upstream solution entirely, just yet. Focus on core use cases and build a community from that.

## Proof of Concept
As this is a complex rewrite, we want to begin by adding a POC so that we can understand what this work entails. Once this POC work begins transpiring we can make more informed decisions about the complexity, approach, and workload. With taht being said, here is our intitial approach to a POC.

### Steps
1. Break the Resolver out into its own repository with its tests passing
2. Ensure that no dependencies exist on OLM packages.
3. Begin working on removing existing Operator Framework API's from the code. Majority of work will take place here, need to replace domain-specific API's with generic ones.
4. Build out a demo where OLM passes its existing E2E suite using this new Resolver package.

### Notes
- POC repo can be found [here](https://github.com/tylerslaton/resolver).

## Proposal

### Untying from OLM concepts
To better understand how to get the `Resolver` into a state where it is generically useable, it is important to first understand how it works today. The initial entry into the `Resolver` today is through the `Resolver` struct.

```go
type Resolver struct {
	cache                     *cache.Cache
	log                       logrus.FieldLogger
	pc                        *predicateConverter
	systemConstraintsProvider constraintProvider
}
```

It contains a number of reciever functions, but the main exported one is `Resolve()` which is responsible for resolving content. It currently takes namespaces and subscriptions which are both OLM sideffects. In order to reach a generic system, these dependencies should be replaced (more on that later).

```go
func (r *Resolver) Resolve(namespaces []string, subs []*v1alpha1.Subscription) ([]*cache.Entry, error) {
```

In that original `Resolver` struct, there was also a caching struct in the form of `cache.Cache`. This is resonsible for gathering and providing a snapshot (thread safe and workable chunk of state) of resources.

```go
type Cache struct {
	logger                 logrus.StdLogger
	sp                     SourceProvider
	sourcePriorityProvider SourcePriorityProvider
	snapshots              map[SourceKey]*snapshotHeader
	sem                    chan struct{}
	m                      sync.RWMutex
}
```

You'll notice that the `cache.Cache` struct contains a reference to a `SourceProvider` struct (along with other pertinent metadata). A SourceProvider is simply an interface to allow a consumer to gather data in a generic manner. Or, as the name would entail, provide sources.

```go
type SourceProvider interface {
	Sources(namespaces ...string) map[SourceKey]Source
}
```

Looking at this interface, we'll notice one of our first refactors that need to occur - the `SourceProvider` interface is expecting us to provide a namespace. This won't work for other proposed non-namespaced consumers (like Deppy or PlatformOperators). The `SourceKey` has the same problem since it too has the concept of namespacing built in.

```go
type SourceKey struct {
	Name      string
	Namespace string
}
```

Namespacing is a concept that is inherently tied to Operator Lifecycle Manager and is core to the current resolver implementation which it uses as a way to filter content. One proposed solution to this is to update the `SourceProvider.Sources` interface to accept `FilterFunc`s which would be responsible for filtering in a manner specified by a consumer. 

```go
type FitlerFunc func(values ...string)map[string]Source
type SourceProvider interface {
	Sources(filters ...FilterFunc) map[string]Source
}
```

### Removing Irrelevant Code
As it exists today, the `Resolver` is actually a fairly light API surface. Where the complexities begin to surface is through OLM code that got placed into the `Resolver`'s package. Most of [this code](https://github.com/operator-framework/operator-lifecycle-manager/tree/c36183ef17f757dbf1f96a2619a2a91184afc579/pkg/controller/registry/resolver) can be removed and given back to OLM's various packages. The following files can and should be removed from the `Resolver` entirely:

1. [source_csvs.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/source_csvs.go)
2. [source_csvs_test.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/source_csvs_test.go)
3. [source_registry.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/source_registry.go)
4. [source_registry_test.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/source_registry_test.go)
5. [step_resolver.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/step_resolver.go) (referencing `InstallPlan` steps)
6. [step_resolver_test.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/step_resolver_test.go)
7. [steps.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/steps.go) (again referencing `InstallPlan` steps)
8. [util_test.go](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/pkg/controller/registry/resolver/util_test.go)

While these are not important to the `Resolver` they are examples of implementations using the `Resolver` and are thus important to OLM. There are likely others, but this will be a core concept to work through during the refactoring.

From there, other files should be whittled down to remove references to the above files or remove code that is unused. This also permeates to the various subpackages like `cache`.

## User Stories

### Story 1
#### Scenario
As a developer on the operator framework organization,
I want to be able to resolve arbitrary resources without relying on OLM apis,
So that I can keep my code agnostic of core OLM.

#### Solution
As a developer on the operator framework organization,
I will cast my arbitrary resources as Resolver Package objects to be resolved. I will then be able to perform resolutions on my resources while keeping my code agonstic from OLM APIs. 

### Story 2
#### Scenario
As a develper on OLM,
I would like for the Resolver to be broken out into its own OLM resource-agnostic package,
So that I can reduce the complexity load on core OLM.

#### Solution

As a developer on the OLM team,
I will be able to use a resolver package that is agnostic of OLM, but will require me to provide more structure of preinstallation/post resolution of operators, but the core load of resolution will be on the resolver package, how I choose to use the output and format the input will be on me.

### Story 3 (less important)
#### Scenario
As a developer outside of the operator framework organization,
I want to generically resolve resources for my custom service,
So that I can easily get access to the underlying SAT solver.
####  Solution
As a open source developer outside of the operator framework org., 
I will be able to cast my resources as resolver package objects that will allow me to customize resolution to my projects. This will allow me to easily apply SAT solver logic for my open source projects.

### Implementation Details/Notes/Constraints [optional]

### Risks and Mitigations

## Design Details

### Test Plan

### Graduation Criteria

### Version Skew Strategy

## Alternatives

### Alternative 1:

#### Pros

#### Cons