You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2018/03/15 10:55:33 UTC

[cloudstack] branch master updated: CLOUDSTACK-10268: Fix and enhance package script (#2433)

This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 1708838  CLOUDSTACK-10268: Fix and enhance package script (#2433)
1708838 is described below

commit 1708838518299d5d04f810d0d01cfb4faf425b03
Author: Khosrow Moossavi <kh...@gmail.com>
AuthorDate: Thu Mar 15 06:55:29 2018 -0400

    CLOUDSTACK-10268: Fix and enhance package script (#2433)
    
    - new flag `-T, --use-timestamp` to use `timestamp` when POM version contains SNAPSHOT
      - in the final artifacts (jar) name
      - in the final package (rpm, deb) name
      - in `/etc/cloudstack-release` file of SystemVMs
      - in the Management Server > About dialog
    - if there's a "branding" string in the POM version (e.g. `x.y.z.a-NAME[-SNAPSHOT]`),
    the branding name will be used in the final generated pacakge name such as following:
      - `cloudstack-management-x.y.z.a-NAME.NUMBER.el7.centos.x86_64`
      - `cloudstack-management_x.y.z.a-NAME-NUMBER~xenial_all.deb`
    - branding string can be overriden with newly added `-b, --brand` flag
    - handle the new format version for VR version
    - fix long opts (they were broken)
    - tolerate and show a warning message for unrecognized flags
    - usage help reformat
    
    * Deprecate Version class in favor or CloudStackVersion
---
 .../cloud/upgrade/DatabaseIntegrityChecker.java    |   5 +-
 packaging/build-deb.sh                             |  94 +++++++++-
 packaging/centos63/cloud.spec                      |   7 +-
 packaging/centos7/cloud.spec                       |   7 +-
 packaging/package.sh                               | 190 +++++++++++++++------
 .../api/query/dao/DomainRouterJoinDaoImpl.java     |  11 +-
 .../cloud/network/router/NetworkHelperImpl.java    |  11 +-
 tools/appliance/build.sh                           |  16 +-
 tools/build/setnextversion.sh                      | 143 +++++++++++-----
 utils/src/main/java/com/cloud/maint/Version.java   |  77 ---------
 .../nicira/nvp/plugin/NiciraNvpApiVersion.java     |   8 +-
 .../apache/cloudstack/utils/CloudStackVersion.java | 152 +++++++++++------
 .../cloudstack/utils/CloudStackVersionTest.java    | 143 +++++++++++++---
 13 files changed, 574 insertions(+), 290 deletions(-)

diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseIntegrityChecker.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseIntegrityChecker.java
index 6111fb1..bb75aac 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseIntegrityChecker.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseIntegrityChecker.java
@@ -26,7 +26,8 @@ import javax.inject.Inject;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import com.cloud.maint.Version;
+import org.apache.cloudstack.utils.CloudStackVersion;
+
 import com.cloud.upgrade.dao.VersionDao;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.component.ComponentLifecycle;
@@ -210,7 +211,7 @@ public class DatabaseIntegrityChecker extends AdapterBase implements SystemInteg
                     return false;
                 }
 
-                if (Version.compare(Version.trimToPatch(dbVersion), Version.trimToPatch("2.2.8")) != 0) {
+                if (CloudStackVersion.compare(dbVersion, "2.2.8") != 0) {
                     txn.commit();
                     return true;
                 }
diff --git a/packaging/build-deb.sh b/packaging/build-deb.sh
index d8f2f8f..52a168a 100755
--- a/packaging/build-deb.sh
+++ b/packaging/build-deb.sh
@@ -40,18 +40,104 @@
 # docker run -ti -v /tmp:/src ubuntu:14.04 /bin/bash -c "apt-get update && apt-get install -y dpkg-dev python debhelper openjdk-8-jdk genisoimage python-mysql.connector maven lsb-release devscripts dh-systemd python-setuptools && /src/cloudstack/packaging/build-deb.sh"
 #
 
-cd `dirname $0`
-cd ..
+function usage() {
+    cat << USAGE
+Usage: ./build-deb.sh [OPTIONS]...
+Package CloudStack for Debian based distribution.
+
+If there's a "branding" string in the POM version (e.g. x.y.z.a-NAME[-SNAPSHOT]), the branding name will
+be used in the final generated pacakge like: cloudstack-management_x.y.z.a-NAME-SNAPSHOT~xenial_all.deb
+note that you can override/provide "branding" string with "-b, --brand" flag as well.
+
+Optional arguments:
+   -b, --brand string                      Set branding to be used in package name (it will override any branding string in POM version)
+   -T, --use-timestamp                     Use epoch timestamp instead of SNAPSHOT in the package name (if not provided, use "SNAPSHOT")
+
+Other arguments:
+   -h, --help                              Display this help message and exit
+
+Examples:
+   build-deb.sh --use-timestamp
+   build-deb.sh --brand foo
+
+USAGE
+    exit 0
+}
+
+BRANDING=""
+USE_TIMESTAMP="false"
+
+while [ -n "$1" ]; do
+    case "$1" in
+        -h | --help)
+            usage
+            ;;
+
+        -b | --brand)
+            if [ -n "$BRANDING" ]; then
+                echo "ERROR: you have already entered value for -b, --brand"
+                exit 1
+            else
+                BRANDING=$2
+                shift 2
+            fi
+            ;;
+
+        -T | --use-timestamp)
+            if [ "$USE_TIMESTAMP" == "true" ]; then
+                echo "ERROR: you have already entered value for -T, --use-timestamp"
+                exit 1
+            else
+                USE_TIMESTAMP="true"
+                shift 1
+            fi
+            ;;
+
+        -*|*)
+            echo "ERROR: no such option $1. -h or --help for help"
+            exit 1
+            ;;
+    esac
+done
 
 DCH=$(which dch)
 if [ -z "$DCH" ] ; then
     echo -e "dch not found, please install devscripts at first. \nDEB Build Failed"
-    exit
+    exit 1
 fi
 
+NOW="$(date +%s)"
+PWD=$(cd $(dirname "$0") && pwd -P)
+cd $PWD/../
+
 VERSION=$(head -n1 debian/changelog  |awk -F [\(\)] '{print $2}')
 DISTCODE=$(lsb_release -sc)
 
