def write_out_config():
    """
    Write out the StorPool configuration file specified in the charm config.
    """
    rdebug('about to write out the /etc/storpool.conf file')
    spstatus.npset('maintenance', 'updating the /etc/storpool.conf file')
    with tempfile.NamedTemporaryFile(dir='/tmp', mode='w+t',
                                     delete=True) as spconf:
        rdebug('about to write the contents to the temporary file {sp}'.format(
            sp=spconf.name))
        templating.render(
            source='storpool.conf',
            target=spconf.name,
            owner='root',
            perms=0o600,
            context={
                'storpool_conf': spconfig.m()['storpool_conf'],
            },
        )
        rdebug('about to invoke txn install')
        txn.install('-o', 'root', '-g', 'root', '-m', '644', '--', spconf.name,
                    '/etc/storpool.conf')
        rdebug('it seems that /etc/storpool.conf has been created')

        rdebug('trying to read it now')
        spconfig.drop_cache()
        cfg = spconfig.get_dict()
        oid = cfg['SP_OURID']
        spconfig.set_our_id(oid)
        rdebug('got {len} keys in the StorPool config, our id is {oid}'.format(
            len=len(cfg), oid=oid))

    rdebug('setting the config-written state')
    reactive.set_state('l-storpool-config.config-written')
    spstatus.npset('maintenance', '')
def config_changed():
    """
    Check if the configuration is complete or has been changed.
    """
    rdebug('config-changed happened')
    reactive.remove_state('l-storpool-config.configure')
    config = spconfig.m()

    # Remove any states that say we have accomplished anything...
    for state in STATES_REDO['unset']:
        reactive.remove_state(state)
    spconfig.unset_our_id()

    spconf = config.get('storpool_conf', None)
    rdebug('and we do{xnot} have a storpool_conf setting'.format(
        xnot=' not' if spconf is None else ''))
    if spconf is None or spconf == '':
        return

    # And let's make sure we try installing any packages we need...
    reactive.set_state('l-storpool-config.config-available')
    reactive.set_state('l-storpool-config.package-try-install')

    # This will probably race with some others, but oh well
    spstatus.npset(
        'maintenance', 'waiting for the StorPool charm configuration and '
        'the StorPool repo setup')
def try_config():
    """
    Check if the configuration has been fully set.
    """
    rdebug('reconfigure')
    reactive.remove_state('storpool-repo-add.configure')
    spstatus.reset_if_allowed('storpool-repo-add')
    config = spconfig.m()

    repo_url = config.get('storpool_repo_url', None)
    if repo_url is None or repo_url == '':
        rdebug('no repository URL set in the config yet')
        reactive.remove_state('storpool-repo-add.configured')
    else:
        rdebug('got a repository URL: {url}'.format(url=repo_url))
        reactive.set_state('storpool-repo-add.configured')
Example #4
0
def install_package():
    """
    Install the StorPool block package.
    """
    rdebug('the block repo has become available and the common packages '
           'have been configured')

    if sputils.check_in_lxc():
        rdebug('running in an LXC container, not doing anything more')
        reactive.set_state('storpool-block.package-installed')
        return

    spstatus.npset('maintenance', 'obtaining the requested StorPool version')
    spver = spconfig.m().get('storpool_version', None)
    if spver is None or spver == '':
        rdebug('no storpool_version key in the charm config yet')
        return

    spstatus.npset('maintenance', 'installing the StorPool block packages')
    (err, newly_installed) = sprepo.install_packages({
        'storpool-block': spver,
    })
    if err is not None:
        rdebug('oof, we could not install packages: {err}'.format(err=err))
        rdebug('removing the package-installed state')
        return

    if newly_installed:
        rdebug('it seems we managed to install some packages: {names}'.format(
            names=newly_installed))
        sprepo.record_packages('storpool-block', newly_installed)
    else:
        rdebug('it seems that all the packages were installed already')

    rdebug('setting the package-installed state')
    reactive.set_state('storpool-block.package-installed')
    spstatus.npset('maintenance', '')
