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).