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 test_environment_setup(self): """Unittest to test the environment_setup function.""" # Set up venv environment.environment_setup(self.venv_dir) # Ensure that there are no packages with self.subTest(): pip_packages = shared.run_script('python3 -m pip freeze')[1] # Retrieve packages without version installed_packages = [ pip_helper(package) for package in pip_packages.split()] result = installed_packages == [] self.assertTrue(result) # Test with installing a package to the venv with self.subTest(): packages.install_missing_pip3('matplotlib', verbose=False) pip_packages = shared.run_script('python3 -m pip freeze')[1] # Retrieve packages without version installed_packages = [ pip_helper(package) for package in pip_packages.split()] result = 'matplotlib' in installed_packages self.assertTrue(result)
def test_check_outdated_packages(self): """Unittest to test the check_outdated_packages function.""" # Initialize key variables package_dict = { 'Flask': '1.1.0', 'pandas': '1.0.5', 'PyNaCl': '1.4.0', 'distro': '1.5.0' } packages = [ 'Flask<=1.1.0', 'pandas==1.0.5', 'PyNaCl>=1.3', 'distro<1.5.0' ] # Install the packages for package in package_dict: shared.run_script('pip3 install {}'.format(package)) # Check if they're outdated based on the packages list check_outdated_packages(packages, verbose=True) # Iterate over package dict and perform unittests for package in package_dict: with self.subTest(): result = get_package_version(package) expected = package_dict.get(package) self.assertEqual(result, expected)
def _check_symlinks(etc_dir, daemon): """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 daemon: The daemon being checked Returns: None """ # Initialize key variables symlink_path = os.path.join(etc_dir, '{}.service'.format(daemon)) # Say what we are doing print('Checking if the {}.service file is a symlink '.format(daemon)) link = os.path.islink(symlink_path) if link is False: # Attempt to remove file remove_file(symlink_path) if getpass.getuser() != 'root': log.log2die_safe(1086, '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)) print('OK: Symlink is present for {}'.format(daemon))
def create_user(user_name, directory, shell, verbose): """Create user and their respective group. Args: user_name: The name and group of the user being created directory: The home directory of the user shell: The shell of the user verbose: A boolean value that a allows the script to run in verbose mode Returns: None """ # Ensure user has sudo privileges if getpass.getuser() == 'root': # If the group specified does not exist, it gets created if not group_exists(user_name): shared.run_script('groupadd {0}'.format(user_name), verbose) # If the user specified does not exist, they get created if not user_exists(user_name): shared.run_script( 'useradd -d {1} -s {2} -g {0} {0}'.format( user_name, directory, shell), verbose) else: # Die if not root shared.log('You are currently not running the script as root')
def test_run_script(self): """Unittest to test the _run_script function.""" # Test case where the script should fail and exit with 2 with self.subTest(): with self.assertRaises(SystemExit) as cm_: shared.run_script("this will exit with 2") self.assertEqual(cm_.exception.code, 2) # Test case where the script should print "this works" to the console with self.subTest(): expected = 0 result = shared.run_script("echo this works")[0] self.assertEqual(result, expected)
def install_missing_pip3(package, verbose=False): """Automatically Install missing pip3 packages. Args: package: The pip3 package to be installed Returns: True: if the package could be successfully installed """ # Validate pip directory shared.run_script('''\ python3 -m pip install {0} -U --force-reinstall'''.format(package), verbose=verbose)
def test_get_package_version(self): """Unittest to test the get_package_version function.""" package = 'PattooShared' with self.subTest(): result = get_package_version(package) expected = None self.assertEqual(result, expected) with self.subTest(): shared.run_script( 'python3 -m pip install {}==0.0.90'.format(package)) result = get_package_version(package) expected = '0.0.90' self.assertEqual(result, expected)
def start_daemon(daemon_name, verbose=False): """Enable and start respective pattoo daemons. Args: daemon_name: The name of the daemon being started verbose: A boolean value to toggle verbose output Returns: None """ # Enable daemon shared.run_script('systemctl enable {}'.format(daemon_name), verbose=verbose) # Start daemon shared.run_script('systemctl start {}'.format(daemon_name), verbose=verbose)
def run_daemon(daemon_name, verbose=False): """Start/Restart pattoo system daemons. Starts daemons if they aren't running and restarts them if running Args: daemon_name: The system daemon verbose: A boolean value to toggle verbose output Returns: None """ # Initialize key variables command = '''\ systemctl is-active {} daemon --quiet service-name'''.format(daemon_name) # Check status code of daemon to see if its running status = shared.run_script(command, die=False, verbose=verbose)[0] if status == 0: print(''' The {} daemon is already enabled/running, restarting daemon '''.format(daemon_name)) # Restart daemon if its running install_daemon(daemon_name, 'restart', verbose=verbose) # Starts daemon if its not running else: print('Enabling and starting {} daemon'.format(daemon_name)) install_daemon(daemon_name, 'start', verbose=verbose)
def test_install(self): """Unittest to test the install function.""" # Test with undefined requirements directory with self.subTest(): with self.assertRaises(SystemExit) as cm_: requirements_dir = data.hashstring(str(random())) install(requirements_dir, self.venv_dir) self.assertEqual(cm_.exception.code, 3) # Test with default expected behaviour with self.subTest(): # At least one expected package expected_package = 'Flask' expected = True # Create temporary directory result = install(ROOT_DIR, self.venv_dir) # Get raw packages in requirements format packages = shared.run_script('python3 -m pip freeze')[1] # Get packages with versions removed installed_packages = [ package.decode().split('==')[0] for package in packages.split() ] result = expected_package in installed_packages self.assertEqual(result, expected)
def install(daemon_list, template_dir, installation_dir, verbose=False): """Installs and runs all daemons entered. Args: daemon_list: A list of the daemons to be run and installed template_dir: The directory the tempalte files are located in installation_dir: The root directory of the pattoo related project that the daemons will be running from verbose: A boolean value to toggle verbose output Returns: None """ # Initialize key variables etc_dir = '/etc/systemd/system/multi-user.target.wants' config_dir = '/etc/pattoo' # Make sure this system supports systemd and that # the required directories exist preflight(config_dir, etc_dir) # Check symlink location of files in that directory target_directory = symlink_dir(etc_dir) # Copy files destination_filepaths = copy_service_files(target_directory, template_dir) # Update the environment strings update_environment_strings( destination_filepaths, config_dir, installation_dir, 'pattoo', 'pattoo') # Perform daemon reload shared.run_script('systemctl daemon-reload', verbose=verbose) # Loop through daemon list and start daemons for daemon in daemon_list: daemon_check(daemon) start_daemon(daemon) # Check if symlinks got created _check_symlinks(etc_dir, daemon_list)
def install_missing_pip3(package, verbose=False): """Automatically Install missing pip3 packages. Args: package: The pip3 package to be installed Returns: None """ # Intitialize key variables command = 'python3 -m pip install {0} -U --force-reinstall'.format(package) try: shared.run_script(command, verbose=verbose) except SystemExit: message = 'Invalid pip package/package version "{}"'.format(package) log.log2die_safe(1088, message)
def make_venv(file_path): """Create virtual environment for pattoo installation. Args: file_path: The path to the virtual environment Returns: None """ # Say what we're doing print('??: Create virtual environment') command = 'python3 -m virtualenv {}'.format(file_path) shared.run_script(command) print('OK: Virtual environment created') # Ensure venv is owned by pattoo if the pattoo user exists if configure.user_exists('pattoo') and configure.group_exists('pattoo'): if getpass.getuser() == 'root': shared.run_script('chown -R pattoo:pattoo {}'.format(file_path))
def install_daemon(daemon_name, command, verbose=False): """Enable and start/restart respective pattoo daemons. Args: daemon_name: The name of the daemon being started command: The command to either start, or restart the daemon verbose: A boolean value to toggle verbose output Returns: None """ # Enable daemon shared.run_script('systemctl enable {}'.format(daemon_name), verbose=verbose) # Start/Restart daemon try: shared.run_script('systemctl {0} {1}'.format(command, daemon_name), verbose=verbose) except SystemExit: message = '''\ Unable to {0} daemon. Run the following command to see what could be causing the problem: \ "systemctl status {1}.service" '''.format(command, daemon_name) log.log2die(1087, message)
def daemon_check(daemon_name, verbose=False): """Check if daemon is enabled/running and stops it. Args: daemon_name: The system daemon being checked verbose: A boolean value to toggle verbose output Returns: None """ # Initialize key variables command = '''\ systemctl is-active {} daemon --quiet service-name'''.format(daemon_name) # Check status code of daemon to see if its running status = shared.run_script(command, die=False, verbose=verbose)[0] if status == 0: print(''' {} daemon is already enabled/running, stopping daemon'''.format(daemon_name)) # Stop daemon if its running shared.run_script('systemctl stop {}'.format(daemon_name), verbose=verbose)
def get_package_version(package_name): """Retrieve installed pip package version. Args: package_name: The name of the package Returns: version: The version of the package if the package is installed. None: If the package is not installed """ try: raw_description = shared.run_script( 'pip3 show {}'.format(package_name))[1] except SystemExit: return None pkg_description = raw_description.decode().split('\n') version = pkg_description[1].replace(' ', '').split(':') return version[1]
def install_dependencies(): """Install the necessary system dependencies for the snmp agent. Args: None Returns: None """ # Initialize key variables distribution = distro.id() if distribution == 'debian' or distribution == 'ubuntu': # Say what we are doing print('Installing easy snmp dependencies...') # Install net-snmp with package manager shared.run_script( 'sudo apt-get install libsnmp-dev snmp-mibs-downloader') # Install easy snmp dependencies shared.run_script('sudo apt-get install gcc python-dev') elif distribution == 'rhel' or distribution == 'centos': # Install net-snmp with package manager shared.run_script('sudo yum install net-snmp-devel') # Install easy snmp dependencies shared.run_script('sudo yum install gcc python-devel') # Die if distribution isn't debian or rhel based else: shared.log('''\ Your operating system does not support Net-SNMP 5.7.x \n \ Please follow this guide to build and install Net-SNMP 5.7.x on your system \ http://www.net-snmp.org/docs/INSTALL.html''')
def install(requirements_dir, installation_directory, verbose=False): """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 = [] # 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 try: _fp = open(filepath, 'r') except PermissionError: log.log2die_safe(1079, '''\ Insufficient permissions for reading the file: {}. \ Ensure the file has read-write permissions and try again'''.format(filepath)) else: 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, 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')