Пример скрипта деплоя.
Задача скрипта – сохранить результаты билда в Artifactory и деплоить из Artifactory на хост с JBoss.
Из “особенностей” – результатом билда являются два *.ear
архива разных типов:
${GIT_COMMIT}-${VERSION}-unlock-service.ear
– бекенд из одного репозитория;${GIT_COMMIT}-${VERSION}-unlock-ui.ear
– фронтенд из второго репозитория.
${GIT_COMMIT}
грепается из git log
, ${VERSION}
– из файла build.gradle
, в котором девелоперы устанавливают версию.
В Artifactory они сохраняются в два разных каталога.
При деплое из Artifactory на хост – по умолчанию выбирается последний модифицированный артефакт из репозитория (?lastModified) – но можно добавить переменную $DEPLOY_VERSION
в билд Jenkins-а и указать имя артефакта для деплоя.
Собственно скрипт:
#!/usr/bin/env python from __future__ import with_statement import os import subprocess import re import requests import argparse import json from fabric.api import run, env, put, sudo, hide # hate globals jfrog_url = 'https://project.artifactoryonline.com/project/' jfrog_api = 'api/storage' jfrog_repo = 'project-releases-local' jfrog_dir = 'repo' jfrog_user = 'username' jfrog_pswd = 'password' def getopts(): # e.g. /var/lib/jenkins/jobs/Project.UI.Build/workspace/ jenkins_home = os.environ['WORKSPACE'] parser = argparse.ArgumentParser() parser.add_argument('-t', '--type', action='store', help='"UI" or "Service" to deploy to Artifactory or JBoss instance') parser.add_argument('-a', '--artifactory', action='store_true', help='Deploy build results to Artifactory') parser.add_argument('-j', '--jboss', action='store_true', help='Deploy build results to JBoss host') parser.add_argument('-H', '--host', action='store', help='JBoss host to deploy to.') parser.add_argument('-T', '--test', action='store_true', help='Test functions option. Use it to run new functionality.') res = parser.parse_args() if res.type == 'UI': if res.artifactory: artifact_path = os.path.join(jenkins_home, 'unlock-ear', 'build', 'libs') artifact_to_art = versioning(res.type, artifact_path) + 'unlock-ui.ear' jfrog_repo_type = 'ui' elif res.type == 'Service': if res.artifactory: artifact_path = os.path.join(jenkins_home, 'unlock-service-ear', 'build', 'libs') artifact_to_art = versioning(res.type, artifact_path) + 'unlock-service.ear' jfrog_repo_type = 'service' else: print ('ERROR: Unknown deploy type. Please set "UI" or "Service". Exit.') exit(1) if res.artifactory: deploy_to_art(res.type, jfrog_repo_type, artifact_path, artifact_to_art) if res.jboss: deploy_to_env(res.type, res.host, jfrog_repo_type) if res.test: getlast(res.type, jfrog_repo_type) def versioning(res_type, artifact_path): # "1.0.0-SNAPSHOT" will be parsed from here # if res_type == 'UI': gradlefile = 'build.gradle' to_grab = 'version ' elif res_type == 'Service': gradlefile = os.path.join('unlock-service-ear', 'build.gradle') to_grab = 'version = ' else: print('ERROR: unknown res_type! Exit.n') exit(1) print('Gradlefile: {}nTo Grab: {}n'.format(gradlefile, to_grab)) if os.path.isdir('.git'): proc = subprocess.Popen('git log | head -n 1', shell=True, stdout=subprocess.PIPE) commitID = re.sub('commit ', '', proc.stdout.read())[0:7] else: print('ERROR: No .git dir found. Exit.n') exit(1) try: with open(gradlefile, 'r') as versionfile: for line in versionfile: if re.search('version', line): # grab 1.0.0-SNAPSHOT from build.gradle file version = re.sub(''', '', re.sub(to_grab, '', line)).rstrip() print('VERSION: {}'.format(version)) # to grab only first occurrence break except IOError: print('ERROR: no {} file found. Exit.n'.format(gradlefile)) exit(1) arch = (commitID + '-' + version + '-') return arch def deploy_to_art(res_type, jfrog_repo_type, artifact_path, artifact_to_art): # i.e. URL: # https://project.artifactoryonline.com/project/project-releases-local/repo/unlock-ui-0.0.1-SNAPSHOT.ear # for artifact: # unlock-ui-0.0.1-SNAPSHOT.ear deployurl = os.path.join(jfrog_url, jfrog_repo, jfrog_dir, jfrog_repo_type, artifact_to_art) if os.path.isfile(os.path.join(artifact_path, artifact_to_art)): print ('n{} artifact found in {}'.format(res_type, artifact_to_art)) print ('nExecuting deploy {} to {}.'.format(artifact_to_art, deployurl)) os.chdir(artifact_path) print ('nWorking now in {}.nnArtifacts ready to deployment:n '.format(artifact_path)) content = os.listdir('.') for f in content: print ('{}'.format(f)) with open(artifact_to_art, 'rb') as inartifact: data_put = requests.put(deployurl, auth=(jfrog_user, jfrog_pswd), data=inartifact) data_put.raise_for_status() print ('nResult code: {}'.format(data_put.status_code)) print ('n{}n'.format(data_put.text)) else: print ('nERROR: {} artifact not found in {}! Exit.n'.format(res_type, artifact_to_art)) exit(1) def getlast(res_type, jfrog_repo_type): try: custom_artifact_name = os.environ['DEPLOY_VERSION'] custom_artifact_url = os.path.join(jfrog_url, jfrog_repo, jfrog_dir, jfrog_repo_type, custom_artifact_name) print('nATTENTION: Custom artifact name used for deploy: {}n'.format(custom_artifact_name)) return [custom_artifact_url, custom_artifact_name] except KeyError: artifact_url = os.path.join(jfrog_url, jfrog_api, jfrog_repo, jfrog_dir, jfrog_repo_type + '?lastModified') data_last = requests.get(artifact_url, auth=(jfrog_user, jfrog_pswd)) json_data = json.loads(data_last.text) last_artifact_api_url = json_data['uri'] # last_artifact_api_url return URL to artifact JSON data # parse downloadUri from here geturl = requests.get(last_artifact_api_url, auth=(jfrog_user, jfrog_pswd)) urldata = json.loads(geturl.text) last_artifact_url = urldata['downloadUri'] # i.e.a1ea78b-1.0.0-SNAPSHOT-unlock-ui.ear last_artifact_name = json_data['uri'].rsplit('/')[-1] # return value with full URL to latest modified artifact in selected directory # from jfrog_repo_type variable - "repo/ui" or "repo/service" # URL example # https://project.artifactoryonline.com/project/api/storage/project-releases-local/repo/ui/a1ea78b-1.0.0-SNAPSHOT-unlock-ui.ear return [last_artifact_url, last_artifact_name] def deploy_to_env(res_type, host, jfrog_repo_type): print ('nDeploying to {}'.format(host)) env.host_string = host env.key_filename = [os.path.join('.ssh', 'id_rsa')] env.user = 'knife' env.project_root = os.path.join(os.sep, 'opt', 'jboss', 'standalone', 'deployments') artifact_to_art = getlast(res_type, jfrog_repo_type)[1] # Commands list if res_type == 'UI': cleanup_file_mask = '*-unlock-ui.ear' elif res_type == 'Service': cleanup_file_mask = '*-unlock-service.ear' # 95c25ba-1.0.0-SNAPSHOT-unlock-service.ear ##cleanup = ('if test -e {0}; then ' ## 'rm -v {0};' ## 'else echo -e "No file found {0}, skipping.";' ## 'fi'.format(os.path.join(env.project_root, artifact_to_art))) cleanup = ('if test -e {0};' 'then rm -v {0};' 'else echo -e "No file found {0}, skipping.";' 'fi'.format(os.path.join(env.project_root, cleanup_file_mask))) # {0} /opt/jboss/standalone/deployments # {1} jfrog_user # {2} jfrog_pswd # {3} full URL to artifact upload = ('cd {0} && wget --user {1} --password={2} {3}'.format( os.path.join(env.project_root), jfrog_user, jfrog_pswd, # os.path.join(jfrog_url, jfrog_repo, jfrog_dir, artifact_to_art), getlast(res_type, jfrog_repo_type)[0] )) chown = ('chown jboss:jboss {}'.format(os.path.join(env.project_root, artifact_to_art))) getcontent = ('ls -l {}'.format(os.path.join(env.project_root, artifact_to_art))) with hide('output', 'running'): print ('nRemoving outdated data:n') removed = sudo(cleanup) print ('{}n'.format(removed)) print ('Uploading {} to {} in to {}...n'.format(os.path.join(jfrog_url, jfrog_repo, jfrog_dir, artifact_to_art), host, os.path.join(env.project_root, artifact_to_art))) sudo(upload) print ("Chown {} to JBoss's user...n".format(os.path.join(env.project_root, artifact_to_art))) sudo(chown) print ('Done:n') ch = run(getcontent) print ('{}n'.format(ch)) if __name__ == "__main__": getopts()
Вызов скрипта в Jenkins-е:
И пример деплоя результатов UI билда в Artifactory:
... [workspace] $ /bin/sh -xe /tmp/hudson2349366895544039566.sh + python ci/deploy.py -a -t UI Gradlefile: build.gradle To Grab: version VERSION: 1.0.0-SNAPSHOT UI artifact found in f50500e-1.0.0-SNAPSHOT-unlock-ui.ear Executing deploy f50500e-1.0.0-SNAPSHOT-unlock-ui.ear to https://project.artifactoryonline.com/project/project-releases-local/repo/ui/f50500e-1.0.0-SNAPSHOT-unlock-ui.ear. Working now in /var/lib/jenkins/jobs/Project.UI.Build/workspace/unlock-ear/build/libs. Artifacts ready to deployment: f50500e-1.0.0-SNAPSHOT-unlock-ui.ear Result code: 201 { "repo" : "project-releases-local", "path" : "/bub/ui/f50500e-1.0.0-SNAPSHOT-unlock-ui.ear", "created" : "2016-01-22T15:04:23.536Z", "createdBy" : "username", "downloadUri" : "https://project.artifactoryonline.com/project/project-releases-local/repo/ui/f50500e-1.0.0-SNAPSHOT-unlock-ui.ear", "mimeType" : "application/java-archive", "size" : "11318654", "checksums" : { "sha1" : "6f0f567f609578974245d7226bc87784d7b35edd", "md5" : "a4c899f08c1017a81fbaa9c62ebbd6e5" }, "originalChecksums" : { }, "uri" : "https://project.artifactoryonline.com/project/project-releases-local/repo/ui/f50500e-1.0.0-SNAPSHOT-unlock-ui.ear" } Triggering projects: Project.UI.Deploy.VMD Finished: SUCCESS