# RFC: OLMv1 Extensibility
**Note**: This was originally a Google Doc that I was unable to get it to share outside of Red Hat. I have added comments from that Google Doc to the corresponding location here.
## Need
OLMv1 is designed to consist of various components that are essential to delivering its core functionality. With this design in mind there is the question - how do we enable additional, optional, functionality to be layered on top of OLMv1’s core functionality?
Providing a solution to this problem:
- Allows for the creation of additional OLMv1 functionality that meets business specific requirements without having to go through the upstream processes to get it included as part of the core components.
- Allows the business to decide to only provide specific extensions through its product offerings.
- Introduces another avenue for community growth. The larger the OLM community the better.
As an example, if additional functionality was required for a specific Kubernetes distribution an extension could be written instead of forcing distribution specific behavior in the upstream project.
### Use Cases
#### Operator Installation Approval
In OLMv0 there is the notion of an InstallPlan that requires approval before an operator is installed. In OLMv1 the InstallPlan API is being removed and the creation of an Operator CR is considered approval to install the specified operator. This assumes that only cluster admins (or highly trusted users) have permissions to create an Operator CR.
While many users may be okay with this, one can imagine a scenario where a cluster admin may want to allow users to request that operators be installed and require approval before installation takes place. Something like this is a good candidate for an extension because it could be useful to a subset of users, but not all users of OLMv1.
#### Custom Hooks on Operator Installation
One can imagine a scenario where a user wants to implement some custom hooks in place to perform some logic whenever an operator is installed.
One plausible scenario is a company that has requirements in place to limit the number of potential vulnerabilities that are running on a cluster. In this scenario they may want to implement their own custom extension that scans a bundle image to ensure installing the operator doesn’t break their vulnerability rules.
#### Oria Operator
The main goal of the Oria Operator is to introduce a pattern of operators requesting permissions rather than demanding permissions and allowing cluster admins to easily grant the permissions at a specific scope. It’s been discussed that this functionality could be useful to cluster admins that are concerned about the security of their clusters and want to ensure that the operators they are installing are following the least privilege principle. This may be functionality that a subset of OLMv1 users would like to have, but not all users.
Since it introduces functionality useful for a subset of users, the Oria Operator would be a good candidate for becoming an extension. Having the Oria Operator as an extension would allow users that are concerned about cluster security to install this extension and be alerted whenever an operator is installed and hold the operator’s installation on a cluster admin’s approval/configuration of permissions. User’s who don’t want/need this functionality can just not install this extension.
**Note**: The Oria Operator is a bit more complex in that it would likely require modification of the operator manifests. This raises an important question - should extensions have the ability to modify manifests?
## Approach
### Overview
Let’s start by defining what an extension is - an extension is an operator that is designed to integrate with OLMv1. The proposed approach for enabling OLMv1 extensions includes:
- New APIs and controller(s):
- `OlmExtension` - API to register an extension with OLMv1
- `ExtensionRequest` - API for OLMv1 to signal that extensions should run
- Requirements for a communication interface between OLMv1 and extensions
- CR spec should implement a specific field defined by OLMv1’s expectations for how to communicate information to extensions
- CR status conditions should be set as defined by OLMv1’s status expectations for extensions
### Communication Interface
Since an extension is an operator specifically designed for integration with OLMv1, it needs to be able to get information from the OLMv1 operator installation process. To facilitate this exchange of information, each extension will have to satisfy specific interface requirements for communication.
The actual information to be exchanged is an implementation detail and is TBD.
The proposed interface requirements are:
- A field in a CR spec that can be populated with OLMv1 specific communications.
- The CR status must be populated with status conditions that can be read by OLMv1. The actual status values are implementation details and TBD.
For example, imagine a `Foo` CR being used for extending OLMv1. Assuming the only information that needs to be passed to an extension is the bundle name, an instance of the extension CR created as part of installing an operator may look something like:
```yaml
apiVersion: foo.io/v1
kind: Foo
metadata:
name: operator-extension-request
spec:
olm:
bundleName: operator.v1.0.0
```
Continuing with this example, let's see what the status conditions could look like. The following assumes that OLMv1 expects a condition of type `Successful` to represent success and `Failed` to represent failure:
```yaml
apiVersion: foo.io/v1
kind: Foo
metadata:
name: operator-extension-request
spec:
olm:
bundleName: operator.v1.0.0
status:
conditions:
- type: Successful
status: True
- type: Failed
status: False
```
### APIs
#### `OlmExtension`
The `OlmExtension` API is used to register a new extension. It should provide OLMv1 with the information it needs to determine how to create a CR for the extension. Following the examples above for the communication interface, let’s see what it could look like to register the Foo extension by creating the appropriate `OlmExtension` CR:
```yaml
apiVersion: olm.operatorframework.io/v1
kind: OlmExtension
metadata:
name: foo
spec:
group: foo.io
version: v1
kind: Foo
```
With this example, we have now registered an extension with OLMv1 and told it what resource it needs to create to use the extension.
#### `ExtensionRequest`
The `ExtensionRequest` API is used by OLMv1 to signal when it has gotten to the point in its execution where it needs to call any extensions that are present. The `ExtensionRequest` CR is reconciled by an internal OLMv1 controller that will go through all the registered `OlmExtensions` and create the corresponding CR. The `ExtensionRequest` CR will use status conditions to express whether or not the extensions are done running and if they have all executed successfully. An example of an `ExtensionRequest`:
```yaml
apiVersion: olm.operatorframework.io/v1
kind: ExtensionRequest
metadata:
name: operator-extension-req
spec:
bundleName: operator.v1.0.0
status:
conditions:
- type: Successful
status: True
```
To further explain what happens as a result of the creation of the example `ExtensionRequest`, let’s see what would happen behind the scenes:
1. The `ExtensionRequest` controller would list all `OlmExtension` resources on the cluster. For this example, let's assume that there is only one OlmExtension that exists - the `Foo`extension that we created in the OlmExtension section
2. The `ExtensionRequest` controller then iterates through the `OlmExtension` resources and creates the corresponding extensions CR. For this example that would look something like:
```yaml
apiVersion: foo.io/v1
kind: Foo
metadata:
name: operator-extension-request
spec:
olm:
bundleName: operator.v1.0.0
```
3. The `Foo` extension reconciles the `Foo` CR and eventually updates the status to indicate success
4. Once all CRs created for a given `ExtensionRequest` are updated to have a status that indicates success, the `ExtensionRequest` status is updated to indicate that all extensions have executed successfully and OLMv1 can continue with installation of the operator
5. OLMv1 sees that the `ExtensionRequest` has a successful status and finishes installing the operator
### Diagram
The below diagram shows a simple visual of what the interactions for this proposed approach could look like:

