Merge "Add pipeline promoting docker images"
diff --git a/build-mirror-image.groovy b/build-mirror-image.groovy
index 8aca89c..793d79d 100644
--- a/build-mirror-image.groovy
+++ b/build-mirror-image.groovy
@@ -144,7 +144,9 @@
salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ['rm -rf /var/lib/cloud/sem/* /var/lib/cloud/instance /var/lib/cloud/instances/*'], null, true)
salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ['cloud-init init'], null, true)
- openstack.runOpenstackCommand("openstack server stop mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
+ retry(3, 5){
+ openstack.runOpenstackCommand("openstack server stop mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
+ }
retry(6, 30){
serverStatus = openstack.runOpenstackCommand("openstack server show --format value -c status mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
@@ -152,12 +154,16 @@
throw new ResourceException("Instance is not ready for image create.")
}
}
- openstack.runOpenstackCommand("openstack server image create --name ${IMAGE_NAME}-${dateTime} --wait mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
+ retry(3, 5){
+ openstack.runOpenstackCommand("openstack server image create --name ${IMAGE_NAME}-${dateTime} --wait mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
+ }
}
stage("Publish image"){
common.infoMsg("Saving image ${IMAGE_NAME}-${dateTime}")
- openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}-${dateTime} ${IMAGE_NAME}-${dateTime}", rcFile, openstackEnv)
+ retry(3, 5){
+ openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}-${dateTime} ${IMAGE_NAME}-${dateTime}", rcFile, openstackEnv)
+ }
sh "md5sum ${IMAGE_NAME}-${dateTime} > ${IMAGE_NAME}-${dateTime}.md5"
common.infoMsg("Uploading image ${IMAGE_NAME}-${dateTime}")
diff --git a/cloud-deploy-pipeline.groovy b/cloud-deploy-pipeline.groovy
index cbb09b7..1b8b5d5 100644
--- a/cloud-deploy-pipeline.groovy
+++ b/cloud-deploy-pipeline.groovy
@@ -400,8 +400,15 @@
}
+ if (common.checkContains('STACK_INSTALL', 'oss')) {
+ stage('Install Oss infra') {
+ orchestrate.installOssInfra(venvPepper)
+ }
+ }
+
if (common.checkContains('STACK_INSTALL', 'cicd')) {
stage('Install Cicd') {
+ orchestrate.installInfra(venvPepper)
orchestrate.installDockerSwarm(venvPepper)
orchestrate.installCicd(venvPepper)
}
@@ -421,6 +428,17 @@
}
}
+ if (common.checkContains('STACK_INSTALL', 'oss')) {
+ stage('Install OSS') {
+ if (!common.checkContains('STACK_INSTALL', 'stacklight')) {
+ // In case if StackLightv2 enabled containers already started
+ orchestrate.installDockerSwarm(venvPepper)
+ salt.enforceState(venvPepper, 'I@docker:swarm:role:master and I@devops_portal:config', 'docker.client', true)
+ }
+ orchestrate.installOss(venvPepper)
+ }
+ }
+
//
// Test
//
diff --git a/docker-mirror-images.groovy b/docker-mirror-images.groovy
index 91a65a6..8f0373c 100644
--- a/docker-mirror-images.groovy
+++ b/docker-mirror-images.groovy
@@ -22,7 +22,7 @@
def imageName = matcher.group(1)
return imageName
}else{
- throw new IllegalFormatException("Wrong format of image name.")
+ throw new IllegalArgumentException("Wrong format of image name.")
}
}
@@ -32,13 +32,18 @@
def creds = common.getPasswordCredentials(TARGET_REGISTRY_CREDENTIALS_ID)
sh "docker login --username=${creds.username} --password=${creds.password.toString()} ${REGISTRY_URL}"
def images = IMAGE_LIST.tokenize('\n')
- def imageName
+ def imageName, imagePath, targetRegistry, imageArray
for (image in images){
- sh "echo ${image}"
- imageName = getImageName(image)
- sh "docker pull ${image}"
- sh "docker tag ${image} ${TARGET_REGISTRY}/${imageName}:${IMAGE_TAG}"
- sh "docker push ${TARGET_REGISTRY}/${imageName}:${IMAGE_TAG}"
+ if(image.trim().indexOf(' ') == -1){
+ throw new IllegalArgumentException("Wrong format of image and target repository input")
+ }
+ imageArray = image.trim().tokenize(' ')
+ imagePath = imageArray[0]
+ targetRegistry = imageArray[1]
+ imageName = getImageName(imagePath)
+ sh """docker pull ${imagePath}
+ docker tag ${imagePath} ${targetRegistry}/${imageName}:${IMAGE_TAG}
+ docker push ${targetRegistry}/${imageName}:${IMAGE_TAG}"""
}
}
} catch (Throwable e) {
diff --git a/opencontrail-upgrade.groovy b/opencontrail-upgrade.groovy
index 805b856..83f17ee 100644
--- a/opencontrail-upgrade.groovy
+++ b/opencontrail-upgrade.groovy
@@ -39,6 +39,10 @@
out = salt.runSaltCommand(pepperEnv, 'local', ['expression': target, 'type': 'compound'], command, null, args, null)
salt.printSaltCommandResult(out)
+ // if Error occured - throw exception
+ if (out.toString().contains('E: ')) {
+ throw new Exception("Command execution failed")
+ }
// wait until $check is in correct state
if ( check == "nodetool status" ) {
salt.commandStatus(pepperEnv, target, check, 'Status=Up')
@@ -81,8 +85,7 @@
try {
salt.cmdRun(pepperEnv, 'I@opencontrail:control', "su root -c '/usr/local/bin/zookeeper-backup-runner.sh'")
} catch (Exception er) {
- common.errorMsg('Zookeeper failed to backup. Please fix it before continuing.')
- return
+ throw new Exception('Zookeeper failed to backup. Please fix it before continuing.')
}
salt.enforceState(pepperEnv, 'I@cassandra:backup:server', 'cassandra.backup')
@@ -91,8 +94,7 @@
try {
salt.cmdRun(pepperEnv, 'I@cassandra:backup:client', "su root -c '/usr/local/bin/cassandra-backup-runner-call.sh'")
} catch (Exception er) {
- common.errorMsg('Cassandra failed to backup. Please fix it before continuing.')
- return
+ throw new Exception('Cassandra failed to backup. Please fix it before continuing.')
}
args = 'apt install contrail-database -y;'
diff --git a/release-mcp-version.groovy b/release-mcp-version.groovy
new file mode 100644
index 0000000..4abaf5d
--- /dev/null
+++ b/release-mcp-version.groovy
@@ -0,0 +1,95 @@
+/**
+ *
+ * Release MCP
+ *
+ * Expected parameters:
+ * MCP_VERSION
+ * RELEASE_APTLY
+ * RELEASE_DOCKER
+ * RELEASE_GIT
+ * APTLY_URL
+ * APTLY_STORAGES
+ * DOCKER_CREDENTIALS
+ * DOCKER_URL
+ * DOCKER_IMAGES
+ * GIT_CREDENTIALS
+ * GIT_REPO_LIST
+ */
+
+def common = new com.mirantis.mk.Common()
+
+def triggerAptlyPromoteJob(aptlyUrl, components, diffOnly, dumpPublish, packages, recreate, source, storages, target){
+ build job: "aptly-promote-all-testing-stable", parameters: [
+ [$class: 'StringParameterValue', name: 'APTLY_URL', value: aptlyUrl],
+ [$class: 'StringParameterValue', name: 'COMPONENTS', value: components],
+ [$class: 'BooleanParameterValue', name: 'DIFF_ONLY', value: diffOnly],
+ [$class: 'BooleanParameterValue', name: 'DUMP_PUBLISH', value: dumpPublish],
+ [$class: 'StringParameterValue', name: 'PACKAGES', value: packages],
+ [$class: 'BooleanParameterValue', name: 'RECREATE', value: recreate],
+ [$class: 'StringParameterValue', name: 'SOURCE', value: source],
+ [$class: 'StringParameterValue', name: 'STORAGES', value: storages],
+ [$class: 'StringParameterValue', name: 'TARGET', value: target]
+ ]
+}
+
+def triggerDockerMirrorJob(dockerCredentials, dockerRegistryUrl, dockerRegistry, mcpVersion, imageList) {
+ build job: "mirror-docker-images", parameters: [
+ [$class: 'StringParameterValue', name: 'TARGET_REGISTRY_CREDENTIALS_ID', value: dockerCredentials],
+ [$class: 'StringParameterValue', name: 'REGISTRY_URL', value: dockerRegistryUrl],
+ [$class: 'StringParameterValue', name: 'TARGET_REGISTRY', value: dockerRegistry],
+ [$class: 'StringParameterValue', name: 'IMAGE_TAG', value: mcpVersion],
+ [$class: 'StringParameterValue', name: 'IMAGE_LIST', value: imageList]
+ ]
+}
+
+def gitRepoAddTag(repoURL, repoName, tag, credentials, ref = "HEAD"){
+ git.checkoutGitRepository(repoName, repoURL, "master")
+ dir(repoName) {
+ def checkTag = sh "git tag -l ${tag}"
+ if(checkTag == ""){
+ sh 'git tag -a ${tag} ${ref} -m "Release of mcp version ${tag}"'
+ }
+ sshagent([credentials]) {
+ sh "git push origin master ${tag}"
+ }
+ }
+}
+
+node() {
+ try {
+ if(RELEASE_APTLY.toBoolean())
+ {
+ stage("Release Aptly"){
+ triggerAptlyPromoteJob(APTLY_URL, 'all', false, true, 'all', false, '(.*)/testing', APTLY_STORAGES, '{0}/stable')
+ triggerAptlyPromoteJob(APTLY_URL, 'all', false, true, 'all', false, '(.*)/stable', APTLY_STORAGES, '{0}/${MCP_VERSION}')
+ }
+ }
+ if(RELEASE_DOCKER.toBoolean())
+ {
+ stage("Release Docker"){
+ triggerDockerMirrorJob(DOCKER_CREDENTIALS, DOCKER_URL, MCP_VERSION, DOCKER_IMAGES)
+ }
+ }
+ if(RELEASE_GIT.toBoolean())
+ {
+ stage("Release Git"){
+ def repos = GIT_REPO_LIST.tokenize('\n')
+ def repoUrl, repoName, repoCommit, repoArray
+ for (repo in repos){
+ if(repo.trim().indexOf(' ') == -1){
+ throw new IllegalArgumentException("Wrong format of repository and commit input")
+ }
+ repoArray = repo.trim().tokenize(' ')
+ repoName = repoArray[0]
+ repoUrl = repoArray[1]
+ repoCommit = repoArray[2]
+ gitRepoAddTag(repoUrl, repoName, MCP_VERSION, GIT_CREDENTIALS, repoCommit)
+ }
+ }
+ }
+ } catch (Throwable e) {
+ // If there was an error or exception thrown, the build failed
+ currentBuild.result = "FAILURE"
+ throw e
+ }
+}
\ No newline at end of file
diff --git a/update-mirror-image.groovy b/update-mirror-image.groovy
index 0e28a4e..238dbb2 100644
--- a/update-mirror-image.groovy
+++ b/update-mirror-image.groovy
@@ -2,8 +2,19 @@
* Update mirror image
*
* Expected parameters:
- * SALT_MASTER_CREDENTIALS Credentials to the Salt API.
- * SALT_MASTER_URL Full Salt API address [https://10.10.10.1:8000].
+ * SALT_MASTER_CREDENTIALS Credentials to the Salt API.
+ * SALT_MASTER_URL Full Salt API address [https://10.10.10.1:8000].
+ * UPDATE_APTLY Option to update Aptly
+ * UPDATE_APTLY_MIRRORS List of mirrors
+ * PUBLISH_APTLY Publish aptly snapshots
+ * RECREATE_APTLY_PUBLISHES Option to recreate Aptly publishes separated by comma
+ * FORCE_OVERWRITE_APTLY_PUBLISHES Option to force overwrite existing packages while publishing
+ * CLEANUP_APTLY Option to cleanup old Aptly snapshots
+ * UPDATE_DOCKER_REGISTRY Option to update Docker Registry
+ * CLEANUP_DOCKER_CACHE Option to cleanup locally cached Docker images
+ * UPDATE_PYPI Option to update Python Packages
+ * UPDATE_GIT Option to update Git repositories
+ * UPDATE_IMAGES Option to update VM images
*
**/
@@ -14,35 +25,75 @@
node() {
try {
-
python.setupPepperVirtualenv(venvPepper, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
- stage('Update Aptly packages'){
- common.infoMsg("Updating Aptly packages.")
- salt.enforceState(venvPepper, 'apt*', ['aptly'], true)
- salt.runSaltProcessStep(venvPepper, 'apt*', 'cmd.run', ['/srv/scripts/aptly-update.sh'], null, true)
- }
+ if(UPDATE_APTLY.toBoolean()){
+ stage('Update Aptly mirrors'){
+ def aptlyMirrorArgs = "-s -v"
- stage('Update Docker images'){
- common.infoMsg("Updating Docker images.")
- salt.enforceState(venvPepper, 'apt*', ['docker.client.registry'], true)
- }
+ salt.enforceState(venvPepper, '*apt*', ['aptly.server'], true)
+ sleep(10)
- stage('Update PyPi packages'){
- common.infoMsg("Updating PyPi packages.")
- salt.runSaltProcessStep(venvPepper, 'apt*', 'cmd.run', ['pip2pi /srv/pypi_mirror/packages/ -r /srv/pypi_mirror/requirements.txt'], null, true)
+ if(UPDATE_APTLY_MIRRORS != ""){
+ common.infoMsg("Updating List of Aptly mirrors.")
+ UPDATE_APTLY_MIRRORS = UPDATE_APTLY_MIRRORS.replaceAll("\\s","")
+ def mirrors = UPDATE_APTLY_MIRRORS.tokenize(",")
+ for(mirror in mirrors){
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_mirror_update.sh', "args=\"${aptlyMirrorArgs} -m ${mirror}\"", 'runas=aptly'], null, true)
+ }
+ }
+ else{
+ common.infoMsg("Updating all Aptly mirrors.")
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_mirror_update.sh', "args=\"${aptlyMirrorArgs}\"", 'runas=aptly'], null, true)
+ }
+ }
}
+ if(PUBLISH_APTLY.toBoolean()){
+ def aptlyPublishArgs = "-av"
- stage('Update Git repositories'){
- common.infoMsg("Updating Git repositories.")
- salt.enforceState(venvPepper, 'apt*', ['git.server'], true)
+ common.infoMsg("Publishing all Aptly snapshots.")
+
+ salt.enforceState(venvPepper, '*apt*', ['aptly.publisher'], true)
+ sleep(10)
+
+ if(CLEANUP_APTLY.toBoolean()){
+ aptlyPublishArgs += "c"
+ }
+ if(RECREATE_APTLY_PUBLISHES.toBoolean()){
+ aptlyPublishArgs += "r"
+ }
+ if(FORCE_OVERWRITE_APTLY_PUBLISHES.toBoolean()){
+ aptlyPublishArgs += "f"
+ }
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_publish_update.sh', "args=\"${aptlyPublishArgs}\"", 'runas=aptly'], null, true)
}
-
- stage('Update VM images'){
- common.infoMsg("Updating VM images.")
- salt.runSaltProcessStep(venvPepper, 'apt*', 'cmd.run', ['/srv/scripts/update-images.sh'], null, true)
+ if(UPDATE_DOCKER_REGISTRY.toBoolean()){
+ stage('Update Docker images'){
+ common.infoMsg("Updating Docker images.")
+ salt.enforceState(venvPepper, '*apt*', ['docker.client.registry'], true)
+ if(CLEANUP_DOCKER_CACHE.toBoolean()){
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ['docker system prune --all --force'], null, true)
+ }
+ }
}
-
+ if(UPDATE_PYPI.toBoolean()){
+ stage('Update PyPi packages'){
+ common.infoMsg("Updating PyPi packages.")
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ['pip2pi /srv/pypi_mirror/packages/ -r /srv/pypi_mirror/requirements.txt'], null, true)
+ }
+ }
+ if(UPDATE_GIT.toBoolean()){
+ stage('Update Git repositories'){
+ common.infoMsg("Updating Git repositories.")
+ salt.enforceState(venvPepper, '*apt*', ['git.server'], true)
+ }
+ }
+ if(UPDATE_IMAGES.toBoolean()){
+ stage('Update VM images'){
+ common.infoMsg("Updating VM images.")
+ salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ['/srv/scripts/update-images.sh'], null, true)
+ }
+ }
} catch (Throwable e) {
// If there was an error or exception thrown, the build failed
currentBuild.result = "FAILURE"
diff --git a/validate-cloud.groovy b/validate-cloud.groovy
index 6159a96..f1a4ab1 100644
--- a/validate-cloud.groovy
+++ b/validate-cloud.groovy
@@ -27,6 +27,8 @@
* RALLY_FLAVOR The name of the flavor for Rally image
* RALLY_CONFIG_REPO Git repository with files for Rally
* RALLY_CONFIG_BRANCH Git branch which will be used during the checkout
+ * RALLY_SCENARIOS Path to file or directory with rally scenarios
+ * RALLY_TASK_ARGS_FILE Path to file with rally tests arguments
* TEST_K8S_API_SERVER Kubernetes API address
* TEST_K8S_CONFORMANCE_IMAGE Path to docker image with conformance e2e tests
* TEST_K8S_NODE Kubernetes node to run tests from
@@ -71,7 +73,7 @@
"rally_image=${RALLY_IMAGE}",
"rally_flavor=${RALLY_FLAVOR}",
"availability_zone=${AVAILABILITY_ZONE}"]
- validate.runRallyTests(pepperEnv, TARGET_NODE, TEST_IMAGE, artifacts_dir, RALLY_CONFIG_REPO, RALLY_CONFIG_BRANCH, rally_variables)
+ validate.runRallyTests(pepperEnv, TARGET_NODE, TEST_IMAGE, artifacts_dir, RALLY_CONFIG_REPO, RALLY_CONFIG_BRANCH, RALLY_SCENARIOS, RALLY_TASK_ARGS_FILE, rally_variables)
} else {
common.infoMsg("Skipping Rally tests")
}