Skip to content

Commit 1159b1a

Browse files
committed
notes on '--gen-csv' flag, config file, versioning
1 parent 849da88 commit 1159b1a

File tree

1 file changed

+81
-67
lines changed

1 file changed

+81
-67
lines changed

doc/design/milestone-0.1.1/csv-generation.md

Lines changed: 81 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,42 @@
22

33
## Goal
44

5-
The `operator-sdk build` sub-command should generate a [**Cluster Service Version (CSV)**][olm-csv-definition] customized using information contained in user-defined yaml manifests and operator source files. Operator developers, *users*, should be able to run `operator-sdk build` and have their operators' state encapsulated in a CSV; this command should be idempotent and only update the CSV when a yaml manifest or source file is changed. Users should not have to directly interact with a CSV, and should not be required to have in-depth CSV knowledge in order for their operator to interact with [**Operator Lifecycle Manager (OLM)**][olm-description] or publish metadata to the [**Catalog**][catalog-description].
5+
The `operator-sdk build` sub-command should generate a [**Cluster Service Version (CSV)**][olm-csv-definition] customized using information contained in user-defined yaml manifests and operator source files. Operator developers, *users*, should be able to run `operator-sdk build` with the `--gen-csv` flag to have their operators' state encapsulated in a CSV; this command should be idempotent and only update the CSV when a yaml manifest or source file is changed. Users should not have to directly interact with a CSV, and should not be required to have in-depth CSV knowledge in order for their operator to interact with [**Operator Lifecycle Manager (OLM)**][olm-description] or publish metadata to the [**Catalog**][catalog-description].
66

77
## Background
88

99
CSV's are yaml manifests created from a users' operator metadata that assist the OLM in running their operator in a cluster:
1010

1111
> A CSV is the metadata that accompanies your Operator container image. It can be used to populate user interfaces with info like your logo/description/version and it is also a source of technical information needed to run the Operator, like the RBAC rules it requires and which Custom Resources it manages or depends on.
1212
13-
The `operator-sdk generate olm-catalog` command currently produces a generic CSV with minimal customization. Defaults and simple metadata components are used to fill fields, with no options to customize. Users must modify the CSV manually or use custom scripts to pull data from various operator component files. These solutions are not scalable because we cannot assume users are, or have time to become, familiar with CSV format or know where to find information required by CSV yaml objects.
13+
The `operator-sdk generate olm-catalog` command currently produces a generic CSV with minimal customization. Defaults and simple metadata components are used to fill fields, with no options to customize. Users must modify the CSV manually or use custom scripts to pull data from various operator component files. These solutions are not scalable because we cannot assume users are, or have time to become, familiar with CSV format or know where to find information required by CSV yaml fields.
1414

1515
## Proposed Solution
1616

17-
Functionality of `operator-sdk generate olm-catalog` is now a branch in `operator-sdk build`, and the former command no longer exists. `operator-sdk build` writes to the `deploy` directory, which is the standard location for all manifests and scripts required to deploy an operator. The SDK can use data from manifests in `deploy` to write a CSV.
17+
Functionality of `operator-sdk generate olm-catalog` is now a branch in `operator-sdk build`, specifically when called with the `--gen-csv` flag; the former command no longer exists. `operator-sdk build "$IMAGE_NAME" --gen-csv"` writes a CSV yaml file using the operators' current version to the `deploy/olm-catalog` directory by default. `deploy` is the standard location for all manifests and scripts required to deploy an operator. The SDK can use data from manifests in `deploy` to write a CSV. Users may have different requirements for what should (not) be included in a CSV, and can configure CSV composition via `deploy/olm-catalog/csv-config.yaml`, described below.
1818

19-
`operator-sdk build` will call the function `renderCSV` to either:
19+
Assuming all configuration defaults are used, `operator-sdk build` will call `scaffold.Execute()`, which will either:
2020

2121
1. Create a new CSV, with the same location and naming convention as exists currently, using available data in yaml manifests and source files.
2222

23-
1. `renderCSV` will check for an existing CSV in `deploy`. Upon not finding one, a [`ClusterServiceVersion` object][olm-csv-struct-code], defined by the OLM, is created and fields easily derived from operator metadata, such as Kubernetes API `ObjectMeta`, are populated.
24-
1. `renderCSV` will search `deploy` for manifests that contain yaml objects a CSV uses, such as a `Deployment` Kubernetes API resource, and set the appropriate CSV fields with object data.
25-
1. Once the search completes, every object field populated will be written back to the CSV yaml file.
26-
- Note that individual yaml objects are overwritten and not the entire file, as descriptions and other non-generated parts of a CSV should be preserved.
23+
1. The update mechanism will check for an existing CSV in `deploy`. Upon not finding one, a [`ClusterServiceVersion` object][olm-csv-struct-code], referred to here as a *cache*, is created and fields easily derived from operator metadata, such as Kubernetes API `ObjectMeta`, are populated.
24+
1. The update mechanism will search `deploy` for manifests that contain data a CSV uses, such as a `Deployment` Kubernetes API resource, and set the appropriate CSV fields in the cache with this data.
25+
1. Once the search completes, every cache field populated will be written back to a CSV yaml file.
26+
- **Note:** individual yaml fields are overwritten and not the entire file, as descriptions and other non-generated parts of a CSV should be preserved.
2727

