Skip to content

Commit

Permalink
Merge pull request #25 from sabre1041/installplan-approval
Browse files Browse the repository at this point in the history
Manual approval strategy
  • Loading branch information
etsauer committed Aug 28, 2020
2 parents 28d1990 + d02d2b2 commit c192a58
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 2 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,38 @@ status:
phase: Active
```

## Managing Operators

Operators are a foundational component of the architecture of OpenShift, and the lifecycle of operators are managed by the [Operator Lifeycle Manager (OLM)](https://docs.openshift.com/container-platform/latest/operators/understanding_olm/olm-understanding-olm.html). As illustrated in a portion of the prior examples, an operator managed by the OLM is enabled in one or more namespaces by an [OperatorGroup](https://docs.openshift.com/container-platform/latest/operators/understanding_olm/olm-understanding-olm.html#olm-operatorgroups-about_olm-understanding-olm) and the intention to install an operator is enabled using a [Subscription](https://docs.openshift.com/container-platform/latest/operators/understanding_olm/olm-understanding-olm.html#olm-subscription_olm-understanding-olm). A subscription defines the source of the operator including the namespace, catalog and can contain the specific ClusterServiceVersion that is intended to be installed. The OLM will then create an associated [InstallPlan](https://docs.openshift.com/container-platform/4.5/operators/understanding_olm/olm-understanding-olm.html#olm-installplan_olm-understanding-olm) which includes the set of resources that wil be installed in association with the operator.

To manage how upgrades are handled when a new version becomes available, operators use an [approval strategy](https://docs.openshift.com/container-platform/4.5/operators/olm-adding-operators-to-cluster.html) which can either be _Manual_ or _Automatic_ (Specified by the `installPlanApproval` of a _Subscription_). If _Automatic_ is chosen, an operator will automatically be upgraded to the latest version when a new version is available. When using the _Manual_ approval strategy, an administrator must manually approve the operator before it is installed.

While the _automatic_ approval strategy offers the simplicity of being able to take advantage of the latest features that an operator can provide, in many cases there is a desire to explicitly specify the version to use without automatically upgrading, thus using the _manual_ approval strategy. Actions that require the intervention of an administrator to approve an operator for it to be deployed contradicts that declarative nature of GitOps. When an operator using the _manual_ approval strategy is approved, the `approved` field on the _InstallPlan_ is set to `true`.

To replicate the actions that would typically be required by an administrator to approve an operator, a _Job_ can be used. The `resource-locker-operator` deployed previously uses the _manual_ approval strategy and is approved by a _Job_ called [installplan-approver](simple-bootstrap/3-operator-configs/installplan-approver-job.yaml) which will automatically approve an _InstallPlan_ if the CSV matches the desired CSV defined in the _Subscription_.

Managing the _manual_ approval strategy uses the following resources:

* A set of [policies](simple-bootstrap/2-rbac/installplan-approver.yaml) including a _ServiceAccount_ for which the job will run as, a _Role_ that grants access to _InstallPlans_ and _Subscriptions_ along with a _RoleBinding_ which associates the _Role_ to the _ServiceAccount_.
* The [installplan-approver Job](simple-bootstrap/3-operator-configs/installplan-approver-job.yaml) that approves the operator

Verify the job completed successfully by executing the following command:

```
$ oc get pods -n resource-locker-operator -l=job-name=installplan-approver
NAME READY STATUS RESTARTS AGE
installplan-approver-vh9dm 0/1 Completed 0 58m
```

When using a GitOps tool, such as ArgoCD, the following annotations can be applied to automatically delete an existing job (if found) to avoid a possible conflict when applying resources.

```
apiVersion: batch/v1
kind: Job
metadata:
annotations:
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
```
4 changes: 2 additions & 2 deletions simple-bootstrap/1-operators/resource-locker-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ metadata:
namespace: resource-locker-operator
spec:
targetNamespaces:
- resource-locker-operator
- resource-locker-operator
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
Expand All @@ -27,7 +27,7 @@ metadata:
namespace: resource-locker-operator
spec:
channel: alpha
installPlanApproval: Automatic
installPlanApproval: Manual
name: resource-locker-operator
source: community-operators
sourceNamespace: openshift-marketplace
Expand Down
53 changes: 53 additions & 0 deletions simple-bootstrap/2-rbac/installplan-approver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
config.example.com/managed-by: gitops
config.example.com/scm-url: git@github.com:redhat-cop/declarative-openshift.git
labels:
config.example.com/name: simple-bootstrap
config.example.com/component: rbac
name: installplan-approver-job
namespace: resource-locker-operator
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
config.example.com/managed-by: gitops
config.example.com/scm-url: git@github.com:redhat-cop/declarative-openshift.git
labels:
config.example.com/name: simple-bootstrap
config.example.com/component: rbac
name: installplan-approver
namespace: resource-locker-operator
rules:
- apiGroups:
- operators.coreos.com
resources:
- installplans
- subscriptions
verbs:
- get
- list
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
annotations:
config.example.com/managed-by: gitops
config.example.com/scm-url: git@github.com:redhat-cop/declarative-openshift.git
labels:
config.example.com/name: simple-bootstrap
config.example.com/component: rbac
name: installplan-approvers
namespace: resource-locker-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: installplan-approver
subjects:
- kind: ServiceAccount
name: installplan-approver-job
Empty file.
53 changes: 53 additions & 0 deletions simple-bootstrap/3-operator-configs/installplan-approver-job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: batch/v1
kind: Job
metadata:
annotations:
config.example.com/managed-by: gitops
config.example.com/scm-url: git@github.com:redhat-cop/declarative-openshift.git
labels:
config.example.com/name: simple-bootstrap
config.example.com/component: configs
name: installplan-approver
namespace: resource-locker-operator
spec:
template:
spec:
containers:
- image: registry.redhat.io/openshift4/ose-cli:v4.4
command:
- /bin/bash
- -c
- |
export HOME=/tmp/approver
echo "Approving operator InstallPlans. Waiting a few seconds to make sure the InstallPlan gets created first."
sleep 10
for subscription in `oc get subscription -o name`
do
desiredcsv=$(oc get $subscription -o jsonpath='{ .spec.startingCSV }')
until [ "$(oc get installplan --template="{{ range \$item := .items }}{{ range \$item.spec.clusterServiceVersionNames }}{{ if eq . \"$desiredcsv\"}}{{ printf \"%s\n\" \$item.metadata.name }}{{end}}{{end}}{{end}}")" != "" ]; do sleep 2; done
installplans=$(oc get installplan --template="{{ range \$item := .items }}{{ range \$item.spec.clusterServiceVersionNames }}{{ if eq . \"$desiredcsv\"}}{{ printf \"%s\n\" \$item.metadata.name }}{{end}}{{end}}{{end}}")
for installplan in $installplans
do
if [ "`oc get installplan $installplan -o jsonpath="{.spec.approved}"`" == "false" ]; then
echo "Approving Subscription $subscription with install plan $installplan"
oc patch installplan $installplan --type=json -p='[{"op":"replace","path": "/spec/approved", "value": true}]'
else
echo "Install Plan '$installplan' already approved"
fi
done
done
imagePullPolicy: Always
name: installplan-approver
dnsPolicy: ClusterFirst
restartPolicy: OnFailure
serviceAccount: installplan-approver-job
serviceAccountName: installplan-approver-job
terminationGracePeriodSeconds: 30

0 comments on commit c192a58

Please sign in to comment.