Когда разрабатываешь локально или на одном дев сервере, то приходится часто вписывать одни и такие же настройки для хостов в 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, может к тому времени когда вы будете читать статью я модифицирую данный код.

создание сайта
Вот пример того что получилось. Скрипт конечно не идеальный но со своими задачами справляется. Главное подать идею для размышления.
