The parent base bundle we explored in the previous lab is also configured to be the default bundle for all managed controllers that do not specify a bundle. This allows you to easily manage configuration across all of your organization’s managed controllers, but it does not allow for any variations in configuration bundles between controllers. Also, the number of manual steps to provision a managed controller, and apply controller specific bundles across numerous controllers, wastes time and is prone to configuration errors. Imagine if you had dozens or even hundreds of controllers (like we do in this workshop), things would quickly become very difficult to manage.
In this lab we will explore a GitOps approach for automating the process of provisioning a controller, to include automating the configuration and assignment of a controller specific configuration bundle. This approach is based on individual repositories representing individual controllers, and takes advantage of the Jenkins GitHub Organization project type and CloudBees CI custom marker file like we used earlier. After we add a new controller-provision GitHub Organization folder job to your ops-controller, a new controller will be provisioned any time you add a new GitHub repository with a controller.yaml file to your workshop GitHub Organization. The managed controller will be provisioned with the configuration bundle from that new GitHub repository (one other approach may be to use folders in one repository to represent each controller).
If we wanted to use an SCM CasC storage service for your controllers’ bundles then we would have to either add everyone’s bundles to one branch of one repository or add an additional SCM external storage configuration to Operations Center for every controller.
We will be using CasC for Operations Center and CasC HTTP API endpoints to dynamically provision controllers using the controller.yaml file and bundle files from your controller repository. For the purposes of the shared workshop environment we will be running the provisioning job from the workshop Ops controller and will leverage CloudBees CI Cross Team Collaboration, triggering the job with the required payload from your Ops controller.
def event = currentBuild.getBuildCauses()[0].event
library 'pipeline-library'
pipeline {
agent none
environment {
OPS_PROVISION_SECRET = credentials('casc-workshop-controller-provision-secret')
CONTROLLER_PROVISION_SECRET = event.secret.toString()
}
options { timeout(time: 10, unit: 'MINUTES') }
triggers {
eventTrigger jmespathQuery("controller.action=='provision'")
}
stages {
stage('Provision Managed Controller') {
agent {
kubernetes {
yaml libraryResource ('podtemplates/kubectl.yml')
}
}
environment {
ADMIN_CLI_TOKEN = credentials('admin-cli-token')
WORKSHOP_ID="cloudbees-ci-casc-workshop"
GITHUB_ORGANIZATION = event.github.organization.toString().replaceAll(" ", "-")
GITHUB_REPOSITORY = event.github.repository.toString().toLowerCase()
CONTROLLER_FOLDER = GITHUB_ORGANIZATION.toLowerCase()
BUNDLE_ID = "${CONTROLLER_FOLDER}-${GITHUB_REPOSITORY}"
AVAILABILITY_PATTERN = "${WORKSHOP_ID}/${GITHUB_ORGANIZATION}/${GITHUB_REPOSITORY}"
}
when {
triggeredBy 'EventTriggerCause'
environment name: 'CONTROLLER_PROVISION_SECRET', value: OPS_PROVISION_SECRET
}
steps {
container("kubectl") {
sh '''
rm -rf ./${BUNDLE_ID} || true
rm -rf ./checkout || true
mkdir -p ${BUNDLE_ID}
mkdir -p checkout
git clone https://github.com/${GITHUB_ORGANIZATION}/${GITHUB_REPOSITORY}.git checkout
'''
dir('checkout/bundle') {
sh '''
cp --parents `find -name \\*.yaml*` ../../${BUNDLE_ID}//
'''
}
sh '''
ls -la ${BUNDLE_ID}
kubectl cp --namespace cbci ${BUNDLE_ID} cjoc-0:/var/jenkins_config/jcasc-bundles-store/ -c jenkins
'''
}
sh '''
curl --user "$ADMIN_CLI_TOKEN_USR:$ADMIN_CLI_TOKEN_PSW" -XPOST \
http://cjoc/cjoc/load-casc-bundles/checkout
curl --user "$ADMIN_CLI_TOKEN_USR:$ADMIN_CLI_TOKEN_PSW" -XPOST \
http://cjoc/cjoc/casc-items/create-items?path=/$WORKSHOP_ID \
--data-binary @./controller.yaml -H 'Content-Type:text/yaml'
'''
}
}
}
}
pipeline: def event = currentBuild.getBuildCauses()[0].event. We do this outside of the declarative pipeline block because you cannot assign objects to variables in declarative pipeline and we need the values before we can execute a script block in a stage.agent at the global level as it would result in the unnecessary provisioning of an agent if the when conditions are not met.eventTrigger is configured to only match a JSON payload containing controller.action=='provision'. We wil come back to this when we update the controller-casc-update pipeline for your Ops controller.stage as the sh steps require a normal (some times referred to as heavy-weight) executor (meaning it must be run on an agent since all managed controllers our configured with 0 executors): agent { label 'default-jnlp' }environment directive is used to capture values published by the Cross Team Collaboration event, to retrieve the controller provisioning secret value from the workshop Ops controller and to retrieve the Operations Center admin API token credential.when conditions are configured so the Provision Managed Controller stage will only run if the job is triggered by an EventTriggerCause and if the PROVISION_SECRET matches the event payload secret.kubectl CLI tool is used to copy CasC bundle files to Operations Center Local folder we have configured.curl command is used to post the contents of the controller.yaml file to the /casc-items/create-items CloudBees CI CasC HTTP API endpoint which will result in the provisioning of a managed controller.Now that we have reviewed the pipeline script for the workshop provisioning of managed controllers, we need to create a new GitHub Organization Folder project that will publish a Cross Team Collaboration event to trigger that pipeline.
ops-controller repository in your workshop GitHub Organization, click on the Pull requests link and click on the Bundle Provision pull request. 
items.yaml file and note the new organizationFolder item using controller.yaml as the marker and the controller-provision Declarative Pipeline script.credentials.yaml file and note the we are adding a new restrictedSystem credential with an id of casc-workshop-controller-provision-secret that matches the id used in the controller-provision Declarative Pipeline script below. 
controller-provision. Notice that the controller-provision Declarative Pipeline script is loading the credential with an id of casc-workshop-controller-provision-secret that was added to the credentials.yaml above and is using the publishEvent to publish an event that will trigger the workshops Ops controller job we reviewed above.library 'pipeline-library'
pipeline {
agent any
options {
timeout(time: 10, unit: 'MINUTES')
}
stages {
stage('Publish Provision Controller Event') {
when {
branch 'main'
}
environment { PROVISION_SECRET = credentials('casc-workshop-controller-provision-secret') }
steps {
gitHubParseOriginUrl()
publishEvent event:jsonEvent("""
{'controller':{'name':'${GITHUB_REPO}','action':'provision'},'github':{'organization':'${GITHUB_ORG}','repository':'${GITHUB_REPO}','user':'${GITHUB_USER}'},'secret':'${PROVISION_SECRET}'}
"""), verbose: true
}
}
}
}
main branch job of the controller-casc-update ops-controller Multibranch pipeline project on your Ops controller. 
main branch job has completed successfully, navigate to the controller-jobs folder and refresh the page until the controller-provision job appears. 
In the previous section you added the controller-provision Organization Folder job to your Ops controller to publish an event to trigger the provisioning of a managed controller. Now you will trigger the provisioning of a new managed controller by adding a controller.yaml file (and a simple CasC bundle) to the main branch of your copy of the dev-controller repository in your workshop GitHub Organization.
dev-controller repository in GitHub, click on the Pull requests tab and then click on the link for the Provision Controller pull request. 
bundle/bundle.yaml and controller.yaml files being added to your dev-controller repository. Note that the bundle/bundle.yaml file does include any other configuration files but it does specify parent: base. 
controller-jobs folder and then click on the controller-provision job. There should now be a dev-controller folder under the controller-provision job for your dev-controller repository. 
main branch of the dev-controller Multi-branch pipeline job on your Ops controller and click on the Build Now link in the left menu. Once the job completes you should see an Event JSON in the build logs similar to the one below (of course the GitHub information will be unique to you). 
