See the License for the specific language governing permissions and
limitations under the License.
-Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
+Neither the name of the SONATA-NFV, Paderborn University
nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
acknowledge the contributions of their colleagues of the SONATA
partner consortium (www.sonata-nfv.eu).
"""
-from mininet.node import Docker
+from mininet.node import Docker, OVSBridge
from mininet.link import Link
from emuvim.dcemulator.resourcemodel import NotEnoughResourcesAvailable
import logging
-import time
-import json
+
LOG = logging.getLogger("dcemulator.node")
LOG.setLevel(logging.DEBUG)
DCDPID_BASE = 1000 # start of switch dpid's used for data center switches
-
+EXTSAPDPID_BASE = 2000 # start of switch dpid's used for external SAP switches
class EmulatorCompute(Docker):
"""
Helper method to receive information about the virtual networks
this compute instance is connected to.
"""
- # format list of tuples (name, Ip, MAC, isUp, status)
- return [{'intf_name':str(i), 'ip':i.IP(), 'mac':i.MAC(), 'up':i.isUp(), 'status':i.status()}
- for i in self.intfList()]
+ # get all links and find dc switch interface
+ networkStatusList = []
+ for i in self.intfList():
+ vnf_name = self.name
+ vnf_interface = str(i)
+ dc_port_name = self.datacenter.net.find_connected_dc_interface(vnf_name, vnf_interface)
+ # format list of tuples (name, Ip, MAC, isUp, status, dc_portname)
+ intf_dict = {'intf_name': str(i), 'ip': "{0}/{1}".format(i.IP(), i.prefixLen), 'netmask': i.prefixLen, 'mac': i.MAC(), 'up': i.isUp(), 'status': i.status(), 'dc_portname': dc_port_name}
+ networkStatusList.append(intf_dict)
+
+ return networkStatusList
def getStatus(self):
"""
status["docker_network"] = self.dcinfo['NetworkSettings']['IPAddress']
status["image"] = self.dimage
status["flavor_name"] = self.flavor_name
- status["cpu_quota"] = self.cpu_quota
- status["cpu_period"] = self.cpu_period
- status["cpu_shares"] = self.cpu_shares
- status["cpuset"] = self.cpuset
- status["mem_limit"] = self.mem_limit
- status["memswap_limit"] = self.memswap_limit
+ status["cpu_quota"] = self.resources.get('cpu_quota')
+ status["cpu_period"] = self.resources.get('cpu_period')
+ status["cpu_shares"] = self.resources.get('cpu_shares')
+ status["cpuset"] = self.resources.get('cpuset_cpus')
+ status["mem_limit"] = self.resources.get('mem_limit')
+ status["memswap_limit"] = self.resources.get('memswap_limit')
status["state"] = self.dcli.inspect_container(self.dc)["State"]
status["id"] = self.dcli.inspect_container(self.dc)["Id"]
+ status["short_id"] = self.dcli.inspect_container(self.dc)["Id"][:12]
+ status["hostname"] = self.dcli.inspect_container(self.dc)["Config"]['Hostname']
status["datacenter"] = (None if self.datacenter is None
else self.datacenter.label)
+
return status
+class EmulatorExtSAP(object):
+ """
+ Emulator specific class that defines an external service access point (SAP) for the service.
+ Inherits from Containernet's OVSBridge class.
+ Represents a single OVS switch connected to a (logical)
+ data center.
+ We can add emulator specific helper functions to it.
+ """
+
+ def __init__(self, sap_name, sap_net, datacenter, **kwargs):
+
+ self.datacenter = datacenter # pointer to current DC
+ self.net = self.datacenter.net
+ self.name = sap_name
+
+ LOG.debug("Starting ext SAP instance %r in data center %r" % (sap_name, str(self.datacenter)))
+
+ # create SAP as separate OVS switch with an assigned ip address
+ self.ip = str(sap_net[1]) + '/' + str(sap_net.prefixlen)
+ self.subnet = sap_net
+ # allow connection to the external internet through the host
+ params = dict(NAT=True)
+ self.switch = self.net.addExtSAP(sap_name, self.ip, dpid=hex(self._get_next_extSAP_dpid())[2:], **params)
+ self.switch.start()
+
+ def _get_next_extSAP_dpid(self):
+ global EXTSAPDPID_BASE
+ EXTSAPDPID_BASE += 1
+ return EXTSAPDPID_BASE
+
+ def getNetworkStatus(self):
+ """
+ Helper method to receive information about the virtual networks
+ this compute instance is connected to.
+ """
+ # get all links and find dc switch interface
+ networkStatusList = []
+ for i in self.switch.intfList():
+ vnf_name = self.name
+ vnf_interface = str(i)
+ if vnf_interface == 'lo':
+ continue
+ dc_port_name = self.datacenter.net.find_connected_dc_interface(vnf_name, vnf_interface)
+ # format list of tuples (name, Ip, MAC, isUp, status, dc_portname)
+ intf_dict = {'intf_name': str(i), 'ip': self.ip, 'netmask': i.prefixLen, 'mac': i.MAC(), 'up': i.isUp(), 'status': i.status(), 'dc_portname': dc_port_name}
+ networkStatusList.append(intf_dict)
+
+ return networkStatusList
+
+ def getStatus(self):
+ return {
+ "name": self.switch.name,
+ "datacenter": self.datacenter.name,
+ "network": self.getNetworkStatus()
+ }
+
class Datacenter(object):
"""
Represents a logical data center to which compute resources
self.name = "dc%d" % Datacenter.DC_COUNTER
Datacenter.DC_COUNTER += 1
# use this for user defined names that can be longer than self.name
- self.label = label
+ self.label = label
# dict to store arbitrary metadata (e.g. latitude and longitude)
self.metadata = metadata
# path to which resource information should be logged (e.g. for experiments). None = no logging
self.switch = None
# keep track of running containers
self.containers = {}
+ # keep track of attached external access points
+ self.extSAPs = {}
# pointer to assigned resource model
self._resource_model = None
def start(self):
pass
- def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny"):
+ def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny", properties=dict(), **params):
"""
Create a new container as compute resource and connect it to this
data center.
:param command: command (string)
:param network: networks list({"ip": "10.0.0.254/8"}, {"ip": "11.0.0.254/24"})
:param flavor_name: name of the flavor for this compute container
+ :param properties: dictionary of properties (key-value) that will be passed as environment variables
:return:
"""
assert name is not None
if len(network) < 1:
network.append({})
+ # apply hard-set resource limits=0
+ cpu_percentage = params.get('cpu_percent')
+ if cpu_percentage:
+ params['cpu_period'] = self.net.cpu_period
+ params['cpu_quota'] = self.net.cpu_period * float(cpu_percentage)
+
+ env = properties
+ properties['VNF_NAME'] = name
# create the container
d = self.net.addDocker(
"%s" % (name),
dimage=image,
dcmd=command,
datacenter=self,
- flavor_name=flavor_name
+ flavor_name=flavor_name,
+ environment = env,
+ **params
)
+
+
# apply resource limits to container if a resource model is defined
if self._resource_model is not None:
try:
self.net.addLink(d, self.switch, params1=nw, cls=Link, intfName1=nw.get('id'))
# do bookkeeping
self.containers[name] = d
+
return d # we might use UUIDs for naming later on
def stopCompute(self, name):
return True
+ def attachExternalSAP(self, sap_name, sap_net, **params):
+ extSAP = EmulatorExtSAP(sap_name, sap_net, self, **params)
+ # link SAP to the DC switch
+ self.net.addLink(extSAP.switch, self.switch, cls=Link)
+ self.extSAPs[sap_name] = extSAP
+
+ def removeExternalSAP(self, sap_name):
+ sap_switch = self.extSAPs[sap_name].switch
+ #sap_switch = self.net.getNodeByName(sap_name)
+ # remove link of SAP to the DC switch
+ self.net.removeLink(link=None, node1=sap_switch, node2=self.switch)
+ self.net.removeExtSAP(sap_name)
+ del self.extSAPs[sap_name]
+
def listCompute(self):
"""
Return a list of all running containers assigned to this
"""
return list(self.containers.itervalues())
+ def listExtSAPs(self):
+ """
+ Return a list of all external SAPs assigned to this
+ data center.
+ """
+ return list(self.extSAPs.itervalues())
+
def getStatus(self):
"""
Return a dict with status information about this DC.
"""
+ container_list = [name for name in self.containers]
+ ext_saplist = [sap_name for sap_name in self.extSAPs]
return {
"label": self.label,
"internalname": self.name,
"switch": self.switch.name,
"n_running_containers": len(self.containers),
- "metadata": self.metadata
+ "metadata": self.metadata,
+ "vnf_list" : container_list,
+ "ext SAP list" : ext_saplist
}
def assignResourceModel(self, rm):