def report_events(self): if ("acti" in self.system_type): event_logger.log_event({'event': 'internal-profit-report', 'profit-value': self.system.cur_profit, 'hostname': self.hostname}) esd_dict = dict() for vm in self.system.vms: esd_dict[vm] = [v.esd for v in self.system.vms[vm].vcpus] event_logger.log_event({'event': 'internal-esd-report', 'values': esd_dict, 'hostname': self.hostname})
def send_snmp_trap(oms_event): # Собираем SNMP трап # Для этого нужен MIB (Management Information Base) # # Есть проблема, Питон не хочет подхватывать напрямую MIB-файл из OMS, # # который лежит $OMS_HOME/network/doc/omstrap.v1. Кроме того, в дефолтном файле # # слишком много ненужной (устаревшей) информации. Поэтому мы удалили все OIDы oraEM4Alert, # # кроме тех которые необходимы для копиляции. После этого скомпилировали полученный MIB # # скриптом mibdump.py, который идет в поставке с пакетом pysmi, который ставиться pip'ом # # и положил полученный *.py файл в /usr/lib/python2.7/site-packages/pysnmp/smi/mibs с правами 644 config = get_config() hostname = config['hostname'] zabbix = config['zabbix'] # Все поля трапа OEM, которые мы будем передавать, получены из MIBа omstrap.v1 trap_parameters = config['trap_parameters'] address = socket.gethostbyname(hostname) # Собираем переменные трапа trap_variables = [(ObjectIdentity('DISMAN-EVENT-MIB', 'sysUpTimeInstance'), TimeTicks(int(time.time()))), (ObjectIdentity('SNMP-COMMUNITY-MIB', 'snmpTrapAddress', 0), address)] for trap_variable in trap_parameters: trap_variables.append( (ObjectIdentity('ORACLE-ENTERPRISE-MANAGER-4-MIB', trap_variable), oms_event[trap_variable].replace('"', "'") if trap_variable in oms_event else '')) # Посылаем трап try: logging.debug('Trying to send SNMP trap') error_indication, error_status, error_index, var_binds = next( sendNotification( SnmpEngine(), CommunityData('public', mpModel=0), UdpTransportTarget((zabbix['host'], zabbix['port'])), ContextData(), 'trap', NotificationType( ObjectIdentity( 'ORACLE-ENTERPRISE-MANAGER-4-MIB', 'oraEMNGEvent')).addVarBinds(*trap_variables))) if error_indication: logging.debug('SNMP exception') oms_event.update({'TrapState': 'exception'}) log_event(oms_event_to_log=oms_event) raise Exception(error_indication) else: logging.debug('SNMP sent') oms_event.update({'TrapState': 'send snmp'}) except Exception as e: log_event(oms_event_to_log=oms_event) raise e
def run_simulation_server(steps): """ This support function creates a simple OPC UA server with node listed in the config file :param steps: Lifecycle of the server :return: """ with open('../src_test/config_test.yaml') as config_file: cfg = yaml.safe_load(config_file) # setup the server server = Server() server.set_endpoint(cfg['opcua']['url']) # setup the namespace uri = "http://examples.freeopcua.github.io" idx = server.register_namespace(uri) # get objects node objects = server.get_objects_node() # server start server.start() log_event(cfg, 'OPCUA TEST SERVER', '', 'INFO', 'OPC UA server started') # populating the address space myobj = objects.add_object(idx, "TestDataAssembly") nodes = [] metrics = cfg['metrics'] for metric in metrics: metric_id = metric['metric_id'] meas = metric['measurement'] tag = metric['tagname'] var = metric['variable'] ns = metric['nodeNamespace'] id = metric['nodeId'] method = metric['method'] time_interval = metric['interval'] node_str = 'ns=' + str(ns) + '; i=' + str(id) nodes.append(myobj.add_variable(node_str, var, -1)) # update variable time.sleep(1) for it in range(steps): for node in nodes: node.set_value(node.get_value() + 1) time.sleep(0.5) time.sleep(2) server.stop() log_event(cfg, 'OPCUA TEST SERVER', '', 'INFO', 'OPC UA server stopped')
def log_action(event_logger, text_type, topic, doc, outcome, seconds): actions = {'s':'VIEW_SNIPPET', 'v':'VIEW_DOC', 'n':'SKIP_DOC', 'r':'DOC_REL', 'n':'DOC_NOTREL', 'u':'DOC_UNSURE'} a = 'ERR' if outcome in actions: a = actions[outcome] tt = 'SNIP' c = len(doc.snippet) l = len( doc.snippet.split(' ')) if text_type == 1: tt = 'DOC' c = len(doc.text) l = len( doc.text.split(' ')) log_event(event_logger, topic.num,tt, doc.docid, doc.relevant, c, l, a, seconds )
def remove_points(self, idx): """ This function removes a set of elements. :param idx: list of indices :return: """ # Removing duplicates idx = list(dict.fromkeys(idx)) # Loop within sorted and reversed list for i in sorted(idx, reverse=True): self.remove_point(i) log_event( self.cfg, self.module_name, '', 'INFO', str(len(idx)) + ' points removed from buffer (size=' + str(self.len()) + ')')
def remove_point(self, idx=0): """ This function removes specified element of the buffer. If not specified, removes the very first element. :param idx: Index of the element to remove :return: """ # Removing operation is only valid if valid index is provided if (idx < 0) or (idx > len(self.buffer) - 1): log_event(self.cfg, self.module_name, '', 'WARN', str(idx) + ' element does not exist in buffer') return del self.buffer[idx] log_event( self.cfg, self.module_name, '', 'INFO', 'Point ' + str(idx) + ' removed from buffer (size=' + str(self.len()) + ')')
def add_point(self, buffer_entity): """ This function puts additional entity into buffer :param buffer_entity: buffer entity consisted of node instance and opcua variant :return: """ # If after adding a point, the buffer will be overfilled, we will remove the first entity in the buffer if len(self.buffer) + 1 > self.max_buffer_size: self.remove_point(0) log_event(self.cfg, self.module_name, '', 'WARN', 'Buffer is full (' + str(len(self.buffer)) + ')') # Append entity self.buffer.append(buffer_entity) log_event(self.cfg, self.module_name, '', 'INFO', 'Point copied into buffer (size=' + str(self.len()) + ')')
def test_reconnection_new_server_one_retry(my_config): my_config['opcua']['number_of_reconnections'] = 1 server_thread = threading.Thread(target=run_simulation_server, args=[20]) server_thread.start() my_buffer = Buffer(my_config) ua_listener = OPCUAListener(my_config, my_buffer) time.sleep(3) ua_listener.connect() time.sleep(40) server_thread.join() buffer_len_after_first_stop = my_buffer.len() log_event(my_config, 'TEST', '', 'INFO', 'Buffer length = ' + str(my_buffer.len())) server_thread = threading.Thread(target=run_simulation_server, args=[20]) server_thread.start() time.sleep(20) ua_listener.exit() time.sleep(15) log_event(my_config, 'TEST', '', 'INFO', 'Buffer length = ' + str(my_buffer.len())) server_thread.join() assert my_buffer.len() == buffer_len_after_first_stop
def log_action(event_logger, text_type, topic, doc, outcome, seconds): actions = { 's': 'VIEW_SNIPPET', 'v': 'VIEW_DOC', 'n': 'SKIP_DOC', 'r': 'DOC_REL', 'n': 'DOC_NOTREL', 'u': 'DOC_UNSURE' } a = 'ERR' if outcome in actions: a = actions[outcome] tt = 'SNIP' c = len(doc.snippet) l = len(doc.snippet.split(' ')) if text_type == 1: tt = 'DOC' c = len(doc.text) l = len(doc.text.split(' ')) log_event(event_logger, topic.num, tt, doc.docid, doc.relevant, c, l, a, seconds)
def host_passes(self, host_state, spec_obj): hostname = host_state.host vm_uuid = spec_obj.instance_uuid flavor_id = spec_obj.flavor.flavorid nr_gold_vms = self.acticlouddb_client.get_nr_gold_vms_by_hostname( hostname) nr_gold_vcpus = self.acticlouddb_client.get_nr_gold_vcpus_by_hostname( hostname) nr_silver_vcpus = self.acticlouddb_client.get_nr_silver_vcpus_by_hostname( hostname) is_gold_vm = flavor_id in ["1001", "1002", "1004", "1008"] nr_vcpus_host = host_state.vcpus_total nr_vcpus_instance = spec_obj.vcpus LOG.info( "============= ActicloudProfitFilter %s ==========================>", hostname) ## If the new VM does not fit return False if not super(ActicloudProfitFilter, self).host_passes( host_state, spec_obj): LOG.info( "=======================================================>") return False ## If host was empty we don't need to check its profit nr_silver_vcpus_ovs = int( math.ceil(float(nr_silver_vcpus) / ACTICLOUD_OVERSUBSCRIPTION)) free_vcpus = nr_vcpus_host - (nr_gold_vcpus + nr_silver_vcpus_ovs) if free_vcpus == nr_vcpus_host: LOG.info("Host %s is empty, so it passes the filter", hostname) LOG.info( "=======================================================>") return True ''' VM fits in the node, now let's check if it will give profit ''' vms = list(self.acticlouddb_client.get_vms_by_hostname(hostname)) ## Calculate current host_profit host_profit_before = calculate_host_profit(vms, nr_vcpus_host) new_vm_uuid = vm_uuid new_vm = self.nova.servers.get(new_vm_uuid) new_vm_vcpus = int(self.nova.flavors.get(new_vm.flavor['id']).vcpus) new_vm_is_gold = int(new_vm.metadata.get('is_gold')) or 0 new_vm_is_noisy = int(new_vm.metadata.get('is_noisy')) or 0 new_vm_is_sensitive = int(new_vm.metadata.get('is_sensitive')) or 0 vms.append({ 'id': new_vm_uuid, 'hostname': hostname, 'nr_vcpus': new_vm_vcpus, 'is_gold': new_vm_is_gold, 'is_noisy': new_vm_is_noisy, 'is_sensitive': new_vm_is_sensitive }) ## Calculate host_profit with new VM host_profit_after = calculate_host_profit(vms, nr_vcpus_host) host_profit_diff = host_profit_after - host_profit_before LOG.info("New profit: %.2f Previous profit: %.2f Difference: %.2f", host_profit_after, host_profit_before, host_profit_diff) LOG.info("=======================================================>") time_now = datetime.datetime.utcnow().strftime("%Y-%m-%d.%X") acticloud_event_logger.log_event({ 'event': 'acticloud-external-openstack-filter-profit-report', 'profit-before': host_profit_before, 'profit-after': host_profit_after, 'profit-diff': host_profit_diff, 'hostname': hostname, 'time': time_now, 'new-vm-uuid': new_vm_uuid }) if host_profit_diff <= 0: return False else: return True
def send_trap(environment): # Выставляем признак неотправки трапа do_not_send_trap = False # Загружаем конфиг # в конфиге должны быть 4 секции: # 1. trap_to_environment_variables - маппинг переменных трапа в переменные окружения # 2. trap_parameters - параметры трапа, которые будут отправлены # 3. hostname - имя хоста ОЕМ # 4. zabbix - параметры хоста самого Заббикса или одного из его прокси, # к которому подключены все(!) хосты, которые мониторятся в ОЕМ with open( os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, 'config', 'snmp.json'), 'r') as json_file: config = json.load(json_file) # Маппинг переменных окружения в переменные трапа в соответствии с MIBом # # Переменные перечислены в соответсвии с главой # # "3.10.2 Passing Event, Incident, Problem Information to an OS Command or Script" # # документа Oracle® Enterprise Manager Cloud Control Administrator's Guide # # Если зачению переменной трапа может соответствовать несколько переменных окружения # # в зависимости от события, которое обрабатывается, такие переменные представлены # # в виде словаря, в которых ключ соответствует переменной ISSUE_TYPE - тип события, # # значение - переменной, которую нужно подставить trap_to_environment_variables = config['trap_to_environment_variables'] # Все поля трапа OEM, которые мы будем передавать, получены из MIBа omstrap.v1 trap_parameters = config['trap_parameters'] hostname = config['hostname'] zabbix = config['zabbix'] # На вход получаем параметры окружения в виде словаря, которые создает OMS при вызове скрипта # Собираем только те параметры, которые укладываются в стандартный MIB omstrap.v1 Oracle OEM 13c # Кроме того, сохраняем в oms_event['oraEMNGEnvironment'] все переменные окружения, мало ли что-то упустили oms_event = { 'oraEMNGEnvironment': environment, 'oraEMNGEventSequenceId': 'null' } for trap_variable, os_variable in trap_to_environment_variables.iteritems( ): if type(os_variable) is unicode: oms_event.update({ trap_variable: environment[os_variable] if os_variable in environment else '' }) elif type(os_variable) is dict: issue_type = environment['ISSUE_TYPE'] oms_event.update({ trap_variable: environment[os_variable[issue_type]] if (issue_type in os_variable and os_variable[issue_type] in environment) else '' }) # Нужно подправить некоторые элементы # Во-первых, подрезаем длину сообщения и URL события до 255 символов, чтобы влезало в трап oms_event.update({ 'oraEMNGEventMessage': oms_event['oraEMNGEventMessage'][:255], 'oraEMNGEventMessageURL': oms_event['oraEMNGEventMessageURL'][:255], 'oraEMNGEventContextAttrs': oms_event['oraEMNGEventContextAttrs'][:255], 'oraEMNGEventTargetName': oms_event['oraEMNGEventTargetName'].replace( '.severstal.severstalgroup.com', '') }) # Во-вторых, для инцидентов и проблем не передается в переменную SequenceID # Будем брать его из SequenceID породившего события if oms_event['oraEMNGIssueType'] in ('2', '3'): logging.debug('Message is incident or problem') oms_event.update({ 'oraEMNGEventIssueId': re.search('&issueID=([ABCDEF|0-9]{32})$', environment['MESSAGE_URL']).group(1) }) emcli = Emcli() event_id = emcli.get_event_id(oms_event['oraEMNGEventIssueId']) if event_id is not None and len(event_id) != 0: logging.debug('Got event ID from OEM %s' % ', '.join(event_id)) oms_event.update({'oraEMNGEventSequenceId': event_id[0]}) else: logging.debug('Event ID not found in OEM') oms_event.update( {'oraEMNGEventSequenceId': oms_event['oraEMNGEventIssueId']}) # В-третьих, нужно проверить, есть ли событие с таким же уровнем severity # и отправлялось ли по нему сообщение # Если есть, трап по инциденту или проблеме отправлять не нужно message_sent = emcli.check_message_sent( oms_event['oraEMNGEventIssueId'], oms_event['oraEMNGEventSeverity']) # Подождем 2 секунды, возможно сообщение по событию запаздывает if not message_sent: logging.debug('Message from OEM not sent') time.sleep(2) message_sent = emcli.check_message_sent( oms_event['oraEMNGEventIssueId'], oms_event['oraEMNGEventSeverity']) if message_sent: logging.debug('Message from OEM sent, skipping') do_not_send_trap = True # Если пришел Acknowledged, трап посылаем с ID породившего события if oms_event['oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug('... But it is an Acknowledge message, sending') do_not_send_trap = False # Если пришла закрывашка, а само событие закрылось без отправки сообщения, # нужно отправить трап, подменив SequenceID на аналогичный параметр события if oms_event['oraEMNGEventSeverity'] == 'Clear': logging.debug('Clear message came') do_not_send_trap = False # Проверяем, если пришла закрывашка, а открывающего события в Заббиксе нет, отправлять не будем try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': request = get_event_by_id(oms_event['oraEMNGEventSequenceId']) if request is None or len(request) == 0: do_not_send_trap = True else: logging.debug('Opening message exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, если пришла закрывашка, будем закрывать через API, не будем отправлять try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug( 'Trying to acknowledge event to close it by API method') result = acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) if result is not None and len(result) != 0: if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'closed by api'}) do_not_send_trap = True else: do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, нет ли случайно в Заббиксе события с таким же текстом # отображаемого на экране # Если есть - отсылать его не нужно try: if check_if_message_exists( '%s %s %s: %s Acknowledge=%s' % (oms_event['oraEMNGEventSequenceId'], oms_event['oraEMNGEventSeverity'], oms_event['oraEMNGEventTargetName'], oms_event['oraEMNGEventMessage'], oms_event['oraEMNGAssocIncidentAcked'])) and not ( oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event['oraEMNGAssocIncidentAcked'] == 'Yes'): logging.debug('Message exists in Zabbix, skipping') do_not_send_trap = True else: logging.debug('Message do not exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Если не стоит признак не посылать трап, if not do_not_send_trap: # Проверяем, нужно ли фильтровать трап # Если да - отсылать не будем if not filter_trap(message=environment['MESSAGE'] if 'MESSAGE' in environment else None, event_name=environment['EVENT_NAME'] if 'EVENT_NAME' in environment else None): logging.debug('Message not filtered') # Для начала закроем событие в заббиксе с таким же ИД # если таковой имеется # но не трогаем закрывашки try: if not oms_event[ 'oraEMNGEventSeverity'] == 'Clear' and not oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug('Trying to acknowledge event in Zabbix') acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Собираем SNMP трап # Для этого нужен MIB (Management Information Base) # # Есть проблема, Питон не хочет подхватывать напрямую MIB-файл из OMS, # # который лежит $OMS_HOME/network/doc/omstrap.v1. Кроме того, в дефолтном файле # # слишком много ненужной (устаревшей) информации. Поэтому мы удалили все OIDы oraEM4Alert, # # кроме тех которые необходимы для копиляции. После этого скомпилировали полученный MIB # # скриптом mibdump.py, который идет в поставке с пакетом pysmi, который ставиться pip'ом # # и положил полученный *.py файл в /usr/lib/python2.7/site-packages/pysnmp/smi/mibs с правами 644 address = socket.gethostbyname(hostname) # Собираем переменные трапа trap_variables = [(ObjectIdentity('DISMAN-EVENT-MIB', 'sysUpTimeInstance'), TimeTicks(int(time.time()))), (ObjectIdentity('SNMP-COMMUNITY-MIB', 'snmpTrapAddress', 0), address)] for trap_variable in trap_parameters: trap_variables.append( (ObjectIdentity('ORACLE-ENTERPRISE-MANAGER-4-MIB', trap_variable), oms_event[trap_variable].replace('"', "'") if trap_variable in oms_event else '')) # Посылаем трап try: logging.debug('Trying to send SNMP trap') error_indication, error_status, error_index, var_binds = next( sendNotification( SnmpEngine(), CommunityData('public', mpModel=0), UdpTransportTarget((zabbix['host'], zabbix['port'])), ContextData(), 'trap', NotificationType( ObjectIdentity( 'ORACLE-ENTERPRISE-MANAGER-4-MIB', 'oraEMNGEvent')).addVarBinds(*trap_variables))) if error_indication: logging.debug('SNMP exception') oms_event.update({'TrapState': 'exception'}) log_event(oms_event_to_log=oms_event) raise Exception(error_indication) else: logging.debug('SNMP sent') oms_event.update({'TrapState': 'send snmp'}) except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Собираем Zabbix трап # Чтобы не было одновременной отправки нескольких сообщений # Добавляем функционал файла блокировок таким образом, чтобы # все наши процессы по отправке заббикс трапов шли по очереди # Нужно запомнить ИД процесса pid = os.getpid() # Разбираемся с лок-файлом # Лок-файл лежит в папке .secure lock_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), os.pardir, '.secure', '.lock') if os.path.isfile(lock_file): # Если такой файл есть, дописываем в него ИД процесса with open(lock_file, 'a+') as lock: lock.write(str(pid) + '\n') else: # Если нет - создаем и записываем with open(lock_file, 'w+') as lock: lock.write(str(pid) + '\n') logging.info('Sent PID %d to lock file' % pid) # Собираем переменные трапа trap_variables = dict() for trap_variable in trap_parameters: if trap_variable in oms_event: trap_variables.update({ trap_variable.encode('ascii'): oms_event[trap_variable].encode('ascii') }) # Формируем метрику try: # В качестве метрики берем тот же набор параметров, # что и для SNMP трапа, но сваливаем его в json # и в таком виде отправляем в Заббикс m = ZabbixMetric( oms_event['oraEMNGEventHostName'], 'data', json.dumps(trap_variables, indent=3, sort_keys=True)) zbx = ZabbixSender(zabbix['host']) # Проверяем, что наша очередь работать # Для этого ИД нашего процесса должен стоять первым в списке processes = list() counter = 0 with open(lock_file, 'r') as lock: for line in lock: if line.replace( '\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append(line.replace('\n', '').strip()) # Если не первый - ждем своей очереди if processes[0] != str(pid): logging.info( 'First PID is %s. It\'s not equal ours, sleeping' % processes[0]) logging.info('Process queue is [%s]. ' % ', '.join(processes)) while processes[0] != str(pid) and counter < 5: # Ждем 1 секунду # Потому, что Заббикс не может разделить два пришедших события # если у них совпадает метка времени # А метка времени у него берется с точностью до секунды time.sleep(1) # Но не более 5 раз counter += 1 processes = list() with open(lock_file, 'r') as lock: for line in lock: if line.replace( '\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append( line.replace('\n', '').strip()) logging.info('Process queue is [%s]. ' % ', '.join(processes)) # Наша очередь, поехали if counter == 5: logging.info('Enough waiting, running') else: logging.info('First PID is ours, running') # Отправляем response = zbx.send([m]) # Проверяем ответ # Наша отправка не должна зафейлиться, но должна быть обработана if response is not None: if response.failed == 1: oms_event.update({ 'TrapState': oms_event['TrapState'] + ', exception zabbix' }) elif response.processed == 1: oms_event.update({ 'TrapState': oms_event['TrapState'] + ', send zabbix' }) except Exception as e: log_event(oms_event_to_log=oms_event) raise e finally: # В конце концов, поработал - прибери за собой # Удаляем из лок-файла свой ИД # По логике, он должен быть первым в файле, но чем черт не шутит # Поэтому считываем весь файл, а потом перезаписываем его всем его содержимым кроме строки с нашим ИД processes = list() with open(lock_file, 'r') as lock: for line in lock: if line.replace( '\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append(line.replace('\n', '').strip()) with open(lock_file, 'w') as lock: for line in processes: if line != str(pid): lock.write(line + '\n') processes.remove(str(pid)) logging.info('Final process queue is [%s]. ' % ', '.join(processes)) if os.path.getsize(lock_file) == 0: os.remove(lock_file) else: logging.debug('Event filtered') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'filtered'}) else: logging.debug('Event skipped') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'skipped'}) log_event(oms_event_to_log=oms_event) # Возвращаем полученный SequenceID return '%s: %s' % (oms_event['oraEMNGEventSequenceId'], oms_event['TrapState'])
def spawn_vm(seq_num, vm_chars, wait_until_finished): ''' Spawns a VM and returns 0 if an error has occured ''' vcpus = vm_chars['nr_vcpus'] is_gold = vm_chars['is_gold'] is_noisy = vm_chars['is_noisy'] is_sensitive = vm_chars['is_sensitive'] bench = vm_chars['bench'] runtime = vm_chars['runtime'] run_mode = bench['run_mode'] gold_str = "gold" if is_gold else "silver" flavor_name = "acticloud." + str(vcpus) + "core." + gold_str flavor = ost_client.get_flavor_by_name(flavor_name) bench_name = bench_get_name(bench) times_to_run = 0 if run_mode == "fixed_time": run_mode += "-" + str(runtime) elif run_mode == "to_completion": runtime_isolation = bench['runtime_isolation'] times_to_run = (runtime * 60.0) / runtime_isolation bench_name += "-%d_times" % times_to_run vm_name = "acticloud-" + gold_str + "-" + bench_name + "-" + run_mode image = get_image_by_bench(bench) udata = get_vm_userdata(seq_num, vcpus, bench, runtime, times_to_run) metadata = { 'seq_num': str(seq_num), 'is_gold': str(is_gold), 'is_noisy': str(is_noisy), 'is_sensitive': str(is_sensitive) } start_time = time.time() new_vm = ost_client.nova.servers.create(vm_name, image, flavor, userdata=udata, key_name="rootkey", meta=metadata) # key_name="rootkey", meta=metadata, # availability_zone="nova:acticloud1") ## Wait for the VM to leave the status "BUILD" while True: new_vm_uuid = new_vm.id new_vm = ost_client.get_vm(new_vm_uuid) while new_vm.status == "BUILD": new_vm = ost_client.get_vm(new_vm_uuid) ## Sleep for a small duration, to avoid too many openstack requests time.sleep(5) break if new_vm.status == "ERROR": logger.info("VM %s failed to spawn with status %s", vm_name, new_vm.status) return 0 end_time = time.time() event_logger.log_event({ 'vm_seq_num': seq_num, 'event': 'spawn', 'host': getattr(new_vm, 'OS-EXT-SRV-ATTR:host'), 'vcpus': vcpus }) # logger.info('EVENT: {"vm_seq_num": %d, "event": "spawn" , "time": "%s", "host": "%s", "vcpus": %d}', # seq_num, time_now, # getattr(new_vm, 'OS-EXT-SRV-ATTR:host'), vcpus) time_now = datetime.datetime.utcnow().strftime("%Y-%m-%d.%X") logger.info( "Spawned new VM with seq_num: %d and name: %s at: %s (in %4.2f seconds) on host %s", seq_num, vm_name, time_now, end_time - start_time, getattr(new_vm, 'OS-EXT-SRV-ATTR:host')) ## If necessary wait for the VM to finish its execution if wait_until_finished: logger.info("Waiting for VM %d to finish its execution", seq_num) new_vm = ost_client.get_vm(new_vm_uuid) while not new_vm.status in ["SHUTOFF", "ERROR"]: time.sleep(1 * 60) new_vm = ost_client.get_vm(new_vm_uuid) if new_vm.status == "ERROR": return 0 return 1
def send_trap_for_oem13(environment): # Выставляем признак неотправки трапа do_not_send_trap = False reason = 'trap not skipped' config = get_config() # Маппинг переменных окружения в переменные трапа в соответствии с MIBом # # Переменные перечислены в соответсвии с главой # # "3.10.2 Passing Event, Incident, Problem Information to an OS Command or Script" # # документа Oracle® Enterprise Manager Cloud Control Administrator's Guide # # Если зачению переменной трапа может соответствовать несколько переменных окружения # # в зависимости от события, которое обрабатывается, такие переменные представлены # # в виде словаря, в которых ключ соответствует переменной ISSUE_TYPE - тип события, # # значение - переменной, которую нужно подставить trap_to_environment_variables = config['13'][ 'trap_to_environment_variables'] # На вход получаем параметры окружения в виде словаря, которые создает OMS при вызове скрипта # Собираем только те параметры, которые укладываются в стандартный MIB omstrap.v1 Oracle OEM 13c # Кроме того, сохраняем в oms_event['oraEMNGEnvironment'] все переменные окружения, мало ли что-то упустили oms_event = { 'oraEMNGEnvironment': environment, 'oraEMNGEventSequenceId': 'null' } for trap_variable, os_variable in trap_to_environment_variables.iteritems( ): if type(os_variable) is unicode: oms_event.update({ trap_variable: environment[os_variable].encode('utf-8') if os_variable in environment else '' }) elif type(os_variable) is dict: issue_type = environment['ISSUE_TYPE'] oms_event.update({ trap_variable: environment[os_variable[issue_type]].encode('utf-8') if (issue_type in os_variable and os_variable[issue_type] in environment) else '' }) # Нужно подправить некоторые элементы # Во-первых: # подрезаем длину сообщения и URL события до 255 символов, чтобы влезало в трап # по просьбе дежурных, удаляем хвост .severstal.severstalgroup.com из имени цели oms_event.update({ 'oraEMNGEventMessage': oms_event['oraEMNGEventMessage'][:255], 'oraEMNGEventMessageURL': oms_event['oraEMNGEventMessageURL'][:255], 'oraEMNGEventContextAttrs': oms_event['oraEMNGEventContextAttrs'][:255], 'oraEMNGEventTargetName': oms_event['oraEMNGEventTargetName'].replace( '.severstal.severstalgroup.com', '') }) # Во-вторых, для инцидентов и проблем не передается в переменную SequenceID # Будем брать его из SequenceID породившего события if oms_event['oraEMNGIssueType'] in ('2', '3'): logging.debug('Message is incident or problem') oms_event.update({ 'oraEMNGEventIssueId': re.search('&issueID=([ABCDEF|0-9]{32})$', environment['MESSAGE_URL']).group(1) }) emcli = Emcli() event_id = emcli.get_event_id(oms_event['oraEMNGEventIssueId']) if event_id is not None and len(event_id) != 0: logging.debug('Got event ID from OEM %s' % ', '.join(event_id)) oms_event.update({'oraEMNGEventSequenceId': event_id[0]}) else: logging.debug('Event ID not found in OEM') oms_event.update( {'oraEMNGEventSequenceId': oms_event['oraEMNGEventIssueId']}) # В-третьих, нужно проверить, есть ли событие с таким же уровнем severity # и отправлялось ли по нему сообщение # Если есть, трап по инциденту или проблеме отправлять не нужно message_sent = emcli.check_message_sent( oms_event['oraEMNGEventIssueId'], oms_event['oraEMNGEventSeverity']) # Подождем 2 секунды, возможно сообщение по событию запаздывает if not message_sent: logging.debug('Message from OEM not sent') time.sleep(2) message_sent = emcli.check_message_sent( oms_event['oraEMNGEventIssueId'], oms_event['oraEMNGEventSeverity']) if message_sent: logging.debug('Message from OEM sent, skipping') do_not_send_trap = True reason = 'Message from OEM sent, skipping' # Если пришел Acknowledged, трап посылаем с ID породившего события if oms_event['oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug('... But it is an Acknowledge message, sending') do_not_send_trap = False # Если пришла закрывашка, а само событие закрылось без отправки сообщения, # нужно отправить трап, подменив SequenceID на аналогичный параметр события if oms_event['oraEMNGEventSeverity'] == 'Clear': logging.debug('Clear message came') do_not_send_trap = False # Проверяем, если пришла закрывашка, а открывающего события в Заббиксе нет, отправлять не будем try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': request = get_event_by_id(oms_event['oraEMNGEventSequenceId']) if request is None or len(request) == 0: do_not_send_trap = True reason = 'Clear\\acknowledge message came, Open message doesn\'t exists' else: logging.debug('Opening message exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, если пришла закрывашка, будем закрывать через API, не будем отправлять try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug( 'Trying to acknowledge event to close it by API method') result = acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) if result is not None and len(result) != 0: if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'closed by api'}) do_not_send_trap = True reason = 'closed by API' else: do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, нет ли случайно в Заббиксе события с таким же текстом # отображаемого на экране # Если есть - отсылать его не нужно try: message = '%s: %s' % (oms_event['oraEMNGEventTargetName'], oms_event['oraEMNGEventMessage']) if check_if_message_exists(message) and not ( oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event['oraEMNGAssocIncidentAcked'] == 'Yes'): logging.debug('Message exists in Zabbix, skipping') do_not_send_trap = True reason = 'Repeated message' else: logging.debug('Message do not exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Если не стоит признак не посылать трап, if not do_not_send_trap: # Проверяем, нужно ли фильтровать трап # Если да - отсылать не будем if not filter_trap(message=oms_event['oraEMNGEventMessage'] if 'oraEMNGEventMessage' in oms_event else None, event_name=oms_event['oraEMNGEventName'] if 'oraEMNGEventName' in oms_event else None): logging.debug('Message not filtered') # Для начала закроем событие в заббиксе с таким же ИД # если таковой имеется # но не трогаем закрывашки try: if not oms_event[ 'oraEMNGEventSeverity'] == 'Clear' and not oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug('Trying to acknowledge event in Zabbix') acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Отправляем SNMPv1 трап send_snmp_trap(oms_event) # Отправляем Zabbix трап # В дальнейшем от одного из этих методов можно будет отказаться # Пока делаем так send_zabbix_trap(oms_event) else: logging.debug('Event filtered') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'filtered'}) else: logging.debug('Event skipped') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'skipped, reason: %s' % reason}) log_event(oms_event_to_log=oms_event) # Возвращаем полученный SequenceID return '%s: %s' % (oms_event['oraEMNGEventSequenceId'], oms_event['TrapState'])
def send_trap_for_oem11(environment): # Выставляем признак неотправки трапа do_not_send_trap = False reason = 'trap not skipped' config = get_config() # Маппинг переменных окружения в переменные трапа в соответствии с MIBом # # Переменные перечислены в соответсвии с главой # # "3.10.2 Passing Event, Incident, Problem Information to an OS Command or Script" # # документа Oracle® Enterprise Manager Cloud Control Administrator's Guide # # Если зачению переменной трапа может соответствовать несколько переменных окружения # # в зависимости от события, которое обрабатывается, такие переменные представлены # # в виде словаря, в которых ключ соответствует переменной ISSUE_TYPE - тип события, # # значение - переменной, которую нужно подставить trap_to_environment_variables = config['11'][ 'trap_to_environment_variables'] # На вход получаем параметры окружения в виде словаря, которые создает OMS при вызове скрипта # Собираем только те параметры, которые укладываются в стандартный MIB omstrap.v1 Oracle OEM 13c # Кроме того, сохраняем в oms_event['oraEMNGEnvironment'] все переменные окружения, мало ли что-то упустили oms_event = { 'oraEMNGEnvironment': environment, 'oraEMNGEventSequenceId': 'null' } for trap_variable, os_variable in trap_to_environment_variables.iteritems( ): oms_event.update({ trap_variable: environment[os_variable].encode('utf-8') if os_variable in environment else '' }) # Нужно подправить некоторые элементы # Во-первых: # подрезаем длину сообщения и URL события до 255 символов, чтобы влезало в трап # по просьбе дежурных, удаляем хвост .severstal.severstalgroup.com из имени цели # заменяем значение oraEMNGAssocIncidentAcked на Yes/No, как в варианте для 13с вместо 1/0 oms_event.update({ 'oraEMNGEventMessage': oms_event['oraEMNGEventMessage'][:255], 'oraEMNGEventTargetName': oms_event['oraEMNGEventTargetName'].replace( '.severstal.severstalgroup.com', ''), 'oraEMNGAssocIncidentAcked': 'No' if oms_event['oraEMNGAssocIncidentAcked'] == '0' else 'Yes' }) # Проверяем, если пришла закрывашка, а открывающего события в Заббиксе нет, отправлять не будем try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': request = get_event_by_id(oms_event['oraEMNGEventSequenceId']) if request is None or len(request) == 0: do_not_send_trap = True reason = 'Clear\\acknowledge message came, Open message doesn\'t exists' else: logging.debug('Opening message exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, если пришла закрывашка, будем закрывать через API, не будем отправлять try: if oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug( 'Trying to acknowledge event to close it by API method') result = acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) if result is not None and len(result) != 0: if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'closed by api'}) do_not_send_trap = True reason = 'closed by API' else: do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Проверяем, нет ли случайно в Заббиксе события с таким же текстом # отображаемого на экране # Если есть - отсылать его не нужно try: message = '%s: %s' % (oms_event['oraEMNGEventTargetName'], oms_event['oraEMNGEventMessage']) if check_if_message_exists(message) and not ( oms_event['oraEMNGEventSeverity'] == 'Clear' or oms_event['oraEMNGAssocIncidentAcked'] == 'Yes'): logging.debug('Message exists in Zabbix, skipping') do_not_send_trap = True reason = 'Repeated message' else: logging.debug('Message do not exists in Zabbix') do_not_send_trap = do_not_send_trap except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Если не стоит признак не посылать трап, if not do_not_send_trap: # Проверяем, нужно ли фильтровать трап # Если да - отсылать не будем if not filter_trap(message=oms_event['oraEMNGEventMessage'] if 'oraEMNGEventMessage' in oms_event else None, event_name=oms_event['oraEMNGEventName'] if 'oraEMNGEventName' in oms_event else None): logging.debug('Message not filtered') # Для начала закроем событие в заббиксе с таким же ИД # если таковой имеется # но не трогаем закрывашки try: if not oms_event[ 'oraEMNGEventSeverity'] == 'Clear' and not oms_event[ 'oraEMNGAssocIncidentAcked'] == 'Yes': logging.debug('Trying to acknowledge event in Zabbix') acknowledge_event_by_id( oms_event['oraEMNGEventSequenceId']) except Exception as e: log_event(oms_event_to_log=oms_event) raise e # Отправляем SNMPv1 трап send_snmp_trap(oms_event) # Отправляем Zabbix трап # В дальнейшем от одного из этих методов можно будет отказаться # Пока делаем так send_zabbix_trap(oms_event) else: logging.debug('Event filtered') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'filtered'}) else: logging.debug('Event skipped') if 'TrapState' not in oms_event: oms_event.update({'TrapState': 'skipped, reason: %s' % reason}) log_event(oms_event_to_log=oms_event) # Возвращаем полученный SequenceID return '%s: %s' % (oms_event['oraEMNGEventSequenceId'], oms_event['TrapState'])
def send_zabbix_trap(oms_event): config = get_config() zabbix = config['zabbix'] # Все поля трапа OEM, которые мы будем передавать, получены из MIBа omstrap.v1 trap_parameters = config['trap_parameters'] # Собираем Zabbix трап # Чтобы не было одновременной отправки нескольких сообщений # Добавляем функционал файла блокировок таким образом, чтобы # все наши процессы по отправке заббикс трапов шли по очереди # Нужно запомнить ИД процесса pid = os.getpid() # Разбираемся с лок-файлом # Лок-файл лежит в папке .secure lock_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, '.secure', '.lock') if os.path.isfile(lock_file): # Если такой файл есть, дописываем в него ИД процесса with open(lock_file, 'a+') as lock: lock.write(str(pid) + '\n') else: # Если нет - создаем и записываем with open(lock_file, 'w+') as lock: lock.write(str(pid) + '\n') logging.info('Sent PID %d to lock file' % pid) # Собираем переменные трапа trap_variables = dict() for trap_variable in trap_parameters: if trap_variable in oms_event: trap_variables.update({trap_variable: oms_event[trap_variable]}) # Формируем метрику try: # В качестве метрики берем тот же набор параметров, # что и для SNMP трапа, но сваливаем его в json # и в таком виде отправляем в Заббикс m = ZabbixMetric(oms_event['oraEMNGEventHostName'], 'data', json.dumps(trap_variables, indent=3, sort_keys=True)) zbx = ZabbixSender(zabbix['host']) # Проверяем, что наша очередь работать # Для этого ИД нашего процесса должен стоять первым в списке processes = list() counter = 0 with open(lock_file, 'r') as lock: for line in lock: if line.replace('\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append(line.replace('\n', '').strip()) # Если не первый - ждем своей очереди if processes[0] != str(pid): logging.info('First PID is %s. It\'s not equal ours, sleeping' % processes[0]) logging.info('Process queue is [%s]. ' % ', '.join(processes)) while processes[0] != str(pid) and counter < 5: # Ждем 1 секунду # Потому, что Заббикс не может разделить два пришедших события # если у них совпадает метка времени # А метка времени у него берется с точностью до секунды time.sleep(1) # Но не более 5 раз counter += 1 processes = list() with open(lock_file, 'r') as lock: for line in lock: if line.replace('\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append(line.replace('\n', '').strip()) logging.info('Process queue is [%s]. ' % ', '.join(processes)) # Наша очередь, поехали if counter == 5: logging.info('Enough waiting, running') else: logging.info('First PID is ours, running') # Отправляем response = zbx.send([m]) # Проверяем ответ # Наша отправка не должна зафейлиться, но должна быть обработана if response is not None: if response.failed == 1: oms_event.update({ 'TrapState': oms_event['TrapState'] + ', exception zabbix' }) elif response.processed == 1: oms_event.update( {'TrapState': oms_event['TrapState'] + ', send zabbix'}) except Exception as e: log_event(oms_event_to_log=oms_event) raise e finally: # В конце концов, поработал - прибери за собой # Удаляем из лок-файла свой ИД # По логике, он должен быть первым в файле, но чем черт не шутит # Поэтому считываем весь файл, а потом перезаписываем его всем его содержимым кроме строки с нашим ИД processes = list() with open(lock_file, 'r') as lock: for line in lock: if line.replace('\n', '').strip() != '' and psutil.pid_exists( int(line.replace('\n', '').strip())): processes.append(line.replace('\n', '').strip()) with open(lock_file, 'w') as lock: for line in processes: if line != str(pid): lock.write(line + '\n') processes.remove(str(pid)) logging.info('Final process queue is [%s]. ' % ', '.join(processes)) if os.path.getsize(lock_file) == 0: os.remove(lock_file)