Friday 12 July 2013

Jenkins Configuration




As I mentioned in an earlier post I am doing the work required for Google Summer of Code within the Paddy Power offices. Due to this I am following their standards for delivering a project.

A big part of this is following a behavior driven development approach. This puts a great emphases on continuous testing and for this reason a build pipeline as developed within Jenkins.

The layout of the pipeline is as follows:

  • Pull in non-oss dependencies
  • Pull in the cloudstack branch I've been working on, move in the non-oss dependencies and build it executing unit tests
  • Run static analysis on the code using sonar source
  • Create a new Cloudstack Database, Start the simulator and run the pre-integration configuration
  • Launch the integration tests
  • Stop the simulator
  • Build a RPM binary of the source
  • Push the binary out onto a local repository
This setup was showcased in a screencast I did awhile back, if you are interested: http://imduffy15.blogspot.ie/2013/06/continuous-testing-environment.html

This post is going to go through the process of creating such a setup. It is assumed you have a clean version of jenkins installed. The configuration of sonar will be detailed in a separate post.

Plugins required:

  • Install the following plugins from Manage Jenkins -> Plugin Manager
  • Build pipeline
  • Jenkins Build timeout
  • Jenkins clone workspace SCM
  • Jenkins GIT
  • Jenkins Parameterized Trigger
  • Jenkins Sonar
After installing these plugins you will need to do a small amount of configuration. Navigate to Manage Jenkins -> Configure System
  • Configure JDK - Under the JDK heading set your java_home path
  • Configure git - Under the git heading fill out the options as necessary
  • Configure maven - Under the maven heading set the path to your Maven 3.0.5 Home
  • Configure sonar - Set its URL, account login, account password, database url(matches the same url in your sonar config), database login, database pasword
  • Job Configuration

Job Configuration

To create a new job simply git "new job" on the sidebar. For most of these jobs I will be using a build a free-style project, unless stated otherwise.

Update non-OSS libs:

  • Configure git to pull git@github.com:vogxn/cloudstack-nonoss.git this is a github repository that contains the non-oss dependencies required for the non-oss build of cloudstack
  • Set a Poll SCM of @hourly
  • Set the build to abort if it's stuck. For this I used Elastic with the default value of 150%
  • Create a post build action of "Trigger parameterized build on other projects". Set projects to build to "build-master-nonoss", set trigger when build is stable, finally check trigger build without parameters.
  • Save the job

Build non-OSS components:


  • Description > Build non-OSS components
  • Discard old builds > Log Rotation
    • Days to keep builds > 5
    • Max # of builds to keep > 5
  • This build is paramaterized > true
    • String Parameter
      • NAME > MAJOR_VERSION_NUMBER
      • DEFAULT VALUE > 4.2
    • String Parameter
      • NAME > PROJECT_REPOSITORY
      • DEFAULT VALUE > https://git-wip-us.apache.org/repos/asf/cloudstack.git
    • String parameter
      • NAME > GROUP_ID
      • DEFAULT VALUE  > org/apache/cloudstack
  • Git Repository
    • Url> $PROJECT_REPOSITORY
    • Branch Specifier > master
  • Build
    • Invoke Maven 3
      • Maven version > Maven
      • Root pom > pom.xml
      • Goals and options > clean install -P developer,systemvm -D simulator -D nonoss
    • Execute shell
      • git checkout -b build-$MAJOR_VERSION_NUMBER.$BUILD_NUMBER
      • git commit -a -m 'Build $MAJOR_VERSION_NUMBER.$BUILD_NUMBER
    • Execute Shell
echo "Getting nonoss patches"
LIBS=$JENKINS_HOME/jobs/mgmt-update-nonoss-libs/workspace

