def call_process(self, cmd): if not isinstance(cmd, list): exceptionhandler('Command is not a list.\n{0}'.format(str(cmd))) rsp = subprocess.call(cmd) if rsp != 0: exceptionhandler('Command failed.\n{0}'.format(str(cmd)))
def _get_system_params(self): """ Handles the setup of the OS workspace and environment. This method also creates the appropriate directories necessary for installation. """ if 'Linux' in self.system: self.system_drive = '/' self._linux_paths() elif 'Windows' in self.system: self.system_drive = os.environ['SYSTEMDRIVE'] self._windows_paths() else: self.logger.fatal('System, {0}, is not recognized?'.format( self.system)) exceptionhandler('The scripts do not recognize this system type: ' '{0}'.format(self.system)) # Create watchmaker directories try: if not os.path.exists(self.system_params['logdir']): os.makedirs(self.system_params['logdir']) if not os.path.exists(self.system_params['workingdir']): os.makedirs(self.system_params['workingdir']) except Exception as exc: self.logger.fatal('Could not create a directory in {0}.\n' 'Exception: {1}'.format( self.system_params['prepdir'], exc)) exceptionhandler(exc)
def extract_contents(self, filepath, to_directory, create_dir): """ :param filepath: :param to_directory: :param create_dir: :return: """ opener = None mode = None if filepath.endswith('.zip'): logging.debug('File Type: zip') opener, mode = zipfile.ZipFile, 'r' elif filepath.endswith('.tar.gz') or filepath.endswith('.tgz'): logging.debug('File Type: GZip Tar') opener, mode = tarfile.open, 'r:gz' elif filepath.endswith('.tar.bz2') or filepath.endswith('.tbz'): logging.debug('File Type: Bzip Tar') opener, mode = tarfile.open, 'r:bz2' else: exceptionhandler('Could not extract "{0}" as no appropriate ' 'extractor is found'.format(filepath)) if create_dir: to_directory = os.sep.join(( to_directory, '.'.join(filepath.split(os.sep)[-1].split('.')[:-1]) )) try: os.makedirs(to_directory) except OSError: if not os.path.isdir(to_directory): raise cwd = os.getcwd() os.chdir(to_directory) try: openfile = opener(filepath, mode) try: openfile.extractall() finally: openfile.close() finally: os.chdir(cwd) print('Extracted file -- \n' ' source = {0}\n' ' dest = {1}'.format(filepath, to_directory))
def _get_s3_file(url, bucket_name, key_name, destination): """ :param url: :param bucket_name: :param key_name: :param destination: :return: """ try: import boto3 from botocore.client import ClientError except ImportError as exc: exceptionhandler(exc) try: s3 = boto3.resource("s3") s3.meta.client.head_bucket(Bucket=bucket_name) s3.Object(bucket_name, key_name).download_file(destination) except ClientError as exc: logging.error('Bucket does not exist.\n' 'bucket = {0}\n' 'Exception: {1}' .format(bucket_name, exc)) raise SystemError('Bucket does not exist.\n' 'bucket = {0}\n' 'Exception: {1}' .format(bucket_name, exc)) except Exception as exc: logging.error('Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, destination, exc)) raise SystemError('Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, destination, exc))
def _install_from_yum(self, packages): """ :param packages: :return: """ yum_cmd = ['sudo', 'yum', '-y', 'install'] if isinstance(packages, list): yum_cmd.extend(packages) else: yum_cmd.append(packages) rsp = subprocess.call(yum_cmd) logging.debug(packages) logging.debug('Return code of yum install: {0}'.format(rsp)) if rsp != 0: exceptionhandler('Installing Salt from Yum has failed!')
def create_working_dir(self, basedir, prefix): """ :param basedir: :param prefix: :return: """ logging.info('Creating a working directory.') workingdir = None original_umask = os.umask(0) try: workingdir = tempfile.mkdtemp(prefix=prefix, dir=basedir) except Exception as exc: exceptionhandler('Could not create workingdir in {0}.\n' 'Exception: {1}'.format(basedir, exc)) logging.debug('Working directory: {0}'.format(workingdir)) self.workingdir = workingdir os.umask(original_umask)
def cleanup(self): """ :return: """ logging.info('+-' * 40) logging.info('Cleanup Time...') try: logging.debug('{0} being cleaned up.'.format(self.workingdir)) shutil.rmtree(self.workingdir) except Exception as exc: # TODO: Update `except` logic logging.fatal('Cleanup Failed!\nException: {0}'.format(exc)) exceptionhandler('Cleanup Failed.\nAborting.') logging.info('Removed temporary data in working directory -- {0}' .format(self.workingdir)) logging.info('Exiting cleanup routine...') logging.info('-+' * 40)
def install_system(self): """ Initiate the installation of the prepared system. After execution the system should be properly provisioned. """ self.logger.info('+' * 80) self._get_system_params() self.logger.info(self.system_params) self._get_scripts_to_execute() self.logger.info('Got scripts to execute: {0}.'.format( self.config[self.system].keys())) if 'Linux' in self.system: workers_manager = LinuxWorkersManager(self.s3, self.system_params, self.execution_scripts, self.saltstates) elif 'Windows' in self.system: workers_manager = WindowsWorkersManager(self.s3, self.system_params, self.execution_scripts, self.saltstates) else: exceptionhandler('There is no known System!') try: workers_manager.worker_cadence() except Exception as e: exceptionhandler( 'Execution of the workers cadence has failed. {0}'.format(e)) if self.noreboot: self.logger.info('Detected `noreboot` switch. System will not be ' 'rebooted.') else: self.logger.info('Reboot scheduled. System will reboot after the ' 'script exits.') subprocess.call(self.system_params['restart'], shell=True) self.logger.info('-' * 80)
def _get_scripts_to_execute(self): """ Parses and updates configuration data. Returns: list: Attribute with configuration data for the target system. """ self._get_config_data() scriptstoexecute = self.config[self.system] for item in self.config[self.system]: try: self.config[self.system][item]['Parameters'].update( self.kwargs) except Exception as exc: self.logger.fatal( 'For {0} in {1} the parameters could not be merged'.format( item, self.config_path)) exceptionhandler(exc) self.execution_scripts = scriptstoexecute
def download_file(self, url, filename, sourceiss3bucket): """ :param url: :param filename: :param sourceiss3bucket: :return: """ logging.debug('Downloading: {0}'.format(url)) logging.debug('Destination: {0}'.format(filename)) logging.debug('S3: {0}'.format(sourceiss3bucket)) # TODO Rework this to properly reflect logic flow cleanly. if sourceiss3bucket: try: import boto3 from botocore.client import ClientError except ImportError as exc: exceptionhandler(exc) bucket_name = url.split('/')[3] key_name = '/'.join(url.split('/')[4:]) logging.debug('Bucket Name: {0}'.format(bucket_name)) logging.debug('key_name: {0}'.format(key_name)) try: s3 = boto3.resource("s3") s3.meta.client.head_bucket(Bucket=bucket_name) s3.Object(bucket_name, key_name).download_file(filename) except (NameError, ClientError): logging.error('NameError: {0}'.format(ClientError)) try: bucket_name = url.split('/')[2].split('.')[0] key_name = '/'.join(url.split('/')[3:]) s3 = boto3.resource("s3") s3.meta.client.head_bucket(Bucket=bucket_name) s3.Object(bucket_name, key_name).download_file(filename) except Exception as exc: logging.error( 'Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, filename, exc) ) raise SystemError( 'Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, filename, exc) ) except Exception as exc: logging.error( 'Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, filename, exc) ) raise SystemError( 'Unable to download file from S3 bucket.\n' 'url = {0}\n' 'bucket = {1}\n' 'key = {2}\n' 'file = {3}\n' 'Exception: {4}' .format(url, bucket_name, key_name, filename, exc)) logging.debug('Downloaded file from S3 bucket -- \n' ' url = {0}\n' ' filename = {1}'.format(url, filename)) else: try: response = urllib.request.urlopen(url) with open(filename, 'wb') as outfile: shutil.copyfileobj(response, outfile) except Exception as exc: # TODO: Update `except` logic logging.error('Unable to download file from web server.\n' 'url = {0}\n' 'filename = {1}\n' 'Exception: {2}' .format(url, filename, exc)) raise SystemError('Unable to download file from web server.\n' 'url = {0}\n' 'filename = {1}\n' 'Exception: {2}' .format(url, filename, exc)) logging.debug('Downloaded file from web server -- \n' ' url = {0}\n' ' filename = {1}'.format(url, filename))
def install(self, configuration, saltstates): """ :param configuration: :param saltstates: :return: """ try: self.config = json.loads(configuration) except ValueError: exceptionhandler( 'The configuration passed was not properly formed JSON. ' 'Execution halted.') self._prepare_for_install() self._install_package() self._build_salt_formula() logging.info('Setting grain `systemprep`...') ent_env = {'enterprise_environment': str(self.entenv)} cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'grains.setval', 'systemprep', str(json.dumps(ent_env)) ] self.call_process(cmd) if self.config['oupath']: print('Setting grain `join-domain`...') oupath = {'oupath': self.config['oupath']} cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'grains.setval', '"join-domain"', json.dumps(oupath) ] self.call_process(cmd) print('Syncing custom salt modules...') cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'saltutil.sync_all' ] self.call_process(cmd) print('Generating winrepo cache file...') cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'winrepo.genrepo' ] self.call_process(cmd) print('Refreshing package databse...') cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'pkg.refresh_db' ] self.call_process(cmd) if saltstates: self.config['saltstates'] = saltstates else: logging.info( 'No command line argument to override configuration file.') if 'none' == self.config['saltstates'].lower(): print('No States were specified. Will not apply any salt states.') else: if 'highstate' == self.config['saltstates'].lower(): logging.info( 'Detected the States parameter is set to `highstate`. ' 'Applying the salt `"highstate`" to the system.') cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'state.highstate' ] cmd.extend(self.saltcall_arguments) self.call_process(cmd) else: logging.info( 'Detected the States parameter is set to: {0}. Applying ' 'the user-defined list of states to the system.'.format( self.config['saltstates'])) cmd = [ self.saltcall, '--local', '--retcode-passthrough', 'state.sls', self.config['saltstates'] ] cmd.extend(self.saltcall_arguments) self.call_process(cmd) logging.info('Salt states all applied successfully! ' 'Details are in the log {0}'.format( self.salt_results_logfile)) if self.workingdir: self.cleanup()