Exemple #1
0
 def hook_install(self):
     cfg = self.config
     self.hook_uninstall()
     self.generate_locales((u'fr_CH.UTF-8',))
     try_makedirs(u'/etc/mysql')
     debconf, mysql = u'debconf-set-selections', u'mysql-server mysql-server'
     # Tip : http://ubuntuforums.org/showthread.php?t=981801
     self.cmd(debconf, input=u'{0}/root_password select {1}'.format(mysql, cfg.mysql_root_password))
     self.cmd(debconf, input=u'{0}/root_password_again select {1}'.format(mysql, cfg.mysql_root_password))
     self.install_packages(WebuiHooks.PACKAGES)
     self.restart_ntp()
     self.info(u'Import Web UI database and create user')
     hostname = socket.gethostname()
     self.cmd(u'service mysql start', fail=False)
     self.mysql_do(u"DROP USER ''@'localhost'; DROP USER ''@'{0}';".format(hostname), fail=False)
     self.mysql_do(u"GRANT ALL PRIVILEGES ON *.* TO 'root'@'%%' WITH GRANT OPTION;")
     self.mysql_do(u'DROP DATABASE IF EXISTS webui')
     self.mysql_do(cli_input=open(self.local_config.site_database_file, u'r', u'utf-8').read())
     self.mysql_do(u"GRANT ALL ON webui.* TO 'webui'@'%%' IDENTIFIED BY '{0}';".format(cfg.mysql_user_password))
     self.info(u'Configure Apache 2')
     self.cmd(u'a2enmod rewrite')
     self.info(u'Copy and pre-configure Web UI')
     rsync(u'www/', self.local_config.site_directory, archive=True, delete=True, exclude_vcs=True, recursive=True)
     chown(self.local_config.site_directory, DAEMON_USER, DAEMON_GROUP, recursive=True)
     self.local_config.encryption_key = WebuiHooks.randpass(32)
     self.info(u'Expose Apache 2 service')
     self.open_port(80, u'TCP')
Exemple #2
0
def post_install():
    from encodebox import lib
    from pytoolbox.console import confirm
    from pytoolbox.encoding import to_bytes
    from pytoolbox.filesystem import chown, from_template, try_makedirs, try_remove
    from pytoolbox.network.http import download

    if not exists(u'/usr/local/bin/neroAacEnc'):
        try:
            print(u'Download and install Nero AAC encoder')
            download(u'ftp://ftp6.nero.com/tools/NeroDigitalAudio.zip',
                     u'/tmp/nero.zip')
            zipfile.ZipFile(u'/tmp/nero.zip').extract(u'linux/neroAacEnc',
                                                      u'/usr/local/bin')
            os.chmod(
                u'/usr/local/bin/neroAacEnc',
                os.stat(u'/usr/local/bin/neroAacEnc').st_mode | stat.S_IEXEC)
        finally:
            try_remove(u'/tmp/nero.zip')

    filename = lib.SETTINGS_FILENAME
    settings = lib.load_settings(u'etc/config.yaml')
    if not exists(filename) or confirm(
            u'Overwrite existing configuration file "{0}"'.format(filename)):
        print(u'Generate configuration file "{0}"'.format(filename))
        password = lib.generate_password()
        settings[u'rabbit_password'] = password
        lib.save_settings(filename, settings)

    print(u'Configure RabbitMQ Message Broker')
    check_call([u'service', u'rabbitmq-server', u'start'])
    call([u'rabbitmqctl', u'add_vhost', u'/'])
    call([u'rabbitmqctl', u'delete_user', u'guest'])
    call([u'rabbitmqctl', u'delete_user', u'encodebox'])
    call([
        u'rabbitmqctl', u'add_user', u'encodebox', settings[u'rabbit_password']
    ])
    check_call([
        u'rabbitmqctl', u'set_permissions', u'-p', u'/', u'encodebox', u'.*',
        u'.*', u'.*'
    ])
    users, vhosts = lib.rabbit_users(), lib.rabbit_vhosts()
    print(u'RabbitMQ users: {0} vhosts: {1}'.format(users, vhosts))
    if u'guest' in users or u'encodebox' not in users:
        raise RuntimeError(to_bytes(u'Unable to configure RabbitMQ'))

    print(u'Create directory for storing persistent data')
    try_makedirs(lib.LIB_DIRECTORY)
    chown(lib.LIB_DIRECTORY,
          lib.USERNAME,
          pwd.getpwnam(lib.USERNAME).pw_gid,
          recursive=True)
    print(u'Register and start our services as user ' + lib.USERNAME)
    from_template(u'etc/encodebox.conf.template',
                  u'/etc/supervisor/conf.d/encodebox.conf', {
                      u'lib_directory': lib.LIB_DIRECTORY,
                      u'user': lib.USERNAME
                  })
    call([u'service', u'supervisor', u'force-reload'])