+if [ "$USE_TIMESTAMP" == "true" ]; then
+    # use timestamp instead of SNAPSHOT
+    if echo "$VERSION" | grep -q SNAPSHOT ; then
+        # apply/override branding, if provided
+        if [ "$BRANDING" != "" ]; then
+            VERSION=$(echo "$VERSION" | cut -d '-' -f 1) # remove any existing branding from POM version to be overriden
+            VERSION="$VERSION-$BRANDING-$NOW"
+        else
+            VERSION=`echo $VERSION | sed 's/-SNAPSHOT/-'$NOW'/g'`
+        fi
+
+        branch=$(cd $PWD; git rev-parse --abbrev-ref HEAD)
+        (cd $PWD; ./tools/build/setnextversion.sh --version $VERSION --sourcedir . --branch $branch --no-commit)
+    fi
+else
+    # apply/override branding, if provided
+    if [ "$BRANDING" != "" ]; then
+        VERSION=$(echo "$VERSION" | cut -d '-' -f 1) # remove any existing branding from POM version to be overriden
+        VERSION="$VERSION-$BRANDING"
+
+        branch=$(cd $PWD; git rev-parse --abbrev-ref HEAD)
+        (cd $PWD; ./tools/build/setnextversion.sh --version $VERSION --sourcedir . --branch $branch --no-commit)
+    fi
+fi
+
 /bin/cp debian/changelog /tmp/changelog.orig
 
 dch -b -v "${VERSION}~${DISTCODE}" -u low -m "Apache CloudStack Release ${VERSION}"
@@ -61,3 +147,5 @@ dpkg-checkbuilddeps
 dpkg-buildpackage -uc -us -b
 
 /bin/mv /tmp/changelog.orig debian/changelog
+
+(cd $PWD; git reset --hard)
diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec
index ba1798e..c26143e 100644
--- a/packaging/centos63/cloud.spec
+++ b/packaging/centos63/cloud.spec
@@ -24,13 +24,8 @@
 Name:      cloudstack
 Summary:   CloudStack IaaS Platform
 #http://fedoraproject.org/wiki/PackageNamingGuidelines#Pre-Release_packages
-%if "%{?_prerelease}" != ""
-%define _maventag %{_ver}-SNAPSHOT
+%define _maventag %{_fullver}
 Release:   %{_rel}%{dist}
-%else
-%define _maventag %{_ver}
-Release:   %{_rel}%{dist}
-%endif
 
 %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
 
diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec
index 481c86c..23d3866 100644
--- a/packaging/centos7/cloud.spec
+++ b/packaging/centos7/cloud.spec
@@ -24,13 +24,8 @@
 Name:      cloudstack
 Summary:   CloudStack IaaS Platform
 #http://fedoraproject.org/wiki/PackageNamingGuidelines#Pre-Release_packages
-%if "%{?_prerelease}" != ""
-%define _maventag %{_ver}-SNAPSHOT
+%define _maventag %{_fullver}
 Release:   %{_rel}%{dist}
-%else
-%define _maventag %{_ver}
-Release:   %{_rel}%{dist}
-%endif
 
 %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
 
diff --git a/packaging/package.sh b/packaging/package.sh
index 8a87661..a823afa 100755
--- a/packaging/package.sh
+++ b/packaging/package.sh
@@ -17,48 +17,68 @@
 # under the License.
 
 function usage() {
-    echo ""
-    echo "usage: ./package.sh [-h|--help] -d|--distribution <name> [-r|--release <version>] [-p|--pack oss|OSS|noredist|NOREDIST] [-s|--simulator default|DEFAULT|simulator|SIMULATOR]"
-    echo ""
-    echo "The supported arguments are:"
-    echo "  To package with only redistributable libraries (default)"
-    echo "    -p|--pack oss|OSS"
-    echo "  To package with non-redistributable libraries"
-    echo "    -p|--pack noredist|NOREDIST"
-    echo "  To build a package for a distribution (mandatory)"
-    echo "    -d|--distribution centos7|centos63|fedora20|fedora21"
-    echo "  To set the package release version (optional)"
-    echo "  (default is 1 for normal and prereleases, empty for SNAPSHOT)"
-    echo "    -r|--release version(integer)"
-    echo "  To build for Simulator (optional)"
-    echo "    -s|--simulator default|DEFAULT|simulator|SIMULATOR"
-    echo "  To display this information"
-    echo "    -h|--help"
-    echo ""
-    echo "Examples: ./package.sh --pack oss"
-    echo "          ./package.sh --pack noredist"
-    echo "          ./package.sh --pack oss --distribution centos7 --release 42"
-    echo "          ./package.sh --distribution centos7 --release 42"
-    echo "          ./package.sh --distribution centos7"
+    cat << USAGE
+Usage: ./package.sh -d DISTRO [OPTIONS]...
+Package CloudStack for specific distribution and provided options.
+
+If there's a "branding" string in the POM version (e.g. x.y.z.a-NAME[-SNAPSHOT]), the branding name will
+be used in the final generated pacakge like: cloudstack-management-x.y.z.a-NAME.NUMBER.el7.centos.x86_64
+note that you can override/provide "branding" string with "-b, --brand" flag as well.
+
+Mandatory arguments:
+   -d, --distribution string               Build package for specified distribution ("centos7"|"centos63")
+
+Optional arguments:
+   -p, --pack string                       Define which type of libraries to package ("oss"|"OSS"|"noredist"|"NOREDIST") (default "oss")
+                                             - oss|OSS to package with only redistributable libraries
+                                             - noredist|NOREDIST to package with non-redistributable libraries
+   -r, --release integer                   Set the package release version (default is 1 for normal and prereleases, empty for SNAPSHOT)
+   -s, --simulator string                  Build package for Simulator ("default"|"DEFAULT"|"simulator"|"SIMULATOR") (default "default")
+   -b, --brand string                      Set branding to be used in package name (it will override any branding string in POM version)
+   -T, --use-timestamp                     Use epoch timestamp instead of SNAPSHOT in the package name (if not provided, use "SNAPSHOT")
+
+Other arguments:
+   -h, --help                              Display this help message and exit
+
+Examples:
+   package.sh --distribution centos7
+   package.sh --distribution centos7 --pack oss
+   package.sh --distribution centos7 --pack noredist
+   package.sh --distribution centos7 --release 42
+   package.sh --distribution centos7 --pack noredist --release 42
+
+USAGE
+    exit 0
 }
 
+PWD=$(cd $(dirname "$0") && pwd -P)
+NOW="$(date +%s)"
+
 # packaging
 #   $1 redist flag
 #   $2 simulator flag
 #   $3 distribution name
 #   $4 package release version
