github.com/fabianvf/ocp-release-operator-sdk@v0.0.0-20190426141702-57620ee2f090/doc/design/milestone-0.2.0/csv-generation.md (about)

     1  # Operator-SDK CSV generation Design Doc
     2  
     3  ## Goal
     4  
     5  The `operator-sdk olm-catalog gen-csv` sub-command will 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*, will run `operator-sdk olm-catalog gen-csv` with the `--csv-version $version` flag to have their operators' state encapsulated in a CSV with the supplied version; this action should be idempotent and only update the CSV file when a new version is supplied, or a yaml manifest or source file is changed. Users should not have to directly modify most fields in a CSV manifest. Those that require modification are defined in the [user docs][csv_user_doc]. A CSV-generating command removes the responsibility from users of having in-depth [**Operator Lifecycle Manager (OLM)**][olm_description] knowledge in order for their operator to interact with OLM or publish metadata to the [**Catalog**][catalog_description].
     6  
     7  ## Background
     8  
     9  CSV's are yaml manifests created from a users' operator metadata that assist the OLM in running their operator in a cluster:
    10  
    11  > 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.
    12  
    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.
    14  
    15  ## Proposed Solution
    16  
    17  Functionality of `operator-sdk generate olm-catalog` is now in `operator-sdk olm-catalog gen-csv`; the former command no longer exists. `operator-sdk olm-catalog gen-csv --csv-version 0.0.1` writes a CSV yaml file to the `deploy/olm-catalog` directory by default.
    18  
    19  `deploy` is the standard location for all manifests required to deploy an operator. The SDK can use data from manifests in `deploy` to write a CSV. Exactly three types of manifests are required to generate a CSV: `operator.yaml`, `*_{crd,cr}.yaml`, and RBAC role files, ex. `role.yaml`. Users may have different versioning requirements for these files and can configure CSV which specific files are included in `deploy/olm-catalog/csv-config.yaml`, described [below](#configuration).
    20  
    21  Assuming all configuration defaults are used, `operator-sdk olm-catalog gen-csv` will call `scaffold.Execute()`, which will either:
    22  
    23  1. Create a new CSV, with the same location and naming convention as exists currently, using available data in yaml manifests and source files.
    24  
    25      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.
    26      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.
    27      1. Once the search completes, every cache field populated will be written back to a CSV yaml file.
    28          - **Note:** individual yaml fields are overwritten and not the entire file, as descriptions and other non-generated parts of a CSV should be preserved.
    29  
    30  1. Update an existing CSV at the currently pre-defined location, using available data in yaml manifests and source files.
    31  
    32      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.
    33      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.
    34      1. Once the search completes, every cache field populated will be written back to a CSV yaml file.
    35          - **Note:** individual yaml fields are overwritten and not the entire file, as descriptions and other non-generated parts of a CSV should be preserved.
    36  
    37  ### Configuration
    38  
    39  Users can configure CSV composition by populating several fields in the file `deploy/olm-catalog/csv-config.yaml`:
    40  
    41  - `operator-path`: (string) the operator resource manifest file path. Defaults to `deploy/operator.yaml`.
    42  - `crd-cr-path-list`: (string(, string)\*) a list of CRD and CR manifest file paths. Defaults to `[deploy/crds/*_{crd,cr}.yaml]`.
    43  - `rbac-path-list`: (string(, string)\*) a list of RBAC role manifest file paths. Defaults to `[deploy/role.yaml]`.
    44  
    45  ### Extensible `CSVUpdater` CSV update mechanism
    46  
    47  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:
    48  
    49  ```Go
    50  import "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
    51  
    52  type CSVUpdater interface {
    53    Apply(*v1alpha1.ClusterServiceVersion) error
    54  }
    55  ```
    56  
    57  `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.
    58  
    59  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.
    60  
    61  The following is an example implementation of an [install strategy][olm_csv_install_strat_doc] `CSVUpdater`:
    62  
    63  ```Go
    64  import (
    65    appsv1 "k8s.io/api/apps/v1"
    66    rbacv1beta1 "k8s.io/api/rbac/v1beta1"
    67    "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
    68    "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
    69  )
    70  
    71  // CSVInstallStrategyUpdate embeds the OLM's install strategy spec.
    72  type CSVInstallStrategyUpdate struct {
    73    *install.StrategyDetailsDeployment
    74  
    75    // Future fields go here.
    76  }
    77  
    78  // getLocalInstallStrategyCache retrieves the local cache singleton and returns the install strategy cache.
    79  func getLocalInstallStrategyCache() *CSVInstallStrategyUpdate {
    80    factory := getLocalCacheFactory()
    81    return factory.InstallStrategyCache
    82  }
    83  
    84  // AddDeploymentSpecToCSVInstallStrategyUpdate adds an RBAC Role to the local cache singletons' permissions.
    85  func AddRoleToCSVInstallStrategyUpdate(yamlDoc []byte) error {
    86    localInstallStrategyUpdate := getLocalInstallStrategyCache()
    87  
    88    newRBACRole := new(rbacv1beta1.Role)
    89    _ = yaml.Unmarshal(yamlDoc, newRBACRole)
    90  
    91    newPermissions := install.StrategyDeploymentPermissions{
    92      ServiceAccountName: newRole.ObjectMeta.Name,
    93      Rules:              newRole.Rules,
    94    }
    95    localInstallStrategyUpdate.Permissions = append(localInstallStrategyUpdate.Permissions, newPermissions)
    96  
    97    return nil
    98  }
    99  
   100  // AddDeploymentSpecToCSVInstallStrategyUpdate adds a Deployment to the local cache singletons' install strategy.
   101  func AddDeploymentSpecToCSVInstallStrategyUpdate(yamlDoc []byte) error {
   102    localInstallStrategyUpdate := getLocalInstallStrategyCache()
   103  
   104    newDeployment := new(appsv1.Deployment)
   105    _ = yaml.Unmarshal(yamlDoc, newDeployment)
   106  
   107    newDeploymentSpec := install.StrategyDeploymentSpec{
   108      Name: newDeployment.ObjectMeta.Name,
   109      Spec: newDeployment.Spec,
   110    }
   111    localInstallStrategyUpdate.DeploymentSpecs = append(localInstallStrategyUpdate.DeploymentSpecs, newDeploymentSpec)
   112  
   113    return nil
   114  }
   115  
   116  // Apply applies cached updates in CSVInstallStrategyUpdate to the appropriate csv fields.
   117  func (us *CSVInstallStrategyUpdate) Apply(csv *v1alpha1.ClusterServiceVersion) error {
   118    // Get install strategy from csv.
   119    var resolver *install.StrategyResolver
   120    strat, _ := resolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
   121    installStrat, _ := strat.(*install.StrategyDetailsDeployment)
   122  
   123    // Update permissions and deployments with custom field update methods.
   124    us.updatePermissions(installStrat)
   125    us.updateDeploymentSpecs(installStrat)
   126  
   127    // Re-serialize permissions into csv install strategy.
   128    updatedStrat, _ := json.Marshal(installStrat)
   129    csv.Spec.InstallStrategy.StrategySpecRaw = updatedStrat
   130  
   131    return nil
   132  }
   133  ```
   134  
   135  [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
   136  [olm_description]:https://github.com/operator-framework/operator-lifecycle-manager/blob/master/README.md
   137  [catalog_description]:https://github.com/operator-framework/operator-lifecycle-manager/blob/master/Documentation/design/architecture.md#catalog-registry-design
   138  [olm_csv_struct_code]:https://github.com/operator-framework/operator-lifecycle-manager/blob/8799f39ef342dc1ff7430eba7a88c1c3c70cbdcc/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go#L261
   139  [olm_csv_spec_code]:https://github.com/operator-framework/operator-lifecycle-manager/blob/8799f39ef342dc1ff7430eba7a88c1c3c70cbdcc/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go
   140  [olm_csv_spec_doc]:https://github.com/operator-framework/operator-lifecycle-manager/blob/16ff8f983b50503c4d8b8015bd0c14b5c7d6786a/Documentation/design/building-your-csv.md#building-a-cluster-service-version-csv-for-the-operator-framework
   141  [olm_csv_install_strat_doc]:https://github.com/operator-framework/operator-lifecycle-manager/blob/16ff8f983b50503c4d8b8015bd0c14b5c7d6786a/Documentation/design/building-your-csv.md#operator-install
   142  [olm_csv_crd_doc]:https://github.com/operator-framework/operator-lifecycle-manager/blob/16ff8f983b50503c4d8b8015bd0c14b5c7d6786a/Documentation/design/building-your-csv.md#owned-crds
   143  [csv_user_doc]:../../user/olm-catalog/generating-a-csv.md#csv-fields