services/jenkins-master/scripts/jenkins_sync_config.py (72 lines of code) (raw):

#!/usr/bin/env python3 # 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. # -*- coding: utf-8 -*- # This script synchronizes the local config with the running configuration on a jenkins master server import argparse import glob import os import re import shutil from distutils.dir_util import copy_tree from tempfile import TemporaryDirectory from jenkins_config_templating import execute_config_templating, read_symlink_entries BASH_SCRIPT_JENKINS_TO_TEMP = \ 'ssh-keygen -R {}; ssh -C ubuntu@{} "bash -s" <<EOS \n' \ 'sudo rm -rf /home/ubuntu/jenkins; mkdir -p /home/ubuntu/jenkins; \n' \ 'sudo cp -RP --verbose /var/lib/jenkins/* /home/ubuntu/jenkins \n' \ 'sudo chown -R ubuntu.ubuntu /home/ubuntu/jenkins; \n' \ 'find /home/ubuntu/jenkins/ -type l -delete; \n' \ 'EOS' BASH_SCRIPT_DOWNLOAD_TEMP = 'rsync --delete -zvaP ubuntu@{}:jenkins/ {}' BASH_SCRIPT_SYNC_LOCAL = 'rsync --delete -zvaP {}/* {}' def main(): parser = argparse.ArgumentParser() parser.add_argument('-jd', '--jenkinsdir', help='Location of the jenkins directory', type=str) parser.add_argument('-vf', '--varfile', help='Location of the variable file', type=str) parser.add_argument('-sf', '--symlinkfile', help='Location of the symlink file', type=str) parser.add_argument('-sd', '--secretsdir', help='Location of the directory containing secrets', type=str) parser.add_argument('-tf', '--tfvarsfile', help='Location of the terraform variable file', type=str) parser.add_argument('-m', '--mode', help='"download" or "upload" config', type=str) args = parser.parse_args() jenkins_sync_config(args.mode, args.jenkinsdir, args.varfile, args.symlinkfile, args.secretsdir, args.tfvarsfile) def jenkins_sync_config(mode, jenkins_dir, var_file, symlink_file, secrets_dir, tfvars_file): # secret_entries = read_secret_entires(var_file) #TODO: Verify no new secrets have been downloaded symlink_config = read_symlink_entries(symlink_file) jenkins_address = 'jenkins.' + _get_tfvars_entry(tfvars_file, 'domain') with TemporaryDirectory() as temp_dir: if mode == 'download': # Copy config to temp dir on jenkins master to avoid permission issues due to owner being jenkins while # rsync is logging in as ubuntu. We're using bash scripts instead of an SSH client because all python # libraries for SSH usage are having trouble when we supply a custom rsa key instead ouf using id_rsa # TODO: Use proper SSH client bash_jenkins_to_temp_cmd = BASH_SCRIPT_JENKINS_TO_TEMP.format(jenkins_address, jenkins_address) os.system(bash_jenkins_to_temp_cmd) # Copy old jenkins to local temp dir to allow rsync and thus speed up the download process due to diff copy_tree(jenkins_dir, temp_dir) bash_jenkins_download_cmd = BASH_SCRIPT_DOWNLOAD_TEMP.format(jenkins_address, temp_dir) os.system(bash_jenkins_download_cmd) # Delete state files. Symlinks are already deleted before config is downloaded, but there might be new dirs # which were not symlinked yet. _delete_state_files(symlink_config, temp_dir) # Remove secrets according to secret config execute_config_templating(var_file, secrets_dir, temp_dir, 'remove', update_secrets=True) # TODO Optional: Verify no new secrets have been downloaded # Move new config to configdir bash_sync_local_cmd = BASH_SCRIPT_SYNC_LOCAL.format(temp_dir, jenkins_dir) os.system(bash_sync_local_cmd) else: raise ValueError('Mode {} not supported'.format(mode)) def _delete_state_files(symlink_config, jenkins_dir): for symlink_entry in symlink_config: result_paths = glob.glob(os.path.join(jenkins_dir, symlink_entry.filepath)) for path in result_paths: if symlink_entry.is_dir: shutil.rmtree(path) else: os.remove(path) def _get_tfvars_entry(tfvars_file, key): # This is just a hack because I don't want to spend the time to write an entire parser for the .tfvars format with open(tfvars_file, 'r') as fp: for line in fp: if line.startswith(key): result = re.search('"(.*)"', line).group(1) return result raise ValueError('Could not find {} in {}'.format(key, tfvars_file)) if __name__ == '__main__': main()