Exemple #3
0
 def storage_remount(self, address=None, fstype=None, mountpoint=None, options=u''):
     if self.storage_config_is_enabled:
         self.info(u'Override storage parameters with charm configuration')
         address = self.config.storage_address
         nat_address = self.config.storage_nat_address
         fstype = self.config.storage_fstype
         mountpoint = self.config.storage_mountpoint
         options = self.config.storage_options
     elif address and fstype and mountpoint:
         self.info(u'Use storage parameters from charm storage relation')
         nat_address = u''
     else:
         return
     if nat_address:
         self.info(u'Update hosts file to map storage internal address {0} to {1}'.format(address, nat_address))
         lines = filter(lambda l: nat_address not in l, open(self.local_config.hosts_file, u'r', u'utf-8'))
         lines += u'{0} {1}\n'.format(nat_address, address)
         open(self.local_config.hosts_file, u'w', u'utf-8').write(u''.join(lines))
     # Avoid unregistering and registering storage if it does not change ...
     if (address == self.local_config.storage_address and nat_address == self.local_config.storage_nat_address and
         fstype == self.local_config.storage_fstype and mountpoint == self.local_config.storage_mountpoint and
         options == self.local_config.storage_options):
         self.remark(u'Skip remount already mounted shared storage')
     else:
         self.storage_unregister()
         self.debug(u"Mount shared storage [{0}] {1}:{2} type {3} options '{4}' -> {5}".format(nat_address, address,
                    mountpoint, fstype, options, self.local_config.storage_path))
         try_makedirs(self.local_config.storage_path)
         # FIXME try X times, a better way to handle failure
         for i in xrange(self.local_config.storage_mount_max_retry):
             if self.storage_is_mounted:
                 break
             mount_address = u'{0}:/{1}'.format(nat_address or address, mountpoint)
             mount_path = self.local_config.storage_path
             if options:
                 self.cmd([u'mount', u'-t', fstype, u'-o', options, mount_address, mount_path])
             else:
                 self.cmd([u'mount', u'-t', fstype, mount_address, mount_path])
             time.sleep(self.local_config.storage_mount_sleep_delay)
         if self.storage_is_mounted:
             # FIXME update /etc/fstab (?)
             self.local_config.storage_address = address
             self.local_config.storage_nat_address = nat_address
             self.local_config.storage_fstype = fstype
             self.local_config.storage_mountpoint = mountpoint
             self.local_config.storage_options = options
             self.remark(u'Shared storage successfully registered')
             self.debug(u'Create directories in the shared storage and ensure it is owned by the right user')
             try_makedirs(self.local_config.storage_medias_path())
             try_makedirs(self.local_config.storage_uploads_path)
             chown(self.local_config.storage_path, DAEMON_USER, DAEMON_GROUP, recursive=True)
         else:
             raise IOError(to_bytes(u'Unable to mount shared storage'))
Exemple #4
0
 def hook_uninstall(self):
     self.info(u'Uninstall prerequisities, unregister service and load default configuration')
     self.hook_stop()
     self.storage_unregister()
     self.subordinate_unregister()
     if self.config.cleanup:
         self.cmd(u'apt-get -y remove --purge {0}'.format(u' '.join(PublisherHooks.PACKAGES)))
         self.cmd(u'apt-get -y remove --purge {0}'.format(u' '.join(PublisherHooks.FIX_PACKAGES)), fail=False)
         self.cmd(u'apt-get -y autoremove')
         shutil.rmtree(u'/etc/apache2/',     ignore_errors=True)
         shutil.rmtree(u'/var/log/apache2/', ignore_errors=True)
     shutil.rmtree(self.publish_path, ignore_errors=True)
     os.makedirs(self.publish_path)
     chown(self.publish_path, DAEMON_USER, DAEMON_GROUP, recursive=True)
     self.local_config.reset()
     self.local_config.update_publish_uri(self.public_address)
