donal
2018-07-03 85ecf2df38725b1cb19a1131f91622a2649df4aa
2-attack-of-the-pipelines/README.md
@@ -1,13 +1,13 @@
# Attack of the Pipelines
> In this lab we will explore the sample TODO List application and create a pipeline in Jenkins to build and deploy our code.
> In this exercise we will explore the sample TODO List application and create a pipeline in Jenkins to build and deploy our code.
![jenkins-time](../images/exercise2/jenkins-time.jpg)
## Exercise Intro
This lesson is focused on creating a pipeline for our application. What is a pipeline? A pipeline is a series of steps or stages that takes our code from source to a deployed application. There can be many stages to a pipeline but a simple flow is to run a `build > bake > deploy`. Usually the first stage is trigger by something like a git commit. There could be many steps in each of these stages; such as compiling code, running tests and linting. All of these are done to try and drive up code quality and give more assurance that what is deployed is behaving as expected. In the exercise we will create Jenkins pipeline by configuring it through the UI, this will create an un-gated pathway to production
This lesson is focused on creating a pipeline for our application. What is a pipeline? A pipeline is a series of steps or stages that takes our code from source to a deployed application. There can be many stages to a pipeline but a simple flow is to run a `build > bake > deploy`. Usually the first stage is triggered by something like a git commit. There could be many steps in each of these stages; such as compiling code, running tests and linting. All of these are done to try and drive up code quality and give more assurance that what is deployed is behaving as expected. In the exercise we will create Jenkins pipeline by configuring it through the UI, this will create an un-gated pathway to production
First we will explore the sample application and get it running locally. The sample app is a `todolist` app - the `Hello World` app of the modern day.
First we will explore the sample application and get it running locally. The sample app is a `todolist` app - the `Hello World` app of the modern day.
#### Why create pipelines
* Assurance - drive up code quality and remove the need for dedicated deployment / release management teams
@@ -44,11 +44,11 @@
## 10,000 Ft View
> _This lab requires users to take the sample TODO app and create a build pipeline in Jenkins by clicking your way to success ending up with an app deployed to each of the namespaces created previously_
2. Import the projects into your gitlab instance. See README of each for build instructions
2. Import the projects into your gitlab instance. See the README of each for build instructions
2. Deploy a `MongoDB` using the provided template to all project namespace.
2. Create 2 pipline with three stages (`build`, `bake`, `deploy`) in jenkins for `develop` & `master` branches on the `todolist-fe` such that:
2. Create 2 pipelines with three stages (`build`, `bake`, `deploy`) in Jenkins for `develop` & `master` branches on the `todolist-fe` such that:
    * a `Build` job is responsible for compiling and packaging our code:
        1. Checkout from source code (`develop` for `<yourname>-dev` & `master` for `<yourname>-test`)
        2. Install node dependencies and run a build / package
@@ -58,8 +58,8 @@
        5. Trigger the `bake` job with the `${BUILD_TAG}` param
    * a `Bake` job should take the package and put it in a Linux Container
        1. Take an input of the previous jobs `${BUILD_TAG}` ie `${JOB_NAME}.${BUILD_NUMBER}`.
        2. Checkout the binary from Nexus and unzip it's contents
        3. Run an oc start-build of the App's BuildConfig and tag it's imagestream with the provided `${BUILD_TAG}`
        2. Checkout the binary from Nexus and unzip its contents
        3. Run an oc start-build of the App's BuildConfig and tag its imagestream with the provided `${BUILD_TAG}`
        4. Trigger a deploy job using the parameter `${BUILD_TAG}`
    * a `deploy` job should roll out the changes by updating the image tag in the DC:
        1. Take an input of the `${BUILD_TAG}`