+#   $5 brand string to apply/override
+#   $6 use timestamp flag
 function packaging() {
-    CWD=$(pwd)
-    RPMDIR=$CWD/../dist/rpmbuild
+    RPMDIR=$PWD/../dist/rpmbuild
     PACK_PROJECT=cloudstack
+
     if [ -n "$1" ] ; then
         DEFOSSNOSS="-D_ossnoss $1"
     fi
     if [ -n "$2" ] ; then
         DEFSIM="-D_sim $2"
     fi
+    if [ "$6" == "true" ]; then
+        INDICATOR="$NOW"
+    else
+        INDICATOR="SNAPSHOT"
+    fi
 
     DISTRO=$3
+
     MVN=$(which mvn)
     if [ -z "$MVN" ] ; then
         MVN=$(locate bin/mvn | grep -e mvn$ | tail -1)
@@ -67,24 +87,63 @@ function packaging() {
             exit 2
         fi
     fi
-    VERSION=$(cd ../; $MVN org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep --color=none '^[0-9]\.')
+
+    VERSION=$(cd $PWD/../; $MVN org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep --color=none '^[0-9]\.')
+    REALVER=$(echo "$VERSION" | cut -d '-' -f 1)
+
+    if [ -n "$5" ]; then
+        BRAND="${5}."
+    else
+        BASEVER=$(echo "$VERSION" | sed 's/-SNAPSHOT//g')
+        BRAND=$(echo "$BASEVER" | cut -d '-' -f 2)
+
+        if [ "$REALVER" != "$BRAND" ]; then
+            BRAND="${BRAND}."
+        else
+            BRAND=""
+        fi
+    fi
+
     if echo "$VERSION" | grep -q SNAPSHOT ; then
-        REALVER=$(echo "$VERSION" | cut -d '-' -f 1)
         if [ -n "$4" ] ; then
-            DEFPRE="-D_prerelease $4"
-            DEFREL="-D_rel SNAPSHOT$4"
+            DEFREL="-D_rel ${BRAND}${INDICATOR0}.$4"
         else
-            DEFPRE="-D_prerelease 1"
-            DEFREL="-D_rel SNAPSHOT"
+            DEFREL="-D_rel ${BRAND}${INDICATOR}"
         fi
     else
-        REALVER="$VERSION"
         if [ -n "$4" ] ; then
-            DEFREL="-D_rel $4"
+            DEFREL="-D_rel ${BRAND}$4"
         else
-            DEFREL="-D_rel 1"
+            DEFREL="-D_rel ${BRAND}1"
         fi
     fi
+
+    if [ "$USE_TIMESTAMP" == "true" ]; then
+        # use timestamp instead of SNAPSHOT
+        if echo "$VERSION" | grep -q SNAPSHOT ; then
+            # apply/override branding, if provided
+            if [ "$BRANDING" != "" ]; then
+                VERSION=$(echo "$VERSION" | cut -d '-' -f 1) # remove any existing branding from POM version to be overriden
+                VERSION="$VERSION-$BRANDING-$NOW"
+            else
+                VERSION=`echo $VERSION | sed 's/-SNAPSHOT/-'$NOW'/g'`
+            fi
+
+            branch=$(cd $PWD/../; git rev-parse --abbrev-ref HEAD)
+            (cd $PWD/../; ./tools/build/setnextversion.sh --version $VERSION --sourcedir . --branch $branch --no-commit)
+        fi
+    else
+        # apply/override branding, if provided
+        if [ "$BRANDING" != "" ]; then
+            VERSION=$(echo "$VERSION" | cut -d '-' -f 1) # remove any existing branding from POM version to be overriden
+            VERSION="$VERSION-$BRANDING"
+
+            branch=$(cd $PWD/../; git rev-parse --abbrev-ref HEAD)
+            (cd $PWD/../; ./tools/build/setnextversion.sh --version $VERSION --sourcedir . --branch $branch --no-commit)
+        fi
+    fi
+
+    DEFFULLVER="-D_fullver $VERSION"
     DEFVER="-D_ver $REALVER"
 
     echo "Preparing to package Apache CloudStack $VERSION"
@@ -96,13 +155,14 @@ function packaging() {
     mkdir -p "$RPMDIR/SOURCES/$PACK_PROJECT-$VERSION"
 
     echo ". preparing source tarball"
-    (cd ../; tar -c --exclude .git --exclude dist . | tar -C "$RPMDIR/SOURCES/$PACK_PROJECT-$VERSION" -x )
+    (cd $PWD/../; tar -c --exclude .git --exclude dist . | tar -C "$RPMDIR/SOURCES/$PACK_PROJECT-$VERSION" -x )
     (cd "$RPMDIR/SOURCES/"; tar -czf "$PACK_PROJECT-$VERSION.tgz" "$PACK_PROJECT-$VERSION")
 
     echo ". executing rpmbuild"
-    cp "$DISTRO/cloud.spec" "$RPMDIR/SPECS"
+    cp "$PWD/$DISTRO/cloud.spec" "$RPMDIR/SPECS"
 
-    (cd "$RPMDIR"; rpmbuild --define "_topdir ${RPMDIR}" "${DEFVER}" "${DEFREL}" ${DEFPRE+"$DEFPRE"} ${DEFOSSNOSS+"$DEFOSSNOSS"} ${DEFSIM+"$DEFSIM"} -bb SPECS/cloud.spec)
+    (cd "$RPMDIR"; rpmbuild --define "_topdir ${RPMDIR}" "${DEFVER}" "${DEFFULLVER}" "${DEFREL}" ${DEFPRE+"$DEFPRE"} ${DEFOSSNOSS+"$DEFOSSNOSS"} ${DEFSIM+"$DEFSIM"} -bb SPECS/cloud.spec)
+    (cd $PWD/../; git reset --hard)
     if [ $? -ne 0 ]; then
         echo "RPM Build Failed "
         exit 3
@@ -116,22 +176,20 @@ TARGETDISTRO=""
 SIM=""
 PACKAGEVAL=""
 RELEASE=""
+BRANDING=""
+USE_TIMESTAMP="false"
 
-SHORTOPTS="hp:s:d:r:"
-LONGOPTS="help,pack:simulator:distribution:release:"
-ARGS=$(getopt -s bash -u -a --options "$SHORTOPTS"  --longoptions "$LONGOPTS" --name "$0" -- "$@")
-eval set -- "$ARGS"
-echo "$ARGS"
-while [ $# -gt 0 ] ; do
+unrecognized_flags=""
+
+while [ -n "$1" ]; do
     case "$1" in
         -h | --help)
             usage
             exit 0
             ;;
+
         -p | --pack)
-            echo "Packaging CloudStack..."
             PACKAGEVAL=$2
-            echo "$PACKAGEVAL"
             if [ "$PACKAGEVAL" == "oss" -o "$PACKAGEVAL" == "OSS" ] ; then
                 PACKAGEVAL=""
             elif [ "$PACKAGEVAL" == "noredist" -o "$PACKAGEVAL" == "NOREDIST" ] ; then
@@ -141,11 +199,11 @@ while [ $# -gt 0 ] ; do
                 usage
                 exit 1
             fi
-            shift
+            shift 2
             ;;
+
         -s | --simulator)
             SIM=$2
-            echo "$SIM"
             if [ "$SIM" == "default" -o "$SIM" == "DEFAULT" ] ; then
                 SIM="false"
             elif [ "$SIM" == "simulator" -o "$SIM" == "SIMULATOR" ] ; then
@@ -155,8 +213,9 @@ while [ $# -gt 0 ] ; do
                 usage
                 exit 1
             fi
-            shift
+            shift 2
             ;;
+
         -d | --distribution)
             TARGETDISTRO=$2
             if [ -z "$TARGETDISTRO" ] ; then
@@ -164,22 +223,41 @@ while [ $# -gt 0 ] ; do
                 usage
                 exit 1
             fi
-            shift
+            shift 2
             ;;
+
         -r | --release)
             RELEASE=$2
-            shift
+            shift 2
             ;;
-        -)
-            echo "Error: Unrecognized option"
-            usage
-            exit 1
+
+        -b | --brand)
+            BRANDING=$2
+            shift 2
             ;;
