#!/usr/bin/env python from __future__ import print_function, unicode_literals # We require Python 2.6 or later import sys import argparse import io import os import random import re import string import subprocess if sys.version_info[:3][0] == 2: import ConfigParser as configparser import StringIO as io if sys.version_info[:3][0] == 3: import configparser as configparser import io as io # prepare base dir base_dir = os.path.dirname(os.path.abspath(__file__)) parser = argparse.ArgumentParser(description='Generate *.cm.yaml') parser.add_argument('-f', default=os.path.join(base_dir, '../harbor.cfg'), dest='config_file', help='[Optional] path of harbor config file') parser.add_argument('-k', default='', dest='private_key', help='[Optional] path of harbor https private key(pem)') parser.add_argument('-c', default='', dest='cert', help='[Optional] harbor path of https cert(pem)') parser.add_argument('-j', default='', dest='jobservice_secret', help="[Optional] path of harbor secret key(16 characters)") parser.add_argument('-s', default='', dest='secret_key', help="[Optional] path of harbor secret key(16 characters)") args = parser.parse_args() # read config file config_str = '' if os.path.isfile(args.config_file): with open(args.config_file) as conf: config_str = conf.read() else: raise Exception('Error: No such file(' + args.config_file + ')') config_str = '[harbor]\n' + config_str fp = io.StringIO() fp.write(config_str) fp.seek(0, os.SEEK_SET) config = configparser.RawConfigParser() config.readfp(fp) def get_config(key): """get value by key """ if config.has_option('harbor', key): return config.get('harbor', key) print('Warning: Key(' + key + ') is not existing. Use empty string as default') return '' def set_config(key, value): """set key & value """ config.set('harbor', key, value) # relative path with config file def rel_path(p): if p[0] == '/': return p config_path = args.config_file if config_path[0] != '/': config_path = os.path.join(os.getcwd(), config_path) return os.path.join(os.path.dirname(config_path), p) # path of private key pk_path = args.private_key if pk_path == '': pk_path = get_config('ssl_cert_key') if pk_path != '': pk_path = rel_path(pk_path) # path of cert cert_path = args.cert if cert_path == '': cert_path = get_config('ssl_cert') if cert_path != '': cert_path = rel_path(cert_path) # validate if get_config('ui_url_protocol') == 'https': if pk_path == '': raise Exception("Error: The protocol is https but attribute ssl_cert_key is not set") if cert_path == '': raise Exception("Error: The protocol is https but attribute ssl_cert is not set") else: pk_path = '' cert_path = '' # read jobservice secret key if args.jobservice_secret != '': if os.path.isfile(args.jobservice_secret): key = '' with open(args.jobservice_secret, 'r') as skey: key = skey.read() if len(key) != 16: raise Exception('Error: The length of secret key has to be 16 characters!') set_config('jobservice_secret', key) else: set_config('jobservice_secret', ''.join(random.choice( string.ascii_letters + string.digits) for i in range(16))) # read ldap secret key if args.secret_key != '': if os.path.isfile(args.secret_key): key = '' with open(args.secret_key, 'r') as skey: key = skey.read() if len(key) != 16: raise Exception('Error: The length of secret key has to be 16 characters!') set_config('secret_key', key) else: set_config('secret_key', ''.join(random.choice( string.ascii_letters + string.digits) for i in range(16))) # read https pkey & cert if pk_path != '': if os.path.isfile(pk_path): with open(pk_path, 'r') as pkey: set_config('https_pkey', pkey.read()) else: raise Exception('Error: https private key is not existing') else: set_config('https_pkey', 'USE_HTTP') if cert_path != '': if os.path.isfile(cert_path): with open(cert_path, 'r') as cert: set_config('https_cert', cert.read()) else: raise Exception('Error: https cert is not existing') else: set_config('https_cert', 'USE_HTTP') # add configs set_config('ui_url', get_config('ui_url_protocol') + '://' + get_config('hostname')) set_config('ui_secret', ''.join(random.choice( string.ascii_letters + string.digits) for i in range(16))) # generate auth pkey & cert with open(os.devnull, 'w') as devnull: openssl = subprocess.call(['which','openssl'], stdout=devnull, stderr=devnull) if openssl == 0: pkey = subprocess.check_output(['openssl','genrsa','4096'], stderr=devnull) empty_subj = "/C=/ST=/L=/O=/CN=/" openssl = subprocess.Popen(['openssl', 'req', '-new', '-x509', '-key', '/dev/stdin', '-days', '3650', '-subj', empty_subj], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=devnull) cert = openssl.communicate(input=pkey)[0] set_config('auth_pkey', pkey.decode()) set_config('auth_cert', cert.decode()) else: set_config('auth_pkey', 'NEED_SET') set_config('auth_cert', 'NEED_SET') print('Warning: auth_pkey and auth_cert cannot be generated automatically without openssl. Please set it manually') variable = re.compile(r'{{.+?}}') detail = re.compile(r'((\d+) )?([a-zA-Z_0-9-]+)') def render_template(tmpl): """render template replace {{(number of leading spaces)name}} with config examples: config: hostname='test\ntest' {{hostname}} -> 'test\ntest' {{4 hostname}} -> 'test\n test' """ matches = variable.findall(tmpl) for match in matches: segs = detail.search(match) if segs.group() == '': raise Exception('Error: Invalid template item(' + match + ')') value = get_config(segs.group(3)) spaces = segs.group(2) if spaces != '' and spaces != None: leading = ''.join(' ' for i in range(int(spaces))) value = str(value).replace('\n', '\n' + leading) tmpl = tmpl.replace(match, value) return tmpl def generate_template(tmpl, dest): """generate file """ with open(tmpl) as tmpl: with open(dest, 'w') as dest: dest.write(render_template(tmpl.read())) template_dir = os.path.join(base_dir, 'templates') output_dir = base_dir generate_template(os.path.join(template_dir, 'ui.cm.yaml'), os.path.join(output_dir, 'ui/ui.cm.yaml')) generate_template(os.path.join(template_dir, 'jobservice.cm.yaml'), os.path.join(output_dir, 'jobservice/jobservice.cm.yaml')) generate_template(os.path.join(template_dir, 'mysql.cm.yaml'), os.path.join(output_dir, 'mysql/mysql.cm.yaml')) generate_template(os.path.join(template_dir, 'registry.cm.yaml'), os.path.join(output_dir, 'registry/registry.cm.yaml')) generate_template(os.path.join(template_dir, 'adminserver.cm.yaml'), os.path.join(output_dir, 'adminserver/adminserver.cm.yaml')) generate_template(os.path.join(template_dir, 'ingress.yaml'), os.path.join(output_dir, 'ingress.yaml'))