2828
1. Update an existing CSV at the currently pre-defined location, using available data in yaml manifests and source files.
29-
30-
1. `renderCSV` will check for an existing CSV in `deploy`. Upon finding one, the CSV yaml file contents will be marshalled into a `ClusterServiceVersion` object.
29+
30+
1. The update mechanism will check for an existing CSV in `deploy`. Upon finding one, the CSV yaml file contents will be marshalled into a `ClusterServiceVersion` cache.
3131
1. Same as above.
3232
1. Same as above.
33-
33+
34+
### Configuration
35+
36+
Users can configure CSV composition by populating several fields in the file `deploy/olm-catalog/csv-config.yaml`:
37+
38+
- `search-directory`: (string) the directory to search for yaml manifest files. Defaults to `deploy`.
39+
- `exclude-files`: ([string[, string]*]) files that match any string in the list are not included in the CSV search; glob matching allowed. Defaults to empty.
40+
3441
### Extensible `CSVUpdater` CSV update mechanism
3542

3643
The CSV spec will likely change over time as new Kubernetes and OLM features are implemented; we need the ability to easily extend the update system. The SDK will define the `CSVUpdater` interface as follows to encapsulate individual CSV field updates in methods:
@@ -39,13 +46,13 @@ The CSV spec will likely change over time as new Kubernetes and OLM features are
3946
import "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
4047