Exemple #5
0
    def hook_install(self):
        local_cfg = self.local_config

        self.hook_uninstall()
        self.generate_locales((u'fr_CH.UTF-8',))
        self.install_packages(OrchestraHooks.PACKAGES + OrchestraHooks.JUJU_PACKAGES, ppas=OrchestraHooks.PPAS)
        self.restart_ntp()
        self.info(u'Copy Orchestra and the local charms repository of OSCIED')
        rsync(local_cfg.api_path, local_cfg.site_directory, **self.rsync_kwargs)
        chown(local_cfg.site_directory, DAEMON_USER, DAEMON_GROUP, recursive=True)
        self.info(u'Expose RESTful API, MongoDB & RabbitMQ service')
        self.open_port(80,    u'TCP')  # Orchestra RESTful API
        self.open_port(27017, u'TCP')  # MongoDB port mongod and mongos instances
        #self.open_port(27018, u'TCP') # MongoDB port when running with shardsvr setting
        #self.open_port(27019, u'TCP') # MongoDB port when running with configsvr setting
        #self.open_port(28017, u'TCP') # MongoDB port for the web status page. This is always +1000
        self.open_port(5672,  u'TCP')  # RabbitMQ service
Exemple #6
0
    def start_celery_worker(self, retries=5, delay=2):
        worker_name = self.local_config.worker_name
        self.info(u'Start the {0} worker'.format(worker_name))

        self.info(u"Ensure that the worker's directory is owned by the right user")
        chown(self.directory, DAEMON_USER, DAEMON_GROUP, recursive=True)

        start_time = time.time()
        for start_delay in xrange(retries):
            if self.cmd(u'service {0} status'.format(worker_name), fail=False)[u'returncode'] == 0:
                delta_time = time.time() - start_time
                self.remark(u'Worker {0} successfully started in {1:0.1f} seconds'.format(worker_name, delta_time))
                return
            else:
                self.cmd(u'service {0} start'.format(worker_name))
                time.sleep(delay)
        # FIXME maybe the latest attempt was successful and we do not check ... hum
        raise RuntimeError(to_bytes(u'Worker {0} is not ready'.format(worker_name)))
Exemple #7
0
def test_chown(tmp_path):
    file_a = tmp_path / 'a.txt'
    file_b = tmp_path / 'b.txt'
    file_c = tmp_path / 'other' / 'c.txt'
    filesystem.makedirs(file_c, parent=True)
    Path(file_a).touch()
    Path(file_b).touch()
    Path(file_c).touch()

    with mock.patch('os.chown') as chown:
        filesystem.chown(file_a, 'root')
    chown.assert_called_once_with(file_a, 0, -1)

    with mock.patch('os.chown') as chown:
        filesystem.chown(tmp_path, 100, 'root')
    chown.assert_called_once_with(tmp_path, 100, 0)

    with mock.patch('os.chown') as chown:
        filesystem.chown(tmp_path, 100, 'root', recursive=True)
    chown.assert_has_calls([
        mock.call(str(tmp_path), 100, 0),
        mock.call(str(file_b), 100, 0),
        mock.call(str(file_a), 100, 0),
        mock.call(str(file_c.parent), 100, 0),
        mock.call(str(file_c), 100, 0),
    ],
                           any_order=True)
Exemple #8
0
 def save_local_config(self):
     u"""Save or update local configuration in charm's and api's path and ensure that is owned by the right user."""
     super(OrchestraHooks, self).save_local_config()
     self.local_config.write(self.local_config.site_local_config_file, makedirs=True)
     chown(self.local_config.site_local_config_file, DAEMON_USER, DAEMON_GROUP)
