Exemple #1
0
    def _run_process(self, filename, command_name, command_args, flush_callback=None, message=None):
        ext = os.path.splitext(filename)[1]
        if ext in (".py", ".pyw", ".pyc"):
            command = self._python_runner

            # -u: sets unbuffered output
            args = [command, "-u", "-W ignore::DeprecationWarning", filename, command_name]

        else:
            command = filename
            args = [command, command_name]

        # Set timeout from command
        cmd_timeout = int(command_args.get("timeout", self.timeout))

        if command_name:
            log.info("Running %s from %s (timeout: %i)" % (command_name, filename, cmd_timeout))

        else:
            log.info("[INIT] Loading commands from %s" % filename)

        mem_clean("spawnProcess [start]")
        crp = CommandRunnerProcess(cmd_timeout, command_args, flush_callback, message)
        d = crp.getDeferredResult()
        reactor.spawnProcess(crp, command, args, env=self.env)

        del cmd_timeout, filename, command_name, command_args
        del flush_callback, message, args

        mem_clean("spawnProcess [end]")
        return d
Exemple #2
0
    def _run_process(self, filename, command_name, command_args, flush_callback=None, message=None):
        ext = os.path.splitext(filename)[1]
        if ext in ('.py', '.pyw', '.pyc'):
            command = self._python_runner

            # -u: sets unbuffered output
            args = [command, '-u', '-W ignore::DeprecationWarning', filename, command_name]

        else:
            command = filename
            args = [command, command_name]

        # Set timeout from command
        cmd_timeout = self.timeout
        if 'timeout' in command_args:
            cmd_timeout = int(command_args['timeout'])

        if command_name:
            log.info("Running %s from %s (timeout: %i)" % (command_name, filename, cmd_timeout))

        else:
            log.info("[INIT] Loading commands from %s" % filename)

        crp = CommandRunnerProcess(cmd_timeout, command_args, flush_callback, message)
        d = crp.getDeferredResult()
        reactor.spawnProcess(crp, command, args, env=self.env)

        return d
Exemple #3
0
    def _processCommand(self, message):
        log.debug('Process Command')

        if self.public_key:
            if not self._verify_message(message):
                log.critical('[RSA CHECK: Failed] Command from %s has bad signature (Ignored)' % message.from_)
                result = (_E_UNVERIFIED_COMMAND, '', 'Bad signature', 0)
                self._onCallFinished(result, message)
                return
        else:
            # No public key, RSA functions are not available on this system
            log.warn('[RSA CHECK: No available] WARNING: Running unverified Command from %s' % message.from_)

        flush_callback = self._Flush
        message.command_replaced = message.command.replace('.', '_')
        d = self.command_runner.run_command(message.command_replaced, message.command_args, flush_callback, message)

        if d:
            d.addCallbacks(self._onCallFinished, self._onCallFailed,
                           callbackKeywords={'message': message},
                           errbackKeywords={'message': message},
            )
            return d

        else:
            log.info("Command Ignored: Unknown command: %s" % message.command)
            result = (_E_RUNNING_COMMAND, '', "Unknown command: %s" % message.command, 0)
            self._onCallFinished(result, message)

        return
Exemple #4
0
    def _rsa_verify(self, text, signature, command, sender):
        def _emsa_pkcs1_v1_5_encode(M, emLen):
            # for PKCS1_V1_5 signing:
            SHA1DER = '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
            SHA1DERLEN = len(SHA1DER) + 0x14

            H = SHA.new(M).digest()
            T = SHA1DER + H
            if emLen < (SHA1DERLEN + 11):
                log.error('[RSA CHECK: Error] intended encoded message length too short (%s)' % emLen)
                return
            ps = '\xff' * (emLen - SHA1DERLEN - 3)
            if len(ps) < 8:
                log.error('[RSA CHECK: Error] ps length too short')
                return
            return '\x00\x01' + ps + '\x00' + T

        signature = base64.b64decode(signature)
        em = _emsa_pkcs1_v1_5_encode(text, len(signature))

        if em:
            signature = number.bytes_to_long(signature)
            if self.public_key.verify(em, (signature,)):
                log.info("[RSA CHECK: OK] command: %s - from: %s" % (command, sender))
                return True

        log.error("[RSA CHECK: Error] %s - from: %s" % (command, sender))
        return False
