harbor/make/prepare
2017-02-17 18:23:21 +08:00

319 lines
12 KiB
Python
Executable File

#!/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 string
import os
import sys
import argparse
import subprocess
import shutil
from io import open
import base64
from Crypto import Random
from Crypto.Cipher import AES
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
def validate(conf):
protocol = rcp.get("configuration", "ui_url_protocol")
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)
def get_secret_key(path):
key_file = os.path.join(path, "secretkey")
if os.path.isfile(key_file):
with open(key_file, 'r') as f:
key = f.read()
print("loaded secret key")
if len(key) != 16:
raise Exception("secret key's length has to be 16 chars, current length: %d" % len(key))
return key
if not os.path.isdir(path):
os.makedirs(path, mode=0600)
key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
with open(key_file, 'w') as f:
f.write(key)
print("generated and saved secret key")
return key
def aesEncrypt(key, raw):
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
base_dir = os.path.dirname(__file__)
config_dir = os.path.join(base_dir, "common/config")
templates_dir = os.path.join(base_dir, "common/templates")
parser = argparse.ArgumentParser()
parser.add_argument('-conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file")
args = parser.parse_args()
#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)
hostname = rcp.get("configuration", "hostname")
protocol = rcp.get("configuration", "ui_url_protocol")
ui_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")
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")
db_password = rcp.get("configuration", "db_password")
self_registration = rcp.get("configuration", "self_registration")
use_compressed_js = rcp.get("configuration", "use_compressed_js")
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")
crt_country = rcp.get("configuration", "crt_country")
crt_state = rcp.get("configuration", "crt_state")
crt_location = rcp.get("configuration", "crt_location")
crt_organization = rcp.get("configuration", "crt_organization")
crt_organizationalunit = rcp.get("configuration", "crt_organizationalunit")
crt_commonname = rcp.get("configuration", "crt_commonname")
crt_email = rcp.get("configuration", "crt_email")
max_job_workers = rcp.get("configuration", "max_job_workers")
token_expiration = rcp.get("configuration", "token_expiration")
verify_remote_cert = rcp.get("configuration", "verify_remote_cert")
proj_cre_restriction = rcp.get("configuration", "project_creation_restriction")
secretkey_path = rcp.get("configuration", "secretkey_path")
secret_key = get_secret_key(secretkey_path)
########
ui_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
#ui_secret = aesEncrypt(secret_key, ui_secret_raw)
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 = os.path.join(config_dir,"ui")
if not os.path.exists(ui_config_dir):
os.makedirs(os.path.join(config_dir, "ui"))
db_config_dir = os.path.join(config_dir, "db")
if not os.path.exists(db_config_dir):
os.makedirs(os.path.join(config_dir, "db"))
job_config_dir = os.path.join(config_dir, "jobservice")
if not os.path.exists(job_config_dir):
os.makedirs(job_config_dir)
registry_config_dir = os.path.join(config_dir, "registry")
if not os.path.exists(registry_config_dir):
os.makedirs(registry_config_dir)
nginx_config_dir = os.path.join(config_dir, "nginx")
if not os.path.exists(nginx_config_dir):
os.makedirs(nginx_config_dir)
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)
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")
jobservice_conf = os.path.join(config_dir, "jobservice", "app.conf")
registry_conf = os.path.join(config_dir, "registry", "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")
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)
delfile(config_dir)
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)
render(os.path.join(templates_dir, "adminserver", "env"),
adminserver_conf_env,
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_timeout=ldap_timeout,
db_password=db_password,
email_host=email_host,
email_port=email_port,
email_usr=email_usr,
email_pwd=email_pwd,
email_ssl=email_ssl,
email_from=email_from,
email_identity=email_identity,
harbor_admin_password=harbor_admin_password,
project_creation_restriction=proj_cre_restriction,
verify_remote_cert=verify_remote_cert,
max_job_workers=max_job_workers,
ui_secret=ui_secret,
secret_key=secret_key,
token_expiration=token_expiration,
use_compressed_js=use_compressed_js
)
render(os.path.join(templates_dir, "ui", "env"),
ui_conf_env,
ui_secret=ui_secret)
render(os.path.join(templates_dir, "registry",
"config.yml"),
registry_conf,
ui_url=ui_url)
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)
print("Generated configuration file: %s" % jobservice_conf)
shutil.copyfile(os.path.join(templates_dir, "jobservice", "app.conf"), jobservice_conf)
print("Generated configuration file: %s" % ui_conf)
shutil.copyfile(os.path.join(templates_dir, "ui", "app.conf"), ui_conf)
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, **kwargs):
stat = func(*args, **kwargs)
message = "Generated configuration file: %s" % kwargs['path'] \
if stat == 0 else "Fail to generate %s" % kwargs['path']
print(message)
if stat != 0:
sys.exit(1)
return check_wrapper
@stat_decorator
def check_private_key_stat(*args, **kwargs):
return subprocess.call(["openssl", "genrsa", "-out", kwargs['path'], "4096"],\
stdout=FNULL, stderr=subprocess.STDOUT)
@stat_decorator
def check_certificate_stat(*args, **kwargs):
dirty_subj = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}/emailAddress={6}"\
.format(crt_country, crt_state, crt_location, crt_organization,\
crt_organizationalunit, crt_commonname, crt_email)
subj = validate_crt_subj(dirty_subj)
return subprocess.call(["openssl", "req", "-new", "-x509", "-key",\
private_key_pem, "-out", root_crt, "-days", "3650", "-subj", subj], \
stdout=FNULL, stderr=subprocess.STDOUT)
def openssl_is_installed(stat):
if stat == 0:
return True
else:
print("Cannot find openssl installed in this computer\nUse default SSL certificate file")
return False
if customize_crt == 'on':
shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT)
if openssl_is_installed(shell_stat):
private_key_pem = os.path.join(config_dir, "ui", "private_key.pem")
root_crt = os.path.join(config_dir, "registry", "root.crt")
check_private_key_stat(path=private_key_pem)
check_certificate_stat(path=root_crt)
else:
print("Generated 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("Generated 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"))
FNULL.close()
print("The configuration files are ready, please use docker-compose to start the service.")