+
+        -T | --use-timestamp)
+            USE_TIMESTAMP="true"
+            shift 1
+            ;;
+
+        -*)
+            unrecognized_flags="${unrecognized_flags}$1 "
+            shift 1
+            ;;
+
         *)
-            shift
+            shift 1
             ;;
     esac
 done
 
-packaging "$PACKAGEVAL" "$SIM" "$TARGETDISTRO" "$RELEASE"
+if [ -n "$unrecognized_flags" ]; then
+    echo "Warning: Unrecognized option(s) found \" ${unrecognized_flags}\""
+    echo "         You're advised to fix your build job scripts and prevent using these"
+    echo "         flags, as in the future release(s) they will break packaging script."
+    echo ""
+fi
 
+echo "Packaging CloudStack..."
+packaging "$PACKAGEVAL" "$SIM" "$TARGETDISTRO" "$RELEASE" "$BRANDING" "$USE_TIMESTAMP"
diff --git a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java
index e3d1e30..729ef2b 100644
--- a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java
@@ -21,16 +21,17 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
 import org.apache.cloudstack.api.response.DomainRouterResponse;
 import org.apache.cloudstack.api.response.NicResponse;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
+import org.apache.cloudstack.utils.CloudStackVersion;
 
 import com.cloud.api.ApiResponseHelper;
 import com.cloud.api.query.vo.DomainRouterJoinVO;
-import com.cloud.maint.Version;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.router.VirtualRouter;
 import com.cloud.network.router.VirtualRouter.Role;
@@ -78,9 +79,9 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
         routerResponse.setIsRedundantRouter(router.isRedundantRouter());
         routerResponse.setRedundantState(router.getRedundantState().toString());
         if (router.getTemplateVersion() != null) {
-            String routerVersion = Version.trimRouterVersion(router.getTemplateVersion());
+            String routerVersion = CloudStackVersion.trimRouterVersion(router.getTemplateVersion());
             routerResponse.setVersion(routerVersion);
-            routerResponse.setRequiresUpgrade((Version.compare(routerVersion, NetworkOrchestrationService.MinVRVersion.valueIn(router.getDataCenterId())) < 0));
+            routerResponse.setRequiresUpgrade((CloudStackVersion.compare(routerVersion, NetworkOrchestrationService.MinVRVersion.valueIn(router.getDataCenterId())) < 0));
         } else {
             routerResponse.setVersion("UNKNOWN");
             routerResponse.setRequiresUpgrade(true);
diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
index fa17e7b..5c84527 100644
--- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
+++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
@@ -27,12 +27,14 @@ import java.util.Map;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 
+import org.apache.log4j.Logger;
+import org.cloud.network.router.deployment.RouterDeploymentDefinition;
+
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.log4j.Logger;
-import org.cloud.network.router.deployment.RouterDeploymentDefinition;
+import org.apache.cloudstack.utils.CloudStackVersion;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
@@ -61,7 +63,6 @@ import com.cloud.host.HostVO;
 import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import com.cloud.maint.Version;
 import com.cloud.network.IpAddressManager;
 import com.cloud.network.Network;
 import com.cloud.network.NetworkModel;
@@ -265,8 +266,8 @@ public class NetworkHelperImpl implements NetworkHelper {
             return false;
         }
         final long dcid = router.getDataCenterId();
-        final String trimmedVersion = Version.trimRouterVersion(router.getTemplateVersion());
-        return Version.compare(trimmedVersion, NetworkOrchestrationService.MinVRVersion.valueIn(dcid)) >= 0;
+        String routerVersion = CloudStackVersion.trimRouterVersion(router.getTemplateVersion());
+        return CloudStackVersion.compare(routerVersion, NetworkOrchestrationService.MinVRVersion.valueIn(dcid)) >= 0;
     }
 
     protected DomainRouterVO start(DomainRouterVO router, final User user, final Account caller, final Map<Param, Object> params, final DeploymentPlan planToDeploy)
diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh
index 8b1032e..893404d 100755
--- a/tools/appliance/build.sh
+++ b/tools/appliance/build.sh
@@ -34,8 +34,12 @@ Usage:
 END
   exit 0
 }
-echo $@ | grep help >/dev/null && usage
-echo $@ | grep '\-h' >/dev/null && usage
+
+for i in $@; do
+    if [ "$i" == "-h" -o "$i" == "--help" -o "$i" == "help" ]; then
+        usage
+    fi
+done
 
 # requires 32-bit vhd-util and faketime binaries to be available (even for 64 bit builds)
 # Something like (on centos 6.5)...
