示例#1
0
def cli(ctx, dname):
    """
    Disable installations under the specified <domain>
    """
    assert isinstance(ctx, Context)

    dname = domain_parse(dname).hostname
    domain = Session.query(Domain).filter(Domain.name == dname).first()
    if not domain:
        click.secho('No such domain: {dn}'.format(dn=dname),
                    fg='red',
                    bold=True,
                    err=True)
        return

    sites = domain.sites
    for site in sites:
        if site.enabled:
            click.secho('Disabling site {sn}'.format(sn=site.name), bold=True)
            site.disable()

    # Restart Nginx
    p = Echo('Restarting web server...')
    FNULL = open(os.devnull, 'w')
    subprocess.check_call(['service', 'nginx', 'restart'],
                          stdout=FNULL,
                          stderr=subprocess.STDOUT)
    p.done()
示例#2
0
    def server_details(self):
        """
        Input server details (database information, etc.)
        """
        self._check_title(self.browser.title())
        p = Echo('Creating MySQL database...')

        # Create the database
        md5hex = md5(self.site.domain.name + self.site.slug).hexdigest()
        db_name = 'ipsv_{md5}'.format(md5=md5hex)
        # MySQL usernames are limited to 16 characters max
        db_user = '******'.format(md5=md5hex[:11])
        rand_pass = ''.join(random.SystemRandom().choice(string.ascii_letters +
                                                         string.digits)
                            for _ in range(random.randint(16, 24)))
        db_pass = rand_pass

        try:
            self.mysql.execute('CREATE DATABASE `{db}`'.format(db=db_name))
        except SQLAlchemyError:
            if not self.force:
                click.confirm(
                    'A previous database for this installation already exists.\n'
                    'Would you like to drop it now? The installation will be aborted if you do not',
                    abort=True)
            self.log.info(
                'Dropping existing database: {db}'.format(db=db_name))
            self.mysql.execute(
                'DROP DATABASE IF EXISTS `{db}`'.format(db=db_name))
            self.mysql.execute('DROP USER `{u}`'.format(u=db_user))
            self.mysql.execute('CREATE DATABASE `{db}`'.format(db=db_name))

        self.mysql.execute(
            "GRANT ALL ON {db}.* TO '{u}'@'localhost' IDENTIFIED BY '{p}'".
            format(db=db_name, u=db_user, p=db_pass))

        # Save the database connection information
        self.site.db_host = 'localhost'
        self.site.db_name = db_name
        self.site.db_user = db_user
        self.site.db_pass = db_pass
        self.ctx.db.commit()

        self.log.debug('MySQL Database Name: %s', db_name)
        self.log.debug('MySQL Database User: %s', db_user)
        self.log.debug('MySQL Database Password: %s', db_pass)

        # Set form fields and submit
        self.browser.select_form(nr=0)
        self.browser.form[self.FIELD_SERVER_SQL_HOST] = 'localhost'
        self.browser.form[self.FIELD_SERVER_SQL_USER] = db_user
        self.browser.form[self.FIELD_SERVER_SQL_PASS] = db_pass
        self.browser.form[self.FIELD_SERVER_SQL_DATABASE] = db_name
        self.browser.submit()
        p.done()
        self.admin()
示例#3
0
    def server_details(self):
        """
        Input server details (database information, etc.)
        """
        self._check_title(self.browser.title())
        p = Echo('Creating MySQL database...')

        # Create the database
        md5hex = md5(self.site.domain.name + self.site.slug).hexdigest()
        db_name = 'ipsv_{md5}'.format(md5=md5hex)
        # MySQL usernames are limited to 16 characters max
        db_user = '******'.format(md5=md5hex[:11])
        rand_pass = ''.join(random.SystemRandom()
                            .choice(string.ascii_letters + string.digits) for _ in range(random.randint(16, 24)))
        db_pass = rand_pass

        try:
            self.mysql.execute('CREATE DATABASE `{db}`'.format(db=db_name))
        except SQLAlchemyError:
            if not self.force:
                click.confirm('A previous database for this installation already exists.\n'
                              'Would you like to drop it now? The installation will be aborted if you do not',
                              abort=True)
            self.log.info('Dropping existing database: {db}'.format(db=db_name))
            self.mysql.execute('DROP DATABASE IF EXISTS `{db}`'.format(db=db_name))
            self.mysql.execute('DROP USER IF EXISTS `{u}`'.format(u=db_user))
            self.mysql.execute('CREATE DATABASE `{db}`'.format(db=db_name))

        self.mysql.execute("GRANT ALL ON {db}.* TO '{u}'@'localhost' IDENTIFIED BY '{p}'"
                           .format(db=db_name, u=db_user, p=db_pass))

        # Save the database connection information
        self.site.db_host = 'localhost'
        self.site.db_name = db_name
        self.site.db_user = db_user
        self.site.db_pass = db_pass
        self.ctx.db.commit()

        self.log.debug('MySQL Database Name: %s', db_name)
        self.log.debug('MySQL Database User: %s', db_user)
        self.log.debug('MySQL Database Password: %s', db_pass)

        # Set form fields and submit
        self.browser.select_form(nr=0)
        self.browser.form[self.FIELD_SERVER_SQL_HOST] = 'localhost'
        self.browser.form[self.FIELD_SERVER_SQL_USER] = db_user
        self.browser.form[self.FIELD_SERVER_SQL_PASS] = db_pass
        self.browser.form[self.FIELD_SERVER_SQL_DATABASE] = db_name
        self.browser.submit()
        p.done()
        self.admin()
示例#4
0
def cli(ctx, dname, site):
    """
    Enable the <site> under the specified <domain>
    """
    assert isinstance(ctx, Context)

    dname = domain_parse(dname).hostname
    domain = Session.query(Domain).filter(Domain.name == dname).first()
    if not domain:
        click.secho('No such domain: {dn}'.format(dn=dname),
                    fg='red',
                    bold=True,
                    err=True)
        return

    site_name = site
    site = Site.get(domain, site_name)
    if not site:
        click.secho('No such site: {site}'.format(site=site_name),
                    fg='red',
                    bold=True,
                    err=True)
        return

    p = Echo('Constructing paths and configuration files...')
    site.enable()
    p.done()

    # Restart Nginx
    p = Echo('Restarting web server...')
    FNULL = open(os.devnull, 'w')
    subprocess.check_call(['service', 'nginx', 'restart'],
                          stdout=FNULL,
                          stderr=subprocess.STDOUT)
    p.done()
示例#5
0
    def applications(self):
        """
        Select the applications to install (currently hardcoded to install all applications)
        """
        # Check for license submission errors
        try:
            self._check_title(self.browser.title())
        except InstallationError:
            rsoup = BeautifulSoup(self.browser.response().read(), "html.parser")
            error = rsoup.find('li', id='license_lkey').find('span', {'class': 'ipsType_warning'}).text
            raise InstallationError(error)

        # TODO: Make this configurable
        p = Echo('Setting applications to install...')
        self.browser.select_form(nr=0)
        self.browser.submit()
        p.done()
        self.server_details()
