Source code for riaps.rfab.api.utils

import toml
import os
from fabric import ThreadingGroup, Group, GroupResult, Result
from fabric.transfer import Result as TransferResult
from fabric.exceptions import GroupException
from riaps.rfab.api.exceptions import RFabException
import socket
from pathlib import Path
from shutil import rmtree
import logging
import time

[docs]def make_log_folder(func_name,logsdir='/home/riaps/.riaps/rfab/logs'): assert func_name[-1] != '_', "function name cannot end in \"_\"" logger = logging.getLogger("TaskRunner") base = Path(logsdir) base.mkdir(parents=True,exist_ok=True) # Sort by last modification time in ascending order history = [(p,p.stat().st_mtime) for p in base.glob(f"{func_name}_*")] history.sort(key = lambda x: x[1],reverse=True) excess = len(history) - 9 for _ in range(0,excess): path,_ = history.pop() logger.debug(f"Removing {path.name}") rmtree(path) now = time.localtime() new_path = base / f"{func_name}_{now.tm_hour:02}_{now.tm_min:02}_{now.tm_sec:02}" new_path.mkdir() symlink_path: Path = base / func_name if symlink_path.is_symlink() or not symlink_path.exists(): symlink_path.unlink(missing_ok=True) else: raise Exception(f"{symlink_path} is not a symlink, so something is wrong. Delete all log contents and try again.") symlink_path.symlink_to(new_path) return new_path
[docs]def isIPaddress(addr): try: socket.inet_aton(addr) return True except socket.error: return False
[docs]def load_hostfile(hosts_file,validate=False): ''' Load a hosts file, construct role definitions ''' def catch(func, *args, **kwargs): try: return func(*args, **kwargs) except Exception: raise Exception("%r" % args) if not os.path.isfile(hosts_file): print('Hosts configuration file doesn\'t exist: %s' % hosts_file) return None try: config = toml.load(hosts_file) except Exception as e: print(' Hosts configuration file %s has a problem: %s.' % (hosts_file, str(e))) return None spec = config.get('RIAPS',None) if spec is None: print('Hosts configuration file %s is missing [RIAPS] section.' % (hosts_file)) return None # control is optional control = spec.get('control', None) if control and type(control) != str: print("String is expected: %r" % control) return None if control in {'localhost', '127.0.0.1'}: print("Control hostname or IP address is expected: %r " % control) return None else: control = socket.gethostname() if control is None else control control_ = control if control.endswith('.local') or isIPaddress(control) else control + '.local' if validate: # Validate control host name try: _control = catch(socket.gethostbyname,control_) except Exception as e: print('Control host name %s cannot be resolved.' % str(e)) # return None # nodes are required nodes = spec.get('nodes', None) if nodes is None: print("No nodes specified in %s." % (hosts_file)) return None if type(nodes) == str: nodes = [nodes] if validate: # Validate target host names for node in nodes: try: _nodes = catch(socket.gethostbyname,node) except Exception as e: print('Host name %s cannot be resolved.' % str(e)) # return None nodes = [node if node != control else control_ for node in nodes] nodeS,controlS = set(nodes), set([control_]) roledefs = {"nodes" : nodes, # Nodes that run apps "control" : [control_], # Control host "remote" : list(nodeS.difference(controlS)),# Only the remote nodes "all" : list(nodeS.union(controlS)) # All nodes } return roledefs
[docs]def load_role(role, hostfile=None, validate=False) -> ThreadingGroup: if hostfile is None: riapsHome = os.getenv('RIAPSHOME') if riapsHome is None: riapsHome = os.getcwd() print(f"RIAPS Configuration - RIAPSHOME is not set, using {riapsHome}") hostfile = riapsHome+'/etc/riaps-hosts.conf' roledefs = load_hostfile(hostfile,validate) if roledefs is None: exit(-1) hosts = roledefs.get(role,None) if hosts is None: raise RFabException(f"No role \"{role}\" in {hostfile}, choose one of {list(roledefs)}") if len(hosts) == 0: raise RFabException(f"Zero hosts for role \"{role}\" in {hostfile}") return ThreadingGroup(*hosts)