@@ -194,8 +198,10 @@ function create_definition() {
     cp -r "${appliance}" "${appliance_build_name}"
     set +e
     if [ ! -z "${version}" ]; then
-    sed ${sed_regex_option} -i -e "s/^CLOUDSTACK_RELEASE=.+/CLOUDSTACK_RELEASE=${version}/" \
-        "${appliance_build_name}/configure_systemvm_services.sh"
+    if [ -f "${appliance_build_name}/scripts/configure_systemvm_services.sh" ]; then
+        sed ${sed_regex_option} -i -e "s/^CLOUDSTACK_RELEASE=.+/CLOUDSTACK_RELEASE=${version}/" \
+            "${appliance_build_name}/scripts/configure_systemvm_services.sh"
+        fi
     fi
     set -e
     add_on_exit rm -rf "${appliance_build_name}"
@@ -215,7 +221,7 @@ function packer_build() {
   cd ${appliance_build_name} && packer build template.json && cd ..
 }
 
-function stage_vmx (){
+function stage_vmx() {
   cat << VMXFILE > "${1}.vmx"
 .encoding = "UTF-8"
 displayname = "${1}"
diff --git a/tools/build/setnextversion.sh b/tools/build/setnextversion.sh
index 2387b89..b4bf914 100755
--- a/tools/build/setnextversion.sh
+++ b/tools/build/setnextversion.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -16,60 +16,125 @@
 # specific language governing permissions and limitations
 # under the License.
 
-version='TESTBUILD'
-sourcedir=~/cloudstack/
-branch='master'
+set -e
 
-usage(){
-    echo "usage: $0 -v version [-b branch] [-s source dir] [-h]"
-    echo "  -v sets the version"
-    echo "  -b sets the branch (defaults to 'master')"
-    echo "  -s sets the source directory (defaults to $sourcedir)"
-    echo "  -h"
+usage() {
+    cat << USAGE
+Usage: setnextversion.sh --version string [OPTIONS]...
+Set the next version of CloudStack in the POMs.
+
+Mandatory arguments:
+   -v, --version string                    Set the next version to be applied
+
+Optional arguments:
+   -b, --branch string                     Set the branch to update the version into (default "master")
+   -s, --sourcedir string                  Set the source directory to clone repo into (default "$sourcedir")
+   -n, --no-commit                         Apply only the version change and don't git commit them (default "false")
+
+Other arguments:
+   -h, --help                              Display this help message and exit
+
+Examples:
+   setnextversion.sh --version x.y.z.a-SNAPSHOT
+   setnextversion.sh --version x.y.z.a-SNAPSHOT --branch foo-feature
+   setnextversion.sh --version x.y.z.a-SNAPSHOT --sourcedir /path/to/cloudstack/repo
+   setnextversion.sh --version x.y.z.a-SNAPSHOT --no-commit
+
+USAGE
+    exit 0
 }
 
-while getopts v:s:b:h opt
-do
-    case "$opt" in
-      v)  version="$OPTARG";;
-      s)  sourcedir="$OPTARG";;
-      b)  branch="$OPTARG";;
-      h)  usage
-          exit 0;;
-      /?)       # unknown flag
-          usage
-          exit 1;;
+while [ -n "$1" ]; do
+    case "$1" in
+        -h | --help)
+            usage
+            ;;
+
+        -v | --version)
+            if [ -n "$version" ]; then
+                echo "ERROR: you have already entered value for -v, --version"
+                exit 1
+            else
+                version=$2
+                shift 2
+            fi
+            ;;
+
+        -b | --branch)
+            if [ -n "$branch" ]; then
+                echo "ERROR: you have already entered value for -b, --branch"
+                exit 1
+            else
+                branch=$2
+                shift 2
+            fi
+            ;;
+
+        -s | --sourcedir)
+            if [ -n "$sourcedir" ]; then
+                echo "ERROR: you have already entered value for -s, --sourcedir"
+                exit 1
+            else
+                sourcedir=$2
+                shift 2
+            fi
+            ;;
+
+        -n | --no-commit)
+            if [ "$nocommit" == "true" ]; then
+                echo "ERROR: you have already entered value for -n, --no-commit"
+                exit 1
+            else
+                nocommit="true"
+                shift 1
+            fi
+            ;;
+
+        -*|*)
+            echo "ERROR: no such option $1. -h or --help for help"
+            exit 1
+            ;;
     esac
 done
-shift `expr $OPTIND - 1`
 
-if [ $version == 'TESTBUILD' ]; then
-    echo >&2 "A version must be specified with the -v option: $0 -v 4.0.0.RC1"
+if [ -z "$version" ]; then
+    echo >&2 "A version must be specified with the -v, --version option: $0 -v 4.0.0.RC1"
     exit 1
 fi
 
-echo "Using version: $version"
-echo "Using source directory: $sourcedir"
-echo "Using branch: $branch"
+if [ -z "$branch" ]; then
+    branch="master"
+fi
+
+if [ -z "$sourcedir" ]; then
+    sourcedir="~/cloudstack/"
+fi
+
+if [ -z "$nocommit" ]; then
+    nocommit="false"
+fi
+
+echo "Using version          : $version"
+echo "Using source directory : $sourcedir"
+echo "Using branch           : $branch"
 
 cd $sourcedir
 
-echo 'checking out correct branch'
+echo "checking out correct branch"
 git checkout $branch
 
-echo 'determining current mvn version'
+echo "determining current POM version"
 export currentversion=`mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['`
 echo "found $currentversion"
 
-echo 'setting version numbers'
-mvn versions:set -DnewVersion=$version -P vmware -P developer -P systemvm -P simulator -P baremetal -P ucs -Dnoredist
-mv deps/XenServerJava/pom.xml.versionsBackup deps/XenServerJava/pom.xml
-perl -pi -e "s/$currentversion/$version/" deps/XenServerJava/pom.xml
+echo "setting new version numbers"
+mvn versions:set -DnewVersion=$version -P vmware -P developer -P systemvm -P simulator -Dnoredist versions:commit
+
 perl -pi -e "s/$currentversion/$version/" tools/apidoc/pom.xml
 perl -pi -e "s/$currentversion/$version/" debian/changelog
 perl -pi -e "s/$currentversion/$version/" tools/marvin/setup.py
 perl -pi -e "s/$currentversion/$version/" services/iam/plugin/pom.xml
-perl -pi -e "s/$currentversion/$version/" services/iam/pom.xm
+perl -pi -e "s/$currentversion/$version/" services/iam/pom.xml
 perl -pi -e "s/$currentversion/$version/" services/iam/server/pom.xml
 perl -pi -e "s/$currentversion/$version/" tools/checkstyle/pom.xml
 perl -pi -e "s/$currentversion/$version/" services/console-proxy/plugin/pom.xml
@@ -85,8 +150,10 @@ perl -pi -e "s/Marvin-(.*).tar.gz/Marvin-${version}.tar.gz/" tools/docker/Docker
 
 git clean -f
 
-echo 'commit changes'
-git commit -a -s -m "Updating pom.xml version numbers for release $version"
-export commitsh=`git show HEAD | head -n 1 | cut -d ' ' -f 2`
+if [ "$nocommit" == "false" ]; then
+    echo "commit changes"
+    git commit -a -s -m "Updating pom.xml version numbers for release $version"
+    export commitsh=`git show HEAD | head -n 1 | cut -d ' ' -f 2`
 
