--- title: (WIP) Active Resolution Design authors: - "@tylerslaton" - "@asmacdo" reviewers: - "@bparees" - "@timflannagan" - "@benluddy" - "@dmesser" - "@oceanc80" - "@perdasilva" approvers: - "@joelanford" - "@bparees" creation-date: 2022-10-11 last-updated: 2022-10-11 tags: deppy --- # Active Resolution ## Controller The controller manages the state of ActiveResolution resources. It executes the main algorithm of producing solver constraints from constraint definitions and entities, triggers resolution, converts results to something consumable by users and writes results out to the particular ActiveResolution resource. ## API definition Though not the final definition for this resource, the following provides an example of what it might look like: ```yaml= apiVersion: deppy.io/v1alpha1 kind: ActiveResolution metadata: name: example-resolution spec: sources: # optional definition of specific sources - "example-operators" constraints: # define constraints necassary for selections - required("first-example-operator", ">= 1.0.0", "stable") # or - required: name: "second-example-operator" versionRange: ">= 1.0.0 < 1.2.0" # optionally channel: "stable" status: conditions: # status conditions ... selections: # items selected in the form of source:name:version:channel - example-operators:first-example-operator:1.2.0:stable - example-operators:second-example-operator:1.1.0:stable - ... ``` ### Interfacing with clients For consumers of `Deppy`, they will be expected to provide the `sources` to reach out to as well as the `constraints` necessary for the desired resolution. Using this information, `Deppy` will then reach out to the appropriate cluster resources to generate a resolution. **`Deppy` will not be responsible for installing this content onto the cluster**, instead it is up to the consumer to determine how to act on a `ActiveResolution`'s status. #### PlatformOperators use case Less generically, its important to illustrate how the platform operators use case can utilize `Deppy` to understand the ultimate contract between the services for Phase 0 of `Deppy`. Say that we have defined an example `PlatformOperator` like so: ```yaml= apiVersion: platform.openshift.io/v1alpha1 kind: PlatformOperator metadata: name: foo-operator spec: package: name: foo-package ``` Upon applying this resource, there are two API's that will now be at play - Deppy and RukPak. To start the process, the `PlatformOperator` controller will create an `ActiveResoltion` for `Deppy` to reconcile. ```yaml= apiVersion: deppy.io/v1alpha1 kind: ActiveResolution metadata: name: foo-resolution spec: constraints: - required: name: "foo-package" channel: "platform" ... ``` For the sake of example, lets say that `foo-package` is reliant on another package called `bar-package`. In this case, `Deppy` will understand and convey this dependency to the status. ```yaml= ... status: conditions: # status conditions ... selections: # items selected in the form of source:name:version:channel - redhat-operators:foo-package:1.2.0:platform - redhat-operators:bar-package:1.1.0:platform ``` Looking at the status, we can see that there is a constructed query that tells us where our resolved entitiy is located at. The `PlatformOperator` controller could read this and perform another query to get the images; However, it may be pertitnent for a new component to be introduced into Deppy - the `ResolutionActivator` (name TBD). #### Resolution Activator The responsibility for the `ResolutionActivator` is to be able to read `ActiveResolution`s and parse out the installable units of work. This could follow an adapter pattern, like Deppy itself does, where the adapters are able to retrieve installable content. In the use case of `PlatformOperator`s this would result in a collections of images being made available. To mark a `ActiveResolution` with the appropriate adapter as well as if it should be activated, we can use annotations. ```yaml= apiVersion: deppy.io/v1alpha1 kind: ActiveResolution metadata: annotations: deppy.io/v1alpha1/activator-class: "PlatformOperator" name: foo-resolution ... ``` This would result in the status being updated to include a new section - entities. ```yaml= ... status: conditions: # status conditions ... selections: # items selected in the form of source:name:version:channel - redhat-operators:foo-package:1.2.0:platform - redhat-operators:bar-package:1.1.0:platform entities: # entities that were made installable via the activator-class annotation - package: foo-package image: quay.io/redhat-operators/foo-package:v1.2.0 - package: bar-package image: quay.io/redhat-operators/bar-package:v1.1.0 ``` From here, the `PlatformOperator` controller can read the resolved `entities` and install them accordingly onto the cluster via `RukPak`. However, it is pertinent to allow `Rukpak` to manage these installables as a group of installed content instead of individuals. This is where the `ResolveSet` bundle format comes into play. A `ResolveSet` bundle is, at its core, just a `plain+v0` bundle of `BundleDeployments`. What this means is that when the `ResolveSet` bundle gets installed the `plain` provisioner will work to reconcile that content as though it were arbitrary manifests, essentially having a wrapper `BundleDeployment` for `BundleDeployments`. Generation of the `ResolveSet` bundle is trivial and can be done on the fly by the `PlatformOperator` controller. If we were to look at a `ResolveSet` bundle's manifests for the above example, it would look something like this: ```console manifests/ |- foo-package-bd.yaml |- bar-package-bd.yaml ``` From this, the `PlatformOperator` controller is able to maintain a single `BundleDeployment` for all of the resolved content. #### Generic use case TODO ## Open Questions - Is ActiveResolution the right name? - What is an example of an InactiveResolution? - Should Deppy act on resolutions or rely on clients to consume them? - Should the ActiveResolution output the content needed to install the resolution? An image, for example?