#Remove old jars
rm -fr deps/*.jar deps/XenServerJava deps/awsapilib deps/*.mar

#Replace with latest from https://github.com/vogxn/cloudstack-nonoss.git cloned into mgmt-update-nonoss-libs
cp -r $LIBS/*.jar $LIBS/XenServerJava/ $LIBS/awsapi-lib/ $LIBS/*.mar deps

#install the non-oss jars into .m2
cd deps
bash -x install-non-oss.sh

#now build the non-oss profile
cd $WORKSPACE
mkdir -p /var/lib/jenkins/jobs/CodeCommit/workspace/services/console-proxy/server/dist
mvn clean install -P developer,systemvm -D simulator -D nonoss
  • Post build actions
    • Archive for cloud workspace scm
      • Files to include in cloned workspace > **
      • Criteria for build to be archieved > Most recent completed build
      • Archive method > Gzipped
    • Trigger paramterized build on other projects
      • Projects to build > static-analysis
      • Trigger when build is > Stable

Static Analysis:

  • Discard old builds > Log Rotation
    • Days to keep builds > 5
    • Max # of builds to keep > 5
  • Source Code Management
    • Clone workspace
    • Parent project > build-master-nonoss
    • Criteria for parent build > Most Recent Completed Build
  • Post build actions
    • Sonar
    • Root pom > pom.xml
    • MAVEN_OPTS > -Dsonar.profile=Cloudstack
  • Trigger parameterized build on other projects
    • Projects to build > start-simulator
    • Trigger when build is > Stable

Start simulator:

  • Discard old builds > Log Rotation
    • Days to keep builds > 5
    • Max # of builds to keep > 5
  • Build
    • Execute shell
mvn -Pdeveloper -pl developer -Ddeploydb
mvn -Pdeveloper -pl developer -Ddeploydb-simulator
export OLD_BUILD_ID=$BUILD_ID
export BUILD_ID=dontKillMe
daemonize -c . -o log.txt /opt/apache-maven-3.0.5/bin/mvn -pl client jetty:run
export BUILD_ID=$OLD_BUILD_ID
while ! nc -vz localhost 8096; do sleep 10; done
export http_proxy=""
nosetests -v --with-marvin --marvin-config=setup/dev/advanced.cfg -w /tmp

  • Trigger paramaterized build on other projects
    • Projects to build > integration-tests.
    • Trigger when build is > stable

Integration tests:

Use a configuration matrix for this

  • Discard old builds > Log Rotation
    • Days to keep builds
    • Max # of builds to keep
  • Configuration Matrix
    • User defined axis
    • Name: suite
    • Values
      • test_affinity_groups
      • test_deploy_vm
      • test_deploy_vm_with_userdata
      • test_disk_offerings
      • test_global_settings
      • test_guest_vlan_range
      • test_internal_lb
      • test_network_acl
      • test_nic
      • test_non_contigiousvlan
      • test_portable_publicip
      • test_privategw_acl
      • test_public_ip_range
      • test_pvlan
      • test_regions
      • test_resource_detail
    • Execute touchstone builds first
      • Filter > suite="test_vm_life_cycle"
    • Required result > "Stable"
  • Build environment
    • Abort the build if its stuck > true
    • Absolute
    • Timeout minutes > 1440
  • Build
    • Execute shell
nosetests --with-xunit --xunit-file=$suite.xml --with-marvin --marvin-config=$WORKSPACE/../../setup/dev/advanced.cfg $WORKSPACE/../../test/integration/smoke/$suite.py --load -a tags=advanced

  • Post Build Actions 
    • Trigger paramaterized build on other projects
    • Projects to build > stop simulator
    • Trigger when build is > Complete

Stop Simulator:

  • Discard old builds > Log Rotation
    • Days to keep builds > 5
    • Max # of builds to keep > 5
  • Build
    • Execute shell
      • mvn -pl :cloud-client-ui jetty:stop
  • Post build actions
    • Trigger paramaterized build on other projects
      • Projects to build > package-rhel63-4.2-nonoss,
      • Trigger when build is > Stable

Package Binary:

  • Discard old builds > Log Rotation
    • Days to keep builds > 5
    • Max # of builds to keep > 5
  • Source code management
    • Clone workspace 
    • Parent project > build-master-nonoss
    • Criteria for parent build > Most recent completed build
  • Build
    • Execute shell
set -x
PACKAGE_VERSION=4.2.0

cd scripts/vm/hypervisor/xenserver/

if [ ! vhd-util ]; then
    wget http://download.cloud.com.s3.amazonaws.com/tools/vhd-util
fi

cd $WORKSPACE/packaging/centos63/
bash -x package.sh

Thursday 4 July 2013

Progress so far


Google summer of code has been in the coding period for 17 days! So its time for a progress review. I'll admit and say there were times where I was thinking the task might of been too much and way beyond my skill set, but things are getting there. You can judge for yourself and let me know in the comments.

In terms of coding I have been working on cleaning up the current LDAP implementation and extending its API features. I'll use the word cleaning here loosely, because if I'm honest it was really more of a re-write. When I reviewed the code for the current LDAP implementation I didn't think it was in a great position to be extended. There was duplicate code, no central manager and no data access objects for LDAP interaction. Extending on such a foundation would of caused major headaches and possible performance issues in the future.

I started of by creating a plugin to handle connections to ldap and creating objects to model the data it returned. This involved creating the following main(I have excluded VOs and DAOs from this list to highlight functionality) classes:

  • LdapManager - Manages all connections with LDAP.
  • LdapConfiguration - Supplies all configuration from the cloudstack database.
  • LdapUserManager - Handles any interaction with LDAP user information e.g. search for an ldap user.
  • LdapUtils - Supplies static helpers e.g. Escape search queries, escapse DNs, get attributes from search queries etc.
  • LdapContextFactory - Manages the creation of contexts
  • LdapAuthenticator - Supplies an authentication system to Cloudstack
So from this I had a solid foundation to start creating API commands I went ahead and created the following:
  • Add Configuration (Support for multi-able LDAP servers added)


  • Delete Configuration


  • ListLdapUsers - All or via a search on the specified username attribute

  • ListLdapConfiguration

Along with this I updated the UI components that currently exist for the configuration of LDAP



I believe the above work puts me on a nice foundation to begin introducing UI features to enable easy user provisioning. Of course there will be some additions to the LDAP API and modifying of other API commands but this should be manageable. I plan to start with this come the second term of the coding period, July 29th (Knowing me it'll probably happen earlier). Until then I'm writing unit tests for the above code and cleaning up any little issues I come across.

The lead Cloudstack mentor, Sebastian will be in Dublin next week on July 10th giving a talk about the Cloudstack API. I have to put together a 5 minute follow up talk about my experience so far and a brief description on how to get involved with the community. If you'd like to come along grab a ticket over here: https://tito.io/tcube/cloudstack-clients-and-wrappers the event is Paddy Power sponsored and you can grab yourself a free pair of underwear just like the ones in the opening photo of this blog posted!