blob: b612e87760b8449b799b1299e91c9bb3172fb3be [file] [log] [blame]
peusterm9c252b62016-01-06 16:59:53 +01001"""
peusterm79ef6ae2016-07-08 13:53:57 +02002Copyright (c) 2015 SONATA-NFV and Paderborn University
3ALL RIGHTS RESERVED.
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
18nor the names of its contributors may be used to endorse or promote
19products derived from this software without specific prior written
20permission.
21
22This work has been performed in the framework of the SONATA project,
23funded by the European Commission under Grant number 671517 through
24the Horizon 2020 and 5G-PPP programmes. The authors would like to
25acknowledge the contributions of their colleagues of the SONATA
26partner consortium (www.sonata-nfv.eu).
27"""
28"""
peusterm9c252b62016-01-06 16:59:53 +010029Distributed Cloud Emulator (dcemulator)
30(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
31"""
32
33import logging
34import threading
35import zerorpc
36
peustermbd44f4a2016-01-13 14:53:30 +010037logging.basicConfig(level=logging.INFO)
peusterm9c252b62016-01-06 16:59:53 +010038
39
40class ZeroRpcApiEndpoint(object):
peusterme4e89d32016-01-07 09:14:54 +010041 """
42 Simple API endpoint that offers a zerorpc-based
43 interface. This interface will be used by the
44 default command line client.
45 It can be used as a reference to implement
46 REST interfaces providing the same semantics,
47 like e.g. OpenStack compute API.
48 """
peusterm9c252b62016-01-06 16:59:53 +010049
50 def __init__(self, listenip, port):
51 self.dcs = {}
52 self.ip = listenip
53 self.port = port
54 logging.debug("Created API endpoint %s(%s:%d)" % (
55 self.__class__.__name__, self.ip, self.port))
56
57 def connectDatacenter(self, dc):
peusterma47db032016-02-04 14:55:29 +010058 self.dcs[dc.label] = dc
peusterm9c252b62016-01-06 16:59:53 +010059 logging.info("Connected DC(%s) to API endpoint %s(%s:%d)" % (
peusterma47db032016-02-04 14:55:29 +010060 dc.label, self.__class__.__name__, self.ip, self.port))
peusterm9c252b62016-01-06 16:59:53 +010061
62 def start(self):
63 thread = threading.Thread(target=self._api_server_thread, args=())
64 thread.daemon = True
65 thread.start()
66 logging.debug("Started API endpoint %s(%s:%d)" % (
67 self.__class__.__name__, self.ip, self.port))
68
69 def _api_server_thread(self):
70 s = zerorpc.Server(MultiDatacenterApi(self.dcs))
71 s.bind("tcp://%s:%d" % (self.ip, self.port))
72 s.run()
73
74
75class MultiDatacenterApi(object):
peusterme4e89d32016-01-07 09:14:54 +010076 """
77 Just pass through the corresponding request to the
78 selected data center. Do not implement provisioning
79 logic here because will will have multiple API
80 endpoint implementations at the end.
81 """
peusterm9c252b62016-01-06 16:59:53 +010082
83 def __init__(self, dcs):
84 self.dcs = dcs
85
stevenvanrossem994245b2016-05-04 12:36:57 +020086 def compute_action_start(self, dc_label, compute_name, image, network, command):
peusterm7f8e8402016-02-28 18:38:10 +010087 """
stevenvanrossem994245b2016-05-04 12:36:57 +020088 Start a new compute instance: A docker container (note: zerorpc does not support keyword arguments)
peusterm7f8e8402016-02-28 18:38:10 +010089 :param dc_label: name of the DC
90 :param compute_name: compute container name
91 :param image: image name
92 :param command: command to execute
stevenvanrossem14c89052016-04-10 23:49:59 +020093 :param network: list of all interface of the vnf, with their parameters (id=id1,ip=x.x.x.x/x),...
94 :return: networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"})
peusterm7f8e8402016-02-28 18:38:10 +010095 """
peusterm4e98b632016-01-12 14:08:07 +010096 # TODO what to return UUID / given name / internal name ?
peusterm70baaf82016-01-06 17:14:40 +010097 logging.debug("RPC CALL: compute start")
peusterm7aae6852016-01-12 14:53:18 +010098 try:
peusterm53504942016-02-04 16:09:28 +010099 c = self.dcs.get(dc_label).startCompute(
stevenvanrossem8fbf9782016-02-17 11:40:23 +0100100 compute_name, image=image, command=command, network=network)
stevenvanrosseme66ef122016-05-03 11:22:54 +0200101 #return str(c.name)
102 # return docker inspect dict
103 return c.getStatus()
peusterm7aae6852016-01-12 14:53:18 +0100104 except Exception as ex:
105 logging.exception("RPC error.")
106 return ex.message
peusterm9c252b62016-01-06 16:59:53 +0100107
peusterm53504942016-02-04 16:09:28 +0100108 def compute_action_stop(self, dc_label, compute_name):
peustermbd44f4a2016-01-13 14:53:30 +0100109 logging.debug("RPC CALL: compute stop")
peusterm7aae6852016-01-12 14:53:18 +0100110 try:
peusterm53504942016-02-04 16:09:28 +0100111 return self.dcs.get(dc_label).stopCompute(compute_name)
peusterm7aae6852016-01-12 14:53:18 +0100112 except Exception as ex:
113 logging.exception("RPC error.")
114 return ex.message
peusterm9c252b62016-01-06 16:59:53 +0100115
peusterm53504942016-02-04 16:09:28 +0100116 def compute_list(self, dc_label):
peustermbd44f4a2016-01-13 14:53:30 +0100117 logging.debug("RPC CALL: compute list")
peusterm7aae6852016-01-12 14:53:18 +0100118 try:
peusterm53504942016-02-04 16:09:28 +0100119 if dc_label is None:
peusterm2ec74e12016-01-13 11:17:53 +0100120 # return list with all compute nodes in all DCs
121 all_containers = []
122 for dc in self.dcs.itervalues():
123 all_containers += dc.listCompute()
124 return [(c.name, c.getStatus())
125 for c in all_containers]
126 else:
127 # return list of compute nodes for specified DC
128 return [(c.name, c.getStatus())
peusterm53504942016-02-04 16:09:28 +0100129 for c in self.dcs.get(dc_label).listCompute()]
peusterm7aae6852016-01-12 14:53:18 +0100130 except Exception as ex:
131 logging.exception("RPC error.")
132 return ex.message
peusterm4e98b632016-01-12 14:08:07 +0100133
peusterm53504942016-02-04 16:09:28 +0100134 def compute_status(self, dc_label, compute_name):
peustermbd44f4a2016-01-13 14:53:30 +0100135 logging.debug("RPC CALL: compute status")
peusterm7aae6852016-01-12 14:53:18 +0100136 try:
137 return self.dcs.get(
peusterm53504942016-02-04 16:09:28 +0100138 dc_label).containers.get(compute_name).getStatus()
peusterm7aae6852016-01-12 14:53:18 +0100139 except Exception as ex:
140 logging.exception("RPC error.")
141 return ex.message
peustermd313dc12016-02-04 15:36:02 +0100142
143 def datacenter_list(self):
144 logging.debug("RPC CALL: datacenter list")
145 try:
146 return [d.getStatus() for d in self.dcs.itervalues()]
147 except Exception as ex:
148 logging.exception("RPC error.")
149 return ex.message
peusterm53504942016-02-04 16:09:28 +0100150
151 def datacenter_status(self, dc_label):
152 logging.debug("RPC CALL: datacenter status")
153 try:
154 return self.dcs.get(dc_label).getStatus()
155 except Exception as ex:
156 logging.exception("RPC error.")
157 return ex.message
stevenvanrossem994245b2016-05-04 12:36:57 +0200158
stevenvanrossem994245b2016-05-04 12:36:57 +0200159