-echo "committed as $commitsh"
+    echo "committed as $commitsh"
+fi
diff --git a/utils/src/main/java/com/cloud/maint/Version.java b/utils/src/main/java/com/cloud/maint/Version.java
deleted file mode 100644
index 925806e..0000000
--- a/utils/src/main/java/com/cloud/maint/Version.java
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-package com.cloud.maint;
-
-public class Version {
-    /**
-     * Compares two version strings and see which one is higher version.
-     * @param ver1
-     * @param ver2
-     * @return positive if ver1 is higher.  negative if ver1 is lower; zero if the same.
-     */
-    public static int compare(String ver1, String ver2) {
-        String[] tokens1 = ver1.split("[.]");
-        String[] tokens2 = ver2.split("[.]");
-//        assert(tokens1.length <= tokens2.length);
-
-        int compareLength = Math.min(tokens1.length, tokens2.length);
-        for (int i = 0; i < compareLength; i++) {
-            long version1 = Long.parseLong(tokens1[i]);
-            long version2 = Long.parseLong(tokens2[i]);
-            if (version1 != version2) {
-                return version1 < version2 ? -1 : 1;
-            }
-        }
-
-        if (tokens1.length > tokens2.length) {
-            return 1;
-        } else if (tokens1.length < tokens2.length) {
-            return -1;
-        }
-
-        return 0;
-    }
-
-    public static String trimToPatch(String version) {
-        int index = version.indexOf("-");
-
-        if (index > 0)
-            version = version.substring(0, index);
-
-        String[] tokens = version.split("[.]");
-
-        if (tokens.length < 3)
-            return "0";
-        return tokens[0] + "." + tokens[1] + "." + tokens[2];
-    }
-
-    public static String trimRouterVersion(String version) {
-        String[] tokens = version.split(" ");
-        if (tokens.length >= 3 && tokens[2].matches("[0-9]+(\\.[0-9]+)*")) {
-            return tokens[2];
-        }
-        return "0";
-    }
-
-    public static void main(String[] args) {
-        System.out.println("Result is " + compare(args[0], args[1]));
-    }
-
-}
diff --git a/utils/src/main/java/com/cloud/utils/nicira/nvp/plugin/NiciraNvpApiVersion.java b/utils/src/main/java/com/cloud/utils/nicira/nvp/plugin/NiciraNvpApiVersion.java
index 4dfd4e2..9090de7 100755
--- a/utils/src/main/java/com/cloud/utils/nicira/nvp/plugin/NiciraNvpApiVersion.java
+++ b/utils/src/main/java/com/cloud/utils/nicira/nvp/plugin/NiciraNvpApiVersion.java
@@ -21,7 +21,7 @@ package com.cloud.utils.nicira.nvp.plugin;
 
 import org.apache.log4j.Logger;
 