4148
type CSVUpdater interface {
42-
Apply(*v1alpha1.ClusterServiceVersion) error
49+
Apply(*v1alpha1.ClusterServiceVersion) error
4350
}
4451
```
4552

46-
`Apply` will use data from the `CSVUpdater` implementer to operate on `*v1alpha1.ClusterServiceVersion` object fields relevant to that updater. The OLM defines the entire CSV spec [in a Golang struct][olm-csv-spec-code] the SDK can alias to implement `CSVUpdater`s.
53+
`Apply` will use data from the `CSVUpdater` implementer to operate on `*v1alpha1.ClusterServiceVersion` cache fields relevant to that updater. The OLM defines the entire CSV spec [in a Golang struct][olm-csv-spec-code] the SDK can alias to implement `CSVUpdater`s.
4754

48-
Once sub-step two is reached when creating or updating a CSV, `renderCSV` will extract each yaml document discovered, and pass document data into a dispatcher function. The dispatcher selects the correct `CSVUpdater` to call based on the documents' `Kind` yaml object, a manifest type identifier used in all operator manifests. A CSV should reflect the current state of an operators' yaml manifests and any codified components in general, so any fields that correspond to data gathered from codified components will be overwritten; data like English descriptions will not be unless updated data is found.
55+
Once sub-step two is reached when creating or updating a CSV, `renderCSV` will extract each yaml document discovered, and pass document data into a dispatcher function. The dispatcher selects the correct `CSVUpdater` to call based on the documents' `Kind` field, a manifest type identifier used in all operator manifests. A CSV should reflect the current state of an operators' yaml manifests and any codified components in general, so any fields that correspond to data gathered from codified components will be overwritten; data like English descriptions will not be unless updated data is found.
4956

5057
The following is an example implementation of an [install strategy][olm-csv-install-strat-doc] `CSVUpdater`:
5158

@@ -60,97 +67,104 @@ import (
6067

6168
// CSVInstallStrategyUpdate embeds the OLM's install strategy spec.
6269
type CSVInstallStrategyUpdate struct {
63-
*install.StrategyDetailsDeployment
70+
*install.StrategyDetailsDeployment
6471

65-
// Future utility fields go here.
72+
// Future utility fields go here.
6673
}
6774

6875
// getLocalInstallStrategyCache retrieves the local cache singleton and returns the install strategy cache.
6976
func getLocalInstallStrategyCache() *CSVInstallStrategyUpdate {
70-
factory := getLocalCacheFactory()
71-
return factory.InstallStrategyCache
77+
factory := getLocalCacheFactory()
78+
return factory.InstallStrategyCache
7279
}
7380

7481
// AddDeploymentSpecToCSVInstallStrategyUpdate adds an RBAC Role to the local cache singletons' permissions.
7582
func AddRoleToCSVInstallStrategyUpdate(yamlDoc []byte) error {
76-
localInstallStrategyUpdate := getLocalInstallStrategyCache()
83+
localInstallStrategyUpdate := getLocalInstallStrategyCache()
7784

78-
newRBACRole := new(rbacv1beta1.Role)
79-
_ = yaml.Unmarshal(yamlDoc, newRBACRole)
85+
newRBACRole := new(rbacv1beta1.Role)
86+
_ = yaml.Unmarshal(yamlDoc, newRBACRole)
8087

81-
newPermissions := install.StrategyDeploymentPermissions{
82-
ServiceAccountName: newRole.ObjectMeta.Name,
83-
Rules: newRole.Rules,
84-
}
85-
localInstallStrategyUpdate.Permissions = append(localInstallStrategyUpdate.Permissions, newPermissions)
88+
newPermissions := install.StrategyDeploymentPermissions{
89+
ServiceAccountName: newRole.ObjectMeta.Name,
90+
Rules: newRole.Rules,
91+
}
92+
localInstallStrategyUpdate.Permissions = append(localInstallStrategyUpdate.Permissions, newPermissions)
8693

87-
return nil
94+
return nil
8895
}
8996

9097
// AddDeploymentSpecToCSVInstallStrategyUpdate adds a Deployment to the local cache singletons' install strategy.
9198
func AddDeploymentSpecToCSVInstallStrategyUpdate(yamlDoc []byte) error {
92-
localInstallStrategyUpdate := getLocalInstallStrategyCache()
99+
localInstallStrategyUpdate := getLocalInstallStrategyCache()
93100

94-
newDeployment := new(appsv1.Deployment)
95-
_ = yaml.Unmarshal(yamlDoc, newDeployment)
101+
newDeployment := new(appsv1.Deployment)
102+
_ = yaml.Unmarshal(yamlDoc, newDeployment)
96103

97-
newDeploymentSpec := install.StrategyDeploymentSpec{
98-
Name: newDeployment.ObjectMeta.Name,
99-
Spec: newDeployment.Spec,
100-
}
101-
localInstallStrategyUpdate.DeploymentSpecs = append(localInstallStrategyUpdate.DeploymentSpecs, newDeploymentSpec)
104+
newDeploymentSpec := install.StrategyDeploymentSpec{
105+
Name: newDeployment.ObjectMeta.Name,
106+
Spec: newDeployment.Spec,
107+
}
108+
localInstallStrategyUpdate.DeploymentSpecs = append(localInstallStrategyUpdate.DeploymentSpecs, newDeploymentSpec)
102109

103-
return nil
110+
return nil
104111
}
105112

106113
// Apply applies cached updates in CSVInstallStrategyUpdate to the appropriate csv fields.
107114
func (us *CSVInstallStrategyUpdate) Apply(csv *v1alpha1.ClusterServiceVersion) error {
108-
// Get install strategy from csv.
109-
var resolver *install.StrategyResolver
110-
strat, _ := resolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
111-
installStrat, _ := strat.(*install.StrategyDetailsDeployment)
115+
// Get install strategy from csv.
116+
var resolver *install.StrategyResolver
117+
strat, _ := resolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
118+
installStrat, _ := strat.(*install.StrategyDetailsDeployment)
112119

113-
// Update permissions and deployments with custom field update methods.
114-
us.updatePermissions(installStrat)
115-
us.updateDeploymentSpecs(installStrat)
120+
// Update permissions and deployments with custom field update methods.
121+
us.updatePermissions(installStrat)
122+
us.updateDeploymentSpecs(installStrat)
116123

117-
// Re-serialize permissions into csv install strategy.
118-
updatedStrat, _ := json.Marshal(installStrat)
119-
csv.Spec.InstallStrategy.StrategySpecRaw = updatedStrat
124+
// Re-serialize permissions into csv install strategy.
125+
updatedStrat, _ := json.Marshal(installStrat)
126+
csv.Spec.InstallStrategy.StrategySpecRaw = updatedStrat
120127

121-
return nil
128+
return nil
122129
}
123130
```
124131

125-
### User-defined yaml objects
132+
### User-defined yaml fields
126133

127-
Many CSV component objects cannot be populated using generated, non-SDK-specific manifests. These objects are mostly human-written, English metadata about the operator and various CRD's. Users must directly modify their CSV yaml file, adding personalized data to the following required objects. A lack of data in any of the required objects will generate an error on `operator-sdk build`.
134+
Many CSV fields cannot be populated using generated, non-SDK-specific manifests. These fields are mostly human-written, English metadata about the operator and various CRD's. Users must directly modify their CSV yaml file, adding personalized data to the following required fields. Users will receive a warning on `operator-sdk build` when a lack of data in any of the required fields is detected.
128135

