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')
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', '')
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']