Operations Center provides a CasC for Controllers storage service that allows storing bundles in a directory and/or source control repository that is accessible by Operations center. These external storage locations, referred to as the Local folder and SCM retrieval methods, are then synced with an internal storage location (the /var/jenkins_home/cb-casc-bundles-store
directory) via polling, an SCM webhook and/or manually. Once a bundle is synced to the internal storage location, it becomes available for use by controllers based on the availability pattern of the bundle, and a polling time (defaults to 5 minutes) or CLI/API calls that makes the controller check for an update on demand.
There are two options available for manually forcing a sync of the bundles from external sources to the internal storage with the first being via the Operations Center UI and the second being via an HTTP API endpoint for Operations Center: POST /load-casc-bundles/checkout
.
You may configure multiple versions of each retrieval method, but bundle names (the folder the bundle files are in) must be unique across all external bundle sources. The CloudBees CI cluster we are using for this workshop has been configured with both an SCM and a Local folder external sources. We are using the SCM source to load bundles at the Operations center initial startup to be used as parent bundles and for the workshop Ops controller used to provision workshop environments. We are using a Local folder source for all of the provisioned workshop controller bundles since they are all in unique source code repositories.
While Operations Center simplifies the management of bundles, it is possible to configure a controller with a bundle without Operations Center using the -Dcore.casc.config.bundle=/path/to/casc-bundle
Java system property.
The labs in this section will explore:
This lab will provide an overview of how configuration bundles are managed via the Operations Center UI and how to manually apply a configuration bundle to a controller. The first part of the overview will be on the Operations Center Configuration as Code bundles settings page that is only accessible by workshop instructors. Therefore, the first part of this lab that will explore the 3 major components on the Operations Center Configuration as Code bundles settings page, wont’ have any hands-on material.
bundle.yaml
.bundle.yaml
via the availabilityPattern
field. Note that setting the Availability pattern with the availabilityPattern
field allows managing this value with each individual bundle rather than having to specify it in the UI, and that is what we are using for this workshop.base
bundle, the Availability pattern is empty and this typically would not match any path, but since the Availability pattern checkbox is checked it is available to all controllers.ops
bundle, the Availability pattern is set to operations/ops
. So that means only a controller with the name ops in the operations folder can use this bundle. If the Availability pattern were set to operations/*
then any controller in the operations folder could use this bundle.base
bundle is also available, but the ops
bundle is not available to select. In this lab we will update the controller-casc-update
job (created by CasC) to automatically update our controllers’ configuration bundles whenever any changes are committed to the GitHub main
branch for the controller’s configuration bundle repository. The controller-casc-update
job is actually a GitHub Organization Folder project with a custom marker file. Instead of using the typical Jenkinsfile
, we will use bundle/bundle.yaml
as our custom marker file. By using the custom marker file with a GitHub Organization Folder project, a Multibranch Pipeline project will automatically be created for all repositories in your workshop GitHub Organization when the main
branch contains a bundle/bundle.yaml
file.
ops-controller
repository in your workshop GitHub Organization.controller-casc-update
file to open it. It will match the contents of the file below.library 'pipeline-library'
pipeline {
agent {
kubernetes {
yaml libraryResource ('podtemplates/kubectl.yml')
}
}
options {
timeout(time: 10, unit: 'MINUTES')
}
stages {
stage('Update Config Bundle') {
when {
beforeAgent true
branch 'main'
not { triggeredBy 'UserIdCause' }
}
steps {
gitHubParseOriginUrl()
container("kubectl") {
sh "mkdir -p ${GITHUB_ORG}-${GITHUB_REPO}"
sh "find -name '*.yaml' | xargs cp --parents -t ${GITHUB_ORG}-${GITHUB_REPO}"
sh "kubectl cp --namespace cbci ${GITHUB_ORG}-${GITHUB_REPO} cjoc-0:/var/jenkins_config/jcasc-bundles-store/ -c jenkins"
}
}
}
}
}
kubectl.yml
Pod template, so we can use the kubectl cp
command to copy your ops-controller
configuration bundle files into the Local folder external storage configured on Operations Center. Once you have finished reviewing the controller-casc-update
pipeline contents, navigate to the top level of your Ops controller and click the on the controller-jobs folder.controller-jobs
folder. Inside of the controller-jobs
folder, click on the controller-casc-update
job. Jenkinsfile
. Click on the Configure link in the left menu so we can fix that. Jenkinsfile
) is used not only as the Pipeline script to run, but also as the marker file - that is, the file that indicates which repositories and branches should be processed by the SCM based Pipeline job. However, with the CloudBees custom script project recognizer for Mulitbranch and Org Folder Pipeline jobs, the marker file and the script file are separated, allowing you to specify an arbitrary file as the marker file and subsequently use an embedded Pipeline script or pull in a Pipeline file from a completely different source control repository. But in order for a GitHub branch
to be recognized, the branch
must contain the marker file.ops-controller
repository in your workshop GitHub Organization. Notice that there is no Jenkinsfile. bundle/bundle.yaml
file as the marker file, so that anytime there is a repository with a bundle/bundle.yaml
file in the GitHub Organization, it will automatically keep its main
branch in-sync with the CasC bundle for the target controller. But before we update the job on your controller to use bundle/bundle.yaml
as the marker file, we have to update the bundle/items.yaml
of the CasC bundle. Otherwise, the job on your controller would be updated to use Jenkinsfile
when the bundle gets updated - we need to update it in both places only this once, and must update the value in the bundle/items.yaml
before the job runs for the first time. We have created a Pull Request with the necessary changes.controller-casc-update
job on your Ops controller and update the Marker file to bundle/bundle.yaml
, and the click the Save button. Normally Organization Folder and Multibranch Pipeline jobs are triggered when they are indexed, but we have configured the suppressFolderAutomaticTriggering
property on the controller-casc-update
job so it will only be triggered by webhook events and manually.
ops-controller
repository, click on the Conversation tab of the Bundle Management pull request, scroll down and click the green Merge pull request button and then click the Confirm merge button.controller-casc-update
job on your Ops controller, click on the ops-controller
Multibranch pipeline project and then click on the pipeline job for the main
branch of your ops-controller
repository. Error from server (Forbidden): pods "cjoc-0" is forbidden: User "system:serviceaccount:controllers:jenkins" cannot get resource "pods" in API group "" in the namespace "cbci"
controllers
namespace
which is a different Kubernetes namespace
than Operations Center and no agent pod
in the controllers
namespace will have the permissions to copy files with kubectl
(a CLI tool for Kubernetes) to the Operations Center Kubernetes pod
. To fix this, you must update the controller-casc-update
pipeline script in your ops-controller
repository to trigger a job (with the CloudBees CI Cross Team Collaboration feature) on another controller that does have permissions to use kubectl
to copy updated bundle files to Operations Center.Provisioning controllers and agents in a different Kubernetes namespace
than Operations Center provides additional isolation and more security for Operations Center on Kubernetes. By default, when controllers are created in the same namespace
as Operations Center and agents, they can provision an agent that can run the pod
exec
command against any other pod
in the namespace
- including the Operations Center’s pod
.
ops-controller
repository in your workshop GitHub Organization and click on the controller-casc-update
file, and note that we replaced the previous steps
with the publishEvent
step (along with the gitHubParseOriginUrl
pipeline library utility step that will provide the GitHub repository the bundle is being updated from). The publishEvent
step will send a notification to a message bus on Operations Center and result in the triggering of any job that is configured to listen for that event. The configuration for the job that it triggers is available here. catalog
section. Feel free to explore the rest of the changes and then click on the Back to Bundle update link. If you don’t see the new version available then click the Check for Updates button. Also, once you click Yes it may take a few minutes for the bundle update to reload.
controller-jobs
folder and click on New Item in the left menu and note that the Freestyle job type is not available. Although we have enabled GitOps to automatically update your CasC bundle on Operations Center whenever there is a commit to the main
branch of your ops-controller
repository, checking for and applying the bundle updates on your controller is still a manual process via the controller UI. CloudBees CI CasC provides HTTP API endpoints (and a CLI) for managing CasC bundles, to include endpoints to check for controller bundle updates and reloading a controller bundle:
${JENKINS_URL}/casc-bundle-mgnt/check-bundle-update
${JENKINS_URL}/casc-bundle-mgnt/reload-bundle
The pipeline snippet below is used by the bundle update job, triggered by your controller-casc-update ops-controller main
branch job, to check for a bundle update and then reload the bundle for your controller:
stage('Auto Reload Bundle') {
when {
environment name: 'AUTO_RELOAD', value: "true"
}
steps {
echo "begin config bundle reload"
withCredentials([usernamePassword(credentialsId: 'admin-cli-token', usernameVariable: 'JENKINS_CLI_USR', passwordVariable: 'JENKINS_CLI_PSW')]) {
sh '''
curl --user $JENKINS_CLI_USR:$JENKINS_CLI_PSW -XGET http://${BUNDLE_ID}.controllers.svc.cluster.local/${BUNDLE_ID}/casc-bundle-mgnt/check-bundle-update
curl --user $JENKINS_CLI_USR:$JENKINS_CLI_PSW -XPOST http://${BUNDLE_ID}.controllers.svc.cluster.local/${BUNDLE_ID}/casc-bundle-mgnt/reload-bundle
'''
}
}
}
So, all you have to do to enable automatic reloading is update the value of the casc.auto_reload
portion of the event payload to true
:
ops-controller
repository in your workshop GitHub Organization and open the controller-casc-update
pipeline script.'casc':{'auto_reload':'false'}
to 'casc':{'auto_reload':'true'}
. Next, scroll to the bottom to reach the “Propose changes” section. Create a new branch called “auto-reload” or similar. On the next screen leave a relevant comment in the present tense and then click “Create pull request”. Then merge your changes. The complete updated contents should match the following:library 'pipeline-library'
pipeline {
agent none
options {
timeout(time: 10, unit: 'MINUTES')
skipDefaultCheckout()
}
stages {
stage('Update Config Bundle') {
agent { label 'default' }
when {
beforeAgent true
branch 'main'
not { triggeredBy 'UserIdCause' }
}
environment { CASC_UPDATE_SECRET = credentials('casc-update-secret') }
steps {
gitHubParseOriginUrl()
publishEvent event:jsonEvent("""
{
'controller':{'name':'${env.GITHUB_ORG}-${GITHUB_REPO}','action':'casc_bundle_update','bundle_id':'${env.GITHUB_ORG}-${GITHUB_REPO}'},
'github':{'organization':'${env.GITHUB_ORG}','repository':'${GITHUB_REPO}'},
'secret':'${CASC_UPDATE_SECRET}',
'casc':{'auto_reload':'true'}
}
"""), verbose: true
}
}
}
}
main
branch of your ops-controller
repository, the changes will be automatically applied to your controller.