Exemple #5
0
    def _processCommand(self, message):
        if not self.verify.signature(message):
            result = (_E_UNVERIFIED_COMMAND, '', 'Bad signature', 0)
            self._onCallFinished(result, message)
            return

        flush_callback = self._flush
        message.command_name = message.command.replace('.', '_')

        mem_clean('run_command [start]')
        d = self.command_runner.run_command(message, flush_callback)
        
        # Clean message
        message.command_args = {}

        if d:
            d.addCallbacks(self._onCallFinished, self._onCallFailed,
                           callbackKeywords={'message': message},
                           errbackKeywords={'message': message},
            )
            del message
            mem_clean('run_command [end]')
            return d

        else:
            log.info("Command Ignored: Unknown command: %s" % message.command)
            result = (_E_RUNNING_COMMAND, '', "Unknown command: %s" % message.command, 0)
            self._onCallFinished(result, message)

        del message
        mem_clean('run_command [end]')
        return
Exemple #6
0
    def _run_process(self, filename, command_name, command_args, flush_callback=None, message=None):
        need_sudo = ['plugin_pip.py', 'plugin_service.py', 'plugin_update.py', 'plugin_haproxy.py', 'plugin_monitor.py', 'plugin_pip_extra.py', 'plugin_puppet.py', 'plugin_saltstack.py', 'plugin_proc.py']
        ext = os.path.splitext(filename)[1]
        if ext == '.py':
            from sys import platform
            if platform.startswith("win32") or os.path.split(filename)[1] not in need_sudo:
                command = self._python_runner
                args = [command, '-u', '-W ignore::DeprecationWarning', filename, command_name]

            else:
                command = 'sudo'
                # -u: sets unbuffered output
                args = [command, self._python_runner, '-u', '-W ignore::DeprecationWarning', filename, command_name]

        else:
            command = filename
            args = [command, command_name]

        # :TODO Set timeout from command
        cmd_timeout = int(command_args.get('timeout',self.timeout))

        if command_name:
            log.info("Running %s from %s (timeout: %i)" % (command_name, filename, cmd_timeout))

        else:
            log.info("[INIT] Loading commands from %s" % filename)

        crp = CommandRunnerProcess(cmd_timeout, command_args, flush_callback, message)
        d = crp.getDeferredResult()
        reactor.spawnProcess(crp, command, args, env=self.env)

        del cmd_timeout, filename, command_name, command_args
        del flush_callback, message, args

        return d
Exemple #7
0
    def _check_memory(self, running_commands):
        rss, vms = mem_usage()
        log.info("Running commands: %i" % running_commands)
        log.info("Current Memory usage: rss=%sMB | vms=%sMB" % (rss, vms))

        if not running_commands and rss > _CHECK_RAM_MAX_RSS_MB:
            log.critical("Max allowed RSS memory exceeded: %s MB, exiting."
                         % _CHECK_RAM_MAX_RSS_MB)
            reactor.stop()
Exemple #8
0
    def _onCallFailed(self, failure, *argv, **kwargs):
        log.error("onCallFailed")
        log.info(failure)

        if 'message' in kwargs:
            message = kwargs['message']
            result = (2, '', failure, 0)
            del self.running_commands[message.command_name]
            self.num_running_commands -= 1
            self._onCallFinished(result, message)
Exemple #9
0
def mem_usage():
    rss, vms = 0, 0
    try:
        rss, vms = psutil.Process(getpid()).get_memory_info()
        rss /= 1000000.0
        vms /= 1000000.0
    except:
        pass
    log.info("Current Memory usage: rss=%sMB | vms=%sMB" % (rss, vms))

    return rss, vms
def mem_clean(where="", dolog=False):
    _collect = collect()
    rss, vms = mem_usage()
    string = "_mem_clean: %s collected %d objects. (current mem: rss=%sMB | vms=%sMB)" % (where, _collect, rss, vms)

    if dolog:
        log.info(string)

    else:
        log.debug(string)

    del _collect, where, dolog, rss, vms, string
