def parser_check(parser, args): """Verify the conditions needed for the installation. Args: parser: The parser object args: The arguments passed into the CLI Returns: None """ # Perform installation check to ensure the environment is okay installation_checks() if args.action == 'install': if shared.root_check() is False and getpass.getuser() != 'travis': shared.log('Please run the script with sudo to continue.') print('Default Installation') elif args.action == 'developer': print('Unittesting mode') if shared.root_check() is True: shared.log('''\ You cannot run the developer installation as root. Please run without sudo privileges to continue''') else: parser.print_help(sys.stderr) sys.exit(1)
def installation_checks(): """Validate conditions needed to start installation. Prevents installation if the script is not run as root and prevents installation if script is run in a home related directory Args: None Returns: True: If conditions for installation are satisfied """ # Check user if getpass.getuser() != 'travis': if getpass.getuser() != 'root': shared.log('You are currently not running the script as root.\ Run as root to continue') # Check installation directory if os.getcwd().startswith('/home'): shared.log('''\ You cloned the repository in a home related directory, please clone in a\ non-home directory to continue''') # Check if virtualenv is installed try: import virtualenv except ModuleNotFoundError: print('virtualenv is not installed. Installing virtualenv') shared.run_script('pip3 install virtualenv')
def _check_symlinks(etc_dir, daemons): """Ensure the files in the etc dir are symlinks. Args: etc_dir: The directory that the symlinks are located in symlink_dir: The directory that the symlinks point to daemons: The list of system daemons Returns: None """ for daemon in daemons: # Initialize key variables symlink_path = os.path.join(etc_dir, daemon) # Say what we are doing print('Checking if the {}.service file is a symlink '.format(daemon)) link = os.path.islink('{0}.service'.format(symlink_path)) if link is False: if getpass.getuser() != 'root': shared.log('Current user is not root') print('Creating symlink for {}'.format(daemon)) # Create symlink if it doesn't exist shared.run_script('systemctl enable {}'.format(daemon))
def _symlink_dir(directory): """Get directory in which the symlinked files are located. Args: directory: Directory with the symlinks Returns: result: Directory to which the files have symlinks """ # Initialize key variables data_dictionary = {} result = None # Get all the filenames in the directory filenames = _filepaths(directory) # Get the name of the directory to which the files are symlinked for filename in filenames: if os.path.islink(filename) is False: continue if '/etc/systemd/system/multi-user.target.wants' not in filename: continue data_dictionary[Path(filename).resolve().absolute()] = True # Get the first directory in the dictionary for key in sorted(data_dictionary.keys()): if '/lib/' not in str(key): continue result = os.path.dirname(str(key)) break # Die if there are no symlinks if bool(result) is False: shared.log( 'No symlinks found in the directory: "{}"'.format(directory)) return result
def _get_runtime_directory(config_directory): """Get the RuntimeDirectory. Args: config_dir: Configuration directory Returns: tuple: (Path, Relative Path to /var/run) """ result = None filepath = os.path.join(config_directory, 'pattoo.yaml') if os.path.isfile(filepath) is False: shared.log('{} does not exist'.format(filepath)) with open(filepath, 'r') as file_handle: yaml_from_file = file_handle.read() config = yaml.safe_load(yaml_from_file) pattoo = config.get('pattoo') if bool(pattoo) is True: result = pattoo.get('system_daemon_directory') if result is None: shared.log('''\ "system_daemon_directory" parameter not found in the {} configuration file\ '''.format(filepath)) _result = result.replace('/var/run/', '') _result = _result.replace('/run/', '') return (result, _result)
def prompt(section, key, default_value): """Log messages and exit abnormally. Args: key: Configuration key default_value: Default value for key Returns: result: Desired value from user """ # Get input from user result = input('''Enter "{}: {}" value (Hit <enter> for: "{}"): \ '''.format(section, key, default_value)) if bool(result) is False: result = default_value # Try to create necessary directories if 'directory' in key: try: os.makedirs(result, mode=0o750, exist_ok=True) except: shared.log('''\ Cannot create directory {} in configuration file. Check parent directory \ permissions and typos'''.format(result)) return result
def install_missing_pip3(package, pip_dir, verbose=True): """Automatically Install missing pip3 packages. Args: package: The pip3 package to be installed pip_dir: The directory the packages should be installed to Returns: True: if the package could be successfully installed """ # Validate pip directory if not os.path.isdir(pip_dir): shared.log('Pip directory is invalid') # Installs to the directory specified as pip_dir if the user is not travis username = getpass.getuser() if username == 'root': shared.run_script('''\ python3 -m pip install {0} -t {1} -U --force-reinstall'''.format(package, pip_dir), verbose=verbose) elif username == 'travis': shared.run_script( 'python3 -m pip install {0}'.format(package), verbose=verbose) else: shared.log('Installation user is not "root" or "travis"')
def preflight(config_dir, etc_dir): """Make sure the environment is OK. Args: config_dir: Location of the configuratiion directory etc_dir: Location of the systemd files Returns: None """ # Make sure config_dir exists if os.path.isdir(config_dir) is False: shared.log('''\ Expected configuration directory "{}" does not exist.'''.format(config_dir)) # Verify whether the script is being run by root or sudo user if bool(os.getuid()) is True: shared.log('This script must be run as the "root" user ' 'or with "sudo" privileges') # Check to see whether this is a systemd system try: check_output(['pidof', 'systemd']) except: shared.log('This is not a "systemd" system. This script should not be run.') # Check existence of /etc/systemd/system/multi-user.target.wants directory if os.path.isdir(etc_dir) is False: shared.log('Expected systemd directory "{}" does not exist.'.format(etc_dir))
def _mkdir(directory): """Recursively creates directory and its parents. Args: directory: Directory to create Returns: None """ # Check if directory already exists if os.path.isdir(directory) is False: try: Path(directory).mkdir(parents=True, mode=0o750, exist_ok=True) except OSError: shared.log('''Cannot create directory {}. Please try again.\ '''.format(directory))
def check_user(): """Validate conditions needed to start installation. Prevents installation if the script is not run as root Args: None Returns: True: If conditions for installation are satisfied """ if getpass.getuser() != 'travis': if getpass.getuser() != 'root': shared.log('You are currently not running the script as root.\ Run as root to continue') return True
def installation_checks(): """Validate conditions needed to start installation. Prevents installation if the script is not run as root and prevents installation if script is run in a home related directory Args: None Returns: True: If conditions for installation are satisfied """ # Check user if getpass.getuser() != 'travis': # Check installation directory if os.getcwd().startswith('/home'): shared.log('''\ You cloned the repository in a home related directory, please clone in a\ non-home directory to continue''')
def main(): """Pattoo CLI script. None Returns: None """ # Initialize key variables _help = 'This program is the CLI interface to configuring pattoo' daemon_list = ['pattoo_apid', 'pattoo_api_agentd', 'pattoo_ingesterd'] template_dir = os.path.join(ROOT_DIR, 'setup/systemd/system') # Process the CLI _parser = Parser(additional_help=_help) (args, parser) = _parser.args() # Perform checks checks.parser_check(_parser.args()[1], _parser.args()[0]) checks.pattoo_shared_check() checks.venv_check() # Import packages that depend on pattoo shared from _pattoo import configure from pattoo_shared.installation import packages, systemd, environment # Set up essentials for creating the virtualenv pattoo_home = get_pattoo_home() venv_dir = os.path.join(pattoo_home, 'pattoo-venv') if getpass.getuser() != 'travis': environment.environment_setup(venv_dir) venv_interpreter = os.path.join(venv_dir, 'bin/python3') installation_dir = '{} {}'.format(venv_interpreter, ROOT_DIR) # Installs all pattoo components if args.qualifier == 'all': print('Installing everything') configure.install(pattoo_home) packages.install(ROOT_DIR, venv_dir, args.verbose) # Import db after pip3 packages are installed from _pattoo import db db.install() if shared.root_check() is True and args.action != 'developer': systemd.install(daemon_list=daemon_list, template_dir=template_dir, installation_dir=installation_dir, verbose=args.verbose) # Configures pattoo and sets up database tables elif args.qualifier == 'database': print('Installing database tables') configure.install(pattoo_home) packages.install(ROOT_DIR, venv_dir) # Import db after pip3 packages are installed from _pattoo import db db.install() # Installs and starts system daemons elif args.qualifier == 'systemd': print('Installing systemd daemons') if shared.root_check() is True: systemd.install(daemon_list=daemon_list, template_dir=template_dir, installation_dir=installation_dir, verbose=True) else: shared.log('You need to be running as root to install the daemons') elif args.qualifier == 'pip': # Installs additionally required pip3 packages packages.install(ROOT_DIR, venv_dir, args.verbose) # Sets up the configuration for pattoo elif args.qualifier == 'configuration': configure.install(pattoo_home) # Print help if no argument options were triggered else: parser.print_help(sys.stderr) sys.exit(1) # Done print('Done')
def pattoo_config(config_directory, prompt_value): """Create pattoo.yaml file. Args: config_directory: Configuration directory Returns: None """ # Initialize key variables filepath = '{}{}pattoo.yaml'.format(config_directory, os.sep) default_config = { 'pattoo': { 'language': 'en', 'log_directory': ('/var/log/pattoo'), 'log_level': 'debug', 'cache_directory': ('/opt/pattoo-cache'), 'daemon_directory': ('/opt/pattoo-daemon'), 'system_daemon_directory': '/var/run/pattoo' }, 'pattoo_agent_api': { 'ip_address': '127.0.0.1', 'ip_bind_port': 20201 }, 'pattoo_web_api': { 'ip_address': '127.0.0.1', 'ip_bind_port': 20202, } } # Say what we are doing print('Configuring {} file.'.format(filepath)) # Get configuration config = read_config(filepath, default_config) forced_directories = ['system_daemon_directory', 'daemon_directory'] for section, item in sorted(config.items()): for key, value in sorted(item.items()): if key in forced_directories: continue if prompt_value: new_value = prompt(section, key, value) config[section][key] = new_value # Check validity of directories for key, value in sorted(config['pattoo'].items()): if 'directory' in key: if os.sep not in value: shared.log('''\ Provide full directory path for "{}" in section "pattoo: {}". \ Please try again.\ '''.format(value, key)) # Attempt to create directory full_directory = os.path.expanduser(value) if os.path.isdir(full_directory) is False: _mkdir(full_directory) initialize_ownership(key, full_directory) # Ensure correct ownership of /var/run/pattoo if full_directory == '{0}var{0}run{0}pattoo'.format(os.sep): _chown(full_directory) # Write file with open(filepath, 'w') as f_handle: yaml.dump(config, f_handle, default_flow_style=False)
def install(requirements_dir, installation_directory=None, verbose=True): """Ensure PIP3 packages are installed correctly. Args: requirements_dir: The directory with the pip_requirements file. installation_directory: Directory where packages must be installed. verbose: Print status messages if True Returns: True if pip3 packages are installed successfully """ # Initialize key variables lines = [] if bool(installation_directory) is False: installation_directory = '/opt/pattoo-daemon/.python' # Create directory if it doesn't exist if os.path.isdir(installation_directory) is False: files.mkdir(installation_directory) # Appends pip3 dir to python path sys.path.append(installation_directory) # Read pip_requirements file filepath = '{}{}pip_requirements.txt'.format(requirements_dir, os.sep) # Say what we are doing print('Checking pip3 packages') if os.path.isfile(filepath) is False: shared.log('Cannot find PIP3 requirements file {}'.format(filepath)) # Opens pip_requirements file for reading with open(filepath, 'r') as _fp: line = _fp.readline() while line: # Strip line _line = line.strip() # Read line if True in [_line.startswith('#'), bool(_line) is False]: pass else: lines.append(_line) line = _fp.readline() # Process each line of the file for line in lines: # Determine the package package = line.split('=', 1)[0] package = package.split('>', 1)[0] # If verbose is true, the package being checked is shown if verbose: print('Installing package {}'.format(package)) command = 'python3 -m pip show {}'.format(package) (returncode, _, _) = shared.run_script( command, verbose=verbose, die=False) # Install any missing pip3 package if bool(returncode) is True: install_missing_pip3( package, installation_directory, verbose=verbose) # Set ownership of any newly installed python packages to pattoo user if getpass.getuser() == 'root': if os.path.isdir(installation_directory) is True: shared.run_script('chown -R pattoo:pattoo {}'.format( installation_directory), verbose=verbose) print('pip3 packages successfully installed')