def execute(self, readonly, precheck=False): if readonly: raise Exception("SQLScript does not support readonly operations") if not uPEM.is_sc_installed(self.owner): uLogging.info("%s is not installed, skipping", self.owner) return None con = uSysDB.connect() cur = con.cursor() rv = None for stmt in self.get_code(): uLogging.debug('executing %s', stmt) kind = stmtKind(stmt) if kind in ('BEGIN', 'COMMIT', 'ROLLBACK'): uLogging.warn( '%s statements are ignored, <SQL> action always implicitly begins and commits transaction', kind) else: cur.execute(stmt) con.commit() uSysDB.close(con) return rv
def _upDirection(con, source_rc, destination_rc): cur = con.cursor() cur.execute( "SELECT parent_path, class_id FROM resource_classes WHERE name = %s", source_rc) row = cur.fetchone() if row is None: uLogging.warn("source rc %s does not exist", source_rc) return None src_rc_path = "%s%dx" % (row[0], row[1]) cur.execute( "SELECT parent_path, class_id FROM resource_classes WHERE name = %s", destination_rc) row = cur.fetchone() if row is None: uLogging.warn("destination rc %s does not exist", destination_rc) return None dst_rc_path = "%s%dx" % (row[0], row[1]) if len(src_rc_path) < len(dst_rc_path): dst_rc_path = dst_rc_path[: len(src_rc_path)] if dst_rc_path == src_rc_path: return False if len(dst_rc_path) < len(src_rc_path): src_rc_path = src_rc_path[: len(dst_rc_path)] if dst_rc_path == src_rc_path: return True raise Exception( "Source RC '%s' shall be child of destination RC '%s'" % (source_rc, destination_rc))
def update_slave(task_item, config): is_slave_updated = None try: if Const.isOsaWinPlatform(task_item.host.platform.os): if task_item.paagent_dist_url: schedule_update_windows_slave(task_item) uAction.ntimes_retried(check_update_windows_slave, 8, 30)(task_item, config) is_slave_updated = True else: linux_update_result = update_linux_slave(task_item, config) check_update_linux_slave(task_item.host, linux_update_result) # This is a workaround: see async restart code in pa-agent RPM async_upgrade_finished_sec = 11 uLogging.debug("Waiting {async_upgrade_finished_sec} sec for agent upgrade process is finished " "on host {host}".format(host=task_item.host, async_upgrade_finished_sec=async_upgrade_finished_sec)) sleep(async_upgrade_finished_sec) uAction.ntimes_retried(wait_for_linux_slave, 8, 30)(task_item) is_slave_updated = True except Exception as e: uLogging.warn("Error happen during upgrade slave {host}, check details in log or wait for moment when " "the result will be processed".format(host=task_item.host)) uLogging.save_traceback() raise e return is_slave_updated
def precheck_for_access_verify_db(config): uLogging.info("Checking verify_db exists...") import uDBValidator import uConfig config_v = copy.copy(config) config_v.database_name = config_v.database_name + '_verify' try: uSysDB.init(config_v) con_v = uSysDB.connect() except Exception, e: uLogging.debug(str(e)) uLogging.warn("%s DB does not exist" % config_v.database_name) try: if config_v.admin_db_password or uUtil.isLocalAddress( config_v.database_host): # try to create verify db: uLogging.info("Trying to create '%s' database..." % config_v.database_name) uDBValidator._recreate_verify_db(config_v) uLogging.info("'%s' is created successfully." % config_v.database_name) else: raise Exception( "Postgres admin user credentials are required to create %s" % config_v.database_name) except Exception, e: uLogging.debug(str(e)) dsn_login_short = re.sub("@.*", "", config_v.dsn_login) raise PrecheckFailed( reason="'%s' database is not accessible or does not exist" % config_v.database_name, what_to_do= "Connect to %s Postgres server as admin user and create database: 'CREATE DATABASE %s OWNER %s'. If database '%s' already exists, make sure its owner is '%s'." % (config_v.database_host, config_v.database_name, dsn_login_short, config_v.database_name, dsn_login_short))
def is_slave_upgradable(host, binfo, config): uLogging.debug("Checking if slave {host} is upgradable".format(host=host)) is_windows_host = Const.isOsaWinPlatform(host.platform.os) if host.host_id in binfo.progress.updated_hosts: uLogging.debug("Skipping already updated slave: {host}".format(host=host)) return False if config.skip_win and is_windows_host: uLogging.debug("Skipping windows host {host} because was passed option '--skip:win'".format(host=host)) return False if config.skip_rpms and not is_windows_host: uLogging.debug("Skipping Linux (RPM) host {host} because was passed option '--skip:rpms'".format(host=host)) return False if not uPEM.canProceedWithHost(host): uLogging.warn("Skipping unavailable slave: {host}".format(host=host)) return False # platform-specific URL for agent agent_url = prepare_paagent_url(host.platform, binfo, config) if not agent_url and is_windows_host: uLogging.debug("Skipping windows slave {host} as we have no pa-agent distrib " "for its platform ({platform})".format(host=host, platform=host.platform)) return False if not agent_url and not config.need_update_paagent and not config.need_update_yum_repourl: uLogging.debug("Skipping slave {host} as we have no pa-agent distrib for its platform ({platform}) " "and updating YUM repourl is not needed also".format(host=host, platform=host.platform)) return False uLogging.debug("Slave is upgradable: {host}".format(host=host)) return True
def rebuildPlatformTree(con): cur = con.cursor() # get any-any-any id cur.execute("SELECT platform_id FROM platforms " "WHERE arch = 'any' AND opsys = 'any' AND osrel = 'any'") row = cur.fetchone() if not row: raise Exception("Platform any-any-any not found") platform_id = row[0] # set l, r for any-any-any and rebuild subplatforms cur.execute("UPDATE platforms SET l = 1, r = 2 WHERE platform_id = %s", platform_id) cur.execute("UPDATE platforms SET l = %s, r = %s WHERE platform_id <> %s", __magic_value, __magic_value, platform_id) __rebuildSubPlatforms(con, platform_id) # check for dangling platforms (that are not children of any-any-any) cur.execute( "SELECT platform_id, arch, opsys, osrel FROM platforms WHERE l = %s OR r = %s", __magic_value, __magic_value) for row in cur.fetchall(): uLogging.warn("Dangling platform #%d (%s-%s-%s)", row[0], row[1], row[2], row[3])
def safe_acquire(self, *args, **kwargs): try: return target_method(self, *args, **kwargs) except (Exception, KeyboardInterrupt) as main_exc: uLogging.warn("Exception happen in threading pool itself, terminating") self.terminateLocked() raise main_exc
def clean_interfaces(): con = uSysDB.connect() cur = con.cursor() cur.execute( "DELETE FROM interfaces WHERE NOT EXISTS (SELECT 1 FROM package_interfaces WHERE package_interfaces.interface_id = interfaces.interface_id UNION ALL SELECT 1 FROM dep_interfaces di WHERE di.interface_id = interfaces.interface_id)" ) con.commit() cur.execute( "SELECT p.pkg_id, p.name, p.ctype, i.service_type FROM interfaces i JOIN dep_interfaces di ON (i.interface_id = di.interface_id) JOIN package_dependencies dp ON (di.dep_id = dp.dep_id) JOIN packages p ON (dp.pkg_id = p.pkg_id) WHERE i.interface_id NOT IN (SELECT interface_id FROM package_interfaces)" ) pkgs = {} for row in cur.fetchall(): pkg_name = row[1], row[2] if not pkgs.has_key(pkg_name): pkgs[pkg_name] = [], [] pkg_id = str(row[0]) iface = row[3] if pkg_id not in pkgs[pkg_name][0]: pkgs[pkg_name][0].append(pkg_id) if iface not in pkgs[pkg_name][1]: pkgs[pkg_name][1].append(iface) for pkg in pkgs: uLogging.warn("%s-%s (%s) depends on non-existing interface(s): %s", pkg[0], pkg[1], ', '.join(pkgs[pkg][0]), ', '.join(pkgs[pkg][1]))
def checkNumberOfActiveTasks(): import uTasks task_number = uTasks.getNumberOfActiveTasks() if task_number > 2000: uLogging.warn("Number of active tasks in Task Manager: %s. Too many active tasks.", task_number) raise uPrecheck.PrecheckFailed("There are %s unprocessed, scheduled, running or failed tasks in Task Manager (including periodic).\nUpdate cannot be performed if this number is more than 2000" % task_number, "Cancel failed tasks or wait for them to complete.") else: uLogging.info("Number of active tasks in Task Manager: %s. OK.", task_number)
def verifyPostgresCertificate(pgsqlOnMaster): uLogging.info("Make sure PostgreSQL server.crt satisfies the installation requirements according to the KB '%s'" % PG_CERT_VERIFY_KB_URL) serverCrtPath = pgsqlOnMaster.get_data_dir() + "/server.crt" runOnMaster = pgsqlOnMaster.get_commander() # make sure certificate exists try: checkExists = runOnMaster("[ -e '%s' ] && echo 'OK'" % serverCrtPath) if checkExists.strip() != 'OK': raise Exception("Certificate '%s' not found" % serverCrtPath) except Exception, ex: uLogging.err(ex.message) exceptionMsg = "Failed to validate existence of '%s' with error '%s'. Please refer to the KB %s" % (serverCrtPath, ex.message, PG_CERT_VERIFY_KB_URL) uLogging.warn("\n%s\n%s\n%s" %( "*" * 150, exceptionMsg, "*" * 150)) raise Exception(exceptionMsg)
def check_free_disk_space(node_id, quota_in_gb, location = "/usr/local"): """Checking node availability, checking free disk space on any node :param node_id: :param quota_in_gb: :param location: default /usr/local :return: """ node_name = getHost(node_id).name uLogging.debug("Making request to node %s for checking free disk space with df utilite.", node_name) try: uLogging.debug("Checking if node %s is available" % node_name) ping(node_id) except uUtil.ExecFailed, e: uLogging.warn("Failed to ping node %s: %s" % (node_name, e)) return
def resetPIDs(): """ Set to null PIDs of POA soloaders in order to show that service controllers aren't started NOTE: PIDs of pleskd and vzpemagent WILL NOT be changed """ try: con = uSysDB.connect() cur = con.cursor() cur.execute( "UPDATE sc_instances SET pid = -1 WHERE sc_id IN (SELECT sc_id FROM service_classes WHERE name NOT IN ('pleskd', 'vzpemagent'))") con.commit() uSysDB.close(con) except Exception, e: uLogging.warn("Failed to reset SoLoader PIDs: %s", e)
def waitForJBossStarted(root): time_to_wait = 120 # Same value as in linux service synchronous script from u import bootstrap while ('started in' in open(bootstrap.getJBossDir(root) + '\\standalone\\log\\standalone.log').read()) != True and time_to_wait > 0: #print("In loop trying to wait for JBoss") time.sleep(1) time_to_wait -= 1 if time_to_wait == 0: try: proclist = sp.check_output('tasklist').splitlines() pid = filter(lambda x:'java' in x, proclist)[0].split()[1] stack = sp.check_output(os.environ['java_home']+'/bin/jstack -F %s ' % pid) uLogging.warn('waitForJBossStarted failed stacktrace below\n'+stack) except Exception, e: uLogging.warn("Failed to jstack jboss", e) raise Exception("Failed to wait for JBoss started")
def check_unfinished_installation_tasks(): unfinished_tasks_num = uTasks.get_num_of_unfinished_installation_tasks() if not unfinished_tasks_num: uLogging.info("No unfinished installation tasks in Task Manager: OK.") else: msg = "A number of unfinished installation tasks have been fetched out during pre-check, " \ "total: %s. " \ "These issues prevent the update of being started." % unfinished_tasks_num uLogging.warn(msg) raise uPrecheck.PrecheckFailed(msg, "To resolve these issues, log in to Odin Automation, " "go to Operations > Tasks, filter the tasks by the 'Install' " "sample in their name, eliminate blocker factors " "or fix the cause of the tasks failure" "then wait for these tasks until they will finish " "with the Successful status." "Also you can cancel these tasks, but only if you know what you doing.")
def set_connection_timeout(self, connection): try: # Get HTTP(S)Connection instance and set timeout on it try: # Python <= 2.6 - connection is HTTP(S) instance http_conn = connection._conn except AttributeError: # Python >= 2.7 - connection is HTTP(S)Connection instance http_conn = connection http_conn.timeout = self.config.timeout if http_conn.sock is not None: http_conn.sock.settimeout(self.config.timeout) except AttributeError: uLogging.warn( "Failed to set OpenAPI connection socket timeout - operation not supported" )
def waitSlaveRecoveryComplete(run): recoveryComplete = False waitRecoveryEnd = 0 while waitRecoveryEnd < PG_SLAVE_END_RECOVERY_TIMEOUT_SECONDS: try: run("""su - postgres -c "psql -t -P format=unaligned -c $'show server_version'" """ ) recoveryComplete = True break except Exception, e: errorMessage = e.message if errorMessage.find("system is starting") != -1: uLogging.warn("Slave database is in recovery mode:\n%s\n'%s'\n%s " % ("="*40 , errorMessage , "="*40)) else: raise Exception("Failed to start slave database server with error '%s'!" % errorMessage) time.sleep(5) waitRecoveryEnd += 5 uLogging.info("Wait until PG is out of the recovery stage. Elapsed '%d' seconds" % waitRecoveryEnd)
def report_skipped_hosts(binfo): if binfo.progress.failed_hosts: uLogging.warn("For some slave nodes ({items_count} items) upgrade was skipped, " "please upgrade pa-agent manually.".format(items_count=len(binfo.progress.failed_hosts))) uLogging.warn("Skipped slaves list:\n{slave_list}".format( slave_list="\n".join([str(x.host) for x in binfo.progress.failed_hosts]))) uLogging.warn("Detailed info about skipped slaves below (per host)") for failed_slave_upgrade in binfo.progress.failed_hosts: uLogging.warn("Host: {host}; details: \n{details}".format( host=failed_slave_upgrade.host, details=failed_slave_upgrade.error))
def check(actions, errors, min_limit, max_limit): for action in filter(lambda x: x.id not in actionBlacklist, actions): errors[action.id] = [] if len(action.id) > 64: errors[action.id] += [ "Action ID '%s' length is > 64 symbols: must be less than 64 symbols" % action.id ] matches = pattern.match(action.id) if matches: identifer = matches.group(1) if identifer is None or len(identifer) == 0: errors[action.id] += [ "Action '%s' has no integer identifer specified" % action.id ] if ignore_upper_limit: if int(identifer) < min_limit: errors[action.id] += [ "Action '%s' has integer identifer '%s' lower than %s" % (action.id, identifer, min_limit) ] else: if int(identifer) < min_limit or int( identifer) > max_limit: errors[action.id] += [ "Action '%s' has integer identifer '%s' outside limits [%s; %s]" % (action.id, identifer, min_limit, max_limit) ] issue = matches.group(2) if issue is None or len(issue) == 0: errors[action.id] += [ "Action '%s' has no linked issue specified" % action.id ] description = matches.group(3) if description is None or len(description) == 0: uLogging.warn("Action '%s' has no description" % action.id) else: errors[action.id] += [ "Action '%s' has malformed name: consider UA naming conventions described in .udl2 file" % action.id ]
def get_identity_columns(table, con): tab = getTable(table, con) columns = [] for col in tab.columns: if isinstance(col.type, uDBTypes.SerialType): m = re.match("nextval\('\"?([^\"]+)\"?'", col.default) if m: col.sequence = m.group(1) columns.append(col) else: # uLogging.warn('Strange Serial type of column {}.{} with default {}'.format(table, col.name, col.default)) uLogging.warn( 'Strange Serial type of column %s.%s with default %s' % (table, col.name, col.default)) if len(columns) > 1: uLogging.warn( 'Strange condition: more then one column with autoincrenet at table {}' .forma(table)) return columns
def dropColumnIfExists(table, column, connection=None): if not connection: con = uSysDB.connect() own = True else: con = connection own = False if isinstance(table, uDBSchema.Table): tab = table else: tab = uDBSchema.getTable(table, con) if tab.getColumn(column): tab.dropColumn(column, con) if own: con.commit() else: uLogging.warn( "Column %s does not exist on table %s. But it's ok, it should be dropped anyway", column, tab.name)
def check_net_bandwidth_for_host(host): uLogging.info("Checking bandwidth between MN and host {host}".format(host=host)) bandwidth_report = HostBandwidthReport(host) try: file_for_test = FileForSpeedtest() test_request = uHCL.Request(host_id=host.host_id) test_request.fetch(srcfile=file_for_test.file_name, urls=[file_for_test.site_url], dstvar="dummy_speedtest_file") test_request.rm(path="${dummy_speedtest_file}") execution_time = measure_hcl_execution_time(request=test_request) bandwidth_report.measuring_finished = True bandwidth_report.calc_mbps(execution_time=execution_time, file_size_bytes=file_for_test.size_bytes) uLogging.debug(bandwidth_report) except Exception as e: uLogging.save_traceback() bandwidth_report.failure_reason = e uLogging.warn(str(bandwidth_report)) finally: return bandwidth_report
def connect_unix(super_user=False): database_name = _config.database_name if super_user: uname = 'postgres' else: uname = _config.dsn_login if not all_connections.has_key((database_name, uname)): all_connections[(database_name, uname)] = get_connection(_config, uname) rv = all_connections[(database_name, uname)] try: cur = rv.cursor() cur.execute("SELECT 1") except (OperationalError, DatabaseError): uLogging.warn("Connection to DB is lost, attempting to reconnect") close(rv) rv = all_connections[(database_name, uname)] = get_connection(_config, uname) return rv
def dropIndexIfExists(table, index, connection=None): if not connection: con = uSysDB.connect() own = True else: con = connection own = False if isinstance(table, uDBSchema.Table): tab = table else: tab = uDBSchema.getTable(table, con) if tab.getIndex(index): uLogging.info("DROP INDEX %s ON %s", index, tab.name) tab.dropIndex(index, con) if own: con.commit() else: uLogging.warn("Index %s does not exist on table %s. But it's ok, it should be dropped anyway", index, tab.name)
def process_one_result(pool_result, pool, binfo, config): processed_result = ProcessedResult(pool_result) host = pool_result.task_item.host if not processed_result.successful and config.batch: pool.terminateLocked() raise Exception("Slave upgrade failed, batch mode is active") if not processed_result.successful: if dialog_need_retry(host): pool.put(pool_result.task_item) uLogging.warn("Slave {host} scheduled for retry".format(host=host)) else: uLogging.warn("Slave {host} failed to update, retry is skipped".format(host=host)) binfo.progress.failed_hosts.append( FailedHost(host=host, error=processed_result.error_as_text) ) else: binfo.progress.updated_hosts.add(host.host_id)
def dropConstraintIfExists(table, constraint, connection=None): if not connection: con = uSysDB.connect() own = True else: con = connection own = False if isinstance(table, uDBSchema.Table): tab = table else: tab = uDBSchema.getTable(table, con) if tab.getConstraint(constraint): uLogging.info("DROP CONSTRAINT %s ON %s", constraint, tab.name) tab.dropConstraint(constraint, con) if own: con.commit() else: uLogging.warn( "Constraint %s does not exist on table %s. But it's ok, it should be dropped anyway", constraint, tab.name)
def tryCheckSQL(instructions): actions = [ x for x in instructions.preparation.actions if isinstance(x, SQLScript) ] actions += [ x for x in instructions.pre.actions if isinstance(x, SQLScript) ] actions += [ x for x in instructions.prepkg.actions if isinstance(x, SQLScript) ] actions += [x for x in instructions.actions if isinstance(x, SQLScript)] actions += [ x for x in instructions.post.actions if isinstance(x, SQLScript) ] actions += [ x for x in instructions.cleanup.actions if isinstance(x, SQLScript) ] # need set some value for ConcatOperator when it is not initialized naturally (when one have database connected) import uSysDB if not uSysDB.ConcatOperator: uSysDB.ConcatOperator = '||' errors = False for action in actions: for stmt in action.parsed_code(): kind, text = stmt if kind in ('CREATE', 'ALTER', 'DROP'): uLogging.err("Action:%s, not portable statement '%s'", action.id, stmt) errors = True elif kind in ('BEGIN', 'COMMIT', 'ROLLBACK'): uLogging.warn( '%s statements are ignored, <SQL> action always implicitly begins and commits transaction', kind) if errors: raise Exception('Non portable SQL in some actions')
def add_package(self, built_package, fail_on_different_versions=False): self.platforms.add(built_package.package.platform) if self.contents.has_key(built_package.package): if self.config and self.config.warning_duplicates: uLogging.warn("%s: duplicate package in build %s", built_package, self.name) vc = compare_versions(built_package.version, self.contents[built_package.package].version) if vc != 0 and fail_on_different_versions: raise Exception( "Two different package versions in build: %s and %s" % (built_package, self.contents[built_package.package].version)) if vc > 0: uLogging.debug("Choosing %s over %s", built_package, self.contents[built_package.package].version) self.__add_package(built_package) elif vc < 0: uLogging.debug("Choosing %s over %s", self.contents[built_package.package], built_package.version) else: self.__add_package(built_package)
def forceHaMasterSyncConf(run): uLogging.info("Force Master DB node to sync PostgreSQL configuration files") try: run("""/usr/local/pem/bin/pgha/pghactl.py sync-pg-conf""") except Exception, ex: uLogging.warn("Failed to synchronise DB nodes configuration files with error '%s'" % ex.message)
def check_internal_net_bandwidth(config): """ Here we are checking network bandwidth to be sure that pa-agents will be delivered in time on all slaves during update. """ if config.skip_check_internal_net_bandwidth: uLogging.warn('Checking internal net bandwidth was skipped.') return from poaupdater import uSlaveUpdater # MB (megabytes) per second, we are assuming to utilize ethernet (100BaseT) # with host count calculated by uSlaveUpdater.max_slave_upgrade_threads() min_mbps = 1 # Initializing file for test firstly to get its instance further and undeploy it finally file_for_speedtest = FileForSpeedtest(config.communication_ip) slaves_with_agent = [host for host in get_hosts_with_agent() if int(host.host_id) != 1] uLogging.debug("Found slaves with agent: \n{slaves}".format(slaves=pprint.pformat(slaves_with_agent))) if config.skip_rpms: slaves_with_agent = filter(lambda host: Const.isOsaWinPlatform(host.platform.os), slaves_with_agent) uLogging.debug("Filtered out Linux slaves because was passed option '--skip:rpms', " "now slave list is \n{slaves}".format(slaves=pprint.pformat(slaves_with_agent))) if config.skip_win: slaves_with_agent = filter(lambda host: not Const.isOsaWinPlatform(host.platform.os), slaves_with_agent) uLogging.debug("Filtered out Windows slaves because was passed option '--skip:win', " "now slave list is \n{slaves}".format(slaves=pprint.pformat(slaves_with_agent))) if not slaves_with_agent: uLogging.debug("No slaves found, no need to check internal network bandwidth") return thread_count = uSlaveUpdater.max_slave_upgrade_threads( hosts_to_upgrade_count=len(slaves_with_agent), slave_upgrade_threads=config.slave_upgrade_threads ) uLogging.info("Checking network bandwidth between MN and slaves " "(parallel: {thread_count})".format(thread_count=thread_count)) pool = uThreadPool.ThreadPool(check_net_bandwidth_for_host) map(pool.put, slaves_with_agent) try: pool.start(thread_count) check_results = pool.get_all_non_empty_results() finally: pool.terminate() file_for_speedtest.undeploy_file_for_test() if "__iter__" not in dir(check_results) or len(check_results) < 1: raise Exception("Check for speed test returned nothing, this is unexpected") completely_failed_checks = filter(lambda result: type(result.result) is not HostBandwidthReport, check_results) if completely_failed_checks: raise Exception("Some of check has completely failed, summary report is inconsistent: \n{failed_items}".format( failed_items=pprint.pformat(completely_failed_checks))) # uThreadPool returns namedtuple ["task_item", "result", "duration"], we need only result check_results = [x.result for x in check_results] uLogging.debug("Checking reports for speed sufficiency") map(lambda report: report.calc_is_sufficient(min_mbps), check_results) uLogging.debug("Results: \n" + pprint.pformat(check_results)) failed_checks_report = [str(check_result) for check_result in check_results if not check_result.sufficient] if failed_checks_report: raise uPrecheck.PrecheckFailed( reason="detected network issue, bandwidth between MN and slave is not sufficient", what_to_do="please fix network issue for hosts reported below: \n{bandwidth_reports}".format( bandwidth_reports="\n".join(failed_checks_report) ) ) uLogging.debug("Checking network bandwidth finished successfully - all slaves are ok.")
def upgradeSC(component_id): con = uSysDB.connect() cur = con.cursor() cur.execute("""SELECT sc.sc_id, p.name, p.version, p.pkg_id, sc.sc_group_id, sc.name FROM service_classes sc JOIN sc_instances si ON (sc.sc_id = si.sc_id) JOIN components c ON (c.component_id = si.component_id) JOIN packages p ON (p.pkg_id = c.pkg_id) WHERE si.component_id = %s""", component_id) row = cur.fetchone() if not row: raise Exception("Component id %s does not exist, or not a service controller" % component_id) sc_id, pkg_name, old_pkg_version, old_pkg_id, sc_group_id, scname = row[0], row[1], row[2], row[3], row[4], row[5] uLogging.debug("Upgrading %s-%s (sc_id = %d, pkg_id = %d)", pkg_name, old_pkg_version, sc_id, old_pkg_id) new_pkg_id = find_newer_sc_pkg_id(con, old_pkg_id, pkg_name, old_pkg_version) if not new_pkg_id: uLogging.warn("No higher version package found") return # TODO: only one service_instance should be auto-updated, rest ones should refer to old components cur.execute("UPDATE components SET pkg_id = %s WHERE component_id = %s", (new_pkg_id, component_id)) cur.execute( "UPDATE service_classes SET version = p.version FROM packages p WHERE sc_id = %s AND p.pkg_id = %s", (sc_id, new_pkg_id)) # update component properties cur.execute(""" SELECT p.prop_id, p.name, p2.prop_id AS new_prop_id FROM component_properties cp JOIN properties p ON (cp.prop_id = p.prop_id) LEFT JOIN properties p2 ON (p.name = p2.name) WHERE p.pkg_id = %s AND p2.pkg_id = %s AND cp.component_id = %s """, (old_pkg_id, new_pkg_id, component_id)) rows = cur.fetchall() for row in rows: old_prop_id, prop_name, new_prop_id = row[0], row[1], row[2] if new_prop_id is None: uLogging.debug("Deleting property %s (old prop_id %s)", prop_name, old_prop_id) cur.execute("""DELETE FROM component_properties WHERE component_id = %s AND prop_id = %s """, (component_id, old_prop_id)) else: uLogging.debug('Copying property %s (old prop_id %s, new prop_id %s)', prop_name, old_prop_id, new_prop_id) cur.execute("""UPDATE component_properties SET prop_id = %s WHERE component_id = %s AND prop_id = %s """, (new_prop_id, component_id, old_prop_id)) # register new properties of updated SC except (they should be set manually in upgrade procedure): # 1. mandatory properties with not specified default # 2. properties which should be got by depend (TODO, probably updater should resolve such depends) cur.execute(""" SELECT p.default_value, p.name FROM properties p WHERE p.pkg_id = %s AND NOT EXISTS (SELECT 1 FROM component_properties cp WHERE cp.component_id = %s AND cp.prop_id = p.prop_id) AND (p.default_value IS NOT NULL or p.mandatory = 'n') AND NOT EXISTS (SELECT 1 FROM dep_get_properties dp JOIN package_dependencies pd ON pd.dep_id = dp.dep_id WHERE pd.pkg_id = p.pkg_id AND dp.name = p.name) """, (new_pkg_id, component_id)) rows = cur.fetchall() for row in rows: prop_val, prop_name = row[0], row[1] uLogging.debug('Register SC %s missing property %s (component_id %s, default_value %s)', scname, prop_name, component_id, prop_val) uPEM.setSCProperty(con, scname, prop_name, prop_val) # update OpenAPI methods and observer interfaces cur.close() cur = con.cursor() cur.execute("SELECT data FROM package_body WHERE pkg_id = %s", new_pkg_id) row = cur.fetchone() data = row[0] data = str(data) manifest = uManifestParser.unsign_package(cStringIO.StringIO(data)) xml = dom.parseString(manifest) observer_interfaces = [node.getAttribute("name") for node in xml.getElementsByTagName( "INTERFACE") if node.getAttribute("observer") == "yes"] uLogging.debug("Attempting to register observer interfaces: %s", ', '.join( ["%s" % service_type for service_type in observer_interfaces])) iparams = [sc_id] for service_type in observer_interfaces: iparams += [service_type] cur.execute(""" INSERT INTO observers(sc_id, interface_id) SELECT %s, interface_id FROM interfaces i WHERE service_type = %s AND NOT EXISTS (SELECT 1 FROM observers o WHERE sc_id = %s AND i.interface_id = o.interface_id)""", (sc_id, service_type, sc_id)) if not observer_interfaces: cur.execute("DELETE FROM observers WHERE sc_id = %s", sc_id) else: cur.execute(("DELETE FROM observers WHERE sc_id = %%s AND interface_id NOT IN (SELECT interface_id FROM interfaces WHERE (%s))" % ' OR '.join(['(service_type = %s)'] * len(observer_interfaces))), iparams) cur.execute( "DELETE FROM openapi_methods WHERE extension_id IN " "(SELECT extension_id FROM openapi_extensions WHERE sc_id = %s)", sc_id) cur.execute( "DELETE FROM openapi_extensions WHERE sc_id = %s", sc_id) new_sc_group_id = None if old_pkg_version >= "2.9": # upgrade SC group id sc_group_ids = [x.getAttribute("value") for x in xml.getElementsByTagName( "ATTRIBUTE") if x.getAttribute("name") == "SC_GROUP_ID"] if not sc_group_ids: uLogging.debug("Cannot find SC Group ID for %s-%s", pkg_name, old_pkg_version) else: try: new_sc_group_id = int(sc_group_ids[0]) uLogging.debug("New SC group id = %s, old = %s", new_sc_group_id, sc_group_id) except Exception: uLogging.err("%s: invalid sc_group_id", sc_group_ids[0]) if new_sc_group_id is not None and sc_group_id != new_sc_group_id: cur.execute("UPDATE service_classes SET sc_group_id = %s WHERE sc_id = %s", new_sc_group_id, sc_id) fixDependencies(con, component_id, new_pkg_id, pkg_name) uModularOpenAPI.update_extensions_from_xml(xml, con) con.commit() uSysDB.close(con)