@@ -77,44 +77,48 @@
### Part 1 - Explore the Todo List App
> _In this part of the exercise we will explore the sample application, become familiar with it locally before building and deploying in OCP Land_
#### Part 1a Todolist-fe
#### 1a Todolist-fe
2. Git clone the `todolist-fe` project to somewhere sensible and checkout the `develop` branch.
2. Git clone the `todolist-fe` project to somewhere sensible and checkout the `develop` branch using the following.
```bash
$ git clone https://github.com/rht-labs/todolist-fe.git
$ cd todolist-fe
$ git checkout develop
cd ~/innovation-labs
```
Followed by;
```bash
git clone https://github.com/rht-labs/todolist-fe.git
```
$ for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do
   git branch --track ${branch#remotes/origin/} $branch
done
```bash
cd todolist-fe
```
```bash
./git-pull-all.sh
```
```bash
git checkout develop
```
2. Open up Gitlab and login. Create a new project (internal) in GitLab called `todolist-fe` to host your clone of the project and copy it's remote address. ![new-gitlab-proj](../images/exercise2/new-gitlab-proj.png)
2. Open up Gitlab and login. Create a new project (internal) in GitLab called `todolist-fe` to host your clone of the project and copy its remote address. ![new-gitlab-proj](../images/exercise2/new-gitlab-proj.png)
2. In your local clone of the `todolist-fe`, remove the origin and add the GitLab origin by replacing `<YOUR_GIT_LAB_PROJECT>`. Push your app to GitLab
```bash
$ git remote set-url origin <YOUR_GIT_LAB_PROJECT>
git remote set-url origin <YOUR_GIT_LAB_PROJECT>
# verify the origin has been updated
$ git remote -v
$ git push -u origin --all
git remote -v
git push -u origin --all
```
2. To get the app running locally; first check you've got node and npm installed
```bash
$ node -v
$ npm -v
node -v
npm -v
```
<p class="tip" >
<p class="tip" >
NOTE - If you are missing these dependencies; install them with ease using the [Node Version Manager](https://github.com/creationix/nvm)
</p>
![node-version](../images/exercise2/node-version.png)
2. The `todolist-fe` has a package.json at the root of the project, this defines some configuration for the app including it's dependencies, dev dependencies, scripts and other configuration. Install the apps dependencies
2. The `todolist-fe` has a package.json at the root of the project, this defines some configuration for the app including its dependencies, dev dependencies, scripts and other configuration. Install the app's dependencies
```bash
$ npm install
npm install
```
2. The `todolist-fe` has some scripts defined in the package.json at the root of the project. A snippet of the npm scripts are shown below. To run any of these scripts run `npm run <SCRIPT_NAME>`. Let's start by serving our application
@@ -167,51 +171,60 @@
where the following are the important things:
    * `./src` is the main collection of files needed by the app. The entrypoint is the `main.js` which is used to load the root `App.vue` file.
    * `./node_modules` is where the dependencies are stored
    * `./test` contains our end-to-end tests and unit tests. More covered on these in later labs.
    * `./test` contains our end-to-end tests and unit tests. More covered on these in later exercises.
    * `./src/components` contains small, lightweight reusable components for our app. For example, the `NewTodo` component which encapsulates the styling, logic and data for adding a new todo to our list
    * `./src/store` is the `vuex` files for managing application state and backend connectivity
    * `./src/views` is the view containers; which are responsible for loading components and managing their interactions.
    * the `./src/router.js` controls routing logic. In our case the app only has one real endpoint.
    * `./src/scss` contains custom  SCSS used in the application.
    * `./src/scss` contains custom SCSS used in the application.
    * `./*.js` is mostly config files for running and managing the app and the tests
2. To prepare Nexus to host the binaries created by the frontend and backend builds we need to run a prepare-nexus script. Before we do this we need to export some variables.
2. To prepare Nexus to host the binaries created by the frontend and backend builds we need to run a prepare-nexus script. Before we do this we need to export some variables and change `<YOUR_NAME>` accordingly in the below commands.
```bash
export NEXUS_SERVICE_HOST=nexus-<YOUR_NAME>-ci-cd.apps.somedomain.com
export NEXUS_SERVICE_HOST=$(oc get route nexus --template='{{.spec.host}}' -n <YOUR_NAME>-ci-cd)
```
```bash
export NEXUS_SERVICE_PORT=80
```
```bash
npm run prepare-nexus
```
<p class="tip">
NOTE - This step in a residency would be automated by a more complex nexus deployment in the ci-cd project
</p>
#### Part 1b Todolist-api
#### 1b Todolist-api
2. Now let's move on to the `todolist-api` and wire them together. As with the `todolist-fe` we need to clone the repo and add it to our GitLab in the cluster.
```bash
$ git clone https://github.com/rht-labs/todolist-api.git
$ cd todolist-api
$ git checkout develop
cd ~/innovation-labs
```
Followed by;
```bash
git clone https://github.com/rht-labs/todolist-api.git
```
$ for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do
   git branch --track ${branch#remotes/origin/} $branch
done
```bash
cd todolist-api
```
```bash
./git-pull-all.sh
```
```bash
git checkout develop
```
2. On GitLab; create a new project (internal) called `todolist-api` to host your clone of the project and copy it's remote address as you did for the previous repositories.
2. On GitLab; create a new project (internal) called `todolist-api` to host your clone of the project and copy its remote address as you did for the previous repositories.
2. In your local clone of the `todolist-api`, remove the origin and add the GitLab origin by replacing `<YOUR_GIT_LAB_PROJECT>`. Push your app to GitLab
```bash
$ git remote set-url origin <YOUR_GIT_LAB_PROJECT>
$ git push -u origin --all
git remote set-url origin <YOUR_GIT_LAB_PROJECT>
```
```bash
git push -u origin --all
```
2. Once pushed; explore the application. It is a NodeJS application with the Express.js framework and MongoDB for persistent storage. Same as before, the `package.json` defines most of the configuration etc. Install the dependencies
```bash
# npm i === npm install
$ npm i
npm i
```
2. While the dependencies are being installed; explore the project structure.
@@ -247,11 +260,11 @@
where the following are the important things:
    * `./server` is the main collection of files needed by the app. The entrypoint is the `app.js`
    * `./node_modules` is where the dependencies are stored
    * `./server/api` is where the api's controller, data model & unit test are stored.
    * `./server/api` is where the api's controller, data model & unit test are stored.
    * `./server/mocks` is a mock server used for when there is no DB access    
    * `./server/config` stores our Express JS config, header information and other middleware.
    * `./server/config/environment` stores enviromnent specific config; such as connectivity to backend services like MongoDB.
    * `./tasks` is a collection of additional `Grunt` tasks which will be used in later labs
    * `./server/config/environment` stores environment specific config; such as connectivity to backend services like MongoDB.
    * `./tasks` is a collection of additional `Grunt` tasks which will be used in later exercises
    * `Grunt` is a taskrunner for use with Node.JS projects
    * `package.json` contains the dependency list and a lot of very helpful scripts for managing the app lifecycle
@@ -271,9 +284,9 @@
  },
```
2. To run the application; start a new instance of the MongoDB by running the following. This will pull a mongodb image from Dockerhub and then start it for our API to connect to.
2. To run the application; start a new instance of MongoDB by running the following. This will pull a mongodb image from Dockerhub and then start it for our API to connect to.
```bash
$ npm run mongo
npm run mongo
```
<p class="tip">
NOTE - `npm run mongo:drop` is used to completely remove the running container. `npm run mongo:stop` & `npm run mongo:start` will preserve data in the container
@@ -281,13 +294,13 @@
2. Fire up the `todolist-api` by running.
```bash
$ npm run start
npm run start
```
![node-app-started](../images/exercise2/node-app-started.png)
2. Check things are up and running by testing the API with a `curl`. The API should return some seeded data (stored in `server/config/seed.js`)
```bash
$ curl localhost:9000/api/todos
curl localhost:9000/api/todos
```
```json
[{
@@ -307,59 +320,10 @@
2. Now let's check out `todolist-fe` app by reloading the browser. We should now see our dummy front end data is replaced by the backend seed data. Adding new todos will add them in the backend, these will persist when the page is refreshed.
![fullstack-app](../images/exercise2/fullstack-app.png)
### Part 2 - Create a NodeJS Build slave
> _In this exercise; we will create a build configuration to generate a slave for Jenkins to use in it's builds_
3. In order for Jenkins to be able to run `npm` builds and installs as we have done locally, we must configure a `jenkins-build-slave` for Jenkins to use. This slave will be dynamically provisioned when we run a build. It needs to have NodeJS and npm installed in it. In your `enablement-cd-cd` repository, checkout the template and configuration. This will bring in the template, the params & the `Dockerfile`.
```bash
$ git checkout exercise2/jenkins-slave docker/ templates/ params/jenkins-slave-npm
```
3. Open the `params/jenkins-slave-npm` file and update `<YOUR_ENABLEMENT_GIT_REPO>` accordingly. This set of parameters will clone from the enablement repo and run a docker build of the Dockerfile stored in `docker/jenkins-slave-npm`.
```bash
SOURCE_REPOSITORY_URL=<YOUR_ENABLEMENT_GIT_REPO>
SOURCE_CONTEXT_DIR=docker/jenkins-slave-npm
NAME=npm-jenkins-slave
```
3. Create an item in the `inventory/host_vars/ci-cd-tooling.yml` under the `ci-cd-builds` object to run the template with.
```yaml
  - name: "jenkins-npm-slave"
    namespace: "{{ ci_cd_namespace }}"
    template: "{{ playbook_dir }}/templates/jenkins-slave-generic-template.yml"
    params: "{{ playbook_dir }}/params/jenkins-slave-npm"
    tags:
    - jenkins-slave
```
![jenkins-slave-ansible](../images/exercise2/jenkins-slave-ansible.png)
3. Commit your changes to the `enablement-ci-cd` repository!
```bash
$ git add .
$ git commit -m "ADD npm slave node for Jenkins"
$ git push
```
3. Run the OpenShift Applier to trigger a build of this jenkins slave image.
```bash
$ ansible-playbook apply.yml -e target=tools \
     -i inventory/ \
     -e "filter_tags=jenkins-slave"
```
3. Verify the build executed successfully by logging into the cluster and checking the `builds` tab of the `<YOUR_NAME>-ci-cd` project.
![jenkins-slave-npm-build](../images/exercise2/jenkins-slave-npm-build.png)
3. You should now be able to apply the label `jenkins-slave-npm` to a build job to run a build on this newly created slave as we will see in the rest of this lab
<p class="tip">
NOTE - Jenkins may need to be restarted for the configuration to appear. To do this; navigate to your jenkins instance and add `/restart` to the url.
</p>
### Part 3 - Add configs to cluster
### Part 2 - Add configs to cluster
> _In this exercise; we will use the OpenShift Applier to drive the creation of cluster content required by the app such as MongoDB and the Apps Build / Deploy Config_
4. On your terminal navigate to the root of the `todolist-fe` application. The app contains a hidden folder called `.openshift-applier`. Move `cd .openshift-applier` into this directory and you should see a familiar looking directory structure for an ansible playbook.
4. On your terminal navigate to the root of the `todolist-fe` application. The app contains a hidden folder called `.openshift-applier`. Move into this `.openshift-applier` directory and you should see a familiar looking directory structure for an Ansible playbook.
```
.openshift-applier
├── README.md
@@ -379,20 +343,20 @@
    â”œâ”€â”€ todolist-fe-build.yml
    â””── todolist-fe-deploy.yml
```
where the following
    * the `apply.yml` file is the entrypoint.
with the following
    * the `apply.yml` file is the entrypoint.
    * the `inventory` contains the objects to populate the cluster with.
    * the `params` contains the variables we'll apply to the `templates`
    * the `templates` required by the app. These include the Build, Deploy configs as well as the services, health checks, and other app definitions.
4. There are a few updates to these manifests we need to make before applying the cluster content. In the `apply.yml` update the namespace `<YOUR_NAME>` variables accordingly.
4. There are a few updates to these manifests we need to make before applying the cluster content. In the `apply.yml` update the namespace `<YOUR_NAME>` variables accordingly.
```yaml
    ci_cd_namespace: donal-ci-cd
    dev_namespace: donal-dev
    test_namespace: donal-test
```
4. In the `params` folder update the `dev` and `test` files with the correct `<YOUR_NAME>` as you've done above. Example for the `dev` file:
4. In the `params` folder update the `dev` and `test` files with the correct `<YOUR_NAME>` as you've done above. Example for the `dev` file:
```bash
PIPELINES_NAMESPACE=donal-ci-cd
NAME=todolist-fe
@@ -403,19 +367,25 @@
4. With those changes in place we can now run the playbook. First install the `openshift-applier` dependency and then run the playbook (from the `.openshift-applier` directory). This will populate the cluster with all the config needed for the front end app.
```bash
$ ansible-galaxy install -r requirements.yml --roles-path=roles
$ ansible-playbook apply.yml -i inventory/
ansible-galaxy install -r requirements.yml --roles-path=roles
```
```bash
ansible-playbook apply.yml -i inventory/
```
![ansible-success](../images/exercise2/ansible-success.png)
4. Once successful, `commit` and `push` your changes to gitlab.
```bash
$ git add .
$ git commit -m "UPDATE - change namespace vars to donal"
$ git push
git add .
```
```bash
git commit -m "UPDATE - change namespace vars to donal"
```
```bash
git push
```
4. Back on your terminal navigate to the root of the `todolist-api` application. Open the `.openshift-applier` directory. The same layout as seen in `todolist-fe` should be visible with one noticeable difference; the api requires `MongoDB` to connect to at runtime.
4. Back on your terminal navigate to the root of the `todolist-api` application. Open the `.openshift-applier` directory in your editor. The same layout as seen in `todolist-fe` should be visible with one noticeable difference; the api requires `MongoDB` to connect to at runtime.
4. In the `apply.yml` update the namespace `<YOUR_NAME>` variables accordingly. For example:
```yaml
@@ -435,15 +405,21 @@
4. Finally; run the Openshift Applier and install its dependencies to run the content into the cluster
```bash
$ ansible-galaxy install -r requirements.yml --roles-path=roles
$ ansible-playbook apply.yml -i inventory/
ansible-galaxy install -r requirements.yml --roles-path=roles
```
```bash
ansible-playbook apply.yml -i inventory/
```
4. Once successful, `commit` and `push` your changes to gitlab.
```bash
$ git add .
$ git commit -m "UPDATE - change namespace vars to donal"
$ git push
git add .
```
```bash
git commit -m "UPDATE - change namespace vars to donal"
```
```bash
git push
```
4. Validate the build and deploy configs have been created in Openshift by checking `<YOUR_NAME> CI-CD builds` for the `BuildConfigs`
@@ -452,7 +428,7 @@
4. Check `<YOUR_NAME>-dev` to see the deployment configs are in place
![ocp-app-dc](../images/exercise2/ocp-app-dc.png)
### Part 4 - Build > Bake > Deploy
### Part 3 - Build > Bake > Deploy
> _In this exercise; we take what we have working locally and get it working in OpenShift_
This exercise will involve creating three stages (or items) in our pipeline, each of these is detailed below at a very high level. Move on to the next step to begin implementation.
@@ -465,8 +441,8 @@
    5. Trigger the `bake` job with the `${BUILD_TAG}` param
* a *bake* job should take the package and put it in a Linux Container
    1. Take an input of the previous jobs `${BUILD_TAG}` ie `${JOB_NAME}.${BUILD_NUMBER}`.
    2. Checkout the binary from Nexus and unzip it's contents
    3. Run an oc start-build of the App's BuildConfig and tag it's imagestream with the provided `${BUILD_TAG}`
    2. Checkout the binary from Nexus and unzip its contents
    3. Run an oc start-build of the App's BuildConfig and tag its imagestream with the provided `${BUILD_TAG}`
    4. Trigger a deploy job using the parameter `${BUILD_TAG}`
* a *deploy* job should roll out the changes by updating the image tag in the DC:
    1. Take an input of the `${BUILD_TAG}`
@@ -475,15 +451,16 @@
    4. Verify the deployment
* We will now go through these steps in detail.
#### Part 4a - Build
#### 3a - Build
5. With the BuildConfig and DeployConfig in place for both our apps (`*-fe` & `*-api`) from previous steps; Log into Jenkins and create a `New Item`. This is just jenkins speak for a new job configuration. ![new-item](../images/exercise2/new-item.png)
5. Name this job `dev-todolist-fe-build` and select `Freestyle Job`. All our jobs will take the form of `<ENV>-<APP_NAME>-<JOB_PURPOSE>`. ![freestyle-job](../images/exercise2/freestyle-job.png)
5. Name this job `dev-todolist-fe-build` and select `Freestyle Project`. All our jobs will take the form of `<ENV>-<APP_NAME>-<JOB_PURPOSE>`. ![freestyle-job](../images/exercise2/freestyle-job.png)
5. The page that loads is the Job Configuration page and it can be returned to at anytime from Jenkins. Let's start configuring our job. To conserve space; we will make sure Jenkins only keeps the last builds artifacts. Tick the `Discard old builds` checkbox and set `Max # of builds to keep with artifacts` to 1 as below ![keep-artifacts](../images/exercise2/keep-artifacts.png)
5. The page that loads is the Job Configuration page and it can be returned to at anytime from Jenkins. Let's start configuring our job. To conserve space; we will make sure Jenkins only keeps the last build's artifacts. Tick the `Discard old builds` checkbox, then `Advanced` and set `Max # of builds to keep with artifacts` to 1 as indicated below
![keep-artifacts](../images/exercise2/keep-artifacts.png)
5. Our NodeJS build needs to be run on the `jenkins-slave-npm` we created earlier. Specify this in the box labelled `Restrict where this project can be run` ![label-jenkins-slave](../images/exercise2/label-jenkins-slave.png)
5. Our NodeJS build needs to be run on the `jenkins-slave-npm` we bought in in the previous chapter. Specify this in the box labelled `Restrict where this project can be run` ![label-jenkins-slave](../images/exercise2/label-jenkins-slave.png)
5. On the Source Code Management tab, select the Git radio button, specify the endpoint for our GitLab `todolist-fe` Project and specify your credentials from the dropdown box. Set the Branch Specifier to `develop`. ![git-scm](../images/exercise2/git-scm.png)
@@ -503,7 +480,7 @@
5. On the Post-build Actions; Add another post-build action from the dropdown called `Git Publisher`. This is useful for tying the git check-in to the feature in your tracking tool to the built product.
    * Tick the box `Push Only If Build Succeeds`
    * Add the Tag to push of
    * Add the Tag to push of
```bash
${JOB_NAME}.${BUILD_NUMBER}
```
@@ -515,10 +492,10 @@
    * Check `Create New Tag` and set `Target remote name` to `origin`
![git-publisher](../images/exercise2/git-publisher.png)
5. Finally; add the trigger for the next job in the pipeline. This is to trigger the bake job with the current build tag. Add another post-build action from the dropdown called `Trigger parameterized build on other projects`.
    * Set the project to build to be `dev-todolist-fe-bake`
    * Set the condition to be `Stable or unstable but not failed`.
    * Click Add Parameters dropdown and select Predefined parameters.
5. Finally; add the trigger for the next job in the pipeline. This is to trigger the bake job with the current build tag. Add another post-build action from the dropdown called `Trigger parameterized build on other projects`.
    * Set the project to build to be `dev-todolist-fe-bake`
    * Set the condition to be `Stable or unstable but not failed`.
    * Click Add Parameters dropdown and select Predefined parameters.
    * In the box, insert our BUILD_TAG as follows
```bash
BUILD_TAG=${JOB_NAME}.${BUILD_NUMBER}
@@ -530,7 +507,7 @@
5. Hit `save` which will take you to the job overview page - and that's it; our *build* phase is complete!
#### Part 4b - Bake
#### 3b - Bake
5. Next we will setup our *bake* phase; which is a little simpler. Go to Jenkins home and create another Freestyle Job (as before) called `dev-todolist-fe-bake`.
@@ -538,12 +515,16 @@
    * Add string parameter type
    * set the Name to `BUILD_TAG`. This will be available to the job as an Enviroment Variable.
    * You can set `dev-todolist-fe-build.` as the default value for ease when triggering manually.
    * The description is not required but a handy one for reference would be `${JOB_NAME}.${BUILD_NUMBER} of previous build eg dev-todolist-fe-build.1232`
    * The description is not required but a handy one for reference would be `${JOB_NAME}.${BUILD_NUMBER} of previous build e.g. dev-todolist-fe-build.1232`
<p class="tip">
    NOTE - Don't forget to include the `.` after `dev-todolist-fe-build` in the Default Value box.
</p>
![param-trigger-bake](../images/exercise2/param-trigger-bake.png)
5. This time set the `Restrict where this project can be run` label to `master`.
<p class="tip">
    `Master` is the default node that jobs run on. We don't want jenkins to execute the *bake* on any other nodes if the `master` is busy so it is always safer to specify it here.
    NOTE - `Master` is the default node that jobs run on. We don't want jenkins to execute the *bake* on any other nodes if the `master` is busy so it is always safer to specify it here.
</p>
5. There is no Git or SCM needed for this job so move down to the Build Environment and tick `Delete workspace before build starts`
@@ -554,7 +535,9 @@
Remember to replace `<YOUR_NAME>` accordingly.
```bash
#!/bin/bash
curl -v -f http://admin:admin123@${NEXUS_SERVICE_HOST}:${NEXUS_SERVICE_PORT}/repository/zip/com/redhat/todolist/${BUILD_TAG}/package-contents.zip -o package-contents.zip
curl -v -f \
    http://admin:admin123@${NEXUS_SERVICE_HOST}:${NEXUS_SERVICE_PORT}/repository/zip/com/redhat/todolist/${BUILD_TAG}/package-contents.zip \
    -o package-contents.zip
unzip package-contents.zip
oc project <YOUR_NAME>-ci-cd
NAME=todolist-fe
@@ -566,12 +549,12 @@
5. Finally; add the trigger for the next job in the pipeline. Add a post-build action from the dropdown called `Trigger parameterized build on other projects`.
    * Set the project to build to be `dev-todolist-fe-deploy`
    * Set the condition to be `Stable`.
    * Click Add Parameters dropdown and select Current build parameters. This will pass the ${BUILD_TAG} to the downstream job which we will create next.
    * Click Add Parameters dropdown and select `Current build parameters`. This will pass the `${BUILD_TAG}` to the downstream job which we will create next.
![downstream-trigger-deploy](../images/exercise2/downstream-trigger-deploy.png)
5. Hit save! That's our *bake* phase done! Finally; on to our *deploy*
#### Part 4c - Deploy
#### 3c - Deploy
5. Next we will setup our *deploy* phase. This job is very similar in setup to the *bake* phase so this time go to Jenkins home and create `dev-todolist-fe-deploy` Job but scroll to the bottom and Copy from `dev-todolist-fe-bake`.
![copy-from](../images/exercise2/copy-from.png)
@@ -592,7 +575,7 @@
```
![deploy-step](../images/exercise2/deploy-step.png)
5. When a deployment has completed; OpenShift can verify it's success. Add another step called by clicking the `Add build Step` on the Build tab then `Verify OpenShift Deployment` including the following:
5. When a deployment has completed; OpenShift can verify its success. Add another step by clicking the `Add build Step` on the Build tab then `Verify OpenShift Deployment` including the following:
    * Set the Project to your `<YOUR_NAME>-dev`
    * Set the DeploymentConfig to your app's name `todolist-fe`
    * Set the replica count to `1`
@@ -600,22 +583,32 @@
5. Finally; delete the Post Build Action to trigger another job (by hitting the red X). Save the configuration. We're almost ready to run the pipeline!
#### Part 4d - Pipeline
#### 3d - Pipeline
5. With our Jenkins setup in place; now move to our `todolist-fe` app's source code. We have to add our configuration to the frontend to tell it where the API layer will be hosted. Open the source in your favourite editor and navigate to `src/config/dev.js`. Update `<YOUR_NAME>` accordingly with the route where the Todo List API will live when it is deployed, update the `somedomain` to the clusters domain. For example:
5. With our Jenkins setup in place; now move to our `todolist-fe` app's source code. We have to add our configuration to the frontend to tell it where the API layer will be hosted. Open the source in your favourite editor and navigate to `src/config/dev.js`.
5. Update `<YOUR_NAME>` accordingly with the route where the Todo List API will live when it is deployed. The correct full URL can also be found on the OpenShift Console; if you copy it from there remember to append `/api/todos` to the URL. For example:
![fe-dev-config](../images/exercise2/fe-dev-config.png)
5. Repeat this for `src/config/test.js` file. Once done; commit your chanages and push them to GitLab
5. Repeat this for `src/config/test.js` file. If you copy the URL from the previous step; change `dev` to `test`.
For example:
![fe-test-config](../images/exercise2/fe-test-config.png)
5. With the config in place; commit your changes and push them to GitLab:
```bash
$ git add .
$ git commit -m "ADD config for api"
$ git push
git add .
```
```bash
git commit -m "ADD config for api"
```
```bash
git push
```
5. Back on Jenkins; We can tie all the jobs in the pipeline together into a nice single view using the Build Pipeline view. Back on the Jenkins home screen Click the + beside the all tab on the top.
![add-view](../images/exercise2/add-view.png)
5. On the view that loads; Give the new view a sensible name like `dev-todolist-fe-pipeline` and select Build Pipeline
5. On the view that loads; Give the new view a sensible name like `dev-todolist-fe-pipeline` and select Build Pipeline View
![new-pipeline](../images/exercise2/new-pipeline.png)
5. Set the Pipeline Flow's Inital Job to `dev-todolist-fe-build` and save.
@@ -624,68 +617,26 @@
5. You should now see the pipeline view. Run the pipeline by hitting run (you can move onto the next part while it is running as it may take some time).
![dev-pipeline-view](../images/exercise2/dev-pipeline-view.jpeg)
### Part 5 - Backend Pipeline
> In this exercise we will use the Jobs created for the `todolist-fe` as a template to create a pipeline for the `todolist-api` app by copying the config.
6. On Jenkins home; create a new job for our backend build called `dev-todolist-api-build`. Use the `Copy from` section to copy all the configuration from the `dev-todolist-fe-build`.
![copy-fe-build](../images/exercise2/copy-fe-build.png)
6. When this has loaded; find and replace both occurrences `-fe` with `-api` within the Job's configuration. Places to make sure you check are:
    * The GitLab project URL
    * Projects to build on the Post Build Action
6. On the Build tab; remove the `:dev` from the `npm run build:ci:dev` so the line reads.
 The rest of the instructions can be left as they are.
```bash
npm run build:ci
```
![api-build-step](../images/exercise2/api-build-step.png)
6. Save the configuration for `dev-todolist-api-build`
6. On Jenkins home; create a new job for our backend bake called `dev-todolist-api-bake`. Use the Copy from section to copy all the configuration from the `dev-todolist-fe-bake` as you've just done.
6. When this has loaded; find and replace the occurrences `-fe` with `-api` within the Job's configuration. Places to make sure you check are:
    * The BUILD_TAG default value and description
    * NAME in the execute shell step
    * Projects to build on the Post Build Action
6. Save the configuration for `dev-todolist-api-build`
6. On Jenkins home; create a new job for our backend build called `dev-todolist-api-deploy`. Use the Copy from section to copy all the configuration from the `dev-todolist-fe-deploy` as you've just done.
6. When this has loaded; find and replace the occurrences `-fe` with `-api` within the Job's configuration. Places to make sure you check are:
    * The BUILD_TAG default value and description
    * NAME in the execute shell step
    * The name of the DeploymentConfig to validate in the Verify OpenShift Deployment
6. Save the configuration for `dev-todolist-api-build` and that's it for wiring together our `todolist-api` pipeline.
6. Run the `dev-todolist-api-build` to trigger the backend pipeline. While this is building, check our front end app and see if it has deployed successfully.
6. To check the deployment in OpenShifty; open the console and go to your `dev` namespace. You should see the deployment was successful; hit the URL to open the app (the screenshot below has both apps deployed).
6. To check the deployment in OpenShift; open the web console and go to your `dev` namespace. You should see the deployment was successful; hit the URL to open the app (the screenshot below has both apps deployed).
![ocp-deployment](../images/exercise2/ocp-deployment.png)
6. If it has been a success we should see our dummyData. This is because there is no backend deployed.
6. If it has been a success we should see our dummyData. This is because there is no backend deployed, in later labs we will deploy the backend and the mongodb for persistence but to do this we will use Jenkins Pipeline as code.
![no-backend-app](../images/exercise2/no-backend-app.png)
6.  When `dev-todolist-api-build` has completed we should see the sample data has changed on refresh.
![with-backend-app](../images/exercise2/with-backend-app.png)
### Part 6 - GitLab Webhooks
### Part 4 - (Optional) GitLab Webhooks
> _In this exercise we will link GitLab to Jenkins so that new build jobs are triggered on each push to the `develop` branch._
<p class="tip" >
NOTE - This section is optional! Git webhooks are useful but not needed for course completion.
NOTE - This section is optional! Git webhooks are useful but not needed for Enablement completion.
</p>
7. In order to allow GitLab trigger Jenkins (because of the OpenShift Auth Plugin), we need to allow the `Annoymous` user trigger builds. Head to your Jenkins Dashboard and click on `Manage Jenkins` on the left hand side. Then scroll down and click `Configure Global Security`. Alternatively, type in `https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/configureSecurity/` . You should see a screen like so:
7. In order to allow GitLab to trigger Jenkins (because of the OpenShift Auth Plugin), we need to allow the `Anonymous` user triggered builds. Head to your Jenkins Dashboard and click on `Manage Jenkins` on the left hand side. Then scroll down and click `Configure Global Security`. Alternatively, type in `https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/configureSecurity/` . You should see a screen like so:
![jenkins-global-security](../images/exercise2/jenkins-global-security.png)
7. Scroll down to the `Authorization` section and allow `Anonymous` to create jobs. Do this by navigating through the matrix of checkboxes and check `Build` and `Cancel` under the Job heading. Leave all other user behaviour as is. Anonymous is the user that GitLab will act as so this allows the WebHook to trigger builds. (The screenshot has been cropped to bring Job further to the left.) Hit `Save` or `Apply`.
![jenkins-anon-permissions](../images/exercise2/jenkins-anon-permissions.png)
7. Go to your `dev-todolist-fe-build` and head to the `configure` section (`https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/job/dev-todolist-fe-build/configure`). Scroll down to the `Build Triggers` section and check the `Build when a change is pushed to GitLab` box. Leave all the other settings as they are but copy the `GitLab webhook URL`. `https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/project/dev-todolist-fe-build`.
7. Go to your `dev-todolist-fe-build` and head to the `configure` section (`https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/job/dev-todolist-fe-build/configure`). Scroll down to the `Build Triggers` section and check the `Build when a change is pushed to GitLab` box. Leave all the other settings as they are but copy the `GitLab webhook URL`. `https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/project/dev-todolist-fe-build`. Remember to Save and Apply this change.
![jenkins-build-triggers-gitlab](../images/exercise2/jenkins-build-triggers-gitlab.png)
7. Switch over to GitLab and select your `todolist-fe` repository. On the left hand task bar hover over the settings cog and select `integrations`. (`https://gitlab-<YOUR_NAME>-ci-cd.apps.some.domain.com/<YOUR_NAME>/todolist-fe/settings/integrations`)
@@ -698,14 +649,6 @@
![gitlab-integrations-details](../images/exercise2/gitlab-webhook-test.png)
7. We can now test this properly by heading into the `todolist-fe` repository through <YOUR_FAVOURITE_EDITOR>. Make a small change to your code, then commit and push it, ensuring you're on the develop branch. Then head over to Jenkins and wait until the `dev-todolist-fe-build` job has been triggered.
7. All that's left to do is to repeat the same steps for `todolist-api`:
Create Build Trigger:
`https://jenkins-<YOUR_NAME>-ci-cd.apps.some.domain.com/job/dev-todolist-api-build/configure`
Create GitLab Integration:
`https://gitlab-<YOUR_NAME>-ci-cd.apps.some.domain.com/donal/todolist-api/settings/integrations`
Check your build status and you should see something like this. With `Started by Gitlab push by <YOUR_NAME>`:
![jenkins-gitlab-webhook-success](../images/exercise2/jenkins-gitlab-webhook-success.png)
7. We now have a working GitLab webhook so any time we push code it will automatically build! Next up we'll show you how to add tests to your pipeline.