apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
  name: quay-bridge-operator.v1.0.0
  namespace: placeholder
  annotations:
    alm-examples: |-
      [
        {
          "apiVersion": "redhatcop.redhat.io/v1alpha1",
          "kind": "QuayIntegration",
          "metadata": {
            "name": "my-quay"
          },
          "spec": {
            "clusterID": "openshift",
            "credentialsSecretName": "<NAMESPACE>/<SECRET>",
            "quayHostname": "https://<QUAY_URL>",
            "insecureRegistry": false,
            "whitelistNamespaces": ["default"]
          }
        }
      ]
    capabilities: Full Lifecycle
    categories: ""
    containerImage:
    createdAt: 2020-3-18 01:03:00
    description: Enhance OCP using Red Hat Quay container registry
    repository: https://github.com/quay/quay-bridge-operator
    tectonic-visibility: ocs
spec:
  description: |-
    ## Overview

    The OpenShift Container Platform contains an in cluster image registry for pushing and pulling images that either produced within the cluster or are references from external sources. Quay is a highly available, enterprise grade image registry with enhanced role based access control (RBAC) features. The goal of this operator is to support replicating the features found within OpenShift intgrated image registry with Quay.

    ## Functionality

    The following capabilities are enabled through this operator:

    * Synchronization of OpenShift namespaces as Quay organizations
        * Creation of Robot accounts for each default namespace service account
        * Creation of Secrets for each created Robot Account
            * Associate Robot Secret to Service Account as Mountable and Image Pull Secret
        * Synchronization of OpenShift ImageStreams as Quay Repositories
    * Automatically rewrite new Builds making use of ImageStreams to output to Quay
    * Automatically import ImageStream tag once build completes

    ## Prerequisites

    The following requirements must be satisfied prior to setting and configuring the integration between OpenShift and Quay:

    * A Red Hat Quay environment with a user with superuser permissions
    * A Red Hat OpenShift Container Platform environment (at least version 3.6 [3.11 recommended]) with cluster-admin permissions on an OpenShift cluster 
    *	OpenShift Command Line tool (CLI)

    ## Setup and Configuration

    The setup process involves steps within both Quay and OpenShift as described below:

    ### Quay Setup

    The integration between OpenShift and Quay makes extensive use of the Quay RESTFul API. To allow for other methods aside from user credentials to be used for authenticating against the API, an application is required to be created. When an application is created, an OAuth token is generated which can be used by the operator in OpenShift. Applications are created within a Quay organization. While an existing organization can be utilized, it is recommended that a dedicated organization be used.

    1.	Login to Quay as a user with superuser access and select the organization for which the external application will be configured within.
    2.	On the left hand side of the page, select **Applications**
    3.	Create a new application by selecting the **Create New Application** button and entering a name for the application
    4.	After the new application has been created, select the application that was created
    5.	On the lefthand navigation bar, select the **Generate Token** button to create a new OAuth2 token
    6.	Select all of the checkboxes to grant the necessary access that is needed for the integration
    7.	Review the permissions that will be assigned and then select the **Authorize Application** button
    8.	Take note of the generated Access Token as it will be needed in the following section

    ### OpenShift Setup

    To complete the process to begin to integrate OpenShift and Quay, several steps are required. Before beginning, ensure that you have the OpenShift Command Line tool installed and that you are logged into OpenShift as a cluster administrator. 

    #### Create A Secret for the Quay OAuth Token

    The Operator will use the previously obtained Access Token to communicate with Quay. Store this token within OpenShift as a secret.

    Execute the following command to create a secret called `quay-integration` with a key called `token` containing the access token:

    ```
    $ oc create secret generic quay-integration --from-literal=token=<access_token>
    ```

    This token will be referenced in the following section.


    #### Create the QuayIntegration Custom Resource

    Finally, to complete the integration between OpenShift and Quay, a `QuayIntegration` custom resource needs to be created.

    The following is an example of a basic definition of a `QuayIntegration` resource associated from the associated CRD.

    ```
    apiVersion: redhatcop.redhat.io/v1alpha1
    kind: QuayIntegration
    metadata:
      name: example-quayintegration
    spec:
      clusterID: openshift
      credentialsSecretName: <NAMESPACE>/<SECRET>
      quayHostname: https://<QUAY_URL>
    ```

    The _clusterID_ is a value which should be unique across the entire ecosystem. This value is optional and defaults to `openshift`.

    The _credentialsSecretName_ is a NamespacedName value of the secret containing the token that was previously created.

    Note: If Quay is using self signed certificates, the property `insecureRegistry: true`

    Organizations within Quay should be created for the related namespaces in OpenShift.

    #### MutatingWebhookConfiguration Support

    Support for dynamic interception of API requests that are performed as part of OpenShift’s typical build process is facilitated through a [MutatingWebhookConfiguration](https://docs.openshift.com/container-platform/3.11/architecture/additional_concepts/dynamic_admission_controllers.html). A MutatingWebhookConfiguration allows for invoking an API running within a project on OpenShift when certain API requests are received. In particular, to support Quay’s integration with OpenShift, any new Build requests should be intercepted so that the output can be modified to target Quay instead of OpenShift’s integrated registry. 

    Kubernetes requires that the webhook endpoint is secured via SSL using a certificate that makes use of the certificate authority for the cluster. Fortunately, OpenShift provides support for generating a certificate signed by the cluster. A script is available in the hack directory in the project repository called [webhook-create-signed-cert.sh](hack/webhook-create-signed-cert.sh) that automates the process for requesting a new certificate.

    First, create a `Service` for the Operator's webhook endpoint:
    ```yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: quay-bridge-operator
      name: quay-bridge-operator
      namespace: openshift-operators
    spec:
      ports:
        - name: https
          port: 443
          protocol: TCP
          targetPort: 8443
      selector:
        name: quay-bridge-operator
      sessionAffinity: None
      type: ClusterIP
    ```

    Execute the following command to request the certificate:

    ```
    hack/webhook-create-signed-cert.sh --namespace openshift-operators --secret quay-bridge-operator-webhook-certs --service quay-bridge-operator
    ```

    The result will place the newly created private key and certificate within a secret within the secret specified. The secret will be mounted into the appropriate located within the operator as declared in the Deployment of the Operator. 

    Once the secret has been created, focus can shift to the `MutatingWebhookConfiguration` (see below). The majority of the content should be in place to apply to the cluster. The one section that requires configuration is the caBundle property. This refers to the Certificate Authority (CA) for the OpenShift environment. The OpenShift CA is available as a _ConfigMap_ within the `kube-system` namespace.

    Execute the following command to retrieve the CA and format the result as a single line so that it can be entered into the MutatingWebhookConfiguration resource:

    ```
    oc get configmap -n kube-system extension-apiserver-authentication -o=jsonpath='{.data.client-ca-file}' | base64 | tr -d '\n'
    ```

    Replace the `${CA_BUNDLE}` variable in the following `MutatingWebhookConfiguration` YAML and create it:

    ```yaml
    apiVersion: admissionregistration.k8s.io/v1beta1
    kind: MutatingWebhookConfiguration 
    metadata:
      name: quay-bridge-operator
    webhooks:
      - name: quayintegration.redhatcop.redhat.io
        clientConfig: 
          service:
            namespace: openshift-operators
            name: quay-bridge-operator
            path: "/admissionwebhook"
          caBundle: "${CA_BUNDLE}"
        rules: 
        - operations:  [ "CREATE" ]
          apiGroups: [ "build.openshift.io" ]
          apiVersions: ["v1" ]
          resources: [ "builds" ]
        failurePolicy: Fail
    ```

    _Note: Until the operator is running, new requests for builds will fail since the webserver the MutatingWebhookConfiguration invokes is not available and a proper is response is required in order for the object to be persisted in etcd._
  displayName: Quay Bridge Operator
  install:
    spec:
      deployments:
      - name: quay-bridge-operator
        spec:
          replicas: 1
          selector:
            matchLabels:
              name: quay-bridge-operator
          template:
            metadata:
              labels:
                name: quay-bridge-operator
            spec:
              serviceAccountName: quay-bridge-operator
              containers:
                - name: quay-bridge-operator
                  image: quay.io/projectquay/quay-bridge-operator@sha256:029fd7a5e09e3f564826257dce39cba76e3e1589d8b8ee0dff828699a5e0abef
                  imagePullPolicy: Always
                  volumeMounts:
                    - mountPath: /etc/webhook/certs
                      name: certs
                      readOnly: true
                  env:
                    - name: POD_NAME
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.name
                    - name: OPERATOR_NAME
                      value: "quay-bridge-operator"
              ports:
                - containerPort: 8443
                  protocol: TCP
              volumes:
                - name: certs
                  secret:
                    secretName: quay-bridge-operator-webhook-certs
      permissions:
      - rules:
        - apiGroups:
          - ""
          resources:
          - secrets
          - events
          - serviceaccounts
          - namespaces
          - pods
          - configmaps
          verbs:
          - create
          - update
          - get
          - list
          - watch
          - delete
          - patch
        - apiGroups:
          - ""
          - image.openshift.io
          resources:
          - imagestreams
          - imagestreamimports
          verbs:
          - create
          - get
          - list
          - patch
          - update
          - watch
        - apiGroups:
          - ""
          - build.openshift.io
          resources:
          - builds
          verbs:
          - create
          - get
          - list
          - patch
          - update
          - watch
        - apiGroups:
          - monitoring.coreos.com
          resources:
          - servicemonitors
          verbs:
          - get
          - create
        - apiGroups:
          - redhatcop.redhat.io
          resources:
          - '*'
          - quayintegrations 
          verbs:
          - '*'
        serviceAccountName:  quay-bridge-operator
    strategy: deployment
  installModes:
  - supported: false
    type: OwnNamespace
  - supported: false
    type: SingleNamespace
  - supported: false
    type: MultiNamespace
  - supported: true
    type: AllNamespaces
  keywords:
  - registry
  - containers
  - quay
  labels:
    alm-owner-quay-bridge-operator: quay-bridge-operator
    operated-by: quay-bridge-operator
  icon:
  - base64data: [encoded data, 4744 characters]
    mediatype: image/png
  maturity: alpha
  links:
  - name: Source Code
    url: https://github.com/quay/quay-bridge-operator
  maintainers:
  - email: quay-devel@redhat.com
    name: Quay Engineering Team
  provider:
    name: Red Hat
  selector:
    matchLabels:
      alm-owner-quay-bridge-operator: quay-bridge-operator
      operated-by: quay-bridge-operator
  version: 1.0.0
  customresourcedefinitions:
    owned:
    - description: Represents a connected Quay instance.
      displayName: Quay Integration
      kind: QuayIntegration
      name: quayintegrations.redhatcop.redhat.io
      version: v1alpha1
      specDescriptors:
      - description: List of namespaces that will not be enabled
        displayName: Blacklisted Namespaces
        path: blacklistNamespaces
        x-descriptors:
        - 'urn:alm:descriptor:com.tectonic.ui:arrayFieldGroup:blacklistNamespaces'
        - 'urn:alm:descriptor:com.tectonic.ui:string'
      - description: List of namespaces that will be enabled
        displayName: Whitelisted Namespaces
        path: whitelistNamespaces
        x-descriptors:
        - 'urn:alm:descriptor:com.tectonic.ui:arrayFieldGroup:whitelistNamespaces'
        - 'urn:alm:descriptor:com.tectonic.ui:string'