def install_package():
    """
    Install the base StorPool packages.
    """
    rdebug('the repo hook has become available and '
           'we do have the configuration')

    spstatus.npset('maintenance', 'obtaining the requested StorPool version')
    spver = spconfig.m().get('storpool_version', None)
    if spver is None or spver == '':
        rdebug('no storpool_version key in the charm config yet')
        return

    spstatus.npset('maintenance',
                   'installing the StorPool configuration packages')
    reactive.remove_state('l-storpool-config.package-try-install')
    (err, newly_installed) = sprepo.install_packages({
        'txn-install': '*',
        'storpool-config': spver,
    })
    if err is not None:
        rdebug('oof, we could not install packages: {err}'.format(err=err))
        rdebug('removing the package-installed state')
        reactive.remove_state('l-storpool-config.package-installed')
        return

    if newly_installed:
        rdebug('it seems we managed to install some packages: {names}'.format(
            names=newly_installed))
        sprepo.record_packages('storpool-config', newly_installed)
    else:
        rdebug('it seems that all the packages were installed already')

    rdebug('setting the package-installed state')
    reactive.set_state('l-storpool-config.package-installed')
    spstatus.npset('maintenance', '')
Example #6
0
def install_package():
    """
    Install the base StorPool packages.
    """
    rdebug('the common repo has become available and '
           'we do have the configuration')

    rdebug('checking the kernel command line')
    with open('/proc/cmdline', mode='r') as f:
        ln = f.readline()
        if not ln:
            sputils.err('Could not read a single line from /proc/cmdline')
            return
        words = ln.split()

        # OK, so this is a bit naive, but it will do the job
        global KERNEL_REQUIRED_PARAMS
        missing = list(
            filter(lambda param: param not in words, KERNEL_REQUIRED_PARAMS))
        if missing:
            if sputils.bypassed('kernel_parameters'):
                hookenv.log(
                    'The "kernel_parameters" bypass is meant FOR '
                    'DEVELOPMENT ONLY!  DO NOT run a StorPool cluster '
                    'in production with it!', hookenv.WARNING)
            else:
                sputils.err('Missing kernel parameters: {missing}'.format(
                    missing=' '.join(missing)))
                return

    spstatus.npset('maintenance', 'obtaining the requested StorPool version')
    spver = spconfig.m().get('storpool_version', None)
    if spver is None or spver == '':
        rdebug('no storpool_version key in the charm config yet')
        return

    spstatus.npset('maintenance', 'installing the StorPool common packages')
    (err, newly_installed) = sprepo.install_packages({
        'storpool-cli':
        spver,
        'storpool-common':
        spver,
        'storpool-etcfiles':
        spver,
        'kmod-storpool-' + os.uname().release:
        spver,
        'python-storpool':
        spver,
    })
    if err is not None:
        rdebug('oof, we could not install packages: {err}'.format(err=err))
        rdebug('removing the package-installed state')
        return

    if newly_installed:
        rdebug('it seems we managed to install some packages: {names}'.format(
            names=newly_installed))
        sprepo.record_packages('storpool-common', newly_installed)
    else:
        rdebug('it seems that all the packages were installed already')

    rdebug('updating the kernel module dependencies')
    spstatus.npset('maintenance', 'updating the kernel module dependencies')
    subprocess.check_call(['depmod', '-a'])

    rdebug('gathering CPU information for the cgroup configuration')
    with open('/proc/cpuinfo', mode='r') as f:
        lns = f.readlines()
        all_cpus = sorted(
            map(
                lambda lst: int(lst[2]),
                filter(lambda lst: lst and lst[0] == 'processor',
                       map(lambda s: s.split(), lns))))
    if sputils.bypassed('very_few_cpus'):
        hookenv.log(
            'The "very_few_cpus" bypass is meant '
            'FOR DEVELOPMENT ONLY!  DO NOT run a StorPool cluster in '
            'production with it!', hookenv.WARNING)
        last_cpu = all_cpus[-1]
        all_cpus.extend([last_cpu, last_cpu, last_cpu])
    if len(all_cpus) < 4:
        sputils.err('Not enough CPUs, need at least 4')
        return
    tdata = {
        'cpu_rdma': str(all_cpus[0]),
        'cpu_beacon': str(all_cpus[1]),
        'cpu_block': str(all_cpus[2]),
        'cpu_rest': '{min}-{max}'.format(min=all_cpus[3], max=all_cpus[-1]),
    }

    rdebug('gathering system memory information for the cgroup configuration')
    with open('/proc/meminfo', mode='r') as f:
        while True:
            line = f.readline()
            if not line:
                sputils.err('Could not find MemTotal in /proc/meminfo')
                return
            words = line.split()
            if words[0] == 'MemTotal:':
                mem_total = int(words[1])
                unit = words[2].upper()
                if unit.startswith('K'):
                    mem_total = int(mem_total / 1024)
                elif unit.startswith('M'):
                    pass
                elif unit.startswith('G'):
                    mem_total = mem_total * 1024
                else:
                    sputils.err('Could not parse the "{u}" unit for '
                                'MemTotal in /proc/meminfo'.format(u=words[2]))
                    return
                break
    mem_system = 4 * 1024
    mem_user = 4 * 1024
    mem_storpool = 1 * 1024
    mem_kernel = 10 * 1024
    if sputils.bypassed('very_little_memory'):
        hookenv.log(
            'The "very_little_memory" bypass is meant '
            'FOR DEVELOPMENT ONLY!  DO NOT run a StorPool cluster in '
            'production with it!', hookenv.WARNING)
        mem_system = 1 * 1900
        mem_user = 1 * 512
        mem_storpool = 1 * 1024
        mem_kernel = 1 * 512
    mem_reserved = mem_system + mem_user + mem_storpool + mem_kernel
    if mem_total <= mem_reserved:
        sputils.err(
            'Not enough memory, only have {total}M, need {mem}M'.format(
                mem=mem_reserved, total=mem_total))
        return
    mem_machine = mem_total - mem_reserved
    tdata.update({
        'mem_system': mem_system,
        'mem_user': mem_user,
        'mem_storpool': mem_storpool,
        'mem_machine': mem_machine,
    })

    rdebug('generating the cgroup configuration: {tdata}'.format(tdata=tdata))
    if not os.path.isdir('/etc/cgconfig.d'):
        os.mkdir('/etc/cgconfig.d', mode=0o755)
    cgconfig_dir = '/usr/share/doc/storpool/examples/cgconfig/ubuntu1604'
    for (path, _, files) in os.walk(cgconfig_dir):
        for fname in files:
            src = path + '/' + fname
            dst = src.replace(cgconfig_dir, '')
            dstdir = os.path.dirname(dst)
            if not os.path.isdir(dstdir):
                os.makedirs(dstdir, mode=0o755)

            if fname in (
                    'machine.slice.conf',
                    'storpool.slice.conf',
                    'system.slice.conf',
                    'user.slice.conf',
                    'machine-cgsetup.conf',
            ):
                with tempfile.NamedTemporaryFile(dir='/tmp',
                                                 mode='w+t',
                                                 delete=True) as tempf:
                    rdebug('- generating {tempf} for {dst}'.format(
                        dst=dst, tempf=tempf.name))
                    templating.render(
                        source=fname,
                        target=tempf.name,
                        owner='root',
                        perms=0o644,
                        context=tdata,
                    )
                    rdebug('- generating {dst}'.format(dst=dst))
                    txn.install('-o', 'root', '-g', 'root', '-m', '644', '--',
                                tempf.name, dst)
            else:
                mode = '{:o}'.format(os.stat(src).st_mode & 0o777)
                rdebug('- installing {src} as {dst}'.format(src=src, dst=dst))
                txn.install('-o', 'root', '-g', 'root', '-m', mode, '--', src,
                            dst)

    rdebug('starting the cgconfig service')
    rdebug('- refreshing the systemctl service database')
    subprocess.check_call(['systemctl', 'daemon-reload'])
    rdebug('- starting the cgconfig service')
    try:
        host.service_resume('cgconfig')
    except Exception:
        pass

    rdebug('setting the package-installed state')
    reactive.set_state('storpool-common.package-installed')
    spstatus.npset('maintenance', '')
def repo_url():
    """
    Get the StorPool package repository URL from the configuration.
    """
    return spconfig.m()['storpool_repo_url']