示例#6
0
    def admin(self):
        """
        Provide admin login credentials
        """
        self._check_title(self.browser.title())
        self.browser.select_form(nr=0)

        # Get the admin credentials
        prompted = []
        user = self.ctx.config.get('User', 'AdminUser')
        if not user:
            user = click.prompt('Admin display name')
            prompted.append('user')

        password = self.ctx.config.get('User', 'AdminPass')
        if not password:
            password = click.prompt('Admin password', hide_input=True, confirmation_prompt='Confirm admin password')
            prompted.append('password')

        email = self.ctx.config.get('User', 'AdminEmail')
        if not email:
            email = click.prompt('Admin email')
            prompted.append('email')

        self.browser.form[self.FIELD_ADMIN_USER] = user
        self.browser.form[self.FIELD_ADMIN_PASS] = password
        self.browser.form[self.FIELD_ADMIN_PASS_CONFIRM] = password
        self.browser.form[self.FIELD_ADMIN_EMAIL] = email
        p = Echo('Submitting admin information...')
        self.browser.submit()
        p.done()

        if len(prompted) >= 3:
            save = click.confirm('Would you like to save and use these admin credentials for future installations?')
            if save:
                self.log.info('Saving admin login credentials')
                self.ctx.config.set('User', 'AdminUser', user)
                self.ctx.config.set('User', 'AdminPass', password)
                self.ctx.config.set('User', 'AdminEmail', email)
                with open(self.ctx.config_path, 'wb') as cf:
                    self.ctx.config.write(cf)

        self.install()
示例#7
0
    def license(self):
        """
        Submit our license to IPS' servers
        """
        p = Echo('Submitting license key...')
        self._check_title(self.browser.title())
        self.browser.select_form(nr=0)

        # Set the fields
        self.browser.form[self.FIELD_LICENSE_KEY] = '{license}-TESTINSTALL'.format(license=self.site.license_key)
        self.browser.find_control('eula_checkbox').items[0].selected = True  # TODO: User prompt?

        # Submit the request
        self.log.debug('Submitting our license')
        self.browser.submit()
        self.log.debug('Response code: %s', self.browser.response().code)

        p.done()
        self.applications()
