ruạṛ
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown at https://opensource.org/licenses/UPL. import argparse import logging import os import sys import time import requests try: # python2 import xmlrpclib except ImportError: # python3 import xmlrpc.client as xmlrpclib from osms import actions from osms import config from osms import utils from osms.i18n import bstr from osms.server import OsmsServer, get_cacert # Action version we understand ACTION_VERSION = 2 # SystemExit exception error code SYSEXIT_CODE = 3 # Action maps ACTIONS = { 'errata.update': actions.errata_update, 'packages.checkNeedUpdate': actions.package_check_need_update, 'packages.fullUpdate': actions.package_full_update, 'packages.refresh_list': actions.package_refresh_list, 'packages.remove': actions.package_remove, 'packages.update': actions.package_update, 'packages.verify': actions.package_verify, 'ksplice.upgrade': actions.ksplice_upgrade, } # Actions that will run each time we execute LOCAL_ACTIONS = [ ("packages.checkNeedUpdate", ()), ] class Checker: def __init__(self): self.server = None self.terminate = False def run(self): if not config.getSystemId(): raise Exception("Unable to read system id.") self.server = OsmsServer() self.run_remote_actions() self.run_local_actions() def rpc(self, method, *args): return getattr(self.server, method)(*args) def get_action(self, status_report): return self.rpc( 'queue.get', config.getSystemId(), ACTION_VERSION, status_report ) def submit_response(self, action_id, status, message, data): return self.rpc( 'queue.submit', config.getSystemId(), action_id, status, message, data ) def run_remote_actions(self): status_report = self.build_status_report() action = self.get_action(status_report) while action not in ['', {}]: if self.is_valid_action(action): self.handle_action(action) action = self.get_action(status_report) def parse_action_data(self, action): """ Parse action data and returns (method, params) """ data = action['action'] parser, decoder = xmlrpclib.getparser() parser.feed(bstr(data)) parser.close() params = decoder.close() method = decoder.getmethodname() return method, params def handle_action(self, action, cache_only=None): logging.info("handle_action: %s", action) method, params = self.parse_action_data(action) status, message, data = self.run_action(method, params, {'cache_only': cache_only}) logging.info("Package: %s, Status: %s", params, message) ret = 0 if not cache_only: logging.debug("Sending back response: %s, %s, %s", status, message, data) ret = self.submit_response(action['id'], status, message, data) if self.terminate: raise Exception('Action handling terminated.') return ret def is_valid_action(self, action): logging.debug("check_action: %s", action) if not isinstance(action, dict): raise Exception("Got unparseable action response from server") for key in ['id', 'version', 'action']: if key not in action: raise Exception("Got invalid response - missing '%s'" % key) try: ver = int(action['version']) except ValueError: ver = -1 if ver > ACTION_VERSION or ver < 0: logging.info("Got unknown action version %d", ver) # the -99 here is kind of magic self.submit_response(action["id"], -99, "Can not handle this version", {}) return False return True def build_status_report(self): status_report = {} status_report["uname"] = list(os.uname()) uptime = utils.get_uptime() if uptime: status_report['uptime'] = uptime effective_kernel = utils.get_effective_kernel() if effective_kernel: status_report['effective_kernel'] = effective_kernel needs_restarting = utils.needs_restarting() if needs_restarting: status_report['needs_restarting'] = '1' else: status_report['needs_restarting'] = '0' return status_report def run_local_actions(self): """Hit any actions that we want to always run.""" for method_params in LOCAL_ACTIONS: method = method_params[0] params = method_params[1] status, message, data = self.run_action(method, params) logging.debug("local action status: %s, %s, %s", status, message, data) def run_action(self, method, params, kwargs=None): kwargs = kwargs or {} logging.debug("run_action: %s, %s, %s", method, params, kwargs) if method not in ACTIONS: logging.error('Invalid function call attempted: %s', method) return 6, 'Invalid function call attempted', {} try: return ACTIONS[method](*params, **kwargs) except SystemExit as err: self.terminate = True # Are we dealing with shutdown script? If yes, send some response to server ASAP. if err.code == SYSEXIT_CODE: extras = { 'output': '', 'base64enc': 0, 'return_code': 0, 'process_start': '', 'process_end': '' } for key in ('process_start', 'process_end'): extras[key] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) return 0, "Script executed. Termination signal occurred during execution", extras except Exception: logging.exception('Failed to run action') # The action code failed in some way. let's let the server know. return 6, 'Fatal error in Python code occurred', {} class SelfTest: @staticmethod def create(server_url=None): if not server_url: server_url = config.getServerlURL()[0] server_url = server_url.replace('XMLRPC', 'agent-self-test') return SelfTest(server_url) def __init__(self, url, proxies=None, signer=None, ssl=True): self.url = url def __do_request(self, headers={}, proxies=None, auth=None, verify=True): return requests.get(self.url, headers=headers, verify=verify, proxies=proxies) def run(self): errmsg = "Unable to connect to server. " \ "Please verify network connectivity and/or network security policies. Machines managed by " \ "OSMS require one of the following: \n" \ "1. A private subnet with a service gateway that uses the All <region> Services in Oracle Services Network CIDR label. \n" \ "2. A private subnet with a NAT gateway. \n " \ "3. A public subnet with an internet gateway." try: print("Performing Agent Self Test with service ...") resp = self.__do_request() doclink = "https://docs.oracle.com/en-us/iaas/os-management/osms/osms-getstarted.htm" msg = "There does not appear to be any network or connectivity issues." \ "If you are having issues with OSMS, check your Policies and Dynamic Group setup. " \ "See {0} for further details.".format(doclink) except requests.exceptions.ConnectionError: # In the event of a network problem (e.g. DNS failure, refused connection, etc), # Requests will raise a ConnectionError exception. msg = errmsg except requests.exceptions.Timeout: msg = errmsg finally: print("#########OSMS Connectivity Test Completed#########") print(msg) print("##################################################") def main(cmds): epilog = 'See "%(prog)s COMMAND -h" for help on a specific command.' parser = argparse.ArgumentParser(epilog=epilog) parser.add_argument( '--log-file', default='/var/log/oracle-cloud-agent/plugins/osms/osms.log', help='Log file (default: %(default)s)' ) parser.add_argument( '--log-level', default='INFO', choices=('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'), help='Log level (default: %(default)s)' ) subparsers = parser.add_subparsers(title='Subcommands', metavar='') subparsers.required = True for name, cmd in sorted(cmds.items()): subparser = subparsers.add_parser(name, help=cmd['help'], description=cmd['help']) for cmdargs, kwargs in cmd.get('args', []): if kwargs.get('required'): kwargs['help'] += ' [required]' subparser.add_argument(*cmdargs, **kwargs) subparser.set_defaults(func=cmd['func']) args = parser.parse_args() utils.init_log(args.log_file, args.log_level) try: args.func(args) except Exception as err: logging.exception("Command failed") print('Command failed: %s' % err) sys.exit(1)
cải xoăn