Exemple #11
0
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting Agent...")

        log.info("Loading Commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.info("Setting up Certificate")
        self.verify = ECVerify()

        log.info("Setting up Memory checker")

        self.running_commands = {}
        self.num_running_commands = 0
        self.timestamp = 0

        self.memory_checker = LoopingCall(self._check_memory, self.running_commands)
        self.memory_checker.start(_CHECK_RAM_INTERVAL)
        
        self.keepalive = LoopingCall(self._reconnect)

        log.debug("Loading XMPP...")
        Client.__init__(
            self,
            config['XMPP'],
            [("/iq[@type='set']", self.__onIq), ],
            resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL)
Exemple #12
0
    def check_config(self):
        uuid = self._get_stored_uuid()
        account_id = self.get_stored_account()

        if not uuid and not account_id:
            # Is not an update and no account is set
            log.error('Please configure agent with ./configure --account=XXXXX')
            raise Exception('Please configure agent with ./configure --account=XXXXX')

        unique_id = self._get_unique_id()

        if not unique_id:
            log.error('Could not obtain UNIQUE_ID. Please set up XMPP manually')
            raise Exception('Could not obtain UNIQUE_ID. Please set up XMPP manually')

        # Check all data valid for v3
        if uuid and not '@' in uuid and account_id and self.is_unique_id_same(unique_id):
            log.debug('UNIQUE ID has not changed. Skip UUID check')

        else:
            # Try to get uuid (one hour and a half loop: 360x15)
            json_data = None

            for i in range(360):
                log.info("Trying to get UUID via URL (meta-data v2)")
                json_data = yield self._get_config(unique_id)
                if json_data:
                    break

                sleep(15)

            # Decode metadata
            meta_data = self.parse_meta_data(json_data)

            if not meta_data:
                log.error('Could not obtain UUID. Please set up XMPP manually')
                raise Exception('Could not obtain UUID. Please set up XMPP manually')

            if not self['XMPP'].get('password'):
                self['XMPP']['password'] = hex(random.getrandbits(256))[2:-1]

            # Updates from v2 to v3 write account info
            if not account_id and meta_data.get('account'):
                self['XMPP']['account'] = meta_data.get('account')

            self['XMPP']['user'] = meta_data['uuid']
            self['XMPP']['unique_id'] = unique_id
            self.write()

        returnValue(True)
Exemple #13
0
    def check_uuid(self):
        mac = self._get_mac()

        # Always generate a new password if not is set
        if not self['XMPP']['password']:
            self['XMPP']['password'] = hex(random.getrandbits(128))[2:-1]

        if mac:
            if str(mac) == str(self._getStoredMAC()):
                log.debug("MAC has not changed. Skip UUID check")

            else:
                # Try to get uuid
                uuid = None
                for i in range(30):
                    try:
                        uuid = yield self._getUUID()
                        if uuid:
                            break

                    except:
                        pass
                    sleep(20)

                if not uuid:
                    log.error("ERROR: Could not obtain UUID. please set up XMPP manually in %s" % self.filename)
                    returnValue(False)

                if str(uuid) == str(self._getStoredUUID()):
                    log.debug("UUID has not changed.")

                    # Update mac
                    self['XMPP']['mac'] = mac
                    self.write()

                else:
                    log.info("UUID has changed, reconfiguring XMPP user/pass")
                    self['XMPP']['user'] = '******'.join((uuid, self['XMPP']['host']))

                    self['XMPP']['mac'] = mac
                    self.write()

            returnValue(True)

        else:
            log.error("ERROR: Could not obtain MAC. please set up XMPP manually in %s" % self.filename)
            returnValue(False)
Exemple #14
0
    def _get_unique_id():
        """
        Try to get a unique identified, Some providers may change UNIQUE_ID on stop/start
        Use a low timeout to speed up agent start when no meta-data url
        """
        log.info("Trying to get UNIQUE ID")
        unique_id = None

        try:
            # Get info from meta-data
            socket.setdefaulttimeout(URL_METADATA_TIMEOUT)

            for metadata_type in URL_METADATA_INSTANCE_ID.keys():

                try:
                    request = urllib2.Request(URL_METADATA_INSTANCE_ID[metadata_type])

                    # Google needs header
                    if metadata_type == 'gce':
                        request.add_header('Metadata-Flavor', 'Google')

                    response = urllib2.urlopen(request)
                    instance_id = response.readlines()[0]
                    response.close()

                except urllib2.URLError:
                    continue

                if instance_id:
                    unique_id = metadata_type + '::' + instance_id
                    break

        except:
            pass
        finally:
            # Set default timeout again
            socket.setdefaulttimeout(10)

        if not unique_id:
            # Use network mac address
            from uuid import getnode
            from re import findall

            unique_id = 'mac::' + ':'.join(findall('..', '%012x' % getnode()))

        return unique_id
Exemple #15
0
    def __init__(self, key_file=None):
        self.public_key = None

        if not key_file:
            key_file = CERTIFICATE_FILE

        try:
            if Crypto.version_info[:2] >= (2, 2):
                _public_key = self._read_pub_key(key_file)
                if _public_key:
                    key = PublicKey.RSA.importKey(_public_key)
                    self.public_key = key.publickey()

        except:
            pass

        if not self.public_key:
            log.info('PyCrypto not available or version is < 2.2: Please upgrade: http://www.pycrypto.org/')
Exemple #16
0
    def check_uuid(self):
        unique_id = self._get_unique_id()

        if unique_id:
            if str(unique_id) == str(self._get_stored_unique_id()):
                log.debug("UNIQUE ID has not changed. Skip UUID check")

            else:
                # Try to get uuid (one hour and a half loop: 360x15)
                uuid = None
                for i in range(360):
                    try:
                        uuid = yield self._get_uuid()
                        if uuid:
                            break

                    except Exception:
                        pass

                    sleep(15)

                if not uuid:
                    log.error("ERROR: Could not obtain UUID. please set up XMPP manually in %s" % self.filename)
                    raise Exception("Could not obtain UUID")

                if str(uuid) == str(self._get_stored_uuid()):
                    log.debug("UUID has not changed.")
                    self["XMPP"]["unique_id"] = unique_id
                    self.write()

                else:
                    log.info("UUID has changed, reconfiguring XMPP user/pass")
                    self["XMPP"]["user"] = "******".join((uuid, self["XMPP"]["host"]))
                    self["XMPP"]["unique_id"] = unique_id
                    self.write()

            returnValue(True)

        else:
            log.error("ERROR: Could not obtain UNIQUE_ID. please set up XMPP manually in %s" % self.filename)
            raise Exception("Could not obtain UUID")
Exemple #17
0
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting agent...")
        self.config = config

        log.info("Setting up certificate")
        self.public_key = None
        try:
            if Crypto.version_info[:2] >= (2, 2):
                _public_key = self._read_pub_key()
                if _public_key:
                    key = PublicKey.RSA.importKey(_public_key)
                    self.public_key = key.publickey()
        except:
            pass

        if not self.public_key:
            log.warn('PyCrypto not available or version is < 2.2: Please upgrade: http://www.pycrypto.org/')

        log.info("Loading commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.debug("Loading XMPP...")
        observers = [
            ('/iq', self.__onIq),
        ]
        Client.__init__(self,
                        self.config['XMPP'],
                        observers,
                        resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL
        )
Exemple #18
0
    def _get_uuid(self):
        if self["XMPP"].as_bool("manual"):
            log.info("Skipping UUID auto configuration as manual flag is set.")
            return self["XMPP"]["user"].split("@")[0]

        else:
            # Try to get from preconfigured
            log.info("try to get UUID via preconfiguration")
            uuid = self._get_uuid_pre_configured()

            if not uuid:
                # Try to configure via URL (ECM meta-data)
                log.info("try to get UUID via URL (ecagent meta-data)")
                uuid = self._get_uuid_via_web()

            return uuid
Exemple #19
0
    def _getUUID(self):
        if self['XMPP'].as_bool('manual'):
            log.info("Skipping UUID auto configuration as manual flag is set.")
            return self['XMPP']['user'].split('@')[0]

        else:
            # Try to get from preconfigured
            log.info("try to get UUID via preconfiguration")
            uuid = self._getUUIDPreConfig()

            if not uuid:
                # Try to configure via URL (ECM meta-data)
                log.info("try to get UUID via URL (ecagent meta-data)")
                uuid = self._getUUIDViaWeb()

            return uuid
Exemple #20
0
 def _reconnect(self):
     """ 
     Disconnect the current reactor to try to connect again
     """
     log.info("No data received in %ss: Trying to reconnect" % KEEPALIVED_TIMEOUT)
     reactor.disconnectAll()