129136
Required:
130-
- `displayName`: a public name to identify the operator.
131-
- `description`: a short description of the operator's functionality.
132-
- `keywords`: 1..N keywords describing the operator.
133-
- `maintainers`: 1..N human or organizational entities maintaining the operator, with a `name` and `email`.
134-
- `provider`: the operators' provider, with a `name`; usually an organization.
135-
- `labels`: 1..N `key`:`value` pairs to be used by operator internals.
136-
- `version`: semantic version of the operator, ex. `0.1.1`.
137-
- `customresourcedefinitions`: any CRD's the operator uses.
138-
- **Note**: this field will be populated automatically by the SDKif any CRD yaml files are present in `deploy`; however, several objects require user input (more details in the [CSV CRD spec section][olm-csv-crd-doc]):
139-
- `description`: description of the CRD.
140-
- `resources`: any Kubernetes resources leveraged by the CRD, ex. `Pod`'s, `StatefulSet`'s.
141-
- `specDescriptors`: UI hints for inputs and outputs of the operator.
137+
138+
- `.metadata.name`: a *unique* name for this CSV. Operator version should be included in the name to ensure uniqueness, ex. `app-operator.v0.1.1`.
139+
- `.spec.displayName`: a public name to identify the operator.
140+
- `.spec.description`: a short description of the operator's functionality.
141+
- `.spec.keywords`: 1..N keywords describing the operator.
142+
- `.spec.maintainers`: 1..N human or organizational entities maintaining the operator, with a `name` and `email`.
143+
- `.spec.provider`: the operators' provider, with a `name`; usually an organization.
144+
- `.spec.labels`: 1..N `key`:`value` pairs to be used by operator internals.
145+
- `.spec.version`: semantic version of the operator, ex. `0.1.1`.
146+
- `.spec.customresourcedefinitions`: any CRD's the operator uses. This field will be populated automatically by the SDK if any CRD yaml files are present in `deploy`; however, several fields require user input (more details in the [CSV CRD spec section][olm-csv-crd-doc]):
147+
- `description`: description of the CRD.
148+
- `resources`: any Kubernetes resources leveraged by the CRD, ex. `Pod`'s, `StatefulSet`'s.
149+
- `specDescriptors`: UI hints for inputs and outputs of the operator.
142150

143151
Optional:
144-
- `replaces`: the CSV being replaced by this CSV.
145-
- `links`: 1..N URL's to websites, documentation, etc. pertaining to the operator or application being managed, each with a `name` and `url`.
146-
- `selector`: selectors by which the operator can pair resources in a cluster.
147-
- `icon`: a base64-encoded icon unique to the operator, set in a `base64data` object with a `mediatype`.
148-
- `maturity`: the operators' stage of development, ex. `beta`.
152+
153+
- `.spec.replaces`: the name of the CSV being replaced by this CSV.
154+
- `.spec.links`: 1..N URL's to websites, documentation, etc. pertaining to the operator or application being managed, each with a `name` and `url`.
155+
- `.spec.selector`: selectors by which the operator can pair resources in a cluster.
156+
- `.spec.icon`: a base64-encoded icon unique to the operator, set in a `base64data` field with a `mediatype`.
157+
- `.spec.maturity`: the operators' stability, ex. `beta`.
149158

150159
Further details on what data each field above should hold are found in the [CSV spec][olm-csv-spec-doc].
151160

152-
**Note**: Several yaml objects currently requiring user intervention can potentially be parsed from operator code; such SDK functionality will be addressed in a future design document.
161+
**Note**: Several yaml fields currently requiring user intervention can potentially be parsed from operator code; such SDK functionality will be addressed in a future design document.
162+
163+
### CSV versioning
164+
165+
The CSV version is the same as the operators', and should be included somewhere in `metadata.name`. A new CSV will be generated when upgrading operator versions.
153166

167+
**TODO:** discuss whether multiple CSV files can be present, each with a unique file name (ex. `app-operator.csv.0.1.1.yaml`), or a single `app-operator.csv.yaml` file that relies on VCS (git) to version the file.
154168

155169
[olm-csv-definition]:https://github.com/operator-framework/operator-lifecycle-manager/blob/master/Documentation/design/building-your-csv.md#what-is-a-cluster-service-version-csv
156170
[olm-description]:https://github.com/operator-framework/operator-lifecycle-manager/blob/master/README.md

0 commit comments

Comments
 (0)