-import com.cloud.maint.Version;
+import org.apache.cloudstack.utils.CloudStackVersion;
 
 public class NiciraNvpApiVersion {
     private static final Logger s_logger = Logger.getLogger(NiciraNvpApiVersion.class);
@@ -33,8 +33,10 @@ public class NiciraNvpApiVersion {
     }
 
     public static synchronized boolean isApiVersionLowerThan(String apiVersion){
-        if (niciraApiVersion == null) return false;
-        int compare = Version.compare(niciraApiVersion, apiVersion);
+        if (niciraApiVersion == null) {
+            return false;
+        }
+        int compare = CloudStackVersion.compare(niciraApiVersion, apiVersion);
         return (compare < 0);
     }
 
diff --git a/utils/src/main/java/org/apache/cloudstack/utils/CloudStackVersion.java b/utils/src/main/java/org/apache/cloudstack/utils/CloudStackVersion.java
index 035f69e..8bd2b6f 100644
--- a/utils/src/main/java/org/apache/cloudstack/utils/CloudStackVersion.java
+++ b/utils/src/main/java/org/apache/cloudstack/utils/CloudStackVersion.java
@@ -39,16 +39,39 @@ import static org.apache.commons.lang.StringUtils.substringBefore;
  */
 public final class CloudStackVersion implements Comparable<CloudStackVersion> {
 
-    private final static Pattern VERSION_FORMAT = Pattern.compile("(\\d+\\.){2}(\\d+\\.)?\\d+");
+    private final static Pattern NUMBER_VERSION_FORMAT = Pattern.compile("(\\d+\\.){2}(\\d+\\.)?\\d+");
+    private final static Pattern FULL_VERSION_FORMAT = Pattern.compile("(\\d+\\.){2}(\\d+\\.)?\\d+(-[a-zA-Z]+)?(-\\d+)?(-SNAPSHOT)?");
+
+    private final int majorRelease;
+    private final int minorRelease;
+    private final int patchRelease;
+    private final Integer securityRelease;
+
+    private CloudStackVersion(final int majorRelease, final int minorRelease, final int patchRelease, final Integer securityRelease) {
+
+        super();
+
+        checkArgument(majorRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a majorRelease greater than 0.");
+        checkArgument(minorRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a minorRelease greater than 0.");
+        checkArgument(patchRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a patchRelease greater than 0.");
+        checkArgument((securityRelease != null && securityRelease >= 0) || (securityRelease == null),
+                CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a null securityRelease or a non-null value greater than 0.");
+
+        this.majorRelease = majorRelease;
+        this.minorRelease = minorRelease;
+        this.patchRelease = patchRelease;
+        this.securityRelease = securityRelease;
+
+    }
 
     /**
      *
      * Parses a <code>String</code> representation of a version that conforms one of the following
      * formats into a <code>CloudStackVersion</code> instance:
      * <ul>
-     *     <li><code><major version>.<minor version>.<patch release></code></li>
-     *     <li><code><major version>.<minor version>.<patch release>.<security release></code></li>
-     *     <li><code><major version>.<minor version>.<patch release>.<security release>-<any string></code></li>
+     *     <li><code>&lt;major&gt;.&lt;minor&gt;.&lt;patch&gt;.&lt;security&gt;</code></li>
+     *     <li><code>&lt;major&gt;.&lt;minor&gt;.&lt;patch&gt;.&lt;security&gt;.&lt;security&gt;</code></li>
+     *     <li><code>&lt;major&gt;.&lt;minor&gt;.&lt;patch&gt;.&lt;security&gt;.&lt;security&gt;-&lt;any string&gt;</code></li>
      * </ul>
      *
      * If the string contains a suffix that begins with a "-" character, then the "-" and all characters following it
@@ -67,7 +90,7 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
         final String trimmedValue = substringBefore(value, "-");
 
         checkArgument(isNotBlank(trimmedValue), CloudStackVersion.class.getName() + ".parse(String) requires a non-blank value");
-        checkArgument(VERSION_FORMAT.matcher(trimmedValue).matches(), CloudStackVersion.class.getName() + "parse(String) passed " +
+        checkArgument(NUMBER_VERSION_FORMAT.matcher(trimmedValue).matches(), CloudStackVersion.class.getName() + ".parse(String) passed " +
                 value + ", but requires a value in the format of int.int.int(.int)(-<legacy patch>)");
 
         final String[] components = trimmedValue.split("\\.");
@@ -84,39 +107,20 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
 
     }
 
-    private final int majorRelease;
-    private final int minorRelease;
-    private final int patchRelease;
-    private final Integer securityRelease;
-
-    private CloudStackVersion(final int majorRelease, final int minorRelease, final int patchRelease, final Integer securityRelease) {
-
-        super();
-
-        checkArgument(majorRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a majorRelease greater than 0.");
-        checkArgument(minorRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a minorRelease greater than 0.");
-        checkArgument(patchRelease >= 0, CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a patchRelease greater than 0.");
-        checkArgument((securityRelease != null && securityRelease >= 0) || (securityRelease == null),
-                CloudStackVersion.class.getName() + "(int, int, int, Integer) requires a null securityRelease or a non-null value greater than 0.");
-
-        this.majorRelease = majorRelease;
-        this.minorRelease = minorRelease;
-        this.patchRelease = patchRelease;
-        this.securityRelease = securityRelease;
-
-    }
-
-    private static ImmutableList<Integer> normalizeVersionValues(final ImmutableList<Integer> values) {
-
-        checkArgument(values != null);
-        checkArgument(values.size() == 3 || values.size() == 4);
-
-        if (values.size() == 3) {
-            return ImmutableList.<Integer>builder().addAll(values).add(0).build();
-        }
-
-        return values;
-
+    /**
+     * Shortcut method to {@link #parse(String)} and {@link #compareTo(CloudStackVersion)} two versions
+     *
+     * @param version1 the first value to be parsed and compared
+     * @param version2 the second value to be parsed and compared
+     *
+     * @return A value less than zero (0) indicates <code>version1</code> is less than <code>version2</code>.  A value
+     *         equal to zero (0) indicates <code>version1</code> equals <code>version2</code>.  A value greater than zero (0)
+     *         indicates <code>version1</code> is greater than <code>version2</code>.
+     *
+     * @since 4.12.0.0
+     */
+    public static int compare(String version1, String version2) {
+        return parse(version1).compareTo(parse(version2));
     }
 
     /**
@@ -125,7 +129,7 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
      * A couple of notes about the comparison rules for this method:
      * <ul>
      *     <li>Three position versions are normalized to four position versions with the security release being
-     *         defaulted to zero (0).  For example, for the purposes of comparision, <code>4.8.1</code> would be
+     *         defaulted to zero (0).  For example, for the purposes of comparison, <code>4.8.1</code> would be
      *         normalized to <code>4.8.1.0</code> for all comparison operations.</li>
      *     <li>A three position version with a null security release is considered equal to a four position
      *         version number where the major release, minor release, and patch release are the same and the security
@@ -167,6 +171,43 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
     }
 
     /**
+     * Trim full version from router version. Valid versions are:
+     *
+     * <ul>
+     *    <li><code>&lt;major&gt;.&lt;minor&gt;[.&lt;patch&gt;[.&lt;security&gt;]]</li>
+     *    <li><code>&lt;major&gt;.&lt;minor&gt;[.&lt;patch&gt;[.&lt;security&gt;]]-&lt;branding&gt;</li>
+     *    <li><code>&lt;major&gt;.&lt;minor&gt;[.&lt;patch&gt;[.&lt;security&gt;]][-&lt;branding&gt;]-SNAPSHOT</li>
+     *    <li><code>&lt;major&gt;.&lt;minor&gt;[.&lt;patch&gt;[.&lt;security&gt;]][-&lt;branding&gt;]-&lt;epoch timestamp&gt;</li>
+     * </ul>
+     *
+     * @param version to trim
+     *
+     * @return actual trimmed version
+     */
+    public static String trimRouterVersion(String version) {
+        final String[] tokens = version.split(" ");
+
+        if (tokens.length >= 3 && FULL_VERSION_FORMAT.matcher(tokens[2]).matches()) {
+            return tokens[2];
+        }
+
+        return "0";
+    }
+
+    private static ImmutableList<Integer> normalizeVersionValues(final ImmutableList<Integer> values) {
+
+        checkArgument(values != null);
+        checkArgument(values.size() == 3 || values.size() == 4);
+
+        if (values.size() == 3) {
+            return ImmutableList.<Integer>builder().addAll(values).add(0).build();
+        }
+
+        return values;
+
+    }
+
+    /**
      *
      * @return The components of this version as an {@link ImmutableList} in order of major release, minor release,
      * patch release, and security release
@@ -187,6 +228,22 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
 
     }
 
+    public int getMajorRelease() {
+        return majorRelease;
+    }
+
+    public int getMinorRelease() {
+        return minorRelease;
+    }
+
+    public int getPatchRelease() {
+        return patchRelease;
+    }
+
+    public Integer getSecurityRelease() {
+        return securityRelease;
+    }
+
     @Override
     public boolean equals(final Object thatObject) {
 
@@ -215,21 +272,4 @@ public final class CloudStackVersion implements Comparable<CloudStackVersion> {
     public String toString() {
         return Joiner.on(".").join(asList());
     }
-
-    public int getMajorRelease() {
-        return majorRelease;
-    }
-
-    public int getMinorRelease() {
-        return minorRelease;
-    }
-
-    public int getPatchRelease() {
-        return patchRelease;
-    }
-
-    public Integer getSecurityRelease() {
-        return securityRelease;
-    }
-
 }
diff --git a/utils/src/test/java/org/apache/cloudstack/utils/CloudStackVersionTest.java b/utils/src/test/java/org/apache/cloudstack/utils/CloudStackVersionTest.java
index ab576bb..eb7a76a 100644
--- a/utils/src/test/java/org/apache/cloudstack/utils/CloudStackVersionTest.java
+++ b/utils/src/test/java/org/apache/cloudstack/utils/CloudStackVersionTest.java
@@ -31,7 +31,12 @@ import static org.junit.Assert.assertNotNull;
 public final class CloudStackVersionTest {
 
     @Test
-    @DataProvider({ "1.2.3, 1.2.3", "1.2.3.4, 1.2.3.4", "1.2.3-12, 1.2.3", "1.2.3.4-14, 1.2.3.4" })
+    @DataProvider({
+        "1.2.3, 1.2.3",
+        "1.2.3.4, 1.2.3.4",
+        "1.2.3-12, 1.2.3",
+        "1.2.3.4-14, 1.2.3.4"
+    })
     public void testValidParse(final String inputValue, final String expectedVersion) {
         final CloudStackVersion version = CloudStackVersion.parse(inputValue);
         assertNotNull(version);
@@ -39,13 +44,26 @@ public final class CloudStackVersionTest {
     }
 
     @Test(expected = IllegalArgumentException.class)
-    @DataProvider({ "1.2", "1", "1.2.3.4.5", "aaaa", "", "  ", "1.2.3.4.5"})
+    @DataProvider({
+        "1.2",
+        "1",
+        "1.2.3.4.5",
+        "aaaa",
+        "",
+        "  ",
+        "1.2.3.4.5"
+    })
     public void testInvalidParse(final String invalidValue) {
         CloudStackVersion.parse(invalidValue);
     }
 
     @Test
-    @DataProvider({ "1.0.0", "1.0.0.0", "1.2.3", "1.2.3.4" })
+    @DataProvider({
+        "1.0.0",
+        "1.0.0.0",
+        "1.2.3",
+        "1.2.3.4"
+    })
     public void testEquals(final String value) {
 
         final CloudStackVersion version = CloudStackVersion.parse(value);
@@ -62,16 +80,19 @@ public final class CloudStackVersionTest {
 
     @Test
     @DataProvider({
-            "1.0.0.0, 1.0.0.0",
-            "1.0.0, 1.0.0",
-            "1.0.0.0, 1.0.0",
-            "1.0.0-10, 1.0.0-10",
-            "1.0.0-10, 1.0.0",
-            "1.0.0.0, 1.0.0-10",
-            "1.0.0.0, 1.0.0.0-10",
-            "1.0.0-10, 1.0.0-11",
-            "1.0.0-10, 1.0.0.0-14",
-            "1.0.0.0-14, 1.0.0.0-15"
+        "1.0.0.0, 1.0.0.0",
+        "1.0.0, 1.0.0",
+        "1.0.0.0, 1.0.0",
+        "1.0.0-10, 1.0.0-10",
+        "1.0.0-10, 1.0.0",
+        "1.0.0.0, 1.0.0-10",
+        "1.0.0.0, 1.0.0.0-10",
+        "1.0.0-10, 1.0.0-11",
+        "1.0.0-10, 1.0.0.0-14",
+        "1.0.0.0-14, 1.0.0.0-15",
+        "1.0.0.0-SNAPSHOT, 1.0.0.0-SNAPSHOT",
+        "1.0.0.0-branding, 1.0.0.0-branding",
+        "1.0.0.0-1518453362, 1.0.0.0-1519453362"
     })
     public void testEqualCompareTo(final String value, final String thatValue) {
 
@@ -88,21 +109,44 @@ public final class CloudStackVersionTest {
 
     @Test
     @DataProvider({
-            "1.2.3.4, 1.2.3",
-            "1.2.3, 1.0.0.0",
-            "1.2.3.4, 1.0.0",
-            "2.0.0, 1.2.3",
-            "2.0.0, 1.2.3.4",
-            "2.0.0.0, 1.2.3",
-            "2.0.0.0, 1.2.3.4",
-            "2.0.0.0, 1.2.3",
-            "1.3.0, 1.2.3.4",
-            "1.3.0.0, 1.2.3.4",
-            "1.3.0.0, 1.2.3",
-            "1.2.3.4-10, 1.0.0.0-5",
-            "1.2.3-10, 1.0.0-5",
-            "1.2.3.4, 1.0.0.0-5",
-            "1.2.3.4-10, 1.0.0"
+        "1.0.0.0, 1.0.0.0",
+        "1.0.0, 1.0.0",
+        "1.0.0.0, 1.0.0",
+        "1.0.0-10, 1.0.0-10",
+        "1.0.0-10, 1.0.0",
+        "1.0.0.0, 1.0.0-10",
+        "1.0.0.0, 1.0.0.0-10",
+        "1.0.0-10, 1.0.0-11",
+        "1.0.0-10, 1.0.0.0-14",
+        "1.0.0.0-14, 1.0.0.0-15",
+        "1.0.0.0-SNAPSHOT, 1.0.0.0-SNAPSHOT",
+        "1.0.0.0-branding, 1.0.0.0-branding",
+        "1.0.0.0-1518453362, 1.0.0.0-1519453362"
+    })
+    public void testEqualCompareDirect(final String value, final String thatValue) {
+
+        assertEquals(0, CloudStackVersion.compare(value, thatValue));
+        assertEquals(0, CloudStackVersion.compare(thatValue, value));
+
+    }
+
+    @Test
+    @DataProvider({
+        "1.2.3.4, 1.2.3",
+        "1.2.3, 1.0.0.0",
+        "1.2.3.4, 1.0.0",
+        "2.0.0, 1.2.3",
+        "2.0.0, 1.2.3.4",
+        "2.0.0.0, 1.2.3",
+        "2.0.0.0, 1.2.3.4",
+        "2.0.0.0, 1.2.3",
+        "1.3.0, 1.2.3.4",
+        "1.3.0.0, 1.2.3.4",
+        "1.3.0.0, 1.2.3",
+        "1.2.3.4-10, 1.0.0.0-5",
+        "1.2.3-10, 1.0.0-5",
+        "1.2.3.4, 1.0.0.0-5",
+        "1.2.3.4-10, 1.0.0"
     })
     public void testGreaterThanAndLessThanCompareTo(final String value, final String thatValue) {
 
@@ -117,4 +161,47 @@ public final class CloudStackVersionTest {
 
     }
 
+    @Test
+    @DataProvider({
+        "1.2.3.4, 1.2.3",
+        "1.2.3, 1.0.0.0",
+        "1.2.3.4, 1.0.0",
+        "2.0.0, 1.2.3",
+        "2.0.0, 1.2.3.4",
+        "2.0.0.0, 1.2.3",
+        "2.0.0.0, 1.2.3.4",
+        "2.0.0.0, 1.2.3",
+        "1.3.0, 1.2.3.4",
+        "1.3.0.0, 1.2.3.4",
+        "1.3.0.0, 1.2.3",
+        "1.2.3.4-10, 1.0.0.0-5",
+        "1.2.3-10, 1.0.0-5",
+        "1.2.3.4, 1.0.0.0-5",
+        "1.2.3.4-10, 1.0.0"
+    })
+    public void testGreaterThanAndLessThanCompareDirect(final String value, final String thatValue) {
+
+        assertEquals(1, CloudStackVersion.compare(value, thatValue));
+        assertEquals(-1, CloudStackVersion.compare(thatValue, value));
+
+    }
+
+    @Test
+    @DataProvider({
+        "Cloudstack Release 1.2.3 Mon Jan  1 10:10:10 UTC 2018, 1.2.3",
+        "Cloudstack Release 1.2.3.4 Mon Jan  1 10:10:10 UTC 2018, 1.2.3.4",
+        "Cloudstack Release 1.2.3-SNAPSHOT Mon Jan  1 10:10:10 UTC 2018, 1.2.3-SNAPSHOT",
+        "Cloudstack Release 1.2.3.4-SNAPSHOT Mon Jan  1 10:10:10 UTC 2018, 1.2.3.4-SNAPSHOT",
+        "Cloudstack Release 1.2.3.4-1519453362 Mon Jan  1 10:10:10 UTC 2018, 1.2.3.4-1519453362",
+        "Cloudstack Release 1.2.3.4-brnading-SNAPSHOT Mon Jan  1 10:10:10 UTC 2018, 1.2.3.4-brnading-SNAPSHOT",
+        "Cloudstack Release 1.2.3.4-brnading-1519453362 Mon Jan  1 10:10:10 UTC 2018, 1.2.3.4-brnading-1519453362",
+        "Cloudstack Release 1.2 Mon Jan  1 10:10:10 UTC 2018, 0",
+        "Cloudstack Release 1.2-SNAPSHOT Mon Jan  1 10:10:10 UTC 2018, 0",
+        "Cloud stack Release 1.2.3.4 Mon Jan  1 10:10:10 UTC 2018, 0"
+    })
+    public void testTrimRouterVersion(final String value, final String expected) {
+
+        assertEquals(expected, CloudStackVersion.trimRouterVersion(value));
+
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
dahn@apache.org.