Exemple #9
0
    def hook_config_changed(self):
        cfg, local_cfg = self.config, self.local_config
        # Apache site files must end with .conf for a2ensite to work
        site_file = self.name_slug + ".conf"

        self.info(u'Start MongoDB and RabbitMQ daemons')
        self.cmd(u'service mongodb start',         fail=False)
        self.cmd(u'service rabbitmq-server start', fail=False)

        self.info(u'Configure JuJu Service Orchestrator')
        juju_config_path = dirname(local_cfg.juju_config_file)
        rsync(local_cfg.juju_template_path, juju_config_path, **self.rsync_kwargs)
        chown(juju_config_path, DAEMON_USER, DAEMON_GROUP, recursive=True)

        self.info(u'Configure Secure Shell')
        rsync(local_cfg.ssh_template_path, local_cfg.ssh_config_path, **self.rsync_kwargs)
        chown(local_cfg.ssh_config_path, DAEMON_USER, DAEMON_GROUP, recursive=True)

        self.info(u'Configure Apache 2')
        self.template2config(local_cfg.htaccess_template_file, local_cfg.htaccess_config_file, {})
        self.template2config(local_cfg.site_template_file, join(local_cfg.sites_available_path, site_file), {
            u'alias': self.api_alias, u'directory': local_cfg.site_directory, u'domain': self.public_address,
            u'wsgi': local_cfg.api_wsgi
        })
        self.cmd(u'a2dissite 000-default')
        self.cmd(u'a2ensite {0}'.format(site_file))

        self.info(u'Configure MongoDB Scalable NoSQL DB')
        with open(u'f.js', u'w', u'utf-8') as mongo_f:
            mongo_f.write(u"db.addUser('admin', '{0}', false);".format(cfg.mongo_admin_password))
        with open(u'g.js', u'w', u'utf-8') as mongo_g:
            mongo_g.write(u"db.addUser('node', '{0}', false);".format(cfg.mongo_node_password))
        self.cmd(u'mongo f.js')
        self.cmd(u'mongo orchestra f.js')
        self.cmd(u'mongo celery g.js')
        [os.remove(f) for f in (u'f.js', u'g.js')]

        mongo_config = ConfigObj(local_cfg.mongo_config_file)
        mongo_config[u'bind_ip'] = u'0.0.0.0'
        mongo_config[u'noauth'] = u'false'
        mongo_config[u'auth'] = u'true'
        mongo_config.write()

        self.configure_rabbitmq()

        if cfg.plugit_api_url:
            self.info(u'Configure PlugIt server')
            infos = {
                u'api_url': cfg.plugit_api_url, u'debug': cfg.verbose, u'base_url': cfg.plugit_base_url,
                u'allowed_networks': u'", "'.join(cfg.plugit_allowed_networks.split(u','))
            }
            self.template2config(local_cfg.plugit_template_file, local_cfg.plugit_config_file, infos)

        self.info(u'Configure Orchestra the Orchestrator')
        local_cfg.verbose = cfg.verbose
        local_cfg.api_url = self.api_url(local=False)
        local_cfg.charms_release = cfg.charms_release
        local_cfg.node_secret = cfg.node_secret
        local_cfg.root_secret = cfg.root_secret
        local_cfg.mongo_admin_connection = self.mongo_admin_connection
        local_cfg.mongo_node_connection = self.mongo_node_connection
        local_cfg.rabbit_connection = self.rabbit_connection
        infos = {
            u'rabbit': unicode(self.rabbit_connection),
            u'port': unicode(27017),
            u'username': u'node',
            u'password': unicode(cfg.mongo_node_password),
        }
        self.template2config(local_cfg.celery_template_file, local_cfg.celery_config_file, infos)
        local_cfg.email_server = cfg.email_server
        local_cfg.email_tls = cfg.email_tls
        local_cfg.email_address = cfg.email_address
        local_cfg.email_username = cfg.email_username
        local_cfg.email_password = cfg.email_password
        local_cfg.plugit_api_url = cfg.plugit_api_url
        self.remark(u'Orchestrator successfully configured')

        self.info(u'Symlink charms default directory to directory for release {0}'.format(cfg.charms_release))
        try_symlink(abspath(local_cfg.charms_default_path), abspath(local_cfg.charms_release_path))

        self.info(u'Ensure that the Apache sites directory is owned by the right user')
        chown(local_cfg.sites_directory, DAEMON_USER, DAEMON_GROUP, recursive=True)

        self.info(u'Configure Cronjob')
        self.template2config(local_cfg.cronjob_template_file, '/etc/cron.d/cron_enco', {})

        self.storage_remount()