Manually added OpenStack  API code
diff --git a/src/emuvim/api/openstack/compute.py b/src/emuvim/api/openstack/compute.py
new file mode 100644
index 0000000..9918c6d
--- /dev/null
+++ b/src/emuvim/api/openstack/compute.py
@@ -0,0 +1,702 @@
+from mininet.link import Link
+from resources import *
+from docker import DockerClient
+import logging
+import threading
+import uuid
+import time
+import ip_handler as IP
+
+
+class HeatApiStackInvalidException(Exception):
+    """
+    Exception thrown when a submitted stack is invalid.
+    """
+
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return repr(self.value)
+
+
+class OpenstackCompute(object):
+    """
+    This class is a datacenter specific compute object that tracks all containers that are running in a datacenter,
+    as well as networks and configured ports.
+    It has some stack dependet logic and can check if a received stack is valid.
+
+    It also handles start and stop of containers.
+    """
+
+    def __init__(self):
+        self.dc = None
+        self.stacks = dict()
+        self.computeUnits = dict()
+        self.routers = dict()
+        self.flavors = dict()
+        self._images = dict()
+        self.nets = dict()
+        self.ports = dict()
+        self.compute_nets = dict()
+        self.dcli = DockerClient(base_url='unix://var/run/docker.sock')
+
+    @property
+    def images(self):
+        """
+        Updates the known images. Asks the docker daemon for a list of all known images and returns
+        the new dictionary.
+
+        :return: Returns the new image dictionary.
+        :rtype: ``dict``
+        """
+        for image in self.dcli.images.list():
+            if len(image.tags) > 0:
+                for t in image.tags:
+                    t = t.replace(":latest", "")  # only use short tag names for OSM compatibility
+                    if t not in self._images:
+                        self._images[t] = Image(t)
+        return self._images
+
+    def add_stack(self, stack):
+        """
+        Adds a new stack to the compute node.
+
+        :param stack: Stack dictionary.
+        :type stack: :class:`heat.resources.stack`
+        """
+        if not self.check_stack(stack):
+            self.clean_broken_stack(stack)
+            raise HeatApiStackInvalidException("Stack did not pass validity checks")
+        self.stacks[stack.id] = stack
+
+    def clean_broken_stack(self, stack):
+        for port in stack.ports.values():
+            if port.id in self.ports:
+                del self.ports[port.id]
+        for server in stack.servers.values():
+            if server.id in self.computeUnits:
+                del self.computeUnits[server.id]
+        for net in stack.nets.values():
+            if net.id in self.nets:
+                del self.nets[net.id]
+
+    def check_stack(self, stack):
+        """
+        Checks all dependencies of all servers, ports and routers and their most important parameters.
+
+        :param stack: A reference of the stack that should be checked.
+        :type stack: :class:`heat.resources.stack`
+        :return: * *True*: If the stack is completely fine.
+         * *False*: Else
+        :rtype: ``bool``
+        """
+        everything_ok = True
+        for server in stack.servers.values():
+            for port_name in server.port_names:
+                if port_name not in stack.ports:
+                    logging.warning("Server %s of stack %s has a port named %s that is not known." %
+                                    (server.name, stack.stack_name, port_name))
+                    everything_ok = False
+            if server.image is None:
+                logging.warning("Server %s holds no image." % (server.name))
+                everything_ok = False
+            if server.command is None:
+                logging.warning("Server %s holds no command." % (server.name))
+                everything_ok = False
+        for port in stack.ports.values():
+            if port.net_name not in stack.nets:
+                logging.warning("Port %s of stack %s has a network named %s that is not known." %
+                                (port.name, stack.stack_name, port.net_name))
+                everything_ok = False
+            if port.intf_name is None:
+                logging.warning("Port %s has no interface name." % (port.name))
+                everything_ok = False
+            if port.ip_address is None:
+                logging.warning("Port %s has no IP address." % (port.name))
+                everything_ok = False
+        for router in stack.routers.values():
+            for subnet_name in router.subnet_names:
+                found = False
+                for net in stack.nets.values():
+                    if net.subnet_name == subnet_name:
+                        found = True
+                        break
+                if not found:
+                    logging.warning("Router %s of stack %s has a network named %s that is not known." %
+                                    (router.name, stack.stack_name, subnet_name))
+                    everything_ok = False
+        return everything_ok
+
+    def add_flavor(self, name, cpu, memory, memory_unit, storage, storage_unit):
+        """
+        Adds a flavor to the stack.
+
+        :param name: Specifies the name of the flavor.
+        :type name: ``str``
+        :param cpu:
+        :type cpu: ``str``
+        :param memory:
+        :type memory: ``str``
+        :param memory_unit:
+        :type memory_unit: ``str``
+        :param storage:
+        :type storage: ``str``
+        :param storage_unit:
+        :type storage_unit: ``str``
+        """
+        flavor = InstanceFlavor(name, cpu, memory, memory_unit, storage, storage_unit)
+        self.flavors[flavor.name] = flavor
+        return flavor
+
+    def deploy_stack(self, stackid):
+        """
+        Deploys the stack and starts the emulation.
+
+        :param stackid: An UUID str of the stack
+        :type stackid: ``str``
+        :return: * *False*: If the Datacenter is None
+            * *True*: Else
+        :rtype: ``bool``
+        """
+        if self.dc is None:
+            return False
+
+        stack = self.stacks[stackid]
+        self.update_compute_dicts(stack)
+
+        # Create the networks first
+        for server in stack.servers.values():
+            self._start_compute(server)
+        return True
+
+    def delete_stack(self, stack_id):
+        """
+        Delete a stack and all its components.
+
+        :param stack_id: An UUID str of the stack
+        :type stack_id: ``str``
+        :return: * *False*: If the Datacenter is None
+            * *True*: Else
+        :rtype: ``bool``
+        """
+        if self.dc is None:
+            return False
+
+        # Stop all servers and their links of this stack
+        for server in self.stacks[stack_id].servers.values():
+            self.stop_compute(server)
+            self.delete_server(server)
+        for net in self.stacks[stack_id].nets.values():
+            self.delete_network(net.id)
+        for port in self.stacks[stack_id].ports.values():
+            self.delete_port(port.id)
+
+        del self.stacks[stack_id]
+        return True
+
+    def update_stack(self, old_stack_id, new_stack):
+        """
+        Determines differences within the old and the new stack and deletes, create or changes only parts that
+        differ between the two stacks.
+
+        :param old_stack_id: The ID of the old stack.
+        :type old_stack_id: ``str``
+        :param new_stack: A reference of the new stack.
+        :type new_stack: :class:`heat.resources.stack`
+        :return: * *True*: if the old stack could be updated to the new stack without any error.
+            * *False*: else
+        :rtype: ``bool``
+        """
+        if old_stack_id not in self.stacks:
+            return False
+        old_stack = self.stacks[old_stack_id]
+
+        # Update Stack IDs
+        for server in old_stack.servers.values():
+            if server.name in new_stack.servers:
+                new_stack.servers[server.name].id = server.id
+        for net in old_stack.nets.values():
+            if net.name in new_stack.nets:
+                new_stack.nets[net.name].id = net.id
+                for subnet in new_stack.nets.values():
+                    if subnet.subnet_name == net.subnet_name:
+                        subnet.subnet_id = net.subnet_id
+                        break
+        for port in old_stack.ports.values():
+            if port.name in new_stack.ports:
+                new_stack.ports[port.name].id = port.id
+        for router in old_stack.routers.values():
+            if router.name in new_stack.routers:
+                new_stack.routers[router.name].id = router.id
+
+        # Update the compute dicts to now contain the new_stack components
+        self.update_compute_dicts(new_stack)
+
+        self.update_ip_addresses(old_stack, new_stack)
+
+        # Update all interface names - after each port has the correct UUID!!
+        for port in new_stack.ports.values():
+            port.create_intf_name()
+
+        if not self.check_stack(new_stack):
+            return False
+
+        # Remove unnecessary networks
+        for net in old_stack.nets.values():
+            if not net.name in new_stack.nets:
+                self.delete_network(net.id)
+
+        # Remove all unnecessary servers
+        for server in old_stack.servers.values():
+            if server.name in new_stack.servers:
+                if not server.compare_attributes(new_stack.servers[server.name]):
+                    self.stop_compute(server)
+                else:
+                    # Delete unused and changed links
+                    for port_name in server.port_names:
+                        if port_name in old_stack.ports and port_name in new_stack.ports:
+                            if not old_stack.ports.get(port_name) == new_stack.ports.get(port_name):
+                                my_links = self.dc.net.links
+                                for link in my_links:
+                                    if str(link.intf1) == old_stack.ports[port_name].intf_name and \
+                                                    str(link.intf1.ip) == \
+                                                    old_stack.ports[port_name].ip_address.split('/')[0]:
+                                        self._remove_link(server.name, link)
+
+                                        # Add changed link
+                                        self._add_link(server.name,
+                                                       new_stack.ports[port_name].ip_address,
+                                                       new_stack.ports[port_name].intf_name,
+                                                       new_stack.ports[port_name].net_name)
+                                        break
+                        else:
+                            my_links = self.dc.net.links
+                            for link in my_links:
+                                if str(link.intf1) == old_stack.ports[port_name].intf_name and \
+                                   str(link.intf1.ip) == old_stack.ports[port_name].ip_address.split('/')[0]:
+                                    self._remove_link(server.name, link)
+                                    break
+
+                    # Create new links
+                    for port_name in new_stack.servers[server.name].port_names:
+                        if port_name not in server.port_names:
+                            self._add_link(server.name,
+                                           new_stack.ports[port_name].ip_address,
+                                           new_stack.ports[port_name].intf_name,
+                                           new_stack.ports[port_name].net_name)
+            else:
+                self.stop_compute(server)
+
+        # Start all new servers
+        for server in new_stack.servers.values():
+            if server.name not in self.dc.containers:
+                self._start_compute(server)
+            else:
+                server.emulator_compute = self.dc.containers.get(server.name)
+
+        del self.stacks[old_stack_id]
+        self.stacks[new_stack.id] = new_stack
+        return True
+
+    def update_ip_addresses(self, old_stack, new_stack):
+        """
+        Updates the subnet and the port IP addresses - which should always be in this order!
+
+        :param old_stack: The currently running stack
+        :type old_stack: :class:`heat.resources.stack`
+        :param new_stack: The new created stack
+        :type new_stack: :class:`heat.resources.stack`
+        """
+        self.update_subnet_cidr(old_stack, new_stack)
+        self.update_port_addresses(old_stack, new_stack)
+
+    def update_port_addresses(self, old_stack, new_stack):
+        """
+        Updates the port IP addresses. First resets all issued addresses. Then get all IP addresses from the old
+        stack and sets them to the same ports in the new stack. Finally all new or changed instances will get new
+        IP addresses.
+
+        :param old_stack: The currently running stack
+        :type old_stack: :class:`heat.resources.stack`
+        :param new_stack: The new created stack
+        :type new_stack: :class:`heat.resources.stack`
+        """
+        for net in new_stack.nets.values():
+            net.reset_issued_ip_addresses()
+
+        for old_port in old_stack.ports.values():
+            for port in new_stack.ports.values():
+                if port.compare_attributes(old_port):
+                    for net in new_stack.nets.values():
+                        if net.name == port.net_name:
+                            if net.assign_ip_address(old_port.ip_address, port.name):
+                                port.ip_address = old_port.ip_address
+                                port.mac_address = old_port.mac_address
+                            else:
+                                port.ip_address = net.get_new_ip_address(port.name)
+
+        for port in new_stack.ports.values():
+            for net in new_stack.nets.values():
+                if port.net_name == net.name and not net.is_my_ip(port.ip_address, port.name):
+                    port.ip_address = net.get_new_ip_address(port.name)
+
+    def update_subnet_cidr(self, old_stack, new_stack):
+        """
+        Updates the subnet IP addresses. If the new stack contains subnets from the old stack it will take those
+        IP addresses. Otherwise it will create new IP addresses for the subnet.
+
+        :param old_stack: The currently running stack
+        :type old_stack: :class:`heat.resources.stack`
+        :param new_stack: The new created stack
+        :type new_stack: :class:`heat.resources.stack`
+        """
+        for old_subnet in old_stack.nets.values():
+            IP.free_cidr(old_subnet.get_cidr(), old_subnet.subnet_id)
+
+        for subnet in new_stack.nets.values():
+            subnet.clear_cidr()
+            for old_subnet in old_stack.nets.values():
+                if subnet.subnet_name == old_subnet.subnet_name:
+                    if IP.assign_cidr(old_subnet.get_cidr(), subnet.subnet_id):
+                        subnet.set_cidr(old_subnet.get_cidr())
+
+        for subnet in new_stack.nets.values():
+            if IP.is_cidr_issued(subnet.get_cidr()):
+                continue
+
+            cird = IP.get_new_cidr(subnet.subnet_id)
+            subnet.set_cidr(cird)
+        return
+
+    def update_compute_dicts(self, stack):
+        """
+        Update and add all stack components tho the compute dictionaries.
+
+        :param stack: A stack reference, to get all required components.
+        :type stack: :class:`heat.resources.stack`
+        """
+        for server in stack.servers.values():
+            self.computeUnits[server.id] = server
+            if isinstance(server.flavor, dict):
+                self.add_flavor(server.flavor['flavorName'],
+                                server.flavor['vcpu'],
+                                server.flavor['ram'], 'MB',
+                                server.flavor['storage'], 'GB')
+                server.flavor = server.flavor['flavorName']
+        for router in stack.routers.values():
+            self.routers[router.id] = router
+        for net in stack.nets.values():
+            self.nets[net.id] = net
+        for port in stack.ports.values():
+            self.ports[port.id] = port
+
+    def _start_compute(self, server):
+        """
+        Starts a new compute object (docker container) inside the emulator.
+        Should only be called by stack modifications and not directly.
+
+        :param server: Specifies the compute resource.
+        :type server: :class:`heat.resources.server`
+        """
+        logging.debug("Starting new compute resources %s" % server.name)
+        network = list()
+
+        for port_name in server.port_names:
+            network_dict = dict()
+            port = self.find_port_by_name_or_id(port_name)
+            if port is not None:
+                network_dict['id'] = port.intf_name
+                network_dict['ip'] = port.ip_address
+                network_dict[network_dict['id']] = self.find_network_by_name_or_id(port.net_name).name
+                network.append(network_dict)
+        self.compute_nets[server.name] = network
+        c = self.dc.startCompute(server.name, image=server.image, command=server.command,
+                                 network=network, flavor_name=server.flavor)
+        server.emulator_compute = c
+
+        for intf in c.intfs.values():
+            for port_name in server.port_names:
+                port = self.find_port_by_name_or_id(port_name)
+                if port is not None:
+                    if intf.name == port.intf_name:
+                        # wait up to one second for the intf to come up
+                        self.timeout_sleep(intf.isUp, 1)
+                        if port.mac_address is not None:
+                            intf.setMAC(port.mac_address)
+                        else:
+                            port.mac_address = intf.MAC()
+
+        # Start the real emulator command now as specified in the dockerfile
+        # ENV SON_EMU_CMD
+        config = c.dcinfo.get("Config", dict())
+        env = config.get("Env", list())
+        for env_var in env:
+            if "SON_EMU_CMD=" in env_var:
+                cmd = str(env_var.split("=")[1])
+                server.son_emu_command = cmd
+                # execute command in new thread to ensure that GK is not blocked by VNF
+                t = threading.Thread(target=c.cmdPrint, args=(cmd,))
+                t.daemon = True
+                t.start()
+
+    def stop_compute(self, server):
+        """
+        Determines which links should be removed before removing the server itself.
+
+        :param server: The server that should be removed
+        :type server: ``heat.resources.server``
+        """
+        logging.debug("Stopping container %s with full name %s" % (server.name, server.full_name))
+        link_names = list()
+        for port_name in server.port_names:
+            link_names.append(self.find_port_by_name_or_id(port_name).intf_name)
+        my_links = self.dc.net.links
+        for link in my_links:
+            if str(link.intf1) in link_names:
+                # Remove all self created links that connect the server to the main switch
+                self._remove_link(server.name, link)
+
+        # Stop the server and the remaining connection to the datacenter switch
+        self.dc.stopCompute(server.name)
+        # Only now delete all its ports and the server itself
+        for port_name in server.port_names:
+            self.delete_port(port_name)
+        self.delete_server(server)
+
+    def find_server_by_name_or_id(self, name_or_id):
+        """
+        Tries to find the server by ID and if this does not succeed then tries to find it via name.
+
+        :param name_or_id: UUID or name of the server.
+        :type name_or_id: ``str``
+        :return: Returns the server reference if it was found or None
+        :rtype: :class:`heat.resources.server`
+        """
+        if name_or_id in self.computeUnits:
+            return self.computeUnits[name_or_id]
+
+        for server in self.computeUnits.values():
+            if server.name == name_or_id or server.template_name == name_or_id or server.full_name == name_or_id:
+                return server
+        return None
+
+    def create_server(self, name, stack_operation=False):
+        """
+        Creates a server with the specified name. Raises an exception when a server with the given name already
+        exists!
+
+        :param name: Name of the new server.
+        :type name: ``str``
+        :param stack_operation: Allows the heat parser to create modules without adapting the current emulation.
+        :type stack_operation: ``bool``
+        :return: Returns the created server.
+        :rtype: :class:`heat.resources.server`
+        """
+        if self.find_server_by_name_or_id(name) is not None and not stack_operation:
+            raise Exception("Server with name %s already exists." % name)
+        server = Server(name)
+        server.id = str(uuid.uuid4())
+        if not stack_operation:
+            self.computeUnits[server.id] = server
+        return server
+
+    def delete_server(self, server):
+        """
+        Deletes the given server from the stack dictionary and the computeUnits dictionary.
+
+        :param server: Reference of the server that should be deleted.
+        :type server: :class:`heat.resources.server`
+        :return: * *False*: If the server name is not in the correct format ('datacentername_stackname_servername') \
+                or when no stack with the correct stackname was found.
+            * *True*: Else
+        :rtype: ``bool``
+        """
+        if server is None:
+            return False
+        name_parts = server.name.split('_')
+        if len(name_parts) < 3:
+            return False
+
+        for stack in self.stacks.values():
+            if stack.stack_name == name_parts[1]:
+                stack.servers.pop(server.id, None)
+        if self.computeUnits.pop(server.id, None) is None:
+            return False
+        return True
+
+    def find_network_by_name_or_id(self, name_or_id):
+        """
+        Tries to find the network by ID and if this does not succeed then tries to find it via name.
+
+        :param name_or_id: UUID or name of the network.
+        :type name_or_id: ``str``
+        :return: Returns the network reference if it was found or None
+        :rtype: :class:`heat.resources.net`
+        """
+        if name_or_id in self.nets:
+            return self.nets[name_or_id]
+        for net in self.nets.values():
+            if net.name == name_or_id:
+                return net
+
+        return None
+
+    def create_network(self, name, stack_operation=False):
+        """
+        Creates a new network with the given name. Raises an exception when a network with the given name already
+        exists!
+
+        :param name: Name of the new network.
+        :type name: ``str``
+        :param stack_operation: Allows the heat parser to create modules without adapting the current emulation.
+        :type stack_operation: ``bool``
+        :return: :class:`heat.resources.net`
+        """
+        logging.debug("Creating network with name %s" % name)
+        if self.find_network_by_name_or_id(name) is not None and not stack_operation:
+            logging.warning("Creating network with name %s failed, as it already exists" % name)
+            raise Exception("Network with name %s already exists." % name)
+        network = Net(name)
+        network.id = str(uuid.uuid4())
+        if not stack_operation:
+            self.nets[network.id] = network
+        return network
+
+    def delete_network(self, name_or_id):
+        """
+        Deletes the given network.
+
+        :param name_or_id: Name or UUID of the network.
+        :type name_or_id: ``str``
+        """
+        net = self.find_network_by_name_or_id(name_or_id)
+        if net is None:
+            raise Exception("Network with name or id %s does not exists." % name_or_id)
+
+        for stack in self.stacks.values():
+            stack.nets.pop(net.name, None)
+
+        self.nets.pop(net.id, None)
+
+    def create_port(self, name, stack_operation=False):
+        """
+        Creates a new port with the given name. Raises an exception when a port with the given name already
+        exists!
+
+        :param name: Name of the new port.
+        :type name: ``str``
+        :param stack_operation: Allows the heat parser to create modules without adapting the current emulation.
+        :type stack_operation: ``bool``
+        :return: Returns the created port.
+        :rtype: :class:`heat.resources.port`
+        """
+        port = self.find_port_by_name_or_id(name)
+        if port is not None and not stack_operation:
+            logging.warning("Creating port with name %s failed, as it already exists" % name)
+            raise Exception("Port with name %s already exists." % name)
+        logging.debug("Creating port with name %s" % name)
+        port = Port(name)
+        if not stack_operation:
+            self.ports[port.id] = port
+            port.create_intf_name()
+        return port
+
+    def find_port_by_name_or_id(self, name_or_id):
+        """
+        Tries to find the port by ID and if this does not succeed then tries to find it via name.
+
+        :param name_or_id: UUID or name of the network.
+        :type name_or_id: ``str``
+        :return: Returns the port reference if it was found or None
+        :rtype: :class:`heat.resources.port`
+        """
+        if name_or_id in self.ports:
+            return self.ports[name_or_id]
+        for port in self.ports.values():
+            if port.name == name_or_id or port.template_name == name_or_id:
+                return port
+
+        return None
+
+    def delete_port(self, name_or_id):
+        """
+        Deletes the given port. Raises an exception when the port was not found!
+
+        :param name_or_id:  UUID or name of the port.
+        :type name_or_id: ``str``
+        """
+        port = self.find_port_by_name_or_id(name_or_id)
+        if port is None:
+            raise Exception("Port with name or id %s does not exists." % name_or_id)
+
+        my_links = self.dc.net.links
+        for link in my_links:
+            if str(link.intf1) == port.intf_name and \
+                            str(link.intf1.ip) == port.ip_address.split('/')[0]:
+                self._remove_link(link.intf1.node.name, link)
+                break
+
+        self.ports.pop(port.id, None)
+        for stack in self.stacks.values():
+            stack.ports.pop(port.name, None)
+
+    def _add_link(self, node_name, ip_address, link_name, net_name):
+        """
+        Adds a new link between datacenter switch and the node with the given name.
+
+        :param node_name: Name of the required node.
+        :type node_name: ``str``
+        :param ip_address: IP-Address of the node.
+        :type ip_address: ``str``
+        :param link_name: Link name.
+        :type link_name: ``str``
+        :param net_name: Network name.
+        :type net_name: ``str``
+        """
+        node = self.dc.net.get(node_name)
+        params = {'params1': {'ip': ip_address,
+                              'id': link_name,
+                              link_name: net_name},
+                  'intfName1': link_name,
+                  'cls': Link}
+        link = self.dc.net.addLink(node, self.dc.switch, **params)
+        OpenstackCompute.timeout_sleep(link.intf1.isUp, 1)
+
+    def _remove_link(self, server_name, link):
+        """
+        Removes a link between server and datacenter switch.
+
+        :param server_name: Specifies the server where the link starts.
+        :type server_name: ``str``
+        :param link: A reference of the link which should be removed.
+        :type link: :class:`mininet.link`
+        """
+        self.dc.switch.detach(link.intf2)
+        del self.dc.switch.intfs[self.dc.switch.ports[link.intf2]]
+        del self.dc.switch.ports[link.intf2]
+        del self.dc.switch.nameToIntf[link.intf2.name]
+        self.dc.net.removeLink(link=link)
+        self.dc.net.DCNetwork_graph.remove_edge(server_name, self.dc.switch.name)
+        self.dc.net.DCNetwork_graph.remove_edge(self.dc.switch.name, server_name)
+        for intf_key in self.dc.net[server_name].intfs.keys():
+            if self.dc.net[server_name].intfs[intf_key].link == link:
+                self.dc.net[server_name].intfs[intf_key].delete()
+                del self.dc.net[server_name].intfs[intf_key]
+
+    @staticmethod
+    def timeout_sleep(function, max_sleep):
+        """
+        This function will execute a function all 0.1 seconds until it successfully returns.
+        Will return after `max_sleep` seconds if not successful.
+
+        :param function: The function to execute. Should return true if done.
+        :type function: ``function``
+        :param max_sleep: Max seconds to sleep. 1 equals 1 second.
+        :type max_sleep: ``float``
+        """
+        current_time = time.time()
+        stop_time = current_time + max_sleep
+        while not function() and current_time < stop_time:
+            current_time = time.time()
+            time.sleep(0.1)