def update_graph_db(self, event, body): """ Updates the heat elements in the graph database. :param event: The event that has occurred. :param body: The details of the event that occurred. """ from heatclient.exc import NotFound LOG.info("[HEAT] Processing event received: %s", event) now_ts = time.time() uuid = body.get('payload', dict()).get('stack_identity', 'UNDEFINED') if '/' in uuid: uuid = uuid.rsplit('/', 1)[1] try: stack = self.heat.stacks.get(uuid) if event in ADD_EVENTS: LOG.info("HEAT: Adding stack: %s", stack) self._add_stack(stack, now_ts) elif event in UPDATE_EVENTS: LOG.info("HEAT: Updating stack: %s", stack) self._update_stack(stack, now_ts) elif event in DELETE_EVENTS: LOG.info("HEAT: deleting stack: %s", stack) self._delete_stack(uuid, now_ts) except NotFound: LOG.warn("HEAT: Stack with UUID %s not found", uuid)
def add_node(self, node_id, identity, state, timestmp): """ Add a node to the Neo4j database, which involves adding the identity node and also the state node and then creating a relationship between them. :param node_id: The id of the identity node. :param identity: The identity node. :param state: State node. :param timestmp: Epoch timestamp of when the node was created. :return: An instance of the py2neo neo4j node. """ identity = _format_node(identity) identity['name'] = node_id iden_node = Node(identity.get('category', 'UNDEFINED'), **identity) existing_node = self.get_node_by_uuid(node_id) if existing_node: LOG.warn("Node with UUID: %s already stored in DB", node_id) return existing_node # Store nodes to the database. transaction = self.graph_db.begin() state = _format_node(state) state_label = identity.get('category', 'UNDEFINED') + '_state' state_node = Node(state_label, **state) state_rel = self._create_edge(iden_node, state_node, timestmp, "STATE") transaction.create(iden_node) transaction.create(state_node) transaction.create(state_rel) transaction.commit() return iden_node
def _add_task(self, task, timestamp): """ Adds a Docker task node to the graph database. :param task: Docker task object. :param timestamp: timestamp. """ LOG.info("[DOCKER] Adding a task node the Graph") if task['DesiredState'] == 'running': identity, state = self._create_docker_task_nodes(task) uuid = task["ID"] node_id = task["NodeID"] container_id = task["Status"]['ContainerStatus']['ContainerID'] service_id = task["ServiceID"] task_node = self.graph_db.add_node(uuid, identity, state, timestamp) LOG.warn(task_node) if task_node is not None: docker_node = self.graph_db.get_node_by_uuid(node_id) container_node = self.graph_db.get_node_by_uuid(container_id) service_node = self.graph_db.get_node_by_uuid(service_id) if docker_node and container_node: self.graph_db.add_edge(container_node, docker_node, timestamp, RELS['docker_container']) if container_node and task_node: self.graph_db.add_edge(task_node, container_node, timestamp, RELS['container_task']) if task_node and service_node: self.graph_db.add_edge(service_node, task_node, timestamp, RELS['task_service'])
def _create_docker_container_nodes(self, container, metadata): """ Creates the identity and state nodes for an individual docker container :param container: docker container. :return: Identity and state node. """ identity = IDEN_ATTR.copy() identity['type'] = 'docker_container' state = metadata.copy() uuid = container.attrs["Id"] LOG.warn("Creating container nodes for container: " + container.attrs["Id"]) # TODO: why can it have multiple names? state['container_name'] = container.attrs["Name"][0].replace('/', '') #state['template'] = container return identity, state
def get_node_by_properties(): """ Returns a graph containing just the nodes that match the properties. """ LOG.info("Retrieving node by props with url %s", request.url) timestamp = request.args.get("timestamp") or time.time() properties_string = request.args.get("properties") if not properties_string: err_msg = "Properties must be specified." LOG.warn(err_msg) abort(400, err_msg) properties = ast.literal_eval(properties_string) graph = LANDSCAPE.graph_db.get_node_by_properties_web( properties, timestamp) return Response(graph, mimetype=MIME)
def get_service_instances(): """ Returns the service instances that match the properties provided """ LOG.info("Accessing URL %s", request.url) properties_string = request.args.get("properties") timestamp = request.args.get("timestamp") or 0 timeframe = request.args.get("timeframe") or int(time.time()) * -1 if not properties_string: err_msg = "Properties must be specified." LOG.warn(err_msg) abort(400, err_msg) properties = ast.literal_eval(properties_string) graph = LANDSCAPE.graph_db.get_node_by_properties_web( properties, timestamp, timeframe) return Response(graph, mimetype=MIME)
def add_edge(self, src_node, dest_node, timestamp, label=None): """ Add an edge between two nodes and attach timestamp details as an attribute, which details when the pointed to node was created, updated or deleted. :param src_node: The source node. :param dest_node: The destination node. :param timestamp: The epoch timestamp of when this edge was created. :param label: Description of the edge. :return: Instance of an edge. """ # Add link between src and dst nodes. edge = self._create_edge(src_node, dest_node, timestamp, label) if edge is not None and self.graph_db.exists(edge): LOG.warn("Trying to add a relation already stored in the DB") return edge transaction = self.graph_db.begin() transaction.create(edge) transaction.commit() return edge
def update_node(self, node_id, timestamp, state=None, extra_attrs=None): """ Updating a node in the database involves expiring the old state node and then creating a new state node and linking it to identity node which is being updated. :param additional_attributes: :param node_id: The identity node id. :param state: The new state. :param timestamp: Epoch timestamp of when the update occurred. :return: Instance of the identity node. """ state_attrs = None identity = self.get_node_by_uuid(node_id) if not identity: umsg = "Node: %s. Node not in the landscape." % node_id LOG.warn(umsg) return (None, umsg) if not state and not extra_attrs: umsg = "Node: %s. No attributes supplied for update." % node_id LOG.warn(umsg) return (identity, umsg) if state: state_attrs = state old_state = self._get_state_node(identity, time.time()) if not old_state: umsg = "Can't update node: %s, as it is already expired." % node_id LOG.warn(umsg) return (identity, umsg) old_node, old_edge = old_state if extra_attrs: if state_attrs: state_attrs.update(extra_attrs) else: state_attrs = dict(old_node) state_attrs.update(extra_attrs) if state_attrs == dict(old_node): umsg = "Node: %s. No update. Current state is identical" % node_id LOG.warn(umsg) return (identity, umsg) # Create new state and edge to identity. state_label = identity.get('category', 'UNDEFINED') + '_state' state_node = Node(state_label, **state_attrs) new_edge = self._create_edge(identity, state_node, timestamp, 'STATE') # Expire old edge between identity and state. self._expire_edge(old_edge, timestamp) # Commit it all self.graph_db.push(old_edge) transaction = self.graph_db.begin() transaction.create(new_edge) transaction.commit() umsg = "Node %s updated successfully" % node_id return (identity, umsg)
def update_graph_db(self, event, body): """ Updates the heat elements in the graph database. :param event: The event that has occurred. :param body: The details of the event that occurred. """ now_ts = time.time() uuid = body.get("Actor", dict()).get('ID', 'UNDEFINED') event_source = body.get("Type", None) LOG.info("[SWARM] Processing event received: %s", event) LOG.info("SWARM-----UUID----- %s", uuid) try: if event in ADD_EVENTS: time.sleep(2) if body['Type'] == 'service': stack = next((x for x in self.swarm_manager.services.list() if x.attrs['ID'] == uuid), None) self._add_service(stack, now_ts) if body['Type'] == 'container': if body['Action'] == 'create': container = next( (x for x in self.swarm_manager.containers.list() if x.attrs['Id'] == uuid), None) self._add_container(container, now_ts) if body['Action'] == 'start': task_id = body['Actor']['Attributes'][ 'com.docker.swarm.task.id'] service = self.swarm_manager.services.get( body['Actor']['Attributes'] ['com.docker.swarm.service.id']) #service = next((x for x in self.swarm_manager.services.list() if # x.attrs['ID'] == uuid), None) task = next( (x for x in service.tasks() if x['ID'] == task_id), None) self._add_task(task, now_ts) elif event in DELETE_EVENTS: LOG.info("SWARM: deleting stack:\n") if body['Type'] == 'container': # delete the adjoining task if 'com.docker.swarm.task.id' in body['Actor'][ 'Attributes']: task_id = body['Actor']['Attributes'][ 'com.docker.swarm.task.id'] self._delete_node(task_id, now_ts) self._delete_node(uuid, now_ts) elif event in UPDATE_EVENTS: if event_source == 'service': LOG.info("SWARM: updating service: " + body['Actor']['ID']) service = self.swarm_manager.services.get( body['Actor']['ID']) #service = next((x for x in self.swarm_manager.services() if # x.attrs['ID'] == uuid), None) self._update_service(service, now_ts, body) except docker.errors.NotFound: #DEBUG code if event in ADD_EVENTS: # self._add_stack(stack, now_ts) LOG.warn("[SWARM] Missed stack into openstack\n EVENT:") LOG.warn(event) for s in self.swarm_manager.services.list(): LOG.warn("Stacks into heat openstack %s\n", s.id) LOG.warn("\n\n BODY:\n") LOG.warn(body) #LOG.warn("\n\nCurrent state of stack: \n") #LOG.warn(stack) #END DEBUG code LOG.warn("SWARM: Stack with UUID %s not found", uuid) elif event in DELETE_EVENTS: #stack = self.heat.stacks.get(uuid) LOG.warn("SWARM: deleting stack:\n") self._delete_node(uuid, now_ts)