2 Copyright (c) 2015 SONATA-NFV and Paderborn University
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
17 Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
29 from flask_restful
import Resource
30 from flask
import request
32 from copy
import deepcopy
36 CORS_HEADER
= {'Access-Control-Allow-Origin': '*'}
38 # the dcs dict is set in the rest_api_endpoint.py upon datacenter init
42 class Compute(Resource
):
44 Start a new compute instance: A docker container (note: zerorpc does not support keyword arguments)
45 :param dc_label: name of the DC
46 :param compute_name: compute container name
47 :param image: image name
48 :param command: command to execute
49 :param network: list of all interface of the vnf, with their parameters (id=id1,ip=x.x.x.x/x),...
50 example networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"})
51 :return: docker inspect dict of deployed docker
56 def put(self
, dc_label
, compute_name
, resource
=None, value
=None):
58 # deploy new container
59 # check if json data is a dict
63 elif type(data
) is not dict:
64 data
= json
.loads(request
.json
)
66 network
= data
.get("network")
67 nw_list
= self
._parse
_network
(network
)
68 image
= data
.get("image")
69 command
= data
.get("docker_command")
72 logging
.debug("API CALL: compute start")
73 c
= dcs
.get(dc_label
).startCompute(
74 compute_name
, image
=image
, command
=command
, network
=nw_list
)
75 # return docker inspect dict
76 return c
.getStatus(), 200, CORS_HEADER
77 except Exception as ex
:
78 logging
.exception("API error.")
79 return ex
.message
, 500, CORS_HEADER
81 def get(self
, dc_label
, compute_name
):
83 logging
.debug("API CALL: compute status")
86 return dcs
.get(dc_label
).containers
.get(compute_name
).getStatus(), 200, CORS_HEADER
87 except Exception as ex
:
88 logging
.exception("API error.")
89 return ex
.message
, 500, CORS_HEADER
91 def delete(self
, dc_label
, compute_name
):
92 logging
.debug("API CALL: compute stop")
94 return dcs
.get(dc_label
).stopCompute(compute_name
), 200, CORS_HEADER
95 except Exception as ex
:
96 logging
.exception("API error.")
97 return ex
.message
, 500, CORS_HEADER
99 def _parse_network(self
, network_str
):
101 parse the options for all network interfaces of the vnf
102 :param network_str: (id=x,ip=x.x.x.x/x), ...
103 :return: list of dicts [{"id":x,"ip":"x.x.x.x/x"}, ...]
107 # TODO make this more robust with regex check
108 if network_str
is None:
111 networks
= network_str
[1:-1].split('),(')
113 nw_dict
= dict(tuple(e
.split('=')) for e
in nw
.split(','))
114 nw_list
.append(nw_dict
)
119 class ComputeList(Resource
):
122 def get(self
, dc_label
=None):
123 logging
.debug("API CALL: compute list")
125 if dc_label
is None or dc_label
== 'None':
126 # return list with all compute nodes in all DCs
129 for dc
in dcs
.itervalues():
130 all_containers
+= dc
.listCompute()
131 all_extSAPs
+= dc
.listExtSAPs()
133 extSAP_list
= [(sap
.name
, sap
.getStatus()) for sap
in all_extSAPs
]
134 container_list
= [(c
.name
, c
.getStatus()) for c
in all_containers
]
135 total_list
= container_list
+ extSAP_list
136 return total_list
, 200, CORS_HEADER
138 # return list of compute nodes for specified DC
139 container_list
= [(c
.name
, c
.getStatus()) for c
in dcs
.get(dc_label
).listCompute()]
140 extSAP_list
= [(sap
.name
, sap
.getStatus()) for sap
in dcs
.get(dc_label
).listExtSAPs()]
141 total_list
= container_list
+ extSAP_list
142 return total_list
, 200, CORS_HEADER
143 except Exception as ex
:
144 logging
.exception("API error.")
145 return ex
.message
, 500, CORS_HEADER
147 class ComputeResources(Resource
):
149 Update the container's resources using the docker.update function
150 re-using the same parameters:
153 cpu_period, cpu_quota, cpu_shares
161 see https://docs.docker.com/engine/reference/commandline/update/
162 or API docs: https://docker-py.readthedocs.io/en/stable/api.html#module-docker.api.container
163 :param dc_label: name of the DC
164 :param compute_name: compute container name
166 :return: docker inspect dict of deployed docker
170 def put(self
, dc_label
, compute_name
):
171 logging
.debug("REST CALL: update container resources")
174 c
= self
._update
_resources
(dc_label
, compute_name
)
175 return c
.getStatus(), 200, CORS_HEADER
176 except Exception as ex
:
177 logging
.exception("API error.")
178 return ex
.message
, 500, CORS_HEADER
180 def _update_resources(self
, dc_label
, compute_name
):
183 params
= request
.args
187 logging
.debug("REST CALL: update container resources {0}".format(params
))
188 #check if container exists
189 d
= dcs
.get(dc_label
).net
.getNodeByName(compute_name
)
191 # general request of cpu percentage
192 # create a mutable copy
193 params
= params
.to_dict()
194 if 'cpu_bw' in params
:
195 cpu_period
= int(dcs
.get(dc_label
).net
.cpu_period
)
196 value
= params
.get('cpu_bw')
197 cpu_quota
= int(cpu_period
* float(value
))
198 #put default values back
199 if float(value
) <= 0:
202 params
['cpu_period'] = cpu_period
203 params
['cpu_quota'] = cpu_quota
204 #d.updateCpuLimit(cpu_period=cpu_period, cpu_quota=cpu_quota)
206 # only pass allowed keys to docker
207 allowed_keys
= ['blkio_weight', 'cpu_period', 'cpu_quota', 'cpu_shares', 'cpuset_cpus',
208 'cpuset_mems', 'mem_limit', 'mem_reservation', 'memswap_limit',
209 'kernel_memory', 'restart_policy']
210 filtered_params
= {key
:params
[key
] for key
in allowed_keys
if key
in params
}
212 d
.update_resources(**filtered_params
)
216 class DatacenterList(Resource
):
220 logging
.debug("API CALL: datacenter list")
222 return [d
.getStatus() for d
in dcs
.itervalues()], 200, CORS_HEADER
223 except Exception as ex
:
224 logging
.exception("API error.")
225 return ex
.message
, 500, CORS_HEADER
228 class DatacenterStatus(Resource
):
231 def get(self
, dc_label
):
232 logging
.debug("API CALL: datacenter status")
234 return dcs
.get(dc_label
).getStatus(), 200, CORS_HEADER
235 except Exception as ex
:
236 logging
.exception("API error.")
237 return ex
.message
, 500, CORS_HEADER