#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals # We require Python 2.6 or later from string import Template import random import os import sys import string import argparse import subprocess import shutil from io import open if sys.version_info[:3][0] == 2: import ConfigParser as ConfigParser import StringIO as StringIO if sys.version_info[:3][0] == 3: import configparser as ConfigParser import io as StringIO DATA_VOL = "/data" def validate(conf, args): if args.ha_mode: db_host = rcp.get("configuration", "db_host") if db_host == "mysql": raise Exception("Error: In HA mode, db_host in harbor.cfg needs to point to an external DB address.") registry_storage_provider_name = rcp.get("configuration", "registry_storage_provider_name").strip() if registry_storage_provider_name == "filesystem" and not args.yes: msg = 'Is the Harbor Docker Registry configured to use shared storage (e.g. NFS, Ceph etc.)? [yes/no]:' if raw_input(msg).lower() != "yes": raise Exception("Error: In HA mode, shared storage configuration for Docker Registry in harbor.cfg is required. Refer to HA installation guide for details.") if args.notary_mode: raise Exception("Error: HA mode doesn't support Notary currently") if args.clair_mode: clair_db_host = rcp.get("configuration", "clair_db_host") if "postgres" == clair_db_host: raise Exception("Error: In HA mode, clair_db_host in harbor.cfg needs to point to an external Postgres DB address.") cert_path = rcp.get("configuration", "ssl_cert") cert_key_path = rcp.get("configuration", "ssl_cert_key") shared_cert_key = os.path.join(base_dir, "ha", os.path.basename(cert_key_path)) shared_cert_path = os.path.join(base_dir, "ha", os.path.basename(cert_path)) if os.path.isfile(shared_cert_key): shutil.copy2(shared_cert_key, cert_key_path) if os.path.isfile(shared_cert_path): shutil.copy2(shared_cert_path, cert_path) protocol = rcp.get("configuration", "ui_url_protocol") if protocol != "https" and args.notary_mode: raise Exception("Error: the protocol must be https when Harbor is deployed with Notary") if protocol == "https": if not rcp.has_option("configuration", "ssl_cert"): raise Exception("Error: The protocol is https but attribute ssl_cert is not set") cert_path = rcp.get("configuration", "ssl_cert") if not os.path.isfile(cert_path): raise Exception("Error: The path for certificate: %s is invalid" % cert_path) if not rcp.has_option("configuration", "ssl_cert_key"): raise Exception("Error: The protocol is https but attribute ssl_cert_key is not set") cert_key_path = rcp.get("configuration", "ssl_cert_key") if not os.path.isfile(cert_key_path): raise Exception("Error: The path for certificate key: %s is invalid" % cert_key_path) project_creation = rcp.get("configuration", "project_creation_restriction") if project_creation != "everyone" and project_creation != "adminonly": raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation) valid_storage_drivers = ["filesystem", "azure", "gcs", "s3", "swift", "oss"] storage_provider_name = rcp.get("configuration", "registry_storage_provider_name").strip() if storage_provider_name not in valid_storage_drivers: raise Exception("Error: storage driver %s is not supported, only the following ones are supported: %s" % (storage_provider_name, ",".join(valid_storage_drivers))) storage_provider_config = rcp.get("configuration", "registry_storage_provider_config").strip() if storage_provider_name != "filesystem": if storage_provider_config == "": raise Exception("Error: no provider configurations are provided for provider %s" % storage_provider_name) redis_host = rcp.get("configuration", "redis_host") if redis_host is None or len(redis_host) < 1: raise Exception("Error: redis_host in harbor.cfg needs to point to an endpoint of Redis server or cluster.") redis_port = rcp.get("configuration", "redis_port") if len(redis_port) < 1: raise Exception("Error: redis_port in harbor.cfg needs to point to the port of Redis server or cluster.") redis_db_index = rcp.get("configuration", "redis_db_index").strip() if len(redis_db_index.split(",")) != 3: raise Exception("Error invalid value for redis_db_index: %s. please set it as 1,2,3" % redis_db_index) #To meet security requirement #By default it will change file mode to 0600, and make the owner of the file to 10000:10000 def mark_file(path, mode=0o600, uid=10000, gid=10000): os.chmod(path, mode) os.chown(path, uid, gid) def prepare_ha(conf, args): #files under ha folder will have high prority protocol = rcp.get("configuration", "ui_url_protocol") if protocol == "https": #copy nginx certificate cert_path = rcp.get("configuration", "ssl_cert") cert_key_path = rcp.get("configuration", "ssl_cert_key") shared_cert_key = os.path.join(base_dir, "ha", os.path.basename(cert_key_path)) shared_cert_path = os.path.join(base_dir, "ha", os.path.basename(cert_path)) if os.path.isfile(shared_cert_key): shutil.copy2(shared_cert_key, cert_key_path) else: if os.path.isfile(cert_key_path): shutil.copy2(cert_key_path, shared_cert_key) if os.path.isfile(shared_cert_path): shutil.copy2(shared_cert_path, cert_path) else: if os.path.isfile(cert_path): shutil.copy2(cert_path, shared_cert_path) #check if ca exsit cert_ca_path = os.path.join(DATA_VOL, 'ca_download', 'ca.crt') shared_ca_path = os.path.join(base_dir, "ha", os.path.basename(cert_ca_path)) if os.path.isfile(shared_ca_path): shutil.copy2(shared_ca_path, cert_ca_path) else: if os.path.isfile(cert_ca_path): shutil.copy2(cert_ca_path, shared_ca_path) #check root.crt and priviate_key.pem private_key_pem = os.path.join(config_dir, "ui", "private_key.pem") root_crt = os.path.join(config_dir, "registry", "root.crt") shared_private_key_pem = os.path.join(base_dir, "ha", "private_key.pem") shared_root_crt = os.path.join(base_dir, "ha", "root.crt") if os.path.isfile(shared_private_key_pem): shutil.copy2(shared_private_key_pem, private_key_pem) else: if os.path.isfile(private_key_pem): shutil.copy2(private_key_pem, shared_private_key_pem) if os.path.isfile(shared_root_crt): shutil.copy2(shared_root_crt, root_crt) else: if os.path.isfile(root_crt): shutil.copy2(root_crt, shared_root_crt) #secretkey shared_secret_key = os.path.join(base_dir, "ha", "secretkey") secretkey_path = rcp.get("configuration", "secretkey_path") secret_key = os.path.join(secretkey_path, "secretkey") if os.path.isfile(shared_secret_key): shutil.copy2(shared_secret_key, secret_key) else: if os.path.isfile(secret_key): shutil.copy2(secret_key, shared_secret_key) def get_secret_key(path): secret_key = _get_secret(path, "secretkey") if len(secret_key) != 16: raise Exception("secret key's length has to be 16 chars, current length: %d" % len(secret_key)) return secret_key def get_alias(path): alias = _get_secret(path, "defaultalias", length=8) return alias def _get_secret(folder, filename, length=16): key_file = os.path.join(folder, filename) if os.path.isfile(key_file): with open(key_file, 'r') as f: key = f.read() print("loaded secret from file: %s" % key_file) mark_file(key_file) return key if not os.path.isdir(folder): os.makedirs(folder) key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(length)) with open(key_file, 'w') as f: f.write(key) print("Generated and saved secret to file: %s" % key_file) mark_file(key_file) return key def prep_conf_dir(root, *name): absolute_path = os.path.join(root, *name) if not os.path.exists(absolute_path): os.makedirs(absolute_path) return absolute_path def render(src, dest, **kw): t = Template(open(src, 'r').read()) with open(dest, 'w') as f: f.write(t.substitute(**kw)) print("Generated configuration file: %s" % dest) base_dir = os.path.dirname(__file__) config_dir = os.path.join(base_dir, "common/config") templates_dir = os.path.join(base_dir, "common/templates") def delfile(src): if os.path.isfile(src): try: os.remove(src) print("Clearing the configuration file: %s" % src) except: pass elif os.path.isdir(src): for item in os.listdir(src): itemsrc=os.path.join(src,item) delfile(itemsrc) parser = argparse.ArgumentParser() parser.add_argument('--conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file") parser.add_argument('--with-notary', dest='notary_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with notary") parser.add_argument('--with-clair', dest='clair_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with clair") parser.add_argument('--ha', dest='ha_mode', default=False, action='store_true', help="the Harbor instance is to be deployed in HA mode") parser.add_argument('--yes', dest='yes', default=False, action='store_true', help="Answer yes to all questions") parser.add_argument('--with-chartmuseum', dest='chart_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with chart repository supporting") args = parser.parse_args() delfile(config_dir) #Read configurations conf = StringIO.StringIO() conf.write("[configuration]\n") conf.write(open(args.cfgfile).read()) conf.seek(0, os.SEEK_SET) rcp = ConfigParser.RawConfigParser() rcp.readfp(conf) validate(rcp, args) reload_config = rcp.get("configuration", "reload_config") if rcp.has_option( "configuration", "reload_config") else "false" hostname = rcp.get("configuration", "hostname") protocol = rcp.get("configuration", "ui_url_protocol") public_url = protocol + "://" + hostname email_identity = rcp.get("configuration", "email_identity") email_host = rcp.get("configuration", "email_server") email_port = rcp.get("configuration", "email_server_port") email_usr = rcp.get("configuration", "email_username") email_pwd = rcp.get("configuration", "email_password") email_from = rcp.get("configuration", "email_from") email_ssl = rcp.get("configuration", "email_ssl") email_insecure = rcp.get("configuration", "email_insecure") harbor_admin_password = rcp.get("configuration", "harbor_admin_password") auth_mode = rcp.get("configuration", "auth_mode") ldap_url = rcp.get("configuration", "ldap_url") # this two options are either both set or unset if rcp.has_option("configuration", "ldap_searchdn"): ldap_searchdn = rcp.get("configuration", "ldap_searchdn") ldap_search_pwd = rcp.get("configuration", "ldap_search_pwd") else: ldap_searchdn = "" ldap_search_pwd = "" ldap_basedn = rcp.get("configuration", "ldap_basedn") # ldap_filter is null by default if rcp.has_option("configuration", "ldap_filter"): ldap_filter = rcp.get("configuration", "ldap_filter") else: ldap_filter = "" ldap_uid = rcp.get("configuration", "ldap_uid") ldap_scope = rcp.get("configuration", "ldap_scope") ldap_timeout = rcp.get("configuration", "ldap_timeout") ldap_verify_cert = rcp.get("configuration", "ldap_verify_cert") ldap_group_basedn = rcp.get("configuration", "ldap_group_basedn") ldap_group_filter = rcp.get("configuration", "ldap_group_filter") ldap_group_gid = rcp.get("configuration", "ldap_group_gid") ldap_group_scope = rcp.get("configuration", "ldap_group_scope") db_password = rcp.get("configuration", "db_password") db_host = rcp.get("configuration", "db_host") db_user = rcp.get("configuration", "db_user") db_port = rcp.get("configuration", "db_port") self_registration = rcp.get("configuration", "self_registration") if protocol == "https": cert_path = rcp.get("configuration", "ssl_cert") cert_key_path = rcp.get("configuration", "ssl_cert_key") customize_crt = rcp.get("configuration", "customize_crt") max_job_workers = rcp.get("configuration", "max_job_workers") token_expiration = rcp.get("configuration", "token_expiration") proj_cre_restriction = rcp.get("configuration", "project_creation_restriction") secretkey_path = rcp.get("configuration", "secretkey_path") if rcp.has_option("configuration", "admiral_url"): admiral_url = rcp.get("configuration", "admiral_url") else: admiral_url = "" clair_db_password = rcp.get("configuration", "clair_db_password") clair_db_host = rcp.get("configuration", "clair_db_host") clair_db_port = rcp.get("configuration", "clair_db_port") clair_db_username = rcp.get("configuration", "clair_db_username") clair_db = rcp.get("configuration", "clair_db") clair_updaters_interval = rcp.get("configuration", "clair_updaters_interval") uaa_endpoint = rcp.get("configuration", "uaa_endpoint") uaa_clientid = rcp.get("configuration", "uaa_clientid") uaa_clientsecret = rcp.get("configuration", "uaa_clientsecret") uaa_verify_cert = rcp.get("configuration", "uaa_verify_cert") uaa_ca_cert = rcp.get("configuration", "uaa_ca_cert") secret_key = get_secret_key(secretkey_path) log_rotate_count = rcp.get("configuration", "log_rotate_count") log_rotate_size = rcp.get("configuration", "log_rotate_size") redis_host = rcp.get("configuration", "redis_host") redis_port = rcp.get("configuration", "redis_port") redis_password = rcp.get("configuration", "redis_password") redis_db_index = rcp.get("configuration", "redis_db_index") db_indexs = redis_db_index.split(',') redis_db_index_reg = db_indexs[0] redis_db_index_js = db_indexs[1] redis_db_index_chart = db_indexs[2] #redis://[arbitrary_username:password@]ipaddress:port/database_index redis_url_js = '' if len(redis_password) > 0: redis_url_js = "redis://anonymous:%s@%s:%s/%s" % (redis_password, redis_host, redis_port, redis_db_index_js) else: redis_url_js = "redis://%s:%s/%s" % (redis_host, redis_port, redis_db_index_js) if rcp.has_option("configuration", "skip_reload_env_pattern"): skip_reload_env_pattern = rcp.get("configuration", "skip_reload_env_pattern") else: skip_reload_env_pattern = "$^" storage_provider_name = rcp.get("configuration", "registry_storage_provider_name").strip() storage_provider_config = rcp.get("configuration", "registry_storage_provider_config").strip() # yaml requires 1 or more spaces between the key and value storage_provider_config = storage_provider_config.replace(":", ": ", 1) ui_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16)) jobservice_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16)) adminserver_config_dir = os.path.join(config_dir,"adminserver") if not os.path.exists(adminserver_config_dir): os.makedirs(os.path.join(config_dir, "adminserver")) ui_config_dir = prep_conf_dir(config_dir,"ui") ui_certificates_dir = prep_conf_dir(ui_config_dir,"certificates") db_config_dir = prep_conf_dir(config_dir, "db") job_config_dir = prep_conf_dir(config_dir, "jobservice") registry_config_dir = prep_conf_dir(config_dir, "registry") registryctl_config_dir = prep_conf_dir(config_dir, "registryctl") nginx_config_dir = prep_conf_dir (config_dir, "nginx") nginx_conf_d = prep_conf_dir(nginx_config_dir, "conf.d") log_config_dir = prep_conf_dir (config_dir, "log") adminserver_conf_env = os.path.join(config_dir, "adminserver", "env") ui_conf_env = os.path.join(config_dir, "ui", "env") ui_conf = os.path.join(config_dir, "ui", "app.conf") ui_cert_dir = os.path.join(config_dir, "ui", "certificates") jobservice_conf = os.path.join(config_dir, "jobservice", "config.yml") registry_conf = os.path.join(config_dir, "registry", "config.yml") registryctl_conf_env = os.path.join(config_dir, "registryctl", "env") registryctl_conf_yml = os.path.join(config_dir, "registryctl", "config.yml") db_conf_env = os.path.join(config_dir, "db", "env") job_conf_env = os.path.join(config_dir, "jobservice", "env") nginx_conf = os.path.join(config_dir, "nginx", "nginx.conf") cert_dir = os.path.join(config_dir, "nginx", "cert") log_rotate_config = os.path.join(config_dir, "log", "logrotate.conf") adminserver_url = "http://adminserver:8080" registry_url = "http://registry:5000" registry_controller_url = "http://registryctl:8080" ui_url = "http://ui:8080" token_service_url = "http://ui:8080/service/token" jobservice_url = "http://jobservice:8080" clair_url = "http://clair:6060" notary_url = "http://notary-server:4443" chart_repository_url = "http://chartmuseum:9999" if len(admiral_url) != 0 and admiral_url != "NA": #VIC overwrites the data volume path, which by default should be same as the value of secretkey_path DATA_VOL = secretkey_path JOB_LOG_DIR = os.path.join(DATA_VOL, "job_logs") if not os.path.exists(JOB_LOG_DIR): os.makedirs(JOB_LOG_DIR) mark_file(JOB_LOG_DIR, mode=0o755) if protocol == "https": target_cert_path = os.path.join(cert_dir, os.path.basename(cert_path)) if not os.path.exists(cert_dir): os.makedirs(cert_dir) shutil.copy2(cert_path,target_cert_path) target_cert_key_path = os.path.join(cert_dir, os.path.basename(cert_key_path)) shutil.copy2(cert_key_path,target_cert_key_path) render(os.path.join(templates_dir, "nginx", "nginx.https.conf"), nginx_conf, ssl_cert = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_path)), ssl_cert_key = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_key_path))) else: render(os.path.join(templates_dir, "nginx", "nginx.http.conf"), nginx_conf) #Use reload_key to avoid reload config after restart harbor reload_key = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) if reload_config == "true" else "" ldap_group_admin_dn = rcp.get("configuration", "ldap_group_admin_dn") if rcp.has_option("configuration", "ldap_group_admin_dn") else "" render(os.path.join(templates_dir, "adminserver", "env"), adminserver_conf_env, reload_config=reload_config, public_url=public_url, ui_url=ui_url, auth_mode=auth_mode, self_registration=self_registration, ldap_url=ldap_url, ldap_searchdn =ldap_searchdn, ldap_search_pwd =ldap_search_pwd, ldap_basedn=ldap_basedn, ldap_filter=ldap_filter, ldap_uid=ldap_uid, ldap_scope=ldap_scope, ldap_verify_cert=ldap_verify_cert, ldap_timeout=ldap_timeout, ldap_group_basedn=ldap_group_basedn, ldap_group_filter=ldap_group_filter, ldap_group_gid=ldap_group_gid, ldap_group_scope=ldap_group_scope, ldap_group_admin_dn=ldap_group_admin_dn, db_password=db_password, db_host=db_host, db_user=db_user, db_port=db_port, email_host=email_host, email_port=email_port, email_usr=email_usr, email_pwd=email_pwd, email_ssl=email_ssl, email_insecure=email_insecure, email_from=email_from, email_identity=email_identity, harbor_admin_password=harbor_admin_password, project_creation_restriction=proj_cre_restriction, max_job_workers=max_job_workers, ui_secret=ui_secret, jobservice_secret=jobservice_secret, token_expiration=token_expiration, admiral_url=admiral_url, with_notary=args.notary_mode, with_clair=args.clair_mode, clair_db_password=clair_db_password, clair_db_host=clair_db_host, clair_db_port=clair_db_port, clair_db_username=clair_db_username, clair_db=clair_db, uaa_endpoint=uaa_endpoint, uaa_clientid=uaa_clientid, uaa_clientsecret=uaa_clientsecret, uaa_verify_cert=uaa_verify_cert, storage_provider_name=storage_provider_name, registry_url=registry_url, token_service_url=token_service_url, jobservice_url=jobservice_url, clair_url=clair_url, notary_url=notary_url, reload_key=reload_key, skip_reload_env_pattern=skip_reload_env_pattern, chart_repository_url=chart_repository_url, registry_controller_url = registry_controller_url, with_chartmuseum=args.chart_mode ) # set cache for chart repo server # default set 'memory' mode, if redis is configured then set to 'redis' chart_cache_driver = "memory" if len(redis_host) > 0: chart_cache_driver = "redis" render(os.path.join(templates_dir, "ui", "env"), ui_conf_env, ui_secret=ui_secret, jobservice_secret=jobservice_secret, redis_host=redis_host, redis_port=redis_port, redis_password=redis_password, adminserver_url = adminserver_url, chart_cache_driver = chart_cache_driver ) registry_config_file_ha = "config_ha.yml" registry_config_file = "config.yml" if storage_provider_name == "filesystem": if not storage_provider_config: storage_provider_config = "rootdirectory: /storage" elif "rootdirectory:" not in storage_provider_config: storage_provider_config = "rootdirectory: /storage" + "," + storage_provider_config # generate storage configuration section in yaml format storage_provider_conf_list = [storage_provider_name + ':'] for c in storage_provider_config.split(","): storage_provider_conf_list.append(c.strip()) storage_provider_info = ('\n' + ' ' * 4).join(storage_provider_conf_list) render(os.path.join(templates_dir, "registry", registry_config_file_ha), registry_conf, storage_provider_info=storage_provider_info, public_url=public_url, ui_url=ui_url, redis_host=redis_host, redis_port=redis_port, redis_password=redis_password, redis_db_index_reg=redis_db_index_reg) render(os.path.join(templates_dir, "registry", registry_config_file), registry_conf, storage_provider_info=storage_provider_info, public_url=public_url, ui_url=ui_url, redis_host=redis_host, redis_port=redis_port, redis_password=redis_password, redis_db_index_reg=redis_db_index_reg) render(os.path.join(templates_dir, "db", "env"), db_conf_env, db_password=db_password) render(os.path.join(templates_dir, "jobservice", "env"), job_conf_env, ui_secret=ui_secret, jobservice_secret=jobservice_secret, adminserver_url=adminserver_url) render(os.path.join(templates_dir, "jobservice", "config.yml"), jobservice_conf, max_job_workers=max_job_workers, redis_url=redis_url_js) render(os.path.join(templates_dir, "log", "logrotate.conf"), log_rotate_config, log_rotate_count=log_rotate_count, log_rotate_size=log_rotate_size) render(os.path.join(templates_dir, "registryctl", "env"), registryctl_conf_env, jobservice_secret=jobservice_secret, ui_secret=ui_secret) shutil.copyfile(os.path.join(templates_dir, "ui", "app.conf"), ui_conf) shutil.copyfile(os.path.join(templates_dir, "registryctl", "config.yml"), registryctl_conf_yml) print("Generated configuration file: %s" % ui_conf) if auth_mode == "uaa_auth": if os.path.isfile(uaa_ca_cert): if not os.path.isdir(ui_cert_dir): os.makedirs(ui_cert_dir) ui_uaa_ca = os.path.join(ui_cert_dir, "uaa_ca.pem") print("Copying UAA CA cert to %s" % ui_uaa_ca) shutil.copyfile(uaa_ca_cert, ui_uaa_ca) else: print("Can not find UAA CA cert: %s, skip" % uaa_ca_cert) def validate_crt_subj(dirty_subj): subj_list = [item for item in dirty_subj.strip().split("/") \ if len(item.split("=")) == 2 and len(item.split("=")[1]) > 0] return "/" + "/".join(subj_list) FNULL = open(os.devnull, 'w') from functools import wraps def stat_decorator(func): @wraps(func) def check_wrapper(*args, **kw): stat = func(*args, **kw) message = "Generated certificate, key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path']) \ if stat == 0 else "Fail to generate key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path']) print(message) if stat != 0: sys.exit(1) return check_wrapper @stat_decorator def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"): rc = subprocess.call(["openssl", "genrsa", "-out", key_path, "4096"], stdout=FNULL, stderr=subprocess.STDOUT) if rc != 0: return rc return subprocess.call(["openssl", "req", "-new", "-x509", "-key", key_path,\ "-out", cert_path, "-days", "3650", "-subj", subj], stdout=FNULL, stderr=subprocess.STDOUT) @stat_decorator def create_cert(subj, ca_key, ca_cert, key_path="./k.key", cert_path="./cert.crt"): cert_dir = os.path.dirname(cert_path) csr_path = os.path.join(cert_dir, "tmp.csr") rc = subprocess.call(["openssl", "req", "-newkey", "rsa:4096", "-nodes","-sha256","-keyout", key_path,\ "-out", csr_path, "-subj", subj], stdout=FNULL, stderr=subprocess.STDOUT) if rc != 0: return rc return subprocess.call(["openssl", "x509", "-req", "-days", "3650", "-in", csr_path, "-CA", \ ca_cert, "-CAkey", ca_key, "-CAcreateserial", "-out", cert_path], stdout=FNULL, stderr=subprocess.STDOUT) def openssl_installed(): shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT) if shell_stat != 0: print("Cannot find openssl installed in this computer\nUse default SSL certificate file") return False return True if customize_crt == 'on' and openssl_installed(): shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT) empty_subj = "/" private_key_pem = os.path.join(config_dir, "ui", "private_key.pem") root_crt = os.path.join(config_dir, "registry", "root.crt") create_root_cert(empty_subj, key_path=private_key_pem, cert_path=root_crt) mark_file(private_key_pem) mark_file(root_crt) else: print("Copied configuration file: %s" % ui_config_dir + "private_key.pem") shutil.copyfile(os.path.join(templates_dir, "ui", "private_key.pem"), os.path.join(ui_config_dir, "private_key.pem")) print("Copied configuration file: %s" % registry_config_dir + "root.crt") shutil.copyfile(os.path.join(templates_dir, "registry", "root.crt"), os.path.join(registry_config_dir, "root.crt")) if args.notary_mode: notary_config_dir = prep_conf_dir(config_dir, "notary") notary_temp_dir = os.path.join(templates_dir, "notary") print("Copying sql file for notary DB") # if os.path.exists(os.path.join(notary_config_dir, "postgresql-initdb.d")): # shutil.rmtree(os.path.join(notary_config_dir, "postgresql-initdb.d")) # shutil.copytree(os.path.join(notary_temp_dir, "postgresql-initdb.d"), os.path.join(notary_config_dir, "postgresql-initdb.d")) if customize_crt == 'on' and openssl_installed(): try: temp_cert_dir = os.path.join(base_dir, "cert_tmp") if not os.path.exists(temp_cert_dir): os.makedirs(temp_cert_dir) ca_subj = "/C=US/ST=California/L=Palo Alto/O=VMware, Inc./OU=Harbor/CN=Self-signed by VMware, Inc." cert_subj = "/C=US/ST=California/L=Palo Alto/O=VMware, Inc./OU=Harbor/CN=notarysigner" signer_ca_cert = os.path.join(temp_cert_dir, "notary-signer-ca.crt") signer_ca_key = os.path.join(temp_cert_dir, "notary-signer-ca.key") signer_cert_path = os.path.join(temp_cert_dir, "notary-signer.crt") signer_key_path = os.path.join(temp_cert_dir, "notary-signer.key") create_root_cert(ca_subj, key_path=signer_ca_key, cert_path=signer_ca_cert) create_cert(cert_subj, signer_ca_key, signer_ca_cert, key_path=signer_key_path, cert_path=signer_cert_path) print("Copying certs for notary signer") shutil.copy2(signer_cert_path, notary_config_dir) shutil.copy2(signer_key_path, notary_config_dir) shutil.copy2(signer_ca_cert, notary_config_dir) finally: srl_tmp = os.path.join(os.getcwd(), ".srl") if os.path.isfile(srl_tmp): os.remove(srl_tmp) if os.path.isdir(temp_cert_dir): shutil.rmtree(temp_cert_dir, True) else: print("Copying certs for notary signer") shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.crt"), notary_config_dir) shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.key"), notary_config_dir) shutil.copy2(os.path.join(notary_temp_dir, "notary-signer-ca.crt"), notary_config_dir) shutil.copy2(os.path.join(registry_config_dir, "root.crt"), notary_config_dir) mark_file(os.path.join(notary_config_dir, "notary-signer.crt")) mark_file(os.path.join(notary_config_dir, "notary-signer.key")) mark_file(os.path.join(notary_config_dir, "notary-signer-ca.crt")) mark_file(os.path.join(notary_config_dir, "root.crt")) print("Copying notary signer configuration file") #Call render instead of copy so the umask will take effect to mark the file as 0644 render(os.path.join(notary_temp_dir, "signer-config.postgres.json"), os.path.join(notary_config_dir, "signer-config.postgres.json")) render(os.path.join(notary_temp_dir, "server-config.postgres.json"), os.path.join(notary_config_dir, "server-config.postgres.json"), token_endpoint=public_url) print("Copying nginx configuration file for notary") shutil.copy2(os.path.join(templates_dir, "nginx", "notary.upstream.conf"), nginx_conf_d) render(os.path.join(templates_dir, "nginx", "notary.server.conf"), os.path.join(nginx_conf_d, "notary.server.conf"), ssl_cert = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_path)), ssl_cert_key = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_key_path))) default_alias = get_alias(secretkey_path) render(os.path.join(notary_temp_dir, "signer_env"), os.path.join(notary_config_dir, "signer_env"), alias = default_alias) shutil.copy2(os.path.join(notary_temp_dir, "server_env"), notary_config_dir) if args.clair_mode: clair_temp_dir = os.path.join(templates_dir, "clair") clair_config_dir = prep_conf_dir(config_dir, "clair") if os.path.exists(os.path.join(clair_config_dir, "postgresql-init.d")): print("Copying offline data file for clair DB") shutil.rmtree(os.path.join(clair_config_dir, "postgresql-init.d")) shutil.copytree(os.path.join(clair_temp_dir, "postgresql-init.d"), os.path.join(clair_config_dir, "postgresql-init.d")) postgres_env = os.path.join(clair_config_dir, "postgres_env") render(os.path.join(clair_temp_dir, "postgres_env"), postgres_env, password = clair_db_password) clair_conf = os.path.join(clair_config_dir, "config.yaml") render(os.path.join(clair_temp_dir, "config.yaml"), clair_conf, password = clair_db_password, username = clair_db_username, host = clair_db_host, port = clair_db_port, dbname = clair_db, interval = clair_updaters_interval) # config http proxy for Clair http_proxy = rcp.get("configuration", "http_proxy").strip() https_proxy = rcp.get("configuration", "https_proxy").strip() no_proxy = rcp.get("configuration", "no_proxy").strip() clair_env = os.path.join(clair_config_dir, "clair_env") render(os.path.join(clair_temp_dir, "clair_env"), clair_env, http_proxy = http_proxy, https_proxy = https_proxy, no_proxy = no_proxy) if args.ha_mode: prepare_ha(rcp, args) # config chart repository if args.chart_mode: chartm_temp_dir = os.path.join(templates_dir, "chartserver") chartm_config_dir = os.path.join(config_dir, "chartserver") chartm_env = os.path.join(config_dir, "chartserver", "env") if not os.path.isdir(chartm_config_dir): print ("Create config folder: %s" % chartm_config_dir) os.makedirs(chartm_config_dir) # process redis info cache_store = "redis" cache_redis_password = redis_password cache_redis_addr = redis_host+":"+redis_port cache_redis_db_index = redis_db_index_chart # process storage info #default using local file system storage_driver = "local" # storage provider configurations # please be aware that, we do not check the validations of the values for the specified keys # convert the configs to config map storage_provider_configs = storage_provider_config.split(",") storgae_provider_confg_map = {} storage_provider_config_options = [] for k_v in storage_provider_configs: if len(k_v) > 0: kvs = k_v.split(": ") # add space suffix to avoid existing ":" in the value if len(kvs) == 2: #key must not be empty if kvs[0].strip() != "": storgae_provider_confg_map[kvs[0].strip()] = kvs[1].strip() if storage_provider_name == "s3": # aws s3 storage storage_driver = "amazon" storage_provider_config_options.append("STORAGE_AMAZON_BUCKET=%s" % storgae_provider_confg_map.get("bucket", "")) storage_provider_config_options.append("STORAGE_AMAZON_PREFIX=%s" % storgae_provider_confg_map.get("rootdirectory", "")) storage_provider_config_options.append("STORAGE_AMAZON_REGION=%s" % storgae_provider_confg_map.get("region", "")) storage_provider_config_options.append("STORAGE_AMAZON_ENDPOINT=%s" % storgae_provider_confg_map.get("regionendpoint", "")) elif storage_provider_name == "gcs": # google cloud storage storage_driver = "google" storage_provider_config_options.append("STORAGE_GOOGLE_BUCKET=%s" % storgae_provider_confg_map.get("bucket", "")) storage_provider_config_options.append("STORAGE_GOOGLE_PREFIX=%s" % storgae_provider_confg_map.get("rootdirectory", "")) elif storage_provider_name == "azure": # azure storage storage_driver = "microsoft" storage_provider_config_options.append("STORAGE_MICROSOFT_CONTAINER=%s" % storgae_provider_confg_map.get("container", "")) storage_provider_config_options.append("STORAGE_MICROSOFT_PREFIX=/azure/harbor/charts") elif storage_provider_name == "swift": # open stack swift storage_driver = "openstack" storage_provider_config_options.append("STORAGE_OPENSTACK_CONTAINER=%s" % storgae_provider_confg_map.get("container", "")) storage_provider_config_options.append("STORAGE_OPENSTACK_PREFIX=%s" % storgae_provider_confg_map.get("rootdirectory", "")) storage_provider_config_options.append("STORAGE_OPENSTACK_REGION=%s" % storgae_provider_confg_map.get("region", "")) elif storage_provider_name == "oss": # aliyun OSS storage_driver = "alibaba" storage_provider_config_options.append("STORAGE_ALIBABA_BUCKET=%s" % storgae_provider_confg_map.get("bucket", "")) storage_provider_config_options.append("STORAGE_ALIBABA_PREFIX=%s" % storgae_provider_confg_map.get("rootdirectory", "")) storage_provider_config_options.append("STORAGE_ALIBABA_ENDPOINT=%s" % storgae_provider_confg_map.get("endpoint", "")) else: # use local file system storage_provider_config_options.append("STORAGE_LOCAL_ROOTDIR=/chart_storage") # generate storage provider configuration all_storage_provider_configs = ('\n').join(storage_provider_config_options) render(os.path.join(chartm_temp_dir, "env"), chartm_env, cache_store=cache_store, cache_redis_addr=cache_redis_addr, cache_redis_password=cache_redis_password, cache_redis_db_index=cache_redis_db_index, ui_secret=ui_secret, storage_driver=storage_driver, all_storage_driver_configs=all_storage_provider_configs) FNULL.close() print("The configuration files are ready, please use docker-compose to start the service.")