def _check_bom(self, bom_pkns): """ Check through what should be installed on the system and what is installed on the system and determine what packages aren't installed that should be and what packages are installed that shouldn't be. bom_pkns -- A list of package names that are intended to be installed on the machine (i.e. the 'bill of materials' """ should_be_installed = [] shouldnt_be_installed = [] pdat = self.progress.get_progress_data(False) installed_pkns, broken_pkns = Progress.get_installed(pdat) all_pkns = set(installed_pkns).union(broken_pkns) all_plus_missing_pkns = self._examine_dependencies(all_pkns) missing_pkns = list(all_plus_missing_pkns - all_pkns) bom_pkns = bom_pkns + missing_pkns dependency_errors = self._get_dependency_errors(bom_pkns, pdat) if dependency_errors: errmsg = "The following packages are installed as " "dependencies %s" % dependency_errors Logger.debug(errmsg) bom_pkns += dependency_errors for pkn in installed_pkns: if pkn not in bom_pkns: shouldnt_be_installed.append(pkn) for pkn in bom_pkns: if pkn not in installed_pkns: should_be_installed.append(pkn) return should_be_installed, shouldnt_be_installed
def is_running(self): 'ability to check if the job is finished' if self.job_thread: if self.job_thread.isAlive(): return True if type(self.job_thread.cmd_status) == type(0) \ or type(self.job_thread.cmd_status) == type('str'): Logger.debug("-- status: %s" % (self.job_thread.cmd_status)) self.job_status = self.job_thread.cmd_status else: msg = "Invalid return status (type: %s)" Logger.error(msg % (type(self.job_thread.cmd_status))) self.job_status = FAIL return False
def run(self): 'Thread interface' Logger.debug("Running %s..." % self.cmd) try: exec(self.import_string) exec("self.cmd_status = %s" % self.cmd) except StandardError, err: Logger.error("Failed to run %s (%s)" % (self.cmd, err)) sio = StringIO.StringIO() traceback.print_exc(file=sio) sio.seek(0) data = sio.read() ermsg = '' for line in data.split('\n'): ermsg += "\n||>>>%s" % line Logger.error(ermsg) self.cmd_status = FAIL
def _get_uninst_pkg_dep(self, pkd, del_pkns, installed_pkns): """Add any packages that are installed already which are dependent upon those to the list as well pkd -- The dictionary of package objects del_pkns -- names of packages we want to remove installed_pkns -- names of packages that are installed already """ msg = "Checking dependencies of packages to be uninstalled %s..." msg = msg % del_pkns Logger.info(msg) v_pkgs = VirtualPackages(self.repository.pkg_data) uninstall_order = copy.deepcopy(del_pkns) while del_pkns: new_dependency_names = [] del_pkns = [] for pkn in installed_pkns: if pkn in pkd.keys(): Logger.debug("Package %s will already be deleted -- " "ignoring" % pkn) continue pkg = self._get_new_pkg(pkn) pkg.action = UNINSTALL for tombstoned_pkns in pkd.keys(): vpn = v_pkgs.get_vpn_from_pkn(tombstoned_pkns) if vpn in pkg.dependencies: erstr = "Adding to package removal list: %s" " (depends on %s)" uninstall_order.insert(0, pkn) Logger.info(erstr % (pkn, tombstoned_pkns)) pkd[tombstoned_pkns].depends_on_me.append(pkn) if pkn not in pkd.keys(): if pkn not in new_dependency_names: pkd[pkn] = pkg new_dependency_names.append(pkn) del_pkns = new_dependency_names proper_order = self._sort_uninstalled_pkgs(uninstall_order) return pkd, proper_order
def _prepare_restore(self, obj, restore_path): """ Command to deal with setting up the environment prior to a restore action obj -- package object which owns methods for restoring, etc. restore_path -- place where restore files have been dropped """ if hasattr(obj, "pre_restore_cmd"): pre_backup_cmd = obj.pre_backup_cmd status = self._find_cmd(obj.pre_restore_cmd) if status != OK: erstr = "%s: restore FAILED because %s failed." Logger.error(erstr % (self.full_name, pre_backup_cmd)) return FAIL backup_data = yaml_load(open(make_path(restore_path, "backup_info.yml")).read()) for backup_target in backup_data: if backup_target.startswith("__"): continue md5_data = backup_data[backup_target].get("md5", {}) backup_file_name = backup_data[backup_target].get("backup_file", '') if not md5_data or not backup_file_name: Logger.error("Corrupted backup data for %s, aborting." % (backup_target)) return FAIL source_file = make_path(restore_path, rpartition(backup_target, os.path.sep)[0][1:], backup_file_name) destination_file = make_path(restore_path, backup_target[1:]) Logger.debug("=================================") Logger.debug("backup_target: %s..." % (backup_target)) Logger.debug("current directory: %s" % (restore_path)) Logger.debug("backup_file_name: %s..." % (backup_file_name)) Logger.debug("destination_file: %s..." % (destination_file)) Logger.debug("source_file: %s" % (source_file)) Logger.debug("=================================") if not os.path.isfile(source_file): Logger.error("Restore file %s does not exist, aborting" % (source_file)) return FAIL rfp = ReversePluggableFileProcessor(source_file, destination_file, md5_data, Logger) rfp.process_all()
def data_request(self): "Obtain configuration data from the server" b64_data = [] while True: #Logger.info( "STARTING READ" ) chunk = sys.stdin.read(STREAM_BLOCK_SIZE).strip() #Logger.info( "READ FROM SERVER: [%s]" % chunk) if not chunk or chunk[0] == ' ' or chunk.endswith("-"): chunk = chunk[:-1] b64_data.append(chunk) break b64_data.append(chunk) sys.stdout.write(">\n") sys.stdout.flush() #Logger.info("FINISHED INPUT LOOP") #print "b64_data: ", b64_data json_data = '' #json_data = zlib.decompress(base64.decodestring(''.join(b64_data))) json_data = base64.decodestring(''.join(b64_data)) #print "json_dataa", json_data Logger.debug("Received %s lines of json" % len(json_data.split('\n'))) try: input_data = json.loads(json_data) #print "input_dataa", input_data except: ermsg = "Configuration data not YAML-parseable: %s" % (repr(json_data)) file_number, filename = tempfile.mkstemp(suffix=".yml") fh = open(filename, 'w') Logger.error("Writing bad data to %s" % filename) for line in json_data.split('\n'): fh.write("[%s]" % line) fh.flush() fh.close() raise ConfigurationException(ermsg) if type(input_data) == type("string"): ermsg = "Configuration data not YAML-parseable: %s" % (repr(json_data)) raise ConfigurationException(ermsg) if type(input_data) != type({}) and type(input_data) != type([]): input_data = input_data.next() config_key = input_data.get("config_key", None) if config_key: try: from bombardier_core.Cipher import Cipher except ImportError: msg = "This machine cannot accept an encrypted configuration" raise ConfigurationException(msg) enc_json_file = make_path(get_spkg_path(), self.instance_name, 'client.yml.enc') if not os.path.isfile(enc_json_file): msg = "%s file doesn't exist" % enc_json_file raise ConfigurationException(msg) enc_data = open(enc_json_file).read() cipher = Cipher(config_key) plain_json_str = cipher.decrypt_string(enc_data) try: input_data = json.loads(plain_json_str) except: ermsg = "Received bad YAML file: %s" % enc_json_file raise ConfigurationException(ermsg) config_data = input_data.get("config_data") if not config_data: raise ConfigurationException("No configuration data received") package_data = input_data.get("package_data", {}) self.config = Config(self.instance_name, config_data) self.repository = Repository(self.instance_name, package_data)
def _find_cmd(self, action, argument='', future_pkns=[], dry_run=False): ''' Perform the action on the system, importing modules from the package and running the appropriate method on the class within. action -- INSTALL, UNINSTALL, CONFIGURE, VERIFY future_pkns -- future package names. Some packages want to know about the packages that will come after them dry_run -- boolean flag to see if we're really going to do this ''' cwd = get_slash_cwd() sys.path.insert(0, self.scripts_dir) os.chdir(self.scripts_dir) files = self._get_possible_module_files() status = FAIL file_found = False for file_name in files: try: obj = Spkg.SpkgV4(self.config, logger=Logger) os.chdir(self.working_dir) letters = [ chr( x ) for x in range(65, 91) ] random.shuffle(letters) rand_string = ''.join(letters) exec("import %s as %s" % (file_name, rand_string)) self.config["__FUTURE_PACKAGES__"] = future_pkns self.config["__INSTANCE__"] = self.instance_name cmd_str = "obj = %s.%s(self.config, Logger)" exec(cmd_str % (rand_string, file_name)) file_found = True if not dry_run: if action == INSTALL: status = obj.installer() elif action == VERIFY: status = obj.verify() elif action == UNINSTALL: status = obj.uninstaller() elif action == CONFIGURE: status = obj.configure() else: raise FeatureRemovedException(action) else: status = OK del rand_string if file_name in sys.modules: sys.modules.pop(file_name) while self.scripts_dir in sys.path: sys.path.remove(self.scripts_dir) break except ImportError: msg = "File %s is not runnable. Looking for others" % file_name Logger.debug(msg) continue except SystemExit, err: if err.code: status = err.code else: status = 0 file_found = True break except KeyboardInterrupt: Logger.error("Keyboard interrupt detected. Exiting...") sys.exit(10)