Когда разрабатываешь локально или на одном дев сервере, то приходится часто вписывать одни и такие же настройки для хостов в Apache, nginx и в случае с localhost сделать запись в файл hosts.
Нам как разработчикам всегда хочется все автоматизировать, из-за этого я решил написать скрипт для такой автоматизации.
В одной из прошлых статей «Установка и настройка web-сервера» я писал про настройку web-сервера. По этому примеру я и буду писать скрипт автоматизации.
Основные настройки
Писать все это дело я решил на python. При запуске скрипта план действий такой: берем аргументы с командной строки, берем настройки с конфигурационного файла, соединяем их, создаем конфигурационные фалы для web-сервера. У меня получился вот такой конфигурационный файл:
[DEFAULT] site_name = test.site.com #название сайта по умолчанию site_path = /Users/nil/Sites/ #путь где будет храниться сайт add_hosts = True # Делать ли запись в /etc/hots create_test_folder = True #Если флаг установлен то будет создана папка с сайтом в site_path и тестовый файл index.html create_nginx = False #Если установлен то создать запись для nginx [HTTPD] #настройка для apache port = 80 email = username@admin.com log_path = logs/ host = * [NGINX] port = 81 proxy_pass = http://127.0.0.1:81 [SYSTEM] httpd_config_path = data/httpd.conf.data #путь к template для конфигурационного файла apache httpd_path = /etc/apache2/other/ #путь куда будут сохранятся наши конфигурационные файл для apache nginx_config_path = data/nginx.conf.data #путь к template для конфигурационного файла nginx nginx_path = data/ #путь куда будут сохранятся наши конфигурационные файл для nginx file_hosts_path = /etc/hosts #путь к hosts hosts_ip = 127.0.0.1 #ip для hosts template_page_path = data/index.html.data
По своей сути мы будем просто брать готовый шаблон для конфигураций и подставлять туда наши настройки.
Вот мой пример такого шаблона для apache который лежит по пути httpd_config_path. Назовем файл httpd.conf.data
ServerAdmin {$.EMAIL} DocumentRoot {$.SITE_PATH}{$.SITE_NAME} ServerName {$.SITE_NAME} ServerAlias www.{$.SITE_NAME} #ErrorLog {$.LOG_PATH}{$.SITE_NAME}-error_log #CustomLog {$.LOG_PATH}{$.SITE_NAME}-access_log common AllowOverride All Options All
Следующий template будет для nginx.
server { listen {$.PORT}; server_name {$.SITE_NAME}; location / { ssi on; default_type text/html; charset utf-8; proxy_pass {$.PROXY_PASS}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; limit_except GET POST { deny all; } } }
Как вы догадались все заменяемые параметры мы обрамляем в специальные фигурные скобки. Все переменные будут браться из наших конфигурационных файлов.
Основной файл
Приступим к программированию. Вот что получилось
#!/usr/bin/python import os import sys import argparse import configparser import utils def do_create_httpd(options): config_path = options['system']['httpd_config_path'] content = utils.get_config_content(config_path) content = get_prepared_content(content, options, 'httpd') httpd_path = options['system']['httpd_path'] file_name = options['httpd']['site_name'] + '.conf' full_file_path = httpd_path + file_name utils.create_file(full_file_path, content) utils.success_msg("Httpd File was Created.") def do_create_nginx(options): if not utils.is_true('create_nginx', options['nginx']): return False; config_path = options['system']['nginx_config_path'] content = utils.get_config_content(config_path) content = get_prepared_content(content, options, 'nginx') httpd_path = options['system']['nginx_path'] file_name = options['nginx']['site_name'] + '.conf' full_file_path = httpd_path + file_name utils.create_file(full_file_path, content) utils.success_msg("Nginx File was Created.") def do_create_site(options): if not utils.is_true('create_test_folder', options['default']): return False if not os.path.isdir(options['default']['site_path']): utils.error_msg('Path to Folder Site Not Found') return False site_folder_path = options['default']['site_path'] + options['default']['site_name'] if os.path.isdir(site_folder_path): utils.error_msg('Site Folder is Exist') return False os.makedirs(site_folder_path) template_path = options['system']['template_page_path'] content = utils.get_config_content(template_path) site_folder_path = site_folder_path + "/index.html" utils.create_file(site_folder_path, content) utils.success_msg("Site Folder was Created.") def do_create_hosts(options): if not utils.is_true('add_hosts', options['default']): return False file_hosts_path = options['system']['file_hosts_path'] if not os.path.isfile(file_hosts_path): raise Exception('File Hosts Not Found') host_ip = options['system']['hosts_ip'] string = "\n" + host_ip + " " + options['default']['site_name'] #add conditions if record exists file = open(file_hosts_path, 'a') file.write(string) file.close() utils.success_msg("Record in Hosts was Added.") def get_config(): config = configparser.ConfigParser() config.read('config.ini') return config; def get_prepared_content(content, options, key_opt): for key in options[key_opt]: reserve_key = '{$.' + key.upper() + '}' if options[key_opt][key]: content = content.replace(reserve_key, options[key_opt][key]) return content def get_prepared_arguments(arguments): arguments = vars(arguments) for key in arguments: if arguments[key] is None: arguments = utils.remove_dict(arguments, key) return arguments def get_options(arguments, config): default_configs = dict(config.items('DEFAULT')) configs_https = dict(config.items('HTTPD')) configs_nginx = dict(config.items('NGINX')) configs_system = dict(config.items('SYSTEM')) arguments = arguments.items() options = { 'default': dict(default_configs.items() + arguments), 'httpd' : dict(default_configs.items() + configs_https.items() + arguments), 'nginx' : dict(default_configs.items() + configs_nginx.items() + arguments), 'system' : dict(default_configs.items() + configs_system.items() + arguments) } return options; def do_create_virtual_host(arguments): arguments = get_prepared_arguments(arguments) config = get_config() options = get_options(arguments, config) do_create_httpd(options) do_create_nginx(options) do_create_hosts(options) do_create_site(options) def create_parser(): parser = argparse.ArgumentParser() parser.add_argument("site_name") parser.add_argument('-i', '--info') parser.add_argument('-a', '--add_hosts') return parser def __init(): parser = create_parser() arguments = parser.parse_args(sys.argv[1:]) do_create_virtual_host(arguments) if __name__ == "__main__": try: __init() except Exception as e: utils.error_msg(str(e))
Utils
Добавим еще файл utils в который я вынес стилизацию сообщений.
#!/usr/bin/python TEXT_COLOR_RED = '\033[91m' TEXT_COLOR_GREEN = '\033[92m' TEXT_COLOR_YELLOW = '\033[93m' TEXT_COLOR_BLUE = '\033[94m' TEXT_COLOR_MAGENTA = '\033[95m' TEXT_COLOR_CYAN = '\033[96m' TEXT_COLOT_WHITE = '\033[97m' TEXT_COLOR_GREY = '\033[90m' TEXT_COLOR_BLACK = '\033[30m' TEXT_STYLE_BOLD = '\033[1m' TEXT_STYLE_ITALIC = '\033[3m' TEXT_STYLE_UNDERLINE = '\033[4m' TEXT_END = '\033[0m' def success_msg(msg): print(color_text(msg, TEXT_COLOR_GREEN)) def error_msg(msg): print(color_text(msg, TEXT_COLOR_RED)) def color_text(text, color): return color + text + TEXT_END def get_config_content(path): data_file = open(path) content = data_file.read() data_file.close() return content def create_file(path, content): file = open(path, 'w') file.write(content) file.close() def remove_dict(dct, key): copy = dct.copy() del copy[key] return copy def str2bool(value): return value.lower() in ("yes", "true", "t", "1") def is_true(key, options): return key in options.keys() and str2bool(options[key])
По коду в принципе я не оставлял комментариев, все можно понять из названия функций. Единственное что я не успел сделать это добавить больше входные параметров для скрипта. Потому что сейчас все данные будут браться из файла конфигураций. Но по желанию можно добавить больше параметров.
def create_parser(): parser = argparse.ArgumentParser() parser.add_argument("site_name") parser.add_argument('-i', '--info') parser.add_argument('-a', '--add_hosts') #можно указывать добавлять ли запись в /etc/hosts return parser
Это можно модифицировать под свои нужды. Мне пока что достаточно настроек которые есть в фале. Я выложу исходники на GitHub, может к тому времени когда вы будете читать статью я модифицирую данный код.
создание сайта
Вот пример того что получилось. Скрипт конечно не идеальный но со своими задачами справляется. Главное подать идею для размышления.