示例#8
0
def cli(ctx, dname, site):
    """
    Enable the <site> under the specified <domain>
    """
    assert isinstance(ctx, Context)

    dname = domain_parse(dname).hostname
    domain = Session.query(Domain).filter(Domain.name == dname).first()
    if not domain:
        click.secho('No such domain: {dn}'.format(dn=dname), fg='red', bold=True, err=True)
        return

    site_name = site
    site = Site.get(domain, site_name)
    if not site:
        click.secho('No such site: {site}'.format(site=site_name), fg='red', bold=True, err=True)
        return

    p = Echo('Constructing paths and configuration files...')
    site.enable()
    p.done()

    # Restart Nginx
    p = Echo('Restarting web server...')
    FNULL = open(os.devnull, 'w')
    subprocess.check_call(['service', 'nginx', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()
示例#9
0
    def install(self):
        """
        Run the actual installation
        """
        self._start_install()
        mr_link = self._get_mr_link()

        # Set up the progress bar
        pbar = ProgressBar(100, 'Running installation...')
        pbar.start()
        mr_j, mr_r = self._ajax(mr_link)

        # Loop until we get a redirect json response
        while True:
            mr_link = self._parse_response(mr_link, mr_j)

            stage = self._get_stage(mr_j)
            progress = self._get_progress(mr_j)
            mr_j, mr_r = self._ajax(mr_link)

            pbar.update(
                min([progress, 100]),
                stage)  # NOTE: Response may return progress values above 100

            # If we're done, finalize the installation and break
            redirect = self._check_if_complete(mr_link, mr_j)
            if redirect:
                pbar.finish()
                break

        p = Echo('Finalizing...')
        mr_r = self._request(redirect, raise_request=False)
        p.done()

        # Install developer tools
        if self.site.in_dev:
            DevToolsInstaller(self.ctx, self.site).install()

        # Get the link to our community homepage
        self._finalize(mr_r)
示例#10
0
    def system_check(self):
        """
        System requirements check
        """
        self._check_title(self.browser.title())
        p = Echo('Running system check...')
        rsoup = BeautifulSoup(self.browser.response().read(), "html.parser")

        # Check for any errors
        errors = []
        for ul in rsoup.find_all('ul', {'class': 'ipsList_checks'}):
            for li in ul.find_all('li', {'class': 'fail'}):
                errors.append(li.text)

        if errors:
            raise InstallationError(errors)

        # Continue
        continue_link = next(self.browser.links(text_regex='Continue'))
        p.done()
        self.browser.follow_link(continue_link)
        self.license()
示例#11
0
    def applications(self):
        """
        Select the applications to install (currently hardcoded to install all applications)
        """
        # Check for license submission errors
        try:
            self._check_title(self.browser.title())
        except InstallationError:
            rsoup = BeautifulSoup(self.browser.response().read(),
                                  "html.parser")
            error = rsoup.find('li', id='license_lkey').find(
                'span', {
                    'class': 'ipsType_warning'
                }).text
            raise InstallationError(error)

        # TODO: Make this configurable
        p = Echo('Setting applications to install...')
        self.browser.select_form(nr=0)
        self.browser.submit()
        p.done()
        self.server_details()
示例#12
0
    def license(self):
        """
        Submit our license to IPS' servers
        """
        p = Echo('Submitting license key...')
        self._check_title(self.browser.title())
        self.browser.select_form(nr=0)

        # Set the fields
        self.browser.form[
            self.FIELD_LICENSE_KEY] = '{license}-TESTINSTALL'.format(
                license=self.site.license_key)
        self.browser.find_control(
            'eula_checkbox').items[0].selected = True  # TODO: User prompt?

        # Submit the request
        self.log.debug('Submitting our license')
        self.browser.submit()
        self.log.debug('Response code: %s', self.browser.response().code)

        p.done()
        self.applications()
示例#13
0
    def install(self):
        """
        Run the actual installation
        """
        self._start_install()
        mr_link = self._get_mr_link()

        # Set up the progress bar
        pbar = ProgressBar(100, 'Running installation...')
        pbar.start()
        mr_j, mr_r = self._ajax(mr_link)

        # Loop until we get a redirect json response
        while True:
            mr_link = self._parse_response(mr_link, mr_j)

            stage = self._get_stage(mr_j)
            progress = self._get_progress(mr_j)
            mr_j, mr_r = self._ajax(mr_link)

            pbar.update(min([progress, 100]), stage)  # NOTE: Response may return progress values above 100

            # If we're done, finalize the installation and break
            redirect = self._check_if_complete(mr_link, mr_j)
            if redirect:
                pbar.finish()
                break

        p = Echo('Finalizing...')
        mr_r = self._request(redirect, raise_request=False)
        p.done()

        # Install developer tools
        if self.site.in_dev:
            DevToolsInstaller(self.ctx, self.site).install()

        # Get the link to our community homepage
        self._finalize(mr_r)
示例#14
0
    def system_check(self):
        """
        System requirements check
        """
        self.browser.open(self.url)
        self._check_title(self.browser.title())
        p = Echo('Running system check...')
        rsoup = BeautifulSoup(self.browser.response().read(), "html.parser")

        # Check for any errors
        errors = []
        for ul in rsoup.find_all('ul', {'class': 'ipsList_checks'}):
            for li in ul.find_all('li', {'class': 'fail'}):
                errors.append(li.text)

        if errors:
            raise InstallationError(errors)

        # Continue
        continue_link = next(self.browser.links(text_regex='Continue'))
        p.done()
        self.browser.follow_link(continue_link)
        self.license()
示例#15
0
def cli(ctx, dname):
    """
    Disable installations under the specified <domain>
    """
    assert isinstance(ctx, Context)

    dname = domain_parse(dname).hostname
    domain = Session.query(Domain).filter(Domain.name == dname).first()
    if not domain:
        click.secho('No such domain: {dn}'.format(dn=dname), fg='red', bold=True, err=True)
        return

    sites = domain.sites
    for site in sites:
        if site.enabled:
            click.secho('Disabling site {sn}'.format(sn=site.name), bold=True)
            site.disable()

    # Restart Nginx
    p = Echo('Restarting web server...')
    FNULL = open(os.devnull, 'w')
    subprocess.check_call(['service', 'nginx', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()
示例#16
0
def cli(ctx):
    """
    Run setup after a fresh Vagrant installation.
    """
    log = logging.getLogger('ipsv.setup')
    assert isinstance(ctx, Context)

    lock_path = os.path.join(ctx.config.get('Paths', 'Data'), 'setup.lck')
    if os.path.exists(lock_path):
        raise Exception('Setup is locked, please remove the setup lock file to continue')

    # Create our package directories
    p = Echo('Creating IPS Vagrant system directories...')
    dirs = ['/etc/ipsv', ctx.config.get('Paths', 'Data'), ctx.config.get('Paths', 'Log'),
            ctx.config.get('Paths', 'NginxSitesAvailable'), ctx.config.get('Paths', 'NginxSitesEnabled'),
            ctx.config.get('Paths', 'NginxSSL')]
    for d in dirs:
        if not os.path.exists(d):
            os.makedirs(d, 0o755)
    p.done()

    p = Echo('Copying IPS Vagrant configuration files...')
    with open('/etc/ipsv/ipsv.conf', 'w+') as f:
        ctx.config.write(f)
    p.done()

    # Set up alembic
    alembic_cfg = Config(os.path.join(ctx.basedir, 'alembic.ini'))
    alembic_cfg.set_main_option("script_location", os.path.join(ctx.basedir, 'migrations'))
    alembic_cfg.set_main_option("sqlalchemy.url", "sqlite:////{path}"
                                .format(path=os.path.join(ctx.config.get('Paths', 'Data'), 'sites.db')))

    command.current(alembic_cfg)
    command.downgrade(alembic_cfg, 'base')
    command.upgrade(alembic_cfg, 'head')

    # Update the system
    p = Echo('Updating package cache...')
    cache = apt.Cache()
    cache.update()
    cache.open(None)
    p.done()
    p = Echo('Upgrading system packages...')
    cache.upgrade()
    cache.commit()
    p.done()

    # Install our required packages
    requirements = ['nginx', 'php5-fpm', 'php5-curl', 'php5-gd', 'php5-imagick', 'php5-json', 'php5-mysql',
                    'php5-readline', 'php5-apcu']

    for requirement in requirements:
        # Make sure the package is available
        p = Echo('Marking package {pkg} for installation'.format(pkg=requirement))
        if requirement not in cache:
            log.warn('Required package {pkg} not available'.format(pkg=requirement))
            p.done(p.FAIL)
            continue

        # Mark the package for installation
        cache[requirement].mark_install()
        p.done()

    log.info('Committing package cache')
    p = Echo('Downloading and installing packages...')
    cache.commit()
    p.done()

    # Disable the default server block
    p = Echo('Configuring Nginx...')
    default_available = os.path.join(ctx.config.get('Paths', 'NginxSitesAvailable'), 'default')
    default_enabled = os.path.join(ctx.config.get('Paths', 'NginxSitesEnabled'), 'default')
    if os.path.isfile(default_available):
        os.remove(default_available)
    if os.path.islink(default_enabled):
        os.unlink(default_enabled)
    p.done()

    # Restart Nginx
    FNULL = open(os.devnull, 'w')
    p = Echo('Restarting Nginx...')
    subprocess.check_call(['service', 'nginx', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()

    # php5-fpm configuration
    p = Echo('Configuring php5-fpm...')
    if os.path.isfile('/etc/php5/fpm/pool.d/www.conf'):
        os.remove('/etc/php5/fpm/pool.d/www.conf')

    fpm_config = FpmPoolConfig().template
    with open('/etc/php5/fpm/pool.d/ips.conf', 'w') as f:
        f.write(fpm_config)
    p.done()

    # Restart php5-fpm
    p = Echo('Restarting php5-fpm...')
    subprocess.check_call(['service', 'php5-fpm', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()

    # Copy the man pages and rebuild the manual database
    p = Echo('Writing manual pages...')
    man_path = os.path.join(ctx.basedir, 'man', 'ipsv.1')
    sys_man_path = '/usr/local/share/man/man1'
    if not os.path.exists(sys_man_path):
        os.makedirs(sys_man_path)

    shutil.copyfile(man_path, os.path.join(sys_man_path, 'ipsv.1'))

    subprocess.check_call(['mandb'], stdout=FNULL, stderr=subprocess.STDOUT)

    # Enable the welcome message
    log.debug('Writing welcome message')
    wm_header = '## DO NOT REMOVE :: AUTOMATICALLY GENERATED BY IPSV ##'
    wm_remove = False

    # Remove old profile data
    for line in fileinput.input('/etc/profile', inplace=True):
        # Header / footer match?
        if line == wm_header:
            # Footer match (Stop removing)
            if wm_remove:
                wm_remove = False
                continue

            # Header match (Start removing)
            wm_remove = True
            continue

        # Removing lines?
        if wm_remove:
            continue

        # Print line and continue as normal
        sys.stdout.write(line)

    # Write new profile data
    with open('/etc/profile', 'a') as f:
        f.write("\n" + wm_header + "\n")
        fl_lock_path = os.path.join(ctx.config.get('Paths', 'Data'), 'first_login.lck')
        f.write('if [ ! -f "{lp}" ]; then'.format(lp=fl_lock_path) + "\n")
        f.write('  less "{wp}"'.format(wp=os.path.join(ctx.basedir, 'WELCOME.rst')) + "\n")
        f.write('  sudo touch "{lp}"'.format(lp=fl_lock_path) + "\n")
        f.write('fi' + "\n")
        f.write(wm_header + "\n")
    p.done()

    log.debug('Writing setup lock file')
    with open(os.path.join(ctx.config.get('Paths', 'Data'), 'setup.lck'), 'w') as f:
        f.write('1')
示例#17
0
def cli(ctx, name, dname, license_key, ips_version, force, enable, ssl, spdy, gzip, cache, install, dev):
    """
    Downloads and installs a new instance of the latest Invision Power Suite release.
    """
    assert isinstance(ctx, Context)
    login_session = ctx.get_login()
    log = logging.getLogger("ipsv.new")
    ctx.cache = cache

    # Prompt for our desired license
    def get_license():
        """
        Prompt the user for a license selection
        @rtype: ips_vagrant.scraper.licenses.LicenseMeta
        """
        licenses = Licenses(login_session).get()
        user_license = license_key or ctx.config.get("User", "LicenseKey")

        # If we already have a license key saved, skip the prompt and use it instead
        if user_license:
            licenses = {license.license_key: license for license in licenses}
            if user_license in licenses:
                return licenses[user_license]

        # Ask the user to select a license key
        opt = choice(
            [
                (key, "{u} ({k})".format(u=license.community_url, k=license.license_key))
                for key, license in enumerate(licenses)
            ],
            1,
            "Which license key would you like to use?",
        )
        license = licenses[opt]

        # Should we save this license?
        if click.confirm("Would you like to save and use this license for future requests?", True):
            ctx.log.debug("Saving license key {k}".format(k=license.license_key))
            ctx.config.set("User", "LicenseKey", license.license_key)
            with open(ctx.config_path, "wb") as configfile:
                ctx.config.write(configfile)

        return license

    # Get the latest IPS release
    lmeta = get_license()
    p = Echo("Fetching IPS version information...")
    ips = IpsManager(ctx, lmeta)
    p.done()
    if ips_version:
        if ips_version == "latest_dev":
            v = ips.dev_version
            if not v:
                click.secho("There is no IPS development release available for download", err=True, fg="red", bold=True)
                raise Exception("There is no IPS development release available for download")
            p = Echo("Downloading IPS development release {vs}...".format(vs=v.version.vstring))
        else:
            ips_version = Version(ips_version)
            v = ips.versions[ips_version.vtuple]
            p = Echo("Fetching IPS version {iv}".format(iv=ips_version.vstring))
    else:
        v = ips.latest
        p = Echo("Downloading IPS release {vs}...".format(vs=v.version.vstring))
    filename = ips.get(v, cache)
    p.done()

    # Parse the specific domain and make sure it's valid
    log.debug("Parsing domain name: %s", dname)
    dname = domain_parse(dname)
    if ssl is None:
        ssl = dname.scheme == "https"
    log.debug("Domain name parsed: %s", dname)

    domain = Domain.get_or_create(dname)

    # Make sure this site does not already exist
    p = Echo("Constructing site data...")
    site = ctx.db.query(Site).filter(Site.domain == domain).filter(collate(Site.name, "NOCASE") == name).count()
    if site:
        p.done(p.FAIL)
        log.error("Site already exists")
        click.secho(
            'An installation named "{s}" has already been created for the domain {d}'.format(s=name, d=dname.hostname),
            err=True,
            fg="red",
            bold=True,
        )
        raise click.Abort

    # Create the site database entry
    site = Site(
        name=name,
        domain=domain,
        license_key=lmeta.license_key,
        version=v.version.vstring,
        ssl=ssl,
        spdy=spdy,
        gzip=gzip,
        enabled=enable,
        in_dev=dev,
    )

    status = p.OK
    if os.path.exists(site.root):
        if not force:
            p.done(p.FAIL)
            click.secho(
                "Installation path already exists and --force was not passed:\n{p}".format(p=site.root),
                err=True,
                fg="red",
                bold=True,
            )
            log.info("Aborting installation, path already exists: {p}".format(p=site.root))
            raise click.Abort

        log.warn("Overwriting existing installation path: {p}".format(p=site.root))
        status = p.WARN

    ctx.db.add(site)
    ctx.db.commit()
    p.done(status)

    # Construct the HTTP path
    p = Echo("Constructing paths and configuration files...")
    site.write_nginx_config()
    p.done()

    # Generate SSL certificates if enabled
    if ssl:
        p = Echo("Generating SSL certificate...")
        ssl_path = os.path.join(ctx.config.get("Paths", "NginxSSL"), domain.name)
        if not os.path.exists(ssl_path):
            log.debug("Creating new SSL path: %s", ssl_path)
            os.makedirs(ssl_path, 0o755)

        sc = CertificateFactory(site).get()
        site.ssl_key = sc.key
        site.ssl_certificate = sc.certificate

        with open(os.path.join(ssl_path, "{s}.key".format(s=site.slug)), "w") as f:
            f.write(sc.key)
        with open(os.path.join(ssl_path, "{s}.pem").format(s=site.slug), "w") as f:
            f.write(sc.certificate)
        p.done()

    # Create a symlink if this site is being enabled
    if site.enabled:
        site.enable(force)

        # Restart Nginx
        p = Echo("Restarting web server...")
        FNULL = open(os.devnull, "w")
        subprocess.check_call(["service", "nginx", "restart"], stdout=FNULL, stderr=subprocess.STDOUT)
        p.done()

    # Extract IPS setup files
    p = Echo("Extracting setup files to tmp...")
    tmpdir = tempfile.mkdtemp("ips")
    setup_zip = os.path.join(tmpdir, "setup.zip")
    setup_dir = os.path.join(tmpdir, "setup")
    os.mkdir(setup_dir)

    log.info("Extracting setup files")
    shutil.copyfile(filename, setup_zip)
    with zipfile.ZipFile(setup_zip) as z:
        namelist = z.namelist()
        if re.match(r"^ips_\w{5}\/?$", namelist[0]):
            log.debug("Setup directory matched: %s", namelist[0])
        else:
            log.error("No setup directory matched, unable to continue")
            raise Exception("Unrecognized setup file format, aborting")

        z.extractall(setup_dir)
        log.debug("Setup files extracted to: %s", setup_dir)
        p.done()
        p = MarkerProgressBar("Copying setup files...")
        setup_tmpdir = os.path.join(setup_dir, namelist[0])
        for dirname, dirnames, filenames in p(os.walk(setup_tmpdir)):
            for filepath in dirnames:
                site_path = os.path.join(site.root, dirname.replace(setup_tmpdir, ""), filepath)
                if not os.path.exists(site_path):
                    log.debug("Creating directory: %s", site_path)
                    os.mkdir(site_path, 0o755)

            for filepath in filenames:
                tmp_path = os.path.join(dirname, filepath)
                site_path = os.path.join(site.root, dirname.replace(setup_tmpdir, ""), filepath)
                shutil.copy(tmp_path, site_path)

        log.info("Setup files copied to: %s", site.root)
    shutil.rmtree(tmpdir)

    # Apply proper permissions
    # p = MarkerProgressBar('Setting file permissions...')
    writeable_dirs = ["uploads", "plugins", "applications", "datastore"]

    for wdir in writeable_dirs:
        log.debug("Setting file permissions in %s", wdir)
        os.chmod(os.path.join(site.root, wdir), 0o777)
        p = MarkerProgressBar("Setting file permissions...", nl=False)
        for dirname, dirnames, filenames in p(os.walk(os.path.join(site.root, wdir))):
            for filename in filenames:
                os.chmod(os.path.join(dirname, filename), 0o666)

            for filename in dirnames:
                os.chmod(os.path.join(dirname, filename), 0o777)
    Echo("Setting file permissions...").done()

    shutil.move(os.path.join(site.root, "conf_global.dist.php"), os.path.join(site.root, "conf_global.php"))
    os.chmod(os.path.join(site.root, "conf_global.php"), 0o777)

    # Run the installation
    if install:
        p = Echo("Initializing installer...")
        i = installer(v.version, ctx, site, force)
        p.done()
        i.start()
    else:
        db_info = None
        if click.confirm("Would you like to create the database for this installation now?", default=True):
            db_info = create_database(site)

        click.echo("------")

        if db_info:
            db_name, db_user, db_pass = db_info

            log.debug("MySQL Database Name: %s", db_name)
            log.debug("MySQL Database User: %s", db_user)
            log.debug("MySQL Database Password: %s", db_pass)

            click.secho("MySQL Database Name: {dbn}".format(dbn=db_name), bold=True)
            click.secho("MySQL Database User: {dbu}".format(dbu=db_user), bold=True)
            click.secho("MySQL Database Password: {dbp}".format(dbp=db_pass), bold=True)

        click.secho(
            "IPS is now ready to be installed. To proceed with the installation, follow the link below",
            fg="yellow",
            bold=True,
        )
        click.echo("{schema}://{host}".format(schema="https" if site.ssl else "http", host=site.domain.name))
示例#18
0
def cli(ctx, name, dname, license_key, ips_version, force, enable, ssl, spdy, gzip, cache, install, dev):
    """
    Downloads and installs a new instance of the latest Invision Power Suite release.
    """
    assert isinstance(ctx, Context)
    login_session = ctx.get_login()
    log = logging.getLogger('ipsv.new')
    ctx.cache = cache

    # Prompt for our desired license
    def get_license():
        """
        Prompt the user for a license selection
        @rtype: ips_vagrant.scraper.licenses.LicenseMeta
        """
        licenses = Licenses(login_session).get()
        user_license = license_key or ctx.config.get('User', 'LicenseKey')

        # If we already have a license key saved, skip the prompt and use it instead
        if user_license:
            licenses = {license.license_key: license for license in licenses}
            if user_license in licenses:
                return licenses[user_license]

        # Ask the user to select a license key
        opt = choice([
            (key, '{u} ({k})'.format(u=license.community_url, k=license.license_key))
            for key, license in enumerate(licenses)
        ], 1, 'Which license key would you like to use?')
        license = licenses[opt]

        # Should we save this license?
        if click.confirm('Would you like to save and use this license for future requests?', True):
            ctx.log.debug('Saving license key {k}'.format(k=license.license_key))
            ctx.config.set('User', 'LicenseKey', license.license_key)
            with open(ctx.config_path, 'wb') as configfile:
                ctx.config.write(configfile)

        return license

    # Get the latest IPS release
    lmeta = get_license()
    p = Echo('Fetching IPS version information...')
    ips = IpsManager(ctx, lmeta)
    p.done()
    if ips_version:
        if ips_version == 'latest_dev':
            v = ips.dev_version
            if not v:
                click.secho('There is no IPS development release available for download', err=True, fg='red', bold=True)
                raise Exception('There is no IPS development release available for download')
            p = Echo('Downloading IPS development release {vs}...'.format(vs=v.version.vstring))
        else:
            ips_version = Version(ips_version)
            v = ips.versions[ips_version.vtuple]
            p = Echo('Fetching IPS version {iv}'.format(iv=ips_version.vstring))
    else:
        v = ips.latest
        p = Echo('Downloading IPS release {vs}...'.format(vs=v.version.vstring))
    filename = ips.get(v, cache)
    p.done()

    # Parse the specific domain and make sure it's valid
    log.debug('Parsing domain name: %s', dname)
    dname = domain_parse(dname)
    if ssl is None:
        ssl = dname.scheme == 'https'
    log.debug('Domain name parsed: %s', dname)

    domain = Domain.get_or_create(dname)

    # Make sure this site does not already exist
    p = Echo('Constructing site data...')
    site = ctx.db.query(Site).filter(Site.domain == domain).filter(collate(Site.name, 'NOCASE') == name).count()
    if site:
        p.done(p.FAIL)
        log.error('Site already exists')
        click.secho('An installation named "{s}" has already been created for the domain {d}'
                    .format(s=name, d=dname.hostname),
                    err=True, fg='red', bold=True)
        raise click.Abort

    # Create the site database entry
    site = Site(name=name, domain=domain, license_key=lmeta.license_key, version=v.version.vstring, ssl=ssl, spdy=spdy,
                gzip=gzip, enabled=enable, in_dev=dev)

    status = p.OK
    if os.path.exists(site.root):
        if not force:
            p.done(p.FAIL)
            click.secho("Installation path already exists and --force was not passed:\n{p}".format(p=site.root),
                        err=True, fg='red', bold=True)
            log.info('Aborting installation, path already exists: {p}'.format(p=site.root))
            raise click.Abort

        log.warn('Overwriting existing installation path: {p}'.format(p=site.root))
        status = p.WARN

    ctx.db.add(site)
    ctx.db.commit()
    p.done(status)

    # Construct the HTTP path
    p = Echo('Constructing paths and configuration files...')
    site.write_nginx_config()
    p.done()

    # Generate SSL certificates if enabled
    if ssl:
        p = Echo('Generating SSL certificate...')
        ssl_path = os.path.join(ctx.config.get('Paths', 'NginxSSL'), domain.name)
        if not os.path.exists(ssl_path):
            log.debug('Creating new SSL path: %s', ssl_path)
            os.makedirs(ssl_path, 0o755)

        sc = CertificateFactory(site).get()
        site.ssl_key = sc.key
        site.ssl_certificate = sc.certificate

        with open(os.path.join(ssl_path, '{s}.key'.format(s=site.slug)), 'w') as f:
            f.write(sc.key)
        with open(os.path.join(ssl_path, '{s}.pem').format(s=site.slug), 'w') as f:
            f.write(sc.certificate)
        p.done()

    # Create a symlink if this site is being enabled
    if site.enabled:
        site.enable(force)

        # Restart Nginx
        p = Echo('Restarting web server...')
        FNULL = open(os.devnull, 'w')
        subprocess.check_call(['service', 'nginx', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
        p.done()

    # Extract IPS setup files
    p = Echo('Extracting setup files to tmp...')
    tmpdir = tempfile.mkdtemp('ips')
    setup_zip = os.path.join(tmpdir, 'setup.zip')
    setup_dir = os.path.join(tmpdir, 'setup')
    os.mkdir(setup_dir)

    log.info('Extracting setup files')
    shutil.copyfile(filename, setup_zip)
    with zipfile.ZipFile(setup_zip) as z:
        namelist = z.namelist()
        if re.match(r'^ips_\w{5}\/?$', namelist[0]):
            log.debug('Setup directory matched: %s', namelist[0])
        else:
            log.error('No setup directory matched, unable to continue')
            raise Exception('Unrecognized setup file format, aborting')

        z.extractall(setup_dir)
        log.debug('Setup files extracted to: %s', setup_dir)
        p.done()
        p = MarkerProgressBar('Copying setup files...')
        setup_tmpdir = os.path.join(setup_dir, namelist[0])
        for dirname, dirnames, filenames in p(os.walk(setup_tmpdir)):
            for filepath in dirnames:
                site_path = os.path.join(site.root, dirname.replace(setup_tmpdir, ''), filepath)
                if not os.path.exists(site_path):
                    log.debug('Creating directory: %s', site_path)
                    os.mkdir(site_path, 0o755)

            for filepath in filenames:
                tmp_path = os.path.join(dirname, filepath)
                site_path = os.path.join(site.root, dirname.replace(setup_tmpdir, ''), filepath)
                shutil.copy(tmp_path, site_path)

        log.info('Setup files copied to: %s', site.root)
    shutil.rmtree(tmpdir)

    # Apply proper permissions
    # p = MarkerProgressBar('Setting file permissions...')
    writeable_dirs = ['uploads', 'plugins', 'applications', 'datastore']
    
    for wdir in writeable_dirs:
        log.debug('Setting file permissions in %s', wdir)
        os.chmod(os.path.join(site.root, wdir), 0o777)
        p = MarkerProgressBar('Setting file permissions...', nl=False)
        for dirname, dirnames, filenames in p(os.walk(os.path.join(site.root, wdir))):
            for filename in filenames:
                os.chmod(os.path.join(dirname, filename), 0o666)

            for filename in dirnames:
                os.chmod(os.path.join(dirname, filename), 0o777)
    Echo('Setting file permissions...').done()

    shutil.move(os.path.join(site.root, 'conf_global.dist.php'), os.path.join(site.root, 'conf_global.php'))
    os.chmod(os.path.join(site.root, 'conf_global.php'), 0o777)

    # Run the installation
    if install:
        p = Echo('Initializing installer...')
        i = installer(v.version, ctx, site, force)
        p.done()
        i.start()
    else:
        click.echo('------')
        click.secho('IPS is now ready to be installed. To proceed with the installation, follow the link below',
                    fg='yellow', bold=True)
        click.echo('{schema}://{host}'.format(schema='https' if site.ssl else 'http', host=site.domain.name))
示例#19
0
def cli(ctx):
    """
    Run setup after a fresh Vagrant installation.
    """
    log = logging.getLogger('ipsv.setup')
    assert isinstance(ctx, Context)

    lock_path = os.path.join(ctx.config.get('Paths', 'Data'), 'setup.lck')
    if os.path.exists(lock_path):
        raise Exception('Setup is locked, please remove the setup lock file to continue')

    # Create our package directories
    p = Echo('Creating IPS Vagrant system directories...')
    dirs = ['/etc/ipsv', ctx.config.get('Paths', 'Data'), ctx.config.get('Paths', 'Log'),
            ctx.config.get('Paths', 'NginxSitesAvailable'), ctx.config.get('Paths', 'NginxSitesEnabled'),
            ctx.config.get('Paths', 'NginxSSL')]
    for d in dirs:
        if not os.path.exists(d):
            os.makedirs(d, 0o755)
    p.done()

    p = Echo('Copying IPS Vagrant configuration files...')
    with open('/etc/ipsv/ipsv.conf', 'w+') as f:
        ctx.config.write(f)
    p.done()

    # Set up alembic
    alembic_cfg = Config(os.path.join(ctx.basedir, 'alembic.ini'))
    alembic_cfg.set_main_option("script_location", os.path.join(ctx.basedir, 'migrations'))
    alembic_cfg.set_main_option("sqlalchemy.url", "sqlite:////{path}"
                                .format(path=os.path.join(ctx.config.get('Paths', 'Data'), 'sites.db')))

    command.current(alembic_cfg)
    command.downgrade(alembic_cfg, 'base')
    command.upgrade(alembic_cfg, 'head')

    # Update the system
    p = Echo('Updating package cache...')
    cache = apt.Cache()
    cache.update()
    cache.open(None)
    p.done()
    p = Echo('Upgrading system packages...')
    cache.upgrade()
    cache.commit()
    p.done()

    # Install our required packages
    requirements = ['nginx', 'php5-fpm', 'php5-curl', 'php5-gd', 'php5-imagick', 'php5-json', 'php5-mysql',
                    'php5-readline', 'php5-apcu', 'php5-xdebug']

    for requirement in requirements:
        # Make sure the package is available
        p = Echo('Marking package {pkg} for installation'.format(pkg=requirement))
        if requirement not in cache:
            log.warn('Required package {pkg} not available'.format(pkg=requirement))
            p.done(p.FAIL)
            continue

        # Mark the package for installation
        cache[requirement].mark_install()
        p.done()

    log.info('Committing package cache')
    p = Echo('Downloading and installing packages...')
    cache.commit()
    p.done()

    # Disable the default server block
    p = Echo('Configuring Nginx...')
    default_available = os.path.join(ctx.config.get('Paths', 'NginxSitesAvailable'), 'default')
    default_enabled = os.path.join(ctx.config.get('Paths', 'NginxSitesEnabled'), 'default')
    if os.path.isfile(default_available):
        os.remove(default_available)
    if os.path.islink(default_enabled):
        os.unlink(default_enabled)
    p.done()

    # Restart Nginx
    FNULL = open(os.devnull, 'w')
    p = Echo('Restarting Nginx...')
    subprocess.check_call(['service', 'nginx', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()

    # php.ini configuration
    p = Echo('Configuring php...')
    with open('/etc/php5/fpm/php.ini', 'a') as f:
        f.write('\n[XDebug]')
        f.write('\nxdebug.cli_color=1')

    temp_fh, temp_path = mkstemp()
    with open(temp_path, 'w') as nf:
        with open('/etc/php5/fpm/php.ini') as of:
            # Configuration options we are replacing
            upload_max_filesize = re.compile( '^upload_max_filesize\s+=\s+(\d+[a-zA-Z])\s*$' )
            post_max_size = re.compile( '^post_max_size\s+=\s+(\d+[a-zA-Z])\s*$' )

            for line in of:
                match = upload_max_filesize.match( line ) if upload_max_filesize is not True else False
                if match:
                    nf.write( 'upload_max_filesize = 1000M\n' )
                    upload_max_filesize = True
                    continue

                match = post_max_size.match( line ) if post_max_size is not True else False
                if match:
                    nf.write( 'post_max_size = 1000M\n' )
                    post_max_size = True
                    continue

                nf.write(line)
    os.close(temp_fh)
    os.remove('/etc/php5/fpm/php.ini')
    shutil.move(temp_path, '/etc/php5/fpm/php.ini')
    os.chmod('/etc/php5/fpm/php.ini', 0o644)
    p.done()

    # php5-fpm configuration
    p = Echo('Configuring php5-fpm...')
    if os.path.isfile('/etc/php5/fpm/pool.d/www.conf'):
        os.remove('/etc/php5/fpm/pool.d/www.conf')

    fpm_config = FpmPoolConfig().template
    with open('/etc/php5/fpm/pool.d/ips.conf', 'w') as f:
        f.write(fpm_config)
    p.done()

    # Restart php5-fpm
    p = Echo('Restarting php5-fpm...')
    subprocess.check_call(['service', 'php5-fpm', 'restart'], stdout=FNULL, stderr=subprocess.STDOUT)
    p.done()

    # Copy the man pages and rebuild the manual database
    p = Echo('Writing manual pages...')
    man_path = os.path.join(ctx.basedir, 'man', 'ipsv.1')
    sys_man_path = '/usr/local/share/man/man1'
    if not os.path.exists(sys_man_path):
        os.makedirs(sys_man_path)

    shutil.copyfile(man_path, os.path.join(sys_man_path, 'ipsv.1'))

    subprocess.check_call(['mandb'], stdout=FNULL, stderr=subprocess.STDOUT)

    # Enable the welcome message
    log.debug('Writing welcome message')
    wm_header = '## DO NOT REMOVE :: AUTOMATICALLY GENERATED BY IPSV ##'
    wm_remove = False

    # Remove old profile data
    for line in fileinput.input('/etc/profile', inplace=True):
        # Header / footer match?
        if line == wm_header:
            # Footer match (Stop removing)
            if wm_remove:
                wm_remove = False
                continue

            # Header match (Start removing)
            wm_remove = True
            continue

        # Removing lines?
        if wm_remove:
            continue

        # Print line and continue as normal
        sys.stdout.write(line)

    # Write new profile data
    with open('/etc/profile', 'a') as f:
        f.write("\n" + wm_header + "\n")
        fl_lock_path = os.path.join(ctx.config.get('Paths', 'Data'), 'first_login.lck')
        f.write('if [ ! -f "{lp}" ]; then'.format(lp=fl_lock_path) + "\n")
        f.write('  less "{wp}"'.format(wp=os.path.join(ctx.basedir, 'WELCOME.rst')) + "\n")
        f.write('  sudo touch "{lp}"'.format(lp=fl_lock_path) + "\n")
        f.write('fi' + "\n")
        f.write(wm_header + "\n")
    p.done()

    log.debug('Writing setup lock file')
    with open(os.path.join(ctx.config.get('Paths', 'Data'), 'setup.lck'), 'w') as f:
        f.write('1')
示例#20
0
    def install(self):
        """
        Run the actual installation
        """
        p = Echo('Fetching Developer Tools version information...')
        dev_tools = DevToolsManager(self.ctx, self.site)
        status = p.OK if dev_tools.latest.request else p.FAIL
        p.done(status)
        p = Echo('Fetching the required Developer Tools release...')
        if self.site.version in dev_tools.versions:
            self.log.info('Dev Tools version matched for this IPS version')
            dev_version = dev_tools.versions[self.site.version]
            status = p.OK
        else:
            dev_version = None
            for dv in dev_tools.versions:
                if (dev_version is None) or (dv <= self.site.version):
                    dev_version = dev_tools.versions[dv]
            self.log.warn('No Dev Tools for IPS release %s found, using closest match (%s)',
                          self.site.version, dev_version.version.vstring)
            status = p.WARN
        filename = dev_tools.get(dev_version)
        p.done(status)

        # Extract dev files
        p = Echo('Extracting Developer Tools...')
        tmpdir = mkdtemp('ips')
        dev_tools_zip = os.path.join(tmpdir, 'dev_tools.zip')
        dev_tools_dir = os.path.join(tmpdir, 'dev_tools')
        os.mkdir(dev_tools_dir)

        shutil.copyfile(filename, dev_tools_zip)
        with ZipFile(dev_tools_zip) as z:
            namelist = z.namelist()
            if re.match(r'^(\d+)|(dev_[0-9a-zA-Z]{5})/?$', namelist[0]):
                self.log.debug('Developer Tools directory matched: %s', namelist[0])
            else:
                self.log.error('No developer tools directory matched, unable to continue')
                raise Exception('Unrecognized dev tools file format, aborting')

            z.extractall(dev_tools_dir)
            self.log.debug('Developer Tools extracted to: %s', dev_tools_dir)
            dev_tmpdir = os.path.join(dev_tools_dir, namelist[0])
            path = dev_tmpdir
            for dirname, dirnames, filenames in os.walk(dev_tmpdir):
                for filepath in dirnames:
                    site_path = os.path.join(self.site.root, dirname.replace(path, ''), filepath)
                    if not os.path.exists(site_path):
                        self.log.debug('Creating directory: %s', site_path)
                        os.mkdir(site_path, 0o755)

                for filepath in filenames:
                    tmp_path = os.path.join(dirname, filepath)
                    site_path = os.path.join(self.site.root, dirname.replace(path, ''), filepath)
                    shutil.copy(tmp_path, site_path)

            self.log.info('Developer Tools copied to: %s', self.site.root)
        shutil.rmtree(tmpdir)
        p.done()

        p = Echo('Putting IPS into IN_DEV mode...')
        const_path = os.path.join(self.site.root, 'constants.php')
        with open(const_path, 'w+') as f:
            f.write("<?php\n")
            f.write("\n")
            f.write("define( 'IN_DEV', TRUE );")
        p.done()
示例#21
0
def cli(ctx, name, dname, license_key, ips_version, force, enable, ssl, spdy,
        gzip, cache, install, dev):
    """
    Downloads and installs a new instance of the latest Invision Power Suite release.
    """
    assert isinstance(ctx, Context)
    login_session = ctx.get_login()
    log = logging.getLogger('ipsv.new')
    ctx.cache = cache

    # Prompt for our desired license
    def get_license():
        """
        Prompt the user for a license selection
        @rtype: ips_vagrant.scraper.licenses.LicenseMeta
        """
        licenses = Licenses(login_session).get()
        user_license = license_key or ctx.config.get('User', 'LicenseKey')

        # If we already have a license key saved, skip the prompt and use it instead
        if user_license:
            licenses = {license.license_key: license for license in licenses}
            if user_license in licenses:
                return licenses[user_license]

        # Ask the user to select a license key
        opt = choice([(key, '{u} ({k})'.format(u=license.community_url,
                                               k=license.license_key))
                      for key, license in enumerate(licenses)], 1,
                     'Which license key would you like to use?')
        license = licenses[opt]

        # Should we save this license?
        if click.confirm(
                'Would you like to save and use this license for future requests?',
                True):
            ctx.log.debug(
                'Saving license key {k}'.format(k=license.license_key))
            ctx.config.set('User', 'LicenseKey', license.license_key)
            with open(ctx.config_path, 'wb') as configfile:
                ctx.config.write(configfile)

        return license

    # Get the latest IPS release
    lmeta = get_license()
    p = Echo('Fetching IPS version information...')
    ips = IpsManager(ctx, lmeta)
    p.done()
    if ips_version:
        if ips_version == 'latest_dev':
            v = ips.dev_version
            if not v:
                click.secho(
                    'There is no IPS development release available for download',
                    err=True,
                    fg='red',
                    bold=True)
                raise Exception(
                    'There is no IPS development release available for download'
                )
            p = Echo('Downloading IPS development release {vs}...'.format(
                vs=v.version.vstring))
        else:
            ips_version = Version(ips_version)
            v = ips.versions[ips_version.vtuple]
            p = Echo(
                'Fetching IPS version {iv}'.format(iv=ips_version.vstring))
    else:
        v = ips.latest
        p = Echo(
            'Downloading IPS release {vs}...'.format(vs=v.version.vstring))
    filename = ips.get(v, cache)
    p.done()

    # Parse the specific domain and make sure it's valid
    log.debug('Parsing domain name: %s', dname)
    dname = domain_parse(dname)
    if ssl is None:
        ssl = dname.scheme == 'https'
    log.debug('Domain name parsed: %s', dname)

    domain = Domain.get_or_create(dname)

    # Make sure this site does not already exist
    p = Echo('Constructing site data...')
    site = ctx.db.query(Site).filter(Site.domain == domain).filter(
        collate(Site.name, 'NOCASE') == name).count()
    if site:
        p.done(p.FAIL)
        log.error('Site already exists')
        click.secho(
            'An installation named "{s}" has already been created for the domain {d}'
            .format(s=name, d=dname.hostname),
            err=True,
            fg='red',
            bold=True)
        raise click.Abort

    # Create the site database entry
    site = Site(name=name,
                domain=domain,
                license_key=lmeta.license_key,
                version=v.version.vstring,
                ssl=ssl,
                spdy=spdy,
                gzip=gzip,
                enabled=enable,
                in_dev=dev)

    status = p.OK
    if os.path.exists(site.root):
        if not force:
            p.done(p.FAIL)
            click.secho(
                "Installation path already exists and --force was not passed:\n{p}"
                .format(p=site.root),
                err=True,
                fg='red',
                bold=True)
            log.info('Aborting installation, path already exists: {p}'.format(
                p=site.root))
            raise click.Abort

        log.warn(
            'Overwriting existing installation path: {p}'.format(p=site.root))
        status = p.WARN

    ctx.db.add(site)
    ctx.db.commit()
    p.done(status)

    # Construct the HTTP path
    p = Echo('Constructing paths and configuration files...')
    site.write_nginx_config()
    p.done()

    # Generate SSL certificates if enabled
    if ssl:
        p = Echo('Generating SSL certificate...')
        ssl_path = os.path.join(ctx.config.get('Paths', 'NginxSSL'),
                                domain.name)
        if not os.path.exists(ssl_path):
            log.debug('Creating new SSL path: %s', ssl_path)
            os.makedirs(ssl_path, 0o755)

        sc = CertificateFactory(site).get()
        site.ssl_key = sc.key
        site.ssl_certificate = sc.certificate

        with open(os.path.join(ssl_path, '{s}.key'.format(s=site.slug)),
                  'w') as f:
            f.write(sc.key)
        with open(os.path.join(ssl_path, '{s}.pem').format(s=site.slug),
                  'w') as f:
            f.write(sc.certificate)
        p.done()

    # Create a symlink if this site is being enabled
    if site.enabled:
        site.enable(force)

        # Restart Nginx
        p = Echo('Restarting web server...')
        FNULL = open(os.devnull, 'w')
        subprocess.check_call(['service', 'nginx', 'restart'],
                              stdout=FNULL,
                              stderr=subprocess.STDOUT)
        p.done()

    # Extract IPS setup files
    p = Echo('Extracting setup files to tmp...')
    tmpdir = tempfile.mkdtemp('ips')
    setup_zip = os.path.join(tmpdir, 'setup.zip')
    setup_dir = os.path.join(tmpdir, 'setup')
    os.mkdir(setup_dir)

    log.info('Extracting setup files')
    shutil.copyfile(filename, setup_zip)
    with zipfile.ZipFile(setup_zip) as z:
        namelist = z.namelist()
        if re.match(r'^ips_\w{5}\/?$', namelist[0]):
            log.debug('Setup directory matched: %s', namelist[0])
        else:
            log.error('No setup directory matched, unable to continue')
            raise Exception('Unrecognized setup file format, aborting')

        z.extractall(setup_dir)
        log.debug('Setup files extracted to: %s', setup_dir)
        p.done()
        p = MarkerProgressBar('Copying setup files...')
        setup_tmpdir = os.path.join(setup_dir, namelist[0])
        for dirname, dirnames, filenames in p(os.walk(setup_tmpdir)):
            for filepath in dirnames:
                site_path = os.path.join(site.root,
                                         dirname.replace(setup_tmpdir, ''),
                                         filepath)
                if not os.path.exists(site_path):
                    log.debug('Creating directory: %s', site_path)
                    os.mkdir(site_path, 0o755)

            for filepath in filenames:
                tmp_path = os.path.join(dirname, filepath)
                site_path = os.path.join(site.root,
                                         dirname.replace(setup_tmpdir, ''),
                                         filepath)
                shutil.copy(tmp_path, site_path)

        log.info('Setup files copied to: %s', site.root)
    shutil.rmtree(tmpdir)

    # Apply proper permissions
    # p = MarkerProgressBar('Setting file permissions...')
    writeable_dirs = ['uploads', 'plugins', 'applications', 'datastore']

    for wdir in writeable_dirs:
        log.debug('Setting file permissions in %s', wdir)
        os.chmod(os.path.join(site.root, wdir), 0o777)
        p = MarkerProgressBar('Setting file permissions...', nl=False)
        for dirname, dirnames, filenames in p(
                os.walk(os.path.join(site.root, wdir))):
            for filename in filenames:
                os.chmod(os.path.join(dirname, filename), 0o666)

            for filename in dirnames:
                os.chmod(os.path.join(dirname, filename), 0o777)
    Echo('Setting file permissions...').done()

    shutil.move(os.path.join(site.root, 'conf_global.dist.php'),
                os.path.join(site.root, 'conf_global.php'))
    os.chmod(os.path.join(site.root, 'conf_global.php'), 0o777)

    # Run the installation
    if install:
        p = Echo('Initializing installer...')
        i = installer(v.version, ctx, site, force)
        p.done()
        i.start()
    else:
        db_info = None
        if click.confirm(
                'Would you like to create the database for this installation now?',
                default=True):
            db_info = create_database(site)

        click.echo('------')

        if db_info:
            db_name, db_user, db_pass = db_info

            log.debug('MySQL Database Name: %s', db_name)
            log.debug('MySQL Database User: %s', db_user)
            log.debug('MySQL Database Password: %s', db_pass)

            click.secho('MySQL Database Name: {dbn}'.format(dbn=db_name),
                        bold=True)
            click.secho('MySQL Database User: {dbu}'.format(dbu=db_user),
                        bold=True)
            click.secho('MySQL Database Password: {dbp}'.format(dbp=db_pass),
                        bold=True)

        click.secho(
            'IPS is now ready to be installed. To proceed with the installation, follow the link below',
            fg='yellow',
            bold=True)
        click.echo('{schema}://{host}'.format(
            schema='https' if site.ssl else 'http', host=site.domain.name))