def _source(self, node): attrs = InfoGraphNode.get_attributes(node) if InfoGraphNode.get_layer(node) == GRAPH_LAYER.PHYSICAL: if 'allocation' in attrs: return attrs['allocation'] # fix due to the landscape else: while attrs.get('attributes', None): attrs = attrs['attributes'] if 'allocation' in attrs: return attrs['allocation'] if InfoGraphNode.get_type(node) == NODE_TYPE.VIRTUAL_MACHINE: if 'vm_name' in attrs: return attrs['vm_name'] if InfoGraphNode.get_type(node) == NODE_TYPE.INSTANCE_DISK: # The machine is the source as this is a libvirt disk. disk_name = InfoGraphNode.get_name(node) vm = self.landscape.get_neighbour_by_type( disk_name, NODE_TYPE.VIRTUAL_MACHINE) machine = self.landscape.get_neighbour_by_type( vm, NODE_TYPE.PHYSICAL_MACHINE) return machine if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: if 'name' in attrs: return attrs['name'] if InfoGraphNode.get_type(node) == NODE_TYPE.DOCKER_CONTAINER: docker_node = self.landscape.get_neighbour_by_type( InfoGraphNode.get_name(node), 'docker_node') if docker_node: machine = self.landscape.get_neighbour_by_type( docker_node, 'machine') return machine return None
def _nova_uuid(self, node): if InfoGraphNode.get_type(node) == NODE_TYPE.INSTANCE_DISK: disk_name = InfoGraphNode.get_name(node) vm = self.landscape.get_neighbour_by_type(disk_name, "vm") return vm if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: vm = self.vms.pop() return vm return None
def _disk(self, node): disk = None if (InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_DISK or InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE): attrs = InfoGraphNode.get_attributes(node) if 'osdev_storage-name' in attrs: disk = attrs["osdev_storage-name"] elif InfoGraphNode.get_type(node) == NODE_TYPE.INSTANCE_DISK: disk = InfoGraphNode.get_name(node).split("_")[1] return disk
def _pu(self, node, metric): pu = None if (InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_PU or InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE): attrs = InfoGraphNode.get_attributes(node) if 'os_index' in attrs: pu = attrs["os_index"] # metric prefix 'cpu' on to the front of the cpu number. if pu and ('intel/proc/schedstat/cpu/' in metric or 'intel/psutil/cpu/' in metric): pu = "cpu{}".format(pu) return pu
def get_metrics(graph, metrics='all'): """ Returns all the metrics associated with the input graph :param graph: (NetworkX Graph) Graph to be annotated with data :param metrics: metric type to be considered. default = all :return: the list of metrics associated with the graph """ metric_list = [] for node in graph.nodes(data=True): node_name = InfoGraphNode.get_name(node) node_layer = InfoGraphNode.get_layer(node) node_type = InfoGraphNode.get_type(node) # This method supports export of either normal metrics coming # from telemetry agent or utilization type of metrics. if metrics == 'all': node_telemetry_data = InfoGraphNode.get_telemetry_data(node) else: node_telemetry_data = InfoGraphNode.get_utilization(node) metric_list.extend([ "{}@{}@{}@{}".format(node_name, node_layer, node_type, metric_name).replace(".", "_") for metric_name in node_telemetry_data.columns.values if metric_name != 'timestamp' ]) return metric_list
def _get_metrics(self, node): """ Retrieves the metrics for a node based on its type. This is done by checking if the node is in the NODE_METRICS dictionary and then pulling out a list of metric heads for that node type. If the metric head matches the metric retrieved from the host then we attach it. """ metrics = [] node_type = InfoGraphNode.get_type(node) if node_type in NODE_METRICS: source_metrics = self._source_metrics(node) for metric in source_metrics: for metric_start in NODE_METRICS[node_type]: if metric.startswith(metric_start) \ and not self._exception(node, metric): if metric.startswith("intel/net/"): nic_id = self._nic(node) if nic_id in metric: metrics.append(metric) if metric.startswith('intel/libvirt/'): self._get_nova_uuids(node) for x in range(0, len(self.vms)): #LOG.info('Adding {}'.format(metric)) metrics.append(metric) else: metrics.append(metric) return metrics
def _create_pandas_data_frame_from_graph(graph, metrics='all'): """ Save on csv files the data in the graph. Stores one csv per node of the graph :param graph: (NetworkX Graph) Graph to be annotated with data :param directory: (str) directory where to store csv files :return: NetworkX Graph annotated with telemetry data """ result = pandas.DataFrame() for node in graph.nodes(data=True): node_name = InfoGraphNode.get_name(node) node_layer = InfoGraphNode.get_layer(node) node_type = InfoGraphNode.get_type(node) # This method supports export of either normal metrics coming # from telemetry agent or utilization type of metrics. if metrics == 'all': node_telemetry_data = InfoGraphNode.get_telemetry_data(node) else: node_telemetry_data = InfoGraphNode.get_utilization(node) # df = node_telemetry_data.copy() # LOG.info("Node Name: {} -- Telemetry: {}".format( # InfoGraphNode.get_name(node), # InfoGraphNode.get_telemetry_data(node).columns.values # )) node_telemetry_data['timestamp'] = node_telemetry_data[ 'timestamp'].astype(float) node_telemetry_data['timestamp'] = node_telemetry_data[ 'timestamp'].round() node_telemetry_data['timestamp'] = node_telemetry_data[ 'timestamp'].astype(int) for metric_name in node_telemetry_data.columns.values: if metric_name == 'timestamp': continue col_name = "{}@{}@{}@{}".\ format(node_name, node_layer, node_type, metric_name) col_name = col_name.replace(".", "_") node_telemetry_data = node_telemetry_data.rename( columns={metric_name: col_name}) # LOG.info("TELEMETRIA: {}".format(node_telemetry_data.columns.values)) if node_telemetry_data.empty or len( node_telemetry_data.columns) <= 1: continue if result.empty: result = node_telemetry_data.copy() else: node_telemetry_data = \ node_telemetry_data.drop_duplicates(subset='timestamp') result = pandas.merge(result, node_telemetry_data, how='outer', on='timestamp') # TODO: Try with this removed # result.set_index(['timestamp']) return result
def _node_is_nic_on_management_net(node, graph, mng_net_name): node_name = InfoGraphNode.get_name(node) node_type = InfoGraphNode.get_type(node) if node_type == InfoGraphNodeType.VIRTUAL_NIC or \ node_type == InfoGraphNodeType.VIRTUAL_NIC_2: neighs = graph.neighbors(node_name) for n in neighs: neighbor = InfoGraphNode.\ get_node(graph, n) if InfoGraphNode.get_type(neighbor) == \ InfoGraphNodeType.VIRTUAL_NETWORK: network_name = \ InfoGraphNode.get_attributes( neighbor)['name'] if network_name == mng_net_name: return True return False
def _pu(self, node, metric): pu = None if (InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_PU or InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE): attrs = InfoGraphNode.get_attributes(node) # fix attributes from landscaper - fixing # permanently on the fly if needed while attrs.get('attributes', None): attrs = attrs['attributes'] if 'os_index' in attrs: pu = attrs["os_index"] # metric prefix 'cpu' on to the front of the cpu number. if pu and ('intel/proc/schedstat/cpu/' in metric or 'intel/psutil/cpu/' in metric): pu = "cpu{}".format(pu) return pu
def _nic(self, node): nic = None if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_NIC: attrs = InfoGraphNode.get_attributes(node) if 'osdev_network-name' in attrs: nic = attrs["osdev_network-name"] # if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: # LOG.info('NODEEEEE: {}'.format(node)) return nic
def _stack(self, node): if InfoGraphNode.get_type(node) == NODE_TYPE.VIRTUAL_MACHINE: # Taking service node to which the VM is connected predecessors = self.landscape.predecessors( InfoGraphNode.get_name(node)) for predecessor in predecessors: predecessor_node = self.landscape.node[predecessor] if predecessor_node['type'] == NODE_TYPE.SERVICE_COMPUTE: if 'stack_name' in predecessor_node: return predecessor_node["stack_name"] return None
def _tag_keys(self, metric, node): tag_keys = [] # always put in instance tag_keys += ["instance"] node_type = InfoGraphNode.get_type(node) if node_type in NODE_TO_METRIC_TAGS: tag_keys = NODE_TO_METRIC_TAGS[node_type] return tag_keys
def _get_query_selectors(self, metric, node): node_type = InfoGraphNode.get_type(node) tags = self._tags(metric, node) selectors = [] for tag, tag_value in tags.iteritems(): if tag == "instance": #and node_type == NODE_TYPE.PHYSICAL_MACHINE: # hostname needs a regexp selector = 'instance=~"{}:.*"'.format(tag_value) else: selector = '{}="{}"'.format(tag, tag_value) selectors.append(selector) s = ','.join(selectors) return s
def _nic(self, node, tag_key): nic = None if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_NIC: attrs = InfoGraphNode.get_attributes(node) if tag_key == "hardware_addr": nic = attrs["address"] elif 'osdev_network-name' in attrs: nic = attrs["osdev_network-name"] elif 'name' in attrs: nic = attrs["name"] # if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: # LOG.info('NODEEEEE: {}'.format(node)) return nic
def _source(self, node): attrs = InfoGraphNode.get_attributes(node) if InfoGraphNode.get_layer(node) == GRAPH_LAYER.PHYSICAL: if 'allocation' in attrs: return attrs['allocation'] if InfoGraphNode.get_type(node) == NODE_TYPE.VIRTUAL_MACHINE: if 'vm_name' in attrs: return attrs['vm_name'] elif 'name' in attrs: return attrs['name'] if InfoGraphNode.get_type(node) == NODE_TYPE.INSTANCE_DISK: # The machine is the source as this is a libvirt disk. disk_name = InfoGraphNode.get_name(node) vm = self.landscape.get_neighbour_by_type( disk_name, NODE_TYPE.VIRTUAL_MACHINE) machine = self.landscape.get_neighbour_by_type( vm, NODE_TYPE.PHYSICAL_MACHINE) return machine if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: if 'name' in attrs: return attrs['name'] return None
def _source_metrics(self, node): """ Retrieves metrics associated with a source/host. The source is identified by the node and then all metrics types are collected for that source. If the node is physical then the metric types are retrieved using just the machine name as the source, if the node is virtual then the source (the vm hostname) and the stack name are required. """ metric_types = [] node_layer = InfoGraphNode.get_layer(node) node_type = InfoGraphNode.get_type(node) if node_layer == GRAPH_LAYER.PHYSICAL \ or node_type == NODE_TYPE.INSTANCE_DISK: try: source = self._source(node) identifier = source query_tags = {"source": source} metric_types = self._cached_metrics(identifier, query_tags) except Exception as ex: LOG.error('Malformed graph: {}'.format( InfoGraphNode.get_name(node))) LOG.error(ex) elif node_layer == GRAPH_LAYER.VIRTUAL: source = self._source(node) stack = self._stack(node) #LOG.info("SOURCE: {}".format(source)) #LOG.info("STACK: {}".format(stack)) if stack is not None: identifier = "{}-{}".format(source, stack) # query_tags = {"source": source, "stack": stack} query_tags = {"stack_name": stack} metric_types = self._cached_metrics(identifier, query_tags) elif node_type == NODE_TYPE.DOCKER_CONTAINER: source = self._source(node) docker_id = InfoGraphNode.get_docker_id(node) if docker_id is not None and source is not None: identifier = "{}-{}".format(source, docker_id) query_tags = {"docker_id": docker_id, "source": source} metric_types = self._cached_metrics(identifier, query_tags) return metric_types
def filter_graph(graph): """ Returns the graph filtered removing all the nodes with no telemetry """ template_mapping = dict() res = graph.copy() for node in res.nodes(data=True): # for p in node[1]['attributes']: # p = str(p) template = node[1]['attributes']['template'] \ if 'template' in node[1]['attributes'] else None # If node is a service node, need to remove the template if template: template_mapping[InfoGraphNode.get_name(node)] = template node[1]['attributes'].pop('template') # Fix format for conversion to JSON (happening in analytics) node[1]['attributes'] = \ str(misc.convert_unicode_dict_to_string(node[1]['attributes'])).\ replace("'", '"') for node in res.nodes(data=True): node_name = InfoGraphNode.get_name(node) telemetry = InfoGraphNode.get_telemetry_data(node) layer = InfoGraphNode.get_layer(node) # if len(telemetry.columns.values) <= 1: if len(telemetry.columns) <= 1 and \ not layer == InfoGraphNodeLayer.SERVICE: InfoGraphNode.set_telemetry_data(node, dict()) res.filter_nodes('node_name', node_name) # Convert attributes back to dict() for node in res.nodes(data=True): string = InfoGraphNode.get_attributes(node) attrs = InfoGraphUtilities.str_to_dict(string) if InfoGraphNode.get_type(node) == \ InfoGraphNodeType.SERVICE_COMPUTE: attrs['template'] = \ template_mapping[InfoGraphNode.get_name(node)] InfoGraphNode.set_attributes(node, attrs) return res
def _tag_keys(self, metric, node): tag_keys = [] # metric keys specific to node type node_type = InfoGraphNode.get_type(node) if node_type == NODE_TYPE.VIRTUAL_MACHINE: tag_keys.append("stack_name") # TODO: Check if this comment causes any problem # tag_keys.append("vm_name") elif node_type == NODE_TYPE.VIRTUAL_NIC: tag_keys.append("ip") # standard metric keys for metric_head, keys in METRIC_TAGS: if metric_head in metric: tag_keys += keys return tag_keys return None
def get_annotated_graph(self, graph, ts_from, ts_to, utilization=True, saturation=True): internal_graph = graph.copy() i = 0 threads = [] cpu_count = multiprocessing.cpu_count() no_node_thread = len(internal_graph.nodes()) / (cpu_count) node_pool = [] node_pools = [] for node in internal_graph.nodes(data=True): if i < no_node_thread: node_pool.append(node) i = i + 1 else: thread1 = ParallelTelemetryAnnotation( i, "Thread-{}".format(InfoGraphNode.get_name(node)), i, node_pool, internal_graph, self.telemetry, ts_to, ts_from) threads.append(thread1) node_pools.append(node_pool) i = 1 node_pool = [node] if len(node_pool) != 0: node_pools.append(node_pool) thread1 = ParallelTelemetryAnnotation( i, "Thread-{}".format(InfoGraphNode.get_name(node)), i, node_pool, internal_graph, self.telemetry, ts_to, ts_from) threads.append(thread1) [t.start() for t in threads] [t.join() for t in threads] for node in internal_graph.nodes(data=True): if InfoGraphNode.get_type(node) == InfoGraphNodeType.PHYSICAL_PU: self.utils.annotate_machine_pu_util(internal_graph, node) elif InfoGraphNode.node_is_disk(node): self.utils.annotate_machine_disk_util(internal_graph, node) elif InfoGraphNode.node_is_nic(node): self.utils.annotate_machine_network_util(internal_graph, node) return internal_graph
def _get_metrics(self, node): """ Retrieves the metrics for a node based on its type. This is done by checking if the node is in the NODE_METRICS dictionary and then pulling out a list of metric heads for that node type. If the metric head matches the metric retrieved from the host then we attach it. """ metrics = [] node_type = InfoGraphNode.get_type(node) LOG.debug('looking for node type = {}, node = {}'.format( node_type, node[0])) # if node_type != 'cache' and node_type != 'pcidev': # dummy = 1 if node_type in NODE_METRICS: metrics = NODE_METRICS[node_type] LOG.debug("METRICS: {}".format(metrics)) return metrics
def _tag_value(self, tag_key, node, metric): # TODO: fully qualify this with metric name, if metric is this and tag tag_value = None if tag_key == "instance": tag_value = self._source(node) elif tag_key == "source": tag_value = self._source(node) if tag_value is None: node_type = InfoGraphNode.get_type(node) if node_type == NODE_TYPE.PHYSICAL_DISK: tag_value = self._disk(node) elif node_type == NODE_TYPE.PHYSICAL_PU: tag_value = self._pu(node, metric) elif node_type == NODE_TYPE.PHYSICAL_NIC: attrs = InfoGraphNode.get_attributes(node) tag_value = self._nic(node) elif node_type == NODE_TYPE.VIRTUAL_MACHINE: tag_value = self._vm(node) return tag_value
def _exception(self, node, metric): # This metric should be attached to the machine and not nic. if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_NIC \ and metric.startswith("intel/psutil/net/all"): return True return False
def _get_nova_uuids(self, node): if InfoGraphNode.get_type(node) == NODE_TYPE.PHYSICAL_MACHINE: phy_name = InfoGraphNode.get_name(node) self.vms = self.landscape.get_neighbours_by_type(phy_name, "vm")
def _vm(self, node): if InfoGraphNode.get_type(node) == NODE_TYPE.VIRTUAL_MACHINE: attrs = InfoGraphNode.get_attributes(node) return attrs['libvirt_instance']
def compute_node_resources(annotated_subgraph, hostname=None): """ This is a type of fingerprint from the infrastructure perspective """ # TODO: Validate graph data = dict() statistics = dict() # Calculation of the fingerprint on top of the virtual resources local_subgraph = annotated_subgraph.copy() for node in local_subgraph.nodes(data=True): layer = InfoGraphNode.get_layer(node) if layer == InfoGraphNodeLayer.VIRTUAL: continue if layer == InfoGraphNodeLayer.SERVICE: continue type = InfoGraphNode.get_type(node) if type == 'core': continue # If hostname has been specified, need to take into account only # nodes that are related to the specific host attrs = InfoGraphNode.get_attributes(node) allocation = attrs['allocation'] if 'allocation' in attrs \ else None if hostname and not hostname == allocation: continue name = InfoGraphNode.get_name(node) statistics[name] = { 'mean': 0, 'median': 0, 'min': 0, 'max': 0, 'var': 0, 'std_dev': 0 } utilization = InfoGraphNode.get_utilization(node) try: utilization = utilization.drop('timestamp', 1) except ValueError: utilization = InfoGraphNode.get_utilization(node) data[name] = utilization if not data[name].empty: mean = data[name]['utilization'].mean() median = (data[name]['utilization']).median() min = data[name]['utilization'].min() maximum = data[name]['utilization'].max() var = data[name]['utilization'].var() std_dev = math.sqrt(var) else: mean = 0 median = 0 min = 0 maximum = 0 var = 0 std_dev = 0 statistics[name] = \ {'mean': mean, 'median': median, 'min': min, 'max': maximum, 'var': var, 'std_dev': std_dev} return [data, statistics]
def utilization_scores(graph): """ Returns a dictionary with the scores of all the nodes of the graph. :param graph: InfoGraph :return: dict[node_name] = score """ res = dict() for node in graph.nodes(data=True): node_name = InfoGraphNode.get_name(node) res[node_name] = dict() util = InfoGraphNode.get_utilization(node) import analytics_engine.common as common LOG = common.LOG res[node_name]['compute'] = 0 res[node_name]['disk'] = 0 res[node_name]['network'] = 0 res[node_name]['memory'] = 0 if (isinstance(util, pandas.DataFrame) and util.empty) or \ (not isinstance(util, pandas.DataFrame) and util==None): continue # intel/use/ if 'intel/use/compute/utilization' in util: res[node_name]['compute'] = ( util.get('intel/use/compute/utilization').mean()) / 100.0 elif 'intel/procfs/cpu/utilization_percentage' in util: res[node_name]['compute'] = (util.get( 'intel/procfs/cpu/utilization_percentage').mean()) / 100.0 if 'intel/use/memory/utilization' in util: res[node_name]['memory'] = ( util.get('intel/use/memory/utilization').mean()) / 100.0 elif 'intel/procfs/memory/utilization_percentage' in util: res[node_name]['memory'] = ( util.get('intel/procfs/memory/utilization_percentage' ).mean()) / 100.0 if 'intel/use/disk/utilization' in util: res[node_name]['disk'] = ( util.get('intel/use/disk/utilization').mean()) / 100.0 elif 'intel/procfs/disk/utilization_percentage' in util: res[node_name]['disk'] = (util.get( 'intel/procfs/disk/utilization_percentage').mean()) / 100.0 if 'intel/use/network/utilization' in util: res[node_name]['network'] = ( util.get('intel/use/network/utilization').mean()) / 100.0 elif 'intel/psutil/net/utilization_percentage' in util: res[node_name]['network'] = (util.get( 'intel/psutil/net/utilization_percentage').mean()) / 100.0 # special handling of cpu, disk & network utilization if node is a machine if InfoGraphNode.node_is_machine(node): # mean from all cpu columns cpu_util = InfoGraphNode.get_compute_utilization(node) cpu_util['total'] = [ sum(row) / len(row) for index, row in cpu_util.iterrows() ] res[node_name]['compute'] = cpu_util['total'].mean() / 100 # mean from all disk columns disk_util = InfoGraphNode.get_disk_utilization(node) if disk_util.empty: res[node_name]['disk'] = 0.0 else: disk_util['total'] = [ sum(row) / len(row) for index, row in disk_util.iterrows() ] res[node_name]['disk'] = disk_util['total'].mean() / 100 # mean from all nic columns net_util = InfoGraphNode.get_network_utilization(node) if net_util.empty: res[node_name]['network'] = 0.0 else: net_util['total'] = [ sum(row) / len(row) for index, row in net_util.iterrows() ] res[node_name]['network'] = net_util['total'].mean() / 100 # custom metric if InfoGraphNode.get_type( node) == InfoGraphNodeType.DOCKER_CONTAINER: node_name = InfoGraphNode.get_docker_id(node) res[node_name] = {} if 'intel/docker/stats/cgroups/cpu_stats/cpu_usage/percentage' in util.columns: res[node_name]['compute'] = util[ 'intel/docker/stats/cgroups/cpu_stats/cpu_usage/percentage'].mean( ) / 100 else: res[node_name]['compute'] = 0 if 'intel/docker/stats/cgroups/memory_stats/usage/percentage' in util.columns: res[node_name]['memory'] = util[ 'intel/docker/stats/cgroups/memory_stats/usage/percentage'].mean( ) / 100 else: res[node_name]['memory'] = 0 if 'intel/docker/stats/network/utilization_percentage' in util.columns: res[node_name]['network'] = util[ 'intel/docker/stats/network/utilization_percentage'].mean( ) / 100 else: res[node_name]['network'] = 0 if 'intel/docker/stats/cgroups/blkio_stats/io_time_recursive/percentage' in util.columns: res[node_name]['disk'] = util[ 'intel/docker/stats/cgroups/blkio_stats/io_time_recursive/percentage'].mean( ) / 100 else: res[node_name]['disk'] = 0 return res
def get_annotated_graph(self, graph, ts_from, ts_to, utilization=False, saturation=False): """ Collect data from cimmaron tsdb in relation to the specified graph and time windows and store an annotated subgraph in specified directory :param graph: (NetworkX Graph) Graph to be annotated with data :param ts_from: (str) Epoch time representation of start time :param ts_to: (str) Epoch time representation of stop time :param utilization: (bool) if True the method calculates also utilization for each node, if available :return: NetworkX Graph annotated with telemetry data """ TelemetryAnnotation._get_annotated_graph_input_validation( graph, ts_from, ts_to) internal_graph = graph.copy() self.internal_graph = internal_graph for node in internal_graph.nodes(data=True): if isinstance(self.telemetry, SnapAnnotation): queries = list() try: queries = self.telemetry.get_queries( internal_graph, node, ts_from, ts_to) # queries = self.telemetry.get_queries(graph, node, ts_from, ts_to) except Exception as e: LOG.error("Exception: {}".format(e)) LOG.error(e) import traceback traceback.print_exc() if len(queries) != 0: InfoGraphNode.set_queries(node, queries) telemetry_data = self.telemetry.get_data(node) InfoGraphNode.set_telemetry_data(node, telemetry_data) if utilization and not telemetry_data.empty: SnapUtils.utilization(internal_graph, node, self.telemetry) # if only procfs is available, results needs to be # propagated at machine level if InfoGraphNode.get_type( node) == InfoGraphNodeType.PHYSICAL_PU: SnapUtils.annotate_machine_pu_util( internal_graph, node) if InfoGraphNode.node_is_disk(node): SnapUtils.annotate_machine_disk_util( internal_graph, node) if InfoGraphNode.node_is_nic(node): SnapUtils.annotate_machine_network_util( internal_graph, node) if saturation: SnapUtils.saturation(internal_graph, node, self.telemetry) elif isinstance(self.telemetry, PrometheusAnnotation): queries = list() try: queries = self.telemetry.get_queries( internal_graph, node, ts_from, ts_to) # queries = self.telemetry.get_queries(graph, node, ts_from, ts_to) except Exception as e: LOG.error("Exception: {}".format(e)) LOG.error(e) import traceback traceback.print_exc() if len(queries) != 0: InfoGraphNode.set_queries(node, queries) telemetry_data = self.telemetry.get_data(node) InfoGraphNode.set_telemetry_data(node, telemetry_data) # if utilization and not telemetry_data.empty: #PrometheusUtils.utilization(internal_graph, node, self.telemetry) # if only procfs is available, results needs to be # propagated at machine level #if InfoGraphNode.get_type(node) == InfoGraphNodeType.PHYSICAL_PU: # PrometheusUtils.annotate_machine_pu_util(internal_graph, node) #if InfoGraphNode.node_is_disk(node): # PrometheusUtils.annotate_machine_disk_util(internal_graph, node) #if InfoGraphNode.node_is_nic(node): # PrometheusUtils.annotate_machine_network_util(internal_graph, node) #if saturation: #PrometheusUtils.saturation(internal_graph, node, self.telemetry) else: telemetry_data = self.telemetry.get_data(node) InfoGraphNode.set_telemetry_data(node, telemetry_data) if utilization and not telemetry_data.empty: SnapUtils.utilization(internal_graph, node, self.telemetry) # if only procfs is available, results needs to be # propagated at machine level if InfoGraphNode.get_type( node) == InfoGraphNodeType.PHYSICAL_PU: source = InfoGraphNode.get_machine_name_of_pu(node) machine = InfoGraphNode.get_node( internal_graph, source) machine_util = InfoGraphNode.get_compute_utilization( machine) if '/intel/use/compute/utilization' not in machine_util.columns: sum_util = None pu_util = InfoGraphNode.get_compute_utilization( node )['intel/procfs/cpu/utilization_percentage'] pu_util = pu_util.fillna(0) if 'intel/procfs/cpu/utilization_percentage' in machine_util.columns: machine_util = machine_util[ 'intel/procfs/cpu/utilization_percentage'] machine_util = machine_util.fillna(0) sum_util = machine_util.add(pu_util, fill_value=0) else: sum_util = pu_util if isinstance(sum_util, pandas.Series): # sum_util.index.name = None sum_util = pandas.DataFrame( sum_util, columns=[ 'intel/procfs/cpu/utilization_percentage' ]) InfoGraphNode.set_compute_utilization( machine, sum_util) else: LOG.debug('Found use for node {}'.format( InfoGraphNode.get_name(node))) if saturation: self._saturation(internal_graph, node, self.telemetry) return internal_graph
def run(self, workload, optimal_node_type='machine'): """ Ranks machines by CPU utilization. :param workload: Contains workload related info and results. :return: heuristic results """ workload_config = workload.get_configuration() graph = workload.get_latest_graph() if not graph: raise KeyError('No graph to be processed.') scores = LandscapeScore.utilization_scores(graph) scores_sat = LandscapeScore.saturation_scores(graph) heuristic_results = pd.DataFrame(columns=[ 'node_name', 'type', 'ipaddress', 'compute utilization', 'compute saturation', 'memory utilization', 'memory saturation', 'network utilization', 'network saturation', 'disk utilization', 'disk saturation', ]) heuristic_results_nt = heuristic_results.copy() device_id_col_name = None project = None if workload_config.get('project'): project = workload_config['project'] device_id_col_name = workload_config['project'] + '_device_id' heuristic_results[device_id_col_name] = None telemetry_filter = workload_config.get('telemetry_filter') for node in graph.nodes(data=True): node_name = InfoGraphNode.get_name(node) node_type = InfoGraphNode.get_type(node) list_node_name = node_name if node_type == optimal_node_type: if InfoGraphNode.node_is_vm(node): vm_name = InfoGraphNode.get_properties(node).get('vm_name') if vm_name: list_node_name = vm_name data = { 'node_name': list_node_name, 'type': node_type, 'ipaddress': InfoGraphNode.get_attributes(node).get('ipaddress'), 'compute utilization': scores[node_name]['compute'], 'compute saturation': scores_sat[node_name]['compute'], 'memory utilization': scores[node_name]['memory'], 'memory saturation': scores_sat[node_name]['memory'], 'network utilization': scores[node_name]['network'], 'network saturation': scores_sat[node_name]['network'], 'disk utilization': scores[node_name]['disk'], 'disk saturation': scores_sat[node_name]['disk'] } if device_id_col_name: dev_id = InfoGraphNode.get_properties(node).get( device_id_col_name) if project == 'mf2c': dev_id = dev_id.replace('_', '-') data[device_id_col_name] = dev_id if InfoGraphNode.get_properties(node).get( "telemetry_data") is not None: heuristic_results = heuristic_results.append( data, ignore_index=True) elif not telemetry_filter: heuristic_results_nt = heuristic_results.append( data, ignore_index=True) if not workload.get_workload_name().startswith('optimal_'): if InfoGraphNode.get_type( node ) == "docker_container" and optimal_node_type == 'machine': node_name = InfoGraphNode.get_docker_id(node) heuristic_results = heuristic_results.append( { 'node_name': node_name, 'type': node_type, 'ipaddress': None, 'compute utilization': scores[node_name]['compute'], 'compute saturation': None, 'memory utilization': scores[node_name]['memory'], 'memory saturation': None, 'network utilization': scores[node_name]['network'], 'network saturation': None, 'disk utilization': scores[node_name]['disk'], 'disk saturation': None }, ignore_index=True) sort_fields = ['compute utilization'] sort_order = workload_config.get('sort_order') if sort_order: sort_fields = [] for val in sort_order: if val == 'cpu': sort_fields.append('compute utilization') if val == 'memory': sort_fields.append('memory utilization') if val == 'network': sort_fields.append('network utilization') if val == 'disk': sort_fields.append('disk utilization') heuristic_results_nt = heuristic_results_nt.replace([0], [None]) heuristic_results = heuristic_results.sort_values(by=sort_fields, ascending=True) heuristic_results = heuristic_results.append(heuristic_results_nt, ignore_index=True) workload.append_metadata(self.__filter_name__, heuristic_results) LOG.info('AVG: {}'.format(heuristic_results)) return heuristic_results