Merge "adding build test jobs"
diff --git a/README.md b/README.md
index 01bab9f..c8dca3d 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,26 @@
 [LF Best practices for
 JJB](http://docs.releng.linuxfoundation.org/projects/global-jjb/en/latest/best-practices.html#)
 
+[LF mailing list for release
+engineering](https://lists.linuxfoundation.org/mailman/listinfo/lf-releng)
+
+The `#lf-releng` channel on Freenode IRC is usually well attendend.
+
+## What should be in my job description?
+
+When writing jobs, there are some things that JJB should be used to handle, and
+some things that should be put in external scripts or Jenkinsfile.
+
+Some things that are good to put in a JJB job:
+
+- Perform all SCM tasks (checkout code, etc.)
+- Specify the executors type and size (don't do this in a Jenkinsfile)
+
+JJB Jobs shold not:
+
+- Have complicated (more than 2-5 lines) scripts inline - instead, include
+  these using `!include-escape` or `!include-raw-escape`.
+
 ### Adding tests to a new git repo
 
 When adding a new git repo that needs tests:
@@ -100,13 +120,30 @@
 to go through the python backtrace to figure out where the error occurred in
 the jenkins-job-builder source code.
 
-### AMI Images and Cloud instances
+If you're writing a new shell script, it's a good idea to test it with
+[shellcheck](https://github.com/koalaman/shellcheck) before including it -
+failing to heed those messages then using `!include-escape` to add it to the
+job may lead to hard to debug problems with the job definition.
 
-If you make changes which create a new packer image, you have to manually set
-the instance `AMI ID` on jenkins in [Global
-Config](https://jenkins-new.opencord.org/configure) > Cloud > Amazon EC2.
+## Jenkins Executors and AMI Images
 
-### Creating new EC2 instance types
+The Jenkins executors are spun up automatically in EC2, and torn down after
+jobs have completed. Some are "one shot" and others (usually static or lint
+checks) are re-used for run multiple jobs.
+
+The AMI images used for these executors built with
+[Packer](https://www.packer.io/) and most of the local configuration happens in
+`packer/provision/basebuild.sh`. If you need a new tool installed in the
+executor, you would add the steps to install it here.  It's verified, and when
+merged generates a new AMI image.
+
+> NOTE: Future builds won't automatically use the new AMI - you have to
+> manually set the instance `AMI ID` on jenkins in [Global
+> Config](https://jenkins-new.opencord.org/configure) > Cloud > Amazon EC2.
+> The new AMI ID can be found near the end of the logs of the run of
+> [ci-management-packer-merge-<ostype>-basebuild](https://jenkins-new.opencord.org/job/ci-management-packer-merge-ubuntu-16.04-basebuild/).
+
+### Adding additional EC2 instance types
 
 If you create a new cloud instance type, make sure to set both the `Security
 group names` and `Subnet ID for VPC` or it will fail to instantiate.
diff --git a/jjb/cord/cord-xos-gui-unit.sh b/jjb/cord/cord-xos-gui-unit.sh
deleted file mode 100644
index 034b8da..0000000
--- a/jjb/cord/cord-xos-gui-unit.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash -ex
-
-# Install npm deps
-npm install
-
-# Install typings deps
-# typings install
-
-# Check code style
-npm run lint
-
-# Execute tests
-npm test
\ No newline at end of file
diff --git a/jjb/cord/cord-xos-gui-unit.yaml b/jjb/cord/cord-xos-gui-unit.yaml
deleted file mode 100644
index f51e863..0000000
--- a/jjb/cord/cord-xos-gui-unit.yaml
+++ /dev/null
@@ -1,104 +0,0 @@
----
-
-- job_boiler_plate: &job_boiler_plate
-    name: job-boiler-plate
-
-    project-type: freestyle
-    node: '{build-node}'
-
-    ######################
-    # Default parameters #
-    ######################
-
-    branch: master
-    submodule-recursive: false
-    git-url: '$GIT_URL/$GERRIT_PROJECT'
-
-    #####################
-    # Job Configuration #
-    #####################
-
-    properties:
-      - lf-infra-properties:
-          project: '{project}'
-          build-days-to-keep: '{build-days-to-keep}'
-
-    parameters:
-      - lf-infra-parameters:
-          project: '{project}'
-          branch: '{stream}'
-          stream: '{stream}'
-          lftools-version: '{lftools-version}'
-
-    wrappers:
-      - lf-infra-wrappers:
-          build-timeout: '{build-timeout}'
-          jenkins-ssh-credential: '{jenkins-ssh-credential}'
-
-- verify_boiler_plate: &verify_boiler_plate
-    name: verify_boiler_plate
-
-    concurrent: true
-
-    scm:
-      - lf-infra-gerrit-scm:
-          git-url: '{git-url}'
-          refspec: '$GERRIT_REFSPEC'
-          branch: '$GERRIT_BRANCH'
-          submodule-recursive: '{submodule-recursive}'
-          choosing-strategy: gerrit
-          jenkins-ssh-credential: '{jenkins-ssh-credential}'
-
-    triggers:
-      - gerrit:
-         #server-name: '{gerrit-server-name}'
-         server-name: 'CORD Project Gerrit'
-         #trigger-on: '{obj:gerrit_verify_triggers}'
-         trigger-on:
-           - patchset-created-event:
-               exclude-drafts: true
-               exclude-trivial-rebase: false
-               exclude-no-code-change: true
-           - draft-published-event
-           - comment-added-contains-event:
-               comment-contains-value: '(?i)^.*recheck$'
-         projects:
-           - project-compare-type: PLAIN
-             project-pattern: '{project}'
-             branches:
-               - branch-compare-type: ANT
-                 branch-pattern: '**/{stream}'
-             #file-paths: '{obj:gerrit_trigger_file_paths}'
-
-# workaround for lack of parameter expansion support in shell: (see above)
-- job-template:
-    #default name is global
-    name: 'cord-xos-gui-unit-{stream}'
-
-    <<: *job_boiler_plate
-    # yamllint disable-line rule:key-duplicates
-    <<: *verify_boiler_plate
-
-    builders:
-    #put shell scripts in file then make sure shell check is installed on verify vms
-      - shell: !include-raw-escape: cord-xos-gui-unit.sh
-
-- project:
-    name: cord-xos-gui-unit
-    project-name: cord-xos-gui-unit
-    project: xos-gui
-
-    build-timeout: '10'
-    build-node: '{build-node}'
-
-    # ideally this would be in defaults.yaml, but that doesn't work
-    supported_versions: &supported_versions
-      - 'master'
-      - 'cord-5.0'
-      - 'cord-4.1'
-      - 'cord-4.0'
-
-    stream: *supported_versions
-
-    jobs:
-      - 'cord-xos-gui-unit-{stream}'
diff --git a/jjb/gui-unit.yaml b/jjb/gui-unit.yaml
new file mode 100644
index 0000000..8b9a68b
--- /dev/null
+++ b/jjb/gui-unit.yaml
@@ -0,0 +1,50 @@
+---
+# xos-gui unit test
+
+- job-template:
+    id: 'gui-unit-test'
+    name: 'verify_{project}_gui-unit-test'
+
+    description: |
+      Created by gui-unit-tests job-template from ci-management/jjb/gui-unit.yaml
+
+    triggers:
+      - cord-infra-gerrit-trigger-patchset:
+          gerrit-server-name: '{gerrit-server-name}'
+          project-regexp: '^{project}$'
+          branch-regexp: '{branch-regexp}'
+          dependency-jobs: '{dependency-jobs}'
+          file-include-regexp: '{all-files-regexp}'
+
+    properties:
+      - cord-infra-properties:
+          build-days-to-keep: '{build-days-to-keep}'
+          artifact-num-to-keep: '{artifact-num-to-keep}'
+
+    # `npm install` can take >10m depending on connectivity
+    wrappers:
+      - lf-infra-wrappers:
+          build-timeout: 20
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    scm:
+      - lf-infra-gerrit-scm:
+          git-url: '$GIT_URL/$GERRIT_PROJECT'
+          refspec: '$GERRIT_REFSPEC'
+          branch: '$GERRIT_BRANCH'
+          submodule-recursive: 'false'
+          choosing-strategy: gerrit
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    node: '{build-node}'
+    project-type: freestyle
+    concurrent: true
+
+    builders:
+      - shell: |
+          #/usr/bin/env bash
+          set -eu -o pipefail
+          time npm install
+          npm run lint
+          npm test
+
diff --git a/jjb/sonar.yaml b/jjb/sonar.yaml
new file mode 100644
index 0000000..693c855
--- /dev/null
+++ b/jjb/sonar.yaml
@@ -0,0 +1,125 @@
+---
+# Sonarqube coverage tests
+#
+# There are two kinds of tests:
+#
+#  - coverage_{project}_sonarqube - run after merge to give an idea of ongoing code health
+#  - verify_{project}_sonarqube - run on patchsets, invoked in the verify/*.yaml
+#
+# JJB module docs:
+#  https://docs.openstack.org/infra/jenkins-job-builder/builders.html?highlight=sonar#builders.sonar
+#
+# Sonarqube docs:
+#  https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Jenkins
+#  https://docs.sonarqube.org/display/SCAN/Advanced+SonarQube+Scanner+Usages
+
+- project:
+    name: 'sonarqube-ongoing-coverage'
+
+    jobs:
+      - 'sonarqube-coverage':
+          branch-regexp: '{supported-branches-regexp}'
+          project:
+            - 'cord'
+            - 'maas'
+            - 'platform-install'
+            - 'xos'
+
+# run ongoing coverage tests on merged patchsets
+- job-template:
+    id: sonarqube-coverage
+    name: 'coverage_{project}_sonarqube'
+    description: |
+      Created by sonarqube-coverage job-template from ci-management/jjb/sonar.yaml
+
+    triggers:
+      - cord-infra-gerrit-trigger-merge:
+          gerrit-server-name: '{gerrit-server-name}'
+          project-regexp: '^{project}$'
+          branch-regexp: '{branch-regexp}'
+          dependency-jobs: '{dependency-jobs}'
+          file-include-regexp: '{all-files-regexp}'
+
+    properties:
+      - cord-infra-properties:
+          build-days-to-keep: '{build-days-to-keep}'
+          artifact-num-to-keep: '{artifact-num-to-keep}'
+
+    wrappers:
+      - lf-infra-wrappers:
+          build-timeout: '{build-timeout}'
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    scm:
+      - lf-infra-gerrit-scm:
+          git-url: '$GIT_URL/$GERRIT_PROJECT'
+          refspec: '$GERRIT_REFSPEC'
+          branch: '$GERRIT_BRANCH'
+          submodule-recursive: 'false'
+          choosing-strategy: gerrit
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    node: '{build-node}'
+    project-type: freestyle
+    concurrent: true
+
+    builders:
+      - sonar:
+          sonar-name: 'sonarqube.opencord.org'
+          properties: |
+            sonar.sources=.
+            sonar.projectKey={project}_$GERRIT_BRANCH
+            sonar.python.pylint=/usr/local/bin/pylint
+
+
+# run Sonarqube as a verification jobs on individual patchsets
+- job-template:
+    id: verify-sonarqube
+    name: 'verify_{project}_sonarqube'
+    description: |
+      Created by verify-sonarqube job-template from ci-management/jjb/sonar.yaml
+
+    triggers:
+      - cord-infra-gerrit-trigger-patchset:
+          gerrit-server-name: '{gerrit-server-name}'
+          project-regexp: '^{project}$'
+          branch-regexp: '{branch-regexp}'
+          dependency-jobs: '{dependency-jobs}'
+          file-include-regexp: '{all-files-regexp}'
+
+    properties:
+      - cord-infra-properties:
+          build-days-to-keep: '{build-days-to-keep}'
+          artifact-num-to-keep: '{artifact-num-to-keep}'
+
+    wrappers:
+      - lf-infra-wrappers:
+          build-timeout: '{build-timeout}'
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    scm:
+      - lf-infra-gerrit-scm:
+          git-url: '$GIT_URL/$GERRIT_PROJECT'
+          refspec: '$GERRIT_REFSPEC'
+          branch: '$GERRIT_BRANCH'
+          submodule-recursive: 'false'
+          choosing-strategy: gerrit
+          jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+    node: '{build-node}'
+    project-type: freestyle
+    concurrent: true
+
+# coverage checks with sonarqube
+# module docs: https://docs.openstack.org/infra/jenkins-job-builder/builders.html?highlight=sonar#builders.sonar
+# Sonarqube docs:
+#  https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Jenkins
+#  https://docs.sonarqube.org/display/SCAN/Advanced+SonarQube+Scanner+Usages
+    builders:
+      - sonar:
+          sonar-name: 'sonarqube.opencord.org'
+          properties: |
+            sonar.sources=.
+            sonar.projectKey=verify_{project}_$GERRIT_BRANCH
+            sonar.python.pylint=/usr/local/bin/pylint
+
diff --git a/jjb/verify/chameleon.yaml b/jjb/verify/chameleon.yaml
index 90262e7..8b5394a 100644
--- a/jjb/verify/chameleon.yaml
+++ b/jjb/verify/chameleon.yaml
@@ -13,5 +13,7 @@
     name: 'verify-chameleon-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_chameleon_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_chameleon_sonarqube'
diff --git a/jjb/verify/cord-tester.yaml b/jjb/verify/cord-tester.yaml
index 11e26b2..cecc814 100644
--- a/jjb/verify/cord-tester.yaml
+++ b/jjb/verify/cord-tester.yaml
@@ -13,5 +13,7 @@
     name: 'verify-cord-tester-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_cord-tester_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_cord-tester_sonarqube'
diff --git a/jjb/verify/cord.yaml b/jjb/verify/cord.yaml
index 601f3b0..7509064 100644
--- a/jjb/verify/cord.yaml
+++ b/jjb/verify/cord.yaml
@@ -15,6 +15,8 @@
       - 'verify-licensed'
       - 'verify-ansible-lint':
           dependency-jobs: 'verify_cord_licensed'
+      - 'verify-sonarqube':
+          dependency-jobs: 'verify_cord_ansible-lint'
       - 'api-test':
-          dependency-jobs: 'verify_cord_licensed, verify_cord_ansible-lint'
+          dependency-jobs: 'verify_cord_sonarqube'
 
diff --git a/jjb/verify/ecord.yaml b/jjb/verify/ecord.yaml
index 38fa940..aa4665b 100644
--- a/jjb/verify/ecord.yaml
+++ b/jjb/verify/ecord.yaml
@@ -15,5 +15,7 @@
       - 'verify-licensed'
       - 'verify-ansible-lint':
           dependency-jobs: 'verify_ecord_licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_ecord_ansible-lint'
+      - 'api-test':
+          dependency-jobs: 'verify_ecord_sonarqube'
diff --git a/jjb/verify/fabric.yaml b/jjb/verify/fabric.yaml
index 185c01c..6afb727 100644
--- a/jjb/verify/fabric.yaml
+++ b/jjb/verify/fabric.yaml
@@ -13,5 +13,7 @@
     name: 'verify-fabric-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_fabric_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_fabric_sonarqube'
diff --git a/jjb/verify/helm-charts.yaml b/jjb/verify/helm-charts.yaml
index 7eaa8bf..621168b 100644
--- a/jjb/verify/helm-charts.yaml
+++ b/jjb/verify/helm-charts.yaml
@@ -13,6 +13,8 @@
     name: 'verify-helm-charts-jobs'
     jobs:
       - 'verify-licensed'
-      - 'verify-helm-lint':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_helm-charts_licensed'
+      - 'verify-helm-lint':
+          dependency-jobs: 'verify_helm-charts_sonarqube'
 
diff --git a/jjb/verify/maas.yaml b/jjb/verify/maas.yaml
index f9c029c..00127de 100644
--- a/jjb/verify/maas.yaml
+++ b/jjb/verify/maas.yaml
@@ -15,4 +15,6 @@
       - 'verify-licensed'
       - 'verify-ansible-lint':
           dependency-jobs: 'verify_maas_licensed'
+      - 'verify-sonarqube':
+          dependency-jobs: 'verify_maas_ansible-lint'
 
diff --git a/jjb/verify/mcord.yaml b/jjb/verify/mcord.yaml
index 204eba1..4fe4751 100644
--- a/jjb/verify/mcord.yaml
+++ b/jjb/verify/mcord.yaml
@@ -15,5 +15,7 @@
       - 'verify-licensed'
       - 'verify-ansible-lint':
           dependency-jobs: 'verify_mcord_licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_mcord_ansible-lint'
+      - 'api-test':
+          dependency-jobs: 'verify_mcord_sonarqube'
diff --git a/jjb/verify/olt-service.yaml b/jjb/verify/olt-service.yaml
index 3a85e14..c4ab6e3 100644
--- a/jjb/verify/olt-service.yaml
+++ b/jjb/verify/olt-service.yaml
@@ -13,5 +13,7 @@
     name: 'verify-olt-service-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_olt-service_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_olt-service_sonarqube'
diff --git a/jjb/verify/onos-service.yaml b/jjb/verify/onos-service.yaml
index 3e878e6..93e21c1 100644
--- a/jjb/verify/onos-service.yaml
+++ b/jjb/verify/onos-service.yaml
@@ -13,5 +13,7 @@
     name: 'verify-onos-service-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_onos-service_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_onos-service_sonarqube'
diff --git a/jjb/verify/openstack.yaml b/jjb/verify/openstack.yaml
index 16d56ad..0436e28 100644
--- a/jjb/verify/openstack.yaml
+++ b/jjb/verify/openstack.yaml
@@ -13,5 +13,7 @@
     name: 'verify-openstack-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_openstack_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_openstack_sonarqube'
diff --git a/jjb/verify/platform-install.yaml b/jjb/verify/platform-install.yaml
index c04db63..241c8bf 100644
--- a/jjb/verify/platform-install.yaml
+++ b/jjb/verify/platform-install.yaml
@@ -15,6 +15,8 @@
       - 'verify-licensed'
       - 'verify-ansible-lint':
           dependency-jobs: 'verify_platform-install_licensed'
+      - 'verify-sonarqube':
+          dependency-jobs: 'verify_platform-install_ansible-lint'
       - 'api-test':
-          dependency-jobs: 'verify_platform-install_licensed, verify_platform-install_ansible-lint'
+          dependency-jobs: 'verify_platform-install_sonarqube'
 
diff --git a/jjb/verify/rcord.yaml b/jjb/verify/rcord.yaml
index a7cbf76..92621c8 100644
--- a/jjb/verify/rcord.yaml
+++ b/jjb/verify/rcord.yaml
@@ -13,5 +13,7 @@
     name: 'verify-rcord-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_rcord_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_rcord_sonarqube'
diff --git a/jjb/verify/vEE.yaml b/jjb/verify/vEE.yaml
index 4e24e13..74aad02 100644
--- a/jjb/verify/vEE.yaml
+++ b/jjb/verify/vEE.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vEE-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vEE_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vEE_sonarqube'
diff --git a/jjb/verify/vEG.yaml b/jjb/verify/vEG.yaml
index c57b95a..1db0b76 100644
--- a/jjb/verify/vEG.yaml
+++ b/jjb/verify/vEG.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vEG-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vEG_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vEG_sonarqube'
diff --git a/jjb/verify/vEPC.yaml b/jjb/verify/vEPC.yaml
index 5b1451d..f3dafa5 100644
--- a/jjb/verify/vEPC.yaml
+++ b/jjb/verify/vEPC.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vEPC-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vEPC_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vEPC_sonarqube'
diff --git a/jjb/verify/vHSS.yaml b/jjb/verify/vHSS.yaml
index d41748e..beb2a95 100644
--- a/jjb/verify/vHSS.yaml
+++ b/jjb/verify/vHSS.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vHSS-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vHSS_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vHSS_sonarqube'
diff --git a/jjb/verify/vMME.yaml b/jjb/verify/vMME.yaml
index 1b87edf..e7a5582 100644
--- a/jjb/verify/vMME.yaml
+++ b/jjb/verify/vMME.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vMME-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vMME_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vMME_sonarqube'
diff --git a/jjb/verify/venb.yaml b/jjb/verify/venb.yaml
index 68f3ced..2d56a82 100644
--- a/jjb/verify/venb.yaml
+++ b/jjb/verify/venb.yaml
@@ -13,5 +13,7 @@
     name: 'verify-venb-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_venb_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_venb_sonarqube'
diff --git a/jjb/verify/vrouter.yaml b/jjb/verify/vrouter.yaml
index 467c5e8..dd9c08d 100644
--- a/jjb/verify/vrouter.yaml
+++ b/jjb/verify/vrouter.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vrouter-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vrouter_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vrouter_sonarqube'
diff --git a/jjb/verify/vsg.yaml b/jjb/verify/vsg.yaml
index 2a70758..e35fe9d 100644
--- a/jjb/verify/vsg.yaml
+++ b/jjb/verify/vsg.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vsg-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vsg_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vsg_sonarqube'
diff --git a/jjb/verify/vspgwc.yaml b/jjb/verify/vspgwc.yaml
index 2bef282..6ded2d3 100644
--- a/jjb/verify/vspgwc.yaml
+++ b/jjb/verify/vspgwc.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vspgwc-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vspgwc_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vspgwc_sonarqube'
diff --git a/jjb/verify/vspgwu.yaml b/jjb/verify/vspgwu.yaml
index d221209..74cf8ec 100644
--- a/jjb/verify/vspgwu.yaml
+++ b/jjb/verify/vspgwu.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vspgwu-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vspgwu_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vspgwu_sonarqube'
diff --git a/jjb/verify/vtn.yaml b/jjb/verify/vtn.yaml
index 31350f5..49936a2 100644
--- a/jjb/verify/vtn.yaml
+++ b/jjb/verify/vtn.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vtn-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vtn_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vtn_sonarqube'
diff --git a/jjb/verify/vtr.yaml b/jjb/verify/vtr.yaml
index 4afca83..6cd0f16 100644
--- a/jjb/verify/vtr.yaml
+++ b/jjb/verify/vtr.yaml
@@ -13,5 +13,7 @@
     name: 'verify-vtr-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_vtr_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_vtr_sonarqube'
diff --git a/jjb/verify/xos-gui.yaml b/jjb/verify/xos-gui.yaml
new file mode 100644
index 0000000..8acd304
--- /dev/null
+++ b/jjb/verify/xos-gui.yaml
@@ -0,0 +1,19 @@
+---
+# verification jobs for 'xos-gui' repo
+
+- project:
+    name: xos-gui
+    project: '{name}'
+
+    jobs:
+      - 'verify-xos-gui-jobs':
+          branch-regexp: '{supported-branches-regexp}'
+
+- job-group:
+    name: 'verify-xos-gui-jobs'
+    jobs:
+      - 'verify-licensed'
+      - 'verify-sonarqube':
+          dependency-jobs: 'verify_xos-gui_licensed'
+      - 'gui-unit-test':
+          dependency-jobs: 'verify_xos-gui_sonarqube'
diff --git a/jjb/verify/xos.yaml b/jjb/verify/xos.yaml
index 8b7c48b..5f3e911 100644
--- a/jjb/verify/xos.yaml
+++ b/jjb/verify/xos.yaml
@@ -13,5 +13,7 @@
     name: 'verify-xos-jobs'
     jobs:
       - 'verify-licensed'
-      - 'api-test':
+      - 'verify-sonarqube':
           dependency-jobs: 'verify_xos_licensed'
+      - 'api-test':
+          dependency-jobs: 'verify_xos_sonarqube'
diff --git a/packer/provision/basebuild.sh b/packer/provision/basebuild.sh
index 76a0204..78d2fa1 100644
--- a/packer/provision/basebuild.sh
+++ b/packer/provision/basebuild.sh
@@ -59,9 +59,15 @@
         nodejs \
         npm \
         python \
+        python-certifi \
+        python-cryptography \
         python-dev \
+        python-idna \
         python-netaddr \
+        python-openssl \
         python-pip \
+        python-urllib3 \
+        ruby \
         ssh \
         sshpass \
         zip
@@ -88,6 +94,11 @@
         virtualenv
         # end of pip install list
 
+    # install ruby gems
+    gem install \
+        mdl
+        # end of gem install list
+
     # install npm modules
     npm install -g \
         gitbook-cli \