## Benefit
The major benefit of this solution is that it provides an answer to the question “How do we enable additional functionality to be layered on top of OLMv1’s core functionality?” by implementing an interface that allows for OLMv1 to be extended.
Some benefits that come along with making OLMv1 extensible are:
- OLMv1 extensions can be created that meets business specific needs without having to go through the upstream processes to get it included as part of the core components
- OLMv1 extensions can be vendor-locked without impacting the core functionality (i.e Kubernetes distributions can offer distribution specific OLMv1 extensions as part of purchasing a license)
- Community growth. Providing ways to extend OLMv1 could result in more community involvement in the development and usage of OLMv1 and extensions.
## Alternatives
At the moment, there are no alternatives that have been considered. I am open to suggestions on alternatives.
### Do Nothing
This alternative is where we do nothing. The result of this is that OLMv1 is not extensible without forcing the new component to become a core component of OLMv1. This is not ideal as only things that are essential to OLMv1’s operation should be a core component to keep the default installation as minimal as possible. Forcing functionality that is only beneficial to a subset of users to become part of the core payload of OLMv1 introduces bloat for users that don’t care for it and will likely cause a level of dissatisfaction for those users.
## Non-Goals
This proposal is not attempting to cover:
- How to create extensions
- Installing extensions
## Open Questions
- What information should be provided to extensions?
- What should happen if an extension is installed after I have already installed an operator?
- Should extensions have the ability to modify the contents of a bundle?