|
|
- #!/usr/bin/python3.6
- # coding: utf8
-
-
- import locale
- from dialog import Dialog
- import os
- import pynginxconfig
- import re
- from goto import with_goto
- # import sys
- # import getopt
- import subprocess
- import shlex
-
-
- nginx_dir = "/etc/nginx"
- nginx_available_sites = nginx_dir + "/sites_available/"
- nginx_enabled_sites = nginx_dir + "/sites_enabled/"
- nginx_templates = nginx_dir + "/templates/"
- template_host = 'host.conf'
- template_ssl = 'host_ssl.conf'
-
-
- errcode = list()
- errcode.append(False)
- errcode.append(True)
- errcode.append("string can't be empty")
- errcode.append('English letters only. To issue for an Internationalized Domain Name, use Punycode.')
- errcode.append('string must be numerical')
- errcode.append('')
-
-
- def get_available():
- f = os.listdir(nginx_available_sites)
- return f
-
-
- def check_if_enabled(vhost_file):
- if os.path.exists(nginx_enabled_sites + vhost_file):
- return True
- else:
- return False
-
-
- def check_cert(domain):
- if os.path.isfile('/etc/letsencrypt/live/' + domain.split(' ')[0] + '/cert.pem'):
- return True
- else:
- return False
-
-
- def make_list(delete=False):
- t = tuple()
- x = get_available()
- a = list()
- for vhost in x:
- if delete is not True:
- t = (vhost, get_server_name(vhost), check_if_enabled(vhost))
- a.append(t)
- else:
- t = (vhost, get_server_name(vhost), False)
- a.append(t)
- s = sorted(a, key=lambda dom: dom[1])
- return s
-
-
- def enable_vhost(vhost):
- try:
- os.symlink(nginx_available_sites + vhost, nginx_enabled_sites + vhost)
- except FileExistsError:
- pass
- return True
-
-
- def renew_enabled(vhosts):
- a = get_available()
- for vhost in a:
- if vhost in vhosts:
- if check_if_enabled(vhost):
- pass
- else:
- enable_vhost(vhost)
- else:
- if check_if_enabled(vhost):
- os.unlink(nginx_enabled_sites + vhost)
- else:
- pass
- restart_nginx()
- return True
-
-
- def get_server_name(vhost_file):
- i = int()
- if vhost_file == 'default.conf':
- ret = 'default.conf'
- else:
- vhost = pynginxconfig.NginxConfig()
- vhost.loadf(nginx_available_sites + vhost_file)
- try:
- ret = vhost.get([('server',), 'server_name'])[1]
- except:
- ret = "None"
- return ret
-
-
- def enable_redirect(cfg):
- filename = cfg
- vhost = pynginxconfig.NginxConfig()
- vhost.loadf(nginx_available_sites + filename)
- vhost[0]['value'].insert(7, ('rewrite', '^ https://$http_host$request_uri? permanent'))
- vhost.savef(nginx_available_sites + filename)
- return
-
-
- def is_ascii(s):
- pattern = r'[^.a-zA-Z0-9- ]'
- if len(s) != 0:
- if re.search(pattern, s):
- return 3
- else:
- return 1
- else:
- return 2
-
-
- def is_num(s):
- pattern = r'[^0-9]'
- if len(s) != 0:
- if re.search(pattern, s):
- return 4
- else:
- return 1
- else:
- return 2
-
-
- def check_data(data):
- msg = list()
- ret = True
- rc = is_ascii(data['Domain'])
- if rc != True:
- ret = False
- msg.append("Domain: " + str(errcode[rc]))
-
- rc = is_ascii(data['SubDomain'])
- if data['SubDomain'] != '':
- if rc != True:
- ret = False
- msg.append("SubDomain: " + str(errcode[rc]))
-
- rc = is_ascii(data['Backend_Addr'])
- if rc != True:
- ret = False
- msg.append("Backend_Addr: " + str(errcode[rc]))
-
- rc = is_num(data['Backend_Port'])
- if rc != True:
- ret = False
- msg.append("Backend_Port: " + str(errcode[rc]))
-
- return ret, msg
-
-
- def delete_vhosts(vhosts):
- for vhost in vhosts:
- try:
- os.unlink(nginx_enabled_sites + vhost)
- except:
- pass
- try:
- os.unlink(nginx_available_sites + vhost)
- except:
- pass
- restart_nginx()
-
-
- def form_one():
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- d.set_background_title("NGINX domains managment")
-
- ret, tags = d.menu("Select action?", width=60, height=10,
- choices=[("Add", "Add new domain"),
- ("Enable/Disable", "Enable/Disable selected domains"),
- ("Delete", "Delete selected domains")],
- title="")
- return ret, tags
-
-
- def edit_form(domain='', subdomain='', backend_addr='', backend_port='80'):
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- ret, val = d.mixedform("Fill the form:\n \n Enter additional domians separate by space\n (for example: www.domain.ru xxx.domain.ru)", height=14, width=60,
- elements=[("Domain name", 1, 3, domain, 1, 22, 30, 255, 0),
- ("Additional domains", 2, 3, subdomain, 2, 22, 30, 65535, 0),
- ("Backend addr", 3, 3, backend_addr, 3, 22, 30, 255, 0),
- ("Backend port", 4, 3, backend_port, 4, 22, 30, 5, 0)]
- )
-
- if ret == 'ok':
- ret = show_yesno('Do you want to do automatically redirect from HTTP to HTTPS?')
- if ret == 'ok':
- values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': True}
- else:
- values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': False}
- return ret, values
- else:
- return ret, ""
-
-
- def select_form():
- vlist = make_list()
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- ret, dom_list = d.checklist("Enable or disable sites", height=30, width=120, list_height=30, choices=vlist)
- if ret == "ok":
- show_info("Please wait. Work in progress")
- renew_enabled(dom_list)
- return ret
-
-
- def delete_form():
- vlist = make_list(True)
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- ret, dom_list = d.checklist("Select to delete:", height=30, width=120, list_height=30, choices=vlist)
- if ret == "ok":
- if show_yesno('Are you sure?\n\nThese domains will be deleted:\n\n' + '\n'.join(dom_list)) == "ok":
- show_info("Please wait. Work in progress")
- delete_vhosts(dom_list)
- else:
- return ret
-
-
- def show_yesno(msg):
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- ret = d.yesno(msg, height=10, width=60)
- return ret
-
-
- def create_domain(vhost, ssl=False):
- if ssl is not True:
- filename = vhost['Domain'] + '.conf'
- template = nginx_templates + template_host
- else:
- filename = vhost['Domain'] + '_ssl.conf'
- template = nginx_templates + template_ssl
-
- domains = vhost['Domain'] + ' '
- for dom in vhost['SubDomain']:
- domains += dom
- vconfig = pynginxconfig.NginxConfig()
- vconfig.loadf(template)
- server_str = vconfig.get([('server',), 'server_name'])[1].replace('[domain_names]', domains)
- log_str = vconfig.get([('server',), 'error_log'])[1].replace('[domain_name]', vhost['Domain'])
- if ssl:
- cert_str = vconfig.get([('server',), 'ssl_certificate'])[1].replace('[domain_name]', vhost['Domain'])
- cert_key_str = vconfig.get([('server',), 'ssl_certificate_key'])[1].replace('[domain_name]', vhost['Domain'])
- vconfig.set([('server',), 'ssl_certificate'], cert_str)
- vconfig.set([('server',), 'ssl_certificate_key'], cert_key_str)
- backend_str = vconfig.get([('server',), 'set'])[1].replace('[host_name]', vhost['Backend_Addr']).replace('[host_port]', vhost['Backend_Port'])
- vconfig.set([('server',), 'server_name'], server_str)
- vconfig.set([('server',), 'error_log'], log_str)
- vconfig.set([('server',), 'set'], backend_str)
- #if vhost['redirect'] is not True:
- # vconfig.remove([('server',), 'rewrite'])
- vconfig.savef(nginx_available_sites + filename)
- return domains, filename
-
-
- def create_cert(domains):
- if check_cert(domains) is not True:
- cmd = 'certbot certonly --agree-tos --email admin@shopband.ru --webroot -w /var/www/lets -d ' + domains.rstrip().replace(' ', ' -d ')
- ret = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- if ret.returncode != 0:
- msg = "Error getting ssl certs\nThe SSL configuration is written to " + nginx_available_sites + ", " \
- "but not enabled.\nGet SSL certs manualy and make symlink to " + nginx_enabled_sites
- show_error(msg + "\nLog saved into " + domains.split(' ')[0] + ".log")
- f = open('./' + domains.split(' ')[0] + ".log", 'w')
- f.write(ret.stderr.decode("utf-8"))
- f.close()
- return False
- elif ret.returncode == 0:
- return True
- else:
- return False
- else:
- return True
-
-
- def restart_nginx():
- ret = subprocess.run(shlex.split('/usr/sbin/nginx -t -c /etc/nginx/nginx.conf'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- if ret.returncode != 0:
- show_error(ret.stderr.decode("utf-8"))
- return False
- elif ret.returncode == 0:
- ret = subprocess.run(shlex.split('service nginx restart'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- if ret.returncode != 0:
- show_error(ret.stderr.decode("utf-8"))
- return False
- return True
-
-
- def show_info(msg):
- s_width = len(msg)
- if s_width > 56:
- s_width = 56
- d = Dialog(dialog="dialog")
- d.infobox(msg, height=3, width=s_width+4)
- return
-
-
- def show_error(msg):
- txt = ''
- if isinstance(msg, list):
- for err in msg:
- txt = txt + err + '\n'
- else:
- txt = msg
- locale.setlocale(locale.LC_ALL, '')
- d = Dialog(dialog="dialog")
- d.msgbox(text=txt, width=80, height=20)
- return txt
-
-
- def enable_site(cfg, domains='', ssl=False):
- if ssl is True:
- if create_cert(domains):
- enable_vhost(cfg)
- else:
- return False
- else:
- enable_vhost(cfg)
-
- if restart_nginx():
- return True
- else:
- return False
-
- # if ssl:
- # ret_code = create_cert(domains)
- # if ret_code:
- # enable_vhost(filename)
- # else:
- # show_error(msg)
- # else:
- # enable_vhost(filename)
- pass
-
-
- @with_goto
- def start_it():
- label .start
- vals = {'Domain': '', 'SubDomain': '', 'Backend_Addr': '', 'Backend_Port': '80'}
- rc, action = form_one()
- if rc == 'ok':
- if action == "Add":
- label .add
- ret, vals = edit_form(vals['Domain'], vals['SubDomain'], vals['Backend_Addr'], vals['Backend_Port'])
- if ret is not 'ok':
- goto .start
- else:
- ret_code, msg = check_data(vals)
- if ret_code is not True:
- show_error(msg)
- goto .add
- else:
- # Create HTTP config
- domains, cfg = create_domain(vals)
- show_info("Please wait. Work in progress")
- if enable_site(cfg) is not True:
- goto .start
- else:
- http_config = cfg
-
- # Create HTTPS config
- domains, cfg = create_domain(vals, True)
- show_info("Please wait. Work in progress")
- if enable_site(cfg, domains, True) is not True:
- print("false")
- goto .start
- else:
- if vals['redirect'] is True:
- enable_redirect(http_config)
- restart_nginx()
- goto .start
- elif action == "Enable/Disable":
- label .endis
- ret = select_form()
- goto .start
- elif action == "Delete":
- label .delete
- delete_form()
- goto .start
-
- start_it()
|