#!/usr/bin/env python # Copyright (C) 2013 Linaro Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see import getpass import fileinput import os import random import subprocess import string import sys REQUIRED_PACKAGES = ["bzr", "postgresql-9.1", "apache2", "python", "python-django", "python-psycopg2", "python-dateutil", "python-feedparser", "libapache2-mod-python", "libapache2-mod-wsgi", "libapache2-mod-fastcgi", "python-django-openid-auth", "python-django-registration", "python-django-south", # todo: not packaged, should be installed with # "pip install longerusername" #"python-django-longerusername", ] # The name of the DB for PostgreSQL. DB_NAME = "patchwork" # SQL string to create the new role in PostgreSQL. POSTGRES_CREATE_ROLE = "CREATE ROLE \"%(role)s\" LOGIN \ CREATEDB PASSWORD '%(pwd)s'" # SQL string to grant permissions to a role in PostgreSQL. POSTGRES_GRANT_PRIVILEGES = "GRANT ALL PRIVILEGES ON ALL TABLES \ IN SCHEMA public TO \"%(role)s\" " # Apache config script name APACHE_CONFIG_SCRIPT = "patchmetrics" # Apache temporary config script name APACHE_CONFIG_SCRIPT_TMP = "patchmetrics.tmp" # Variable to replace in apache config WORKING_DIR = "$WORKING_DIR" # Variable to replace in local settings file. GENERATED_SECRET_KEY = "$GENERATED_SECRET_KEY" # Apache sites default path. APACHE_DEFAULT_DIR = "/etc/apache2/sites-available/" # Local settings file template. LOCAL_SETTINGS_TEMPLATE = "local_settings_template.py" # Local settings file. LOCAL_SETTINGS = "local_settings.py" # Apps directory. APPS_DIR = "apps/" # Postgres user. POSTGRES_USER = "postgres" # Postgres ubuntu user. POSTGRES_LOCAL_USER = getpass.getuser() # Postgres 'www-data' user. POSTGRES_WWW_USER = "www-data" # Apache websites to disable. APACHE_DISABLE_SITES = ["default"] def execute_command(cmd_args, work_dir=os.getcwd(), with_sudo=True, input_str=None, continue_on_error=False): """Runs the command passed. :param cmd_args: List of command and options to run. :type list :param word_dir: Where the command must be run. Defaults to current dir. :type str :param with_sudo: If the command must be executed as root. Defaults to True. :type bool :param input_str: String to pass to the process as input, in order to automate as much as possible. :type str :param continue_on_error: If an error arise, continue instead of exiting. Default to False. :type bool """ if not isinstance(cmd_args, list): cmd_args = list(cmd_args) if with_sudo: cmd_args.insert(0, "sudo") if input_str: process = subprocess.Popen(cmd_args, cwd=work_dir, stdin=subprocess.PIPE) process.communicate(input=input_str) else: process = subprocess.Popen(cmd_args, cwd=work_dir) process.communicate() if continue_on_error: return elif process.returncode != 0: print "Error executing the following command: %s" % " ".join(cmd_args) sys.exit(1) def update_repositories(): """Performs an 'apt-get update' on the system.""" cmd_args = ["apt-get", "update"] execute_command(cmd_args) def install_packages(packages, assume_yes=True): """Installs a new package in the system. :param packages: The packages to install. :type list """ if not isinstance(packages, list): packages = [packages] cmd_args = ["apt-get", "install"] if assume_yes: cmd_args = ["apt-get", "-y", "install"] cmd_args += packages execute_command(cmd_args) def prepare_apache_config(): """Update apache config file and copy it to sites enables dir.""" cmd_args = ["cp", APACHE_CONFIG_SCRIPT, APACHE_CONFIG_SCRIPT_TMP] execute_command(cmd_args, with_sudo=True) for line in fileinput.input(APACHE_CONFIG_SCRIPT_TMP, inplace=1): if WORKING_DIR in line: line = line.replace(WORKING_DIR, os.path.abspath( os.path.join(os.path.dirname( __file__ ), '..'))) print line, cmd_args = ["cp", APACHE_CONFIG_SCRIPT_TMP, os.path.join(APACHE_DEFAULT_DIR, APACHE_CONFIG_SCRIPT)] execute_command(cmd_args, with_sudo=True) def prepare_settings_file(): """Update local settings file and copy it to apps dir.""" chars = string.letters + string.digits + string.punctuation secret_key = repr("".join([random.choice(chars) for i in range(0,50)])) settings_path = os.path.join(os.path.dirname( __file__ ), '..', APPS_DIR, LOCAL_SETTINGS) cmd_args = ["cp", LOCAL_SETTINGS_TEMPLATE, settings_path] execute_command(cmd_args, with_sudo=True) for line in fileinput.input(settings_path, inplace=1): if GENERATED_SECRET_KEY in line: line = line.replace(GENERATED_SECRET_KEY, secret_key) if WORKING_DIR in line: line = line.replace(WORKING_DIR, os.path.abspath( os.path.join(os.path.dirname( __file__ ), '..'))) print line, def run_django_syncdb(): """Runs the django manage.py syncdb command.""" work_dir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', APPS_DIR)) cmd_args = ["python", "manage.py", "syncdb"] execute_command(cmd_args, work_dir=work_dir, with_sudo=False) def create_postgresql_role(role, pwd, postgres_usr="postgres"): """Creates a new PostgreSQL role. :param role: The name of the role to create. :type str :param pwd: The password to set to the new role. :type str :param postgres_usr: The superuser for PostreSQL. Defaults to 'postgres'. :type str """ postgres_commamd = POSTGRES_CREATE_ROLE % dict(role=str(role), pwd=str(pwd)) cmd_args = ["-u", postgres_usr, "psql", "-c", str(postgres_commamd)] execute_command(cmd_args) def create_postgresql_db(db_name, role): """Creates the PostgreSQL database. :param db_name: The name of the database to create. :type str :param role: The name of the postregsql user. :type str """ print "Creating PostgreSQL database..." cmd_args = ["-u", role, "createdb", db_name] execute_command(cmd_args) def reload_apache_service(): """Reloads Apache configuration.""" cmd_args = ["service", "apache2", "reload"] execute_command(cmd_args) def grant_postgresql_privileges(role, postgres_usr="postgres"): """Grants PostgreSQL privilges to a role. :param role: The name of the role to grant privileges to. :type str :param postgres_usr: The superuser for PostreSQL. Defaults to 'postgres'. :type str """ postgres_commamd = POSTGRES_GRANT_PRIVILEGES % dict(role=str(role)) cmd_args = ["-u", postgres_usr, "psql", "-c", str(postgres_commamd), DB_NAME] execute_command(cmd_args) def disable_apache_sites(sites): """Disables Apache sites. :param sites: The list of sites to disable. :type list """ if not isinstance(sites, list): sites = [sites] for site in sites: cmd_args = ["a2dissite", site] execute_command(cmd_args) def enable_apache_sites(sites): """Enables Apache sites. :param sites: The list of sites to enable. :type list """ if not isinstance(sites, list): sites = [sites] for site in sites: cmd_args = ["a2ensite", site] execute_command(cmd_args) def enable_apache_modules(modules): """Enables Apache modules. :param modules: List of modules to enable. :type list """ if not isinstance(modules, list): modules = [modules] for module in modules: cmd_args = ["a2enmod", module] execute_command(cmd_args) if __name__ == '__main__': update_repositories() install_packages(REQUIRED_PACKAGES) prepare_apache_config() prepare_settings_file() create_postgresql_role(POSTGRES_LOCAL_USER, POSTGRES_LOCAL_USER) create_postgresql_role(POSTGRES_WWW_USER, POSTGRES_WWW_USER) create_postgresql_db(DB_NAME, POSTGRES_WWW_USER) run_django_syncdb() grant_postgresql_privileges(POSTGRES_LOCAL_USER) grant_postgresql_privileges(POSTGRES_WWW_USER) disable_apache_sites(APACHE_DISABLE_SITES) enable_apache_sites("patchmetrics") reload_apache_service()