Change-Id: Ibb3d2cb9257c11f00139e7a5448aed7a1ccd2830
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
import json
import yaml
import logging
import json
import yaml
import logging
from urllib.parse import quote
from uuid import UUID
from copy import deepcopy
from urllib.parse import quote
from uuid import UUID
from copy import deepcopy
version_date = "2018-05-16"
requests = None
version_date = "2018-05-16"
requests = None
class ROClientException(Exception):
def __init__(self, message, http_code=400):
class ROClientException(Exception):
def __init__(self, message, http_code=400):
+ """Common Exception for all RO client exceptions"""
self.http_code = http_code
Exception.__init__(self, message)
self.http_code = http_code
Exception.__init__(self, message)
- """Common Exception for all openmano client exceptions"""
def remove_envelop(item, indata=None):
def remove_envelop(item, indata=None):
elif index == 'endpoint_url':
return self.endpoint_url
else:
elif index == 'endpoint_url':
return self.endpoint_url
else:
- raise KeyError("Invalid key '%s'" %str(index))
+ raise KeyError("Invalid key '{}'".format(index))
- def __setitem__(self,index, value):
+ def __setitem__(self, index, value):
if index == 'tenant':
self.tenant_id_name = value
elif index == 'datacenter' or index == 'vim':
if index == 'tenant':
self.tenant_id_name = value
elif index == 'datacenter' or index == 'vim':
raise KeyError("Invalid key '{}'".format(index))
self.tenant = None # force to reload tenant with different credentials
self.datacenter = None # force to reload datacenter with different credentials
raise KeyError("Invalid key '{}'".format(index))
self.tenant = None # force to reload tenant with different credentials
self.datacenter = None # force to reload datacenter with different credentials
def _parse(self, descriptor, descriptor_format, response=False):
def _parse(self, descriptor, descriptor_format, response=False):
if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml":
if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml":
- raise ROClientException("'descriptor_format' must be a 'json' or 'yaml' text")
+ raise ROClientException("'descriptor_format' must be a 'json' or 'yaml' text")
if descriptor_format != "json":
try:
return yaml.load(descriptor)
if descriptor_format != "json":
try:
return yaml.load(descriptor)
error_pos = ""
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
error_pos = ""
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
- error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
+ error_pos = " at line:{} column:{}s".format(mark.line + 1, mark.column + 1)
error_text = "yaml format error" + error_pos
elif descriptor_format != "yaml":
try:
error_text = "yaml format error" + error_pos
elif descriptor_format != "yaml":
try:
- return json.loads(descriptor)
+ return json.loads(descriptor)
except Exception as e:
if response:
error_text = "json format error" + str(e)
if response:
raise ROClientException(error_text)
except Exception as e:
if response:
error_text = "json format error" + str(e)
if response:
raise ROClientException(error_text)
- raise ROClientException(error_text)
+ raise ROClientException(error_text)
def _parse_yaml(self, descriptor, response=False):
try:
def _parse_yaml(self, descriptor, response=False):
try:
error_pos = ""
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
error_pos = ""
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
- error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
+ error_pos = " at line:{} column:{}s".format(mark.line + 1, mark.column + 1)
error_text = "yaml format error" + error_pos
if response:
raise ROClientException(error_text)
error_text = "yaml format error" + error_pos
if response:
raise ROClientException(error_text)
- raise ROClientException(error_text)
+ raise ROClientException(error_text)
@staticmethod
def check_if_uuid(uuid_text):
@staticmethod
def check_if_uuid(uuid_text):
ns_info[str(vnf["member_vnf_index"])] = vnfr_info
return ns_info
ns_info[str(vnf["member_vnf_index"])] = vnfr_info
return ns_info
async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
if all_tenants:
tenant_text = "/any"
async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
if all_tenants:
tenant_text = "/any"
url += "/" + item_id_name
elif item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'"):
item_id_name = item_id_name[1:-1]
url += "/" + item_id_name
elif item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'"):
item_id_name = item_id_name[1:-1]
- self.logger.debug("openmano GET %s", url)
+ self.logger.debug("RO GET %s", url)
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
self.logger.debug("GET {} [{}] {}".format(url, response.status, response_text[:100]))
if response.status == 404: # NOT_FOUND
raise ROClientException("No {} found with id '{}'".format(item[:-1], item_id_name),
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
self.logger.debug("GET {} [{}] {}".format(url, response.status, response_text[:100]))
if response.status == 404: # NOT_FOUND
raise ROClientException("No {} found with id '{}'".format(item[:-1], item_id_name),
if response.status >= 300:
raise ROClientException(response_text, http_code=response.status)
content = self._parse_yaml(response_text, response=True)
if response.status >= 300:
raise ROClientException(response_text, http_code=response.status)
content = self._parse_yaml(response_text, response=True)
else:
# check that exist
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
else:
# check that exist
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
- self.logger.debug("GET %s", url )
+ self.logger.debug("GET %s", url)
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
await self._get_tenant(session)
tenant_text = "/" + self.tenant
payload_req = yaml.safe_dump(descriptor)
await self._get_tenant(session)
tenant_text = "/" + self.tenant
payload_req = yaml.safe_dump(descriptor)
api_version_text = ""
if item == "vnfs":
api_version_text = ""
if item == "vnfs":
item = "nsd"
if not item_id_name:
item = "nsd"
if not item_id_name:
elif self.check_if_uuid(item_id_name):
uuid = "/{}".format(item_id_name)
else:
elif self.check_if_uuid(item_id_name):
uuid = "/{}".format(item_id_name)
else:
else:
action = "/".format(action)
else:
action = "/".format(action)
- url = "{}{apiver}{tenant}/{item}{id}{action}".format(self.endpoint_url, apiver=api_version_text, tenant=tenant_text,
- item=item, id=uuid, action=action)
- self.logger.debug("openmano POST %s %s", url, payload_req)
+ url = "{}{apiver}{tenant}/{item}{id}{action}".format(self.endpoint_url, apiver=api_version_text,
+ tenant=tenant_text, item=item, id=uuid, action=action)
+ self.logger.debug("RO POST %s %s", url, payload_req)
with aiohttp.Timeout(self.timeout_large):
async with session.post(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_large):
async with session.post(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants=_all_tenants)
else:
uuid = item_id_name
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants=_all_tenants)
else:
uuid = item_id_name
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
self.logger.debug("DELETE %s", url)
with aiohttp.Timeout(self.timeout_short):
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
self.logger.debug("DELETE %s", url)
with aiohttp.Timeout(self.timeout_short):
if not self.tenant:
await self._get_tenant(session)
tenant_text = "/" + self.tenant
if not self.tenant:
await self._get_tenant(session)
tenant_text = "/" + self.tenant
url = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
separator = "?"
if filter_dict:
for k in filter_dict:
url = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
separator = "?"
if filter_dict:
for k in filter_dict:
- url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
+ url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
- self.logger.debug("openmano GET %s", url)
+ self.logger.debug("RO GET %s", url)
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_short):
async with session.get(url, headers=self.headers_req) as response:
response_text = await response.read()
payload_req = yaml.safe_dump(descriptor)
payload_req = yaml.safe_dump(descriptor)
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, item_id)
url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, item_id)
- self.logger.debug("openmano PUT %s %s", url, payload_req)
+ self.logger.debug("RO PUT %s %s", url, payload_req)
with aiohttp.Timeout(self.timeout_large):
async with session.put(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_large):
async with session.put(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
_all_tenants = all_tenants
if item == 'vim':
_all_tenants = True
_all_tenants = all_tenants
if item == 'vim':
_all_tenants = True
- item_id = await self._get_item_uuid(session, self.client_to_RO[item], item_id_name, all_tenants=_all_tenants)
+ item_id = await self._get_item_uuid(session, self.client_to_RO[item], item_id_name,
+ all_tenants=_all_tenants)
# await self._get_tenant(session)
# await self._get_tenant(session)
- outdata = await self._edit_item(session, self.client_to_RO[item], item_id, create_desc, all_tenants=all_tenants)
+ outdata = await self._edit_item(session, self.client_to_RO[item], item_id, create_desc,
+ all_tenants=_all_tenants)
return remove_envelop(item, outdata)
except aiohttp.errors.ClientOSError as e:
raise ROClientException(e, http_code=504)
return remove_envelop(item, outdata)
except aiohttp.errors.ClientOSError as e:
raise ROClientException(e, http_code=504)
await self._get_tenant(session)
url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=self.tenant,
await self._get_tenant(session)
url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=self.tenant,
- datacenter=item_id)
- self.logger.debug("openmano POST %s %s", url, payload_req)
+ datacenter=item_id)
+ self.logger.debug("RO POST %s %s", url, payload_req)
with aiohttp.Timeout(self.timeout_large):
async with session.post(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_large):
async with session.post(url, headers=self.headers_req, data=payload_req) as response:
response_text = await response.read()
raise ROClientException(response_text, http_code=response.status)
response_desc = self._parse_yaml(response_text, response=True)
raise ROClientException(response_text, http_code=response.status)
response_desc = self._parse_yaml(response_text, response=True)
- desc = remove_envelop("vim", response_desc)
+ desc = remove_envelop("vim", response_desc)
return desc
async def detach_datacenter(self, datacenter=None):
return desc
async def detach_datacenter(self, datacenter=None):
- #TODO replace the code with delete_item(vim_account,...)
+ # TODO replace the code with delete_item(vim_account,...)
with aiohttp.ClientSession(loop=self.loop) as session:
# check that exist
item_id = await self._get_item_uuid(session, "datacenters", datacenter, all_tenants=False)
tenant = await self._get_tenant(session)
url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=tenant,
with aiohttp.ClientSession(loop=self.loop) as session:
# check that exist
item_id = await self._get_item_uuid(session, "datacenters", datacenter, all_tenants=False)
tenant = await self._get_tenant(session)
url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=tenant,
- datacenter=item_id)
- self.logger.debug("openmano DELETE %s", url)
+ datacenter=item_id)
+ self.logger.debug("RO DELETE %s", url)
with aiohttp.Timeout(self.timeout_large):
async with session.delete(url, headers=self.headers_req) as response:
response_text = await response.read()
with aiohttp.Timeout(self.timeout_large):
async with session.delete(url, headers=self.headers_req) as response:
response_text = await response.read()
desc = remove_envelop("vim", response_desc)
return desc
desc = remove_envelop("vim", response_desc)
return desc
# TODO convert to asyncio
# TODO convert to asyncio
- #DATACENTERS
-
- def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
+ def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False,
+ **kwargs):
"""Edit the parameters of a datacenter
Params: must supply a descriptor or/and a parameter to change
uuid or/and name. If only name is supplied, there must be only one or an exception is raised
"""Edit the parameters of a datacenter
Params: must supply a descriptor or/and a parameter to change
uuid or/and name. If only name is supplied, there must be only one or an exception is raised
elif descriptor:
pass
elif kwargs:
elif descriptor:
pass
elif kwargs:
- descriptor={"datacenter": {}}
+ descriptor = {"datacenter": {}}
else:
raise ROClientException("Missing descriptor")
else:
raise ROClientException("Missing descriptor")
- if 'datacenter' not in descriptor or len(descriptor)!=1:
+ if 'datacenter' not in descriptor or len(descriptor) != 1:
raise ROClientException("Descriptor must contain only one 'datacenter' field")
for param in kwargs:
raise ROClientException("Descriptor must contain only one 'datacenter' field")
for param in kwargs:
+ if param == 'new_name':
descriptor['datacenter']['name'] = kwargs[param]
else:
descriptor['datacenter'][param] = kwargs[param]
return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
descriptor['datacenter']['name'] = kwargs[param]
else:
descriptor['datacenter'][param] = kwargs[param]
return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
"""Edit the parameters of a scenario
def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
"""Edit the parameters of a scenario
elif descriptor:
pass
elif kwargs:
elif descriptor:
pass
elif kwargs:
- descriptor={"scenario": {}}
+ descriptor = {"scenario": {}}
else:
raise ROClientException("Missing descriptor")
else:
raise ROClientException("Missing descriptor")
- if 'scenario' not in descriptor or len(descriptor)>2:
+ if 'scenario' not in descriptor or len(descriptor) > 2:
raise ROClientException("Descriptor must contain only one 'scenario' field")
for param in kwargs:
raise ROClientException("Descriptor must contain only one 'scenario' field")
for param in kwargs:
+ if param == 'new_name':
descriptor['scenario']['name'] = kwargs[param]
else:
descriptor['scenario'][param] = kwargs[param]
return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
descriptor['scenario']['name'] = kwargs[param]
else:
descriptor['scenario'][param] = kwargs[param]
return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
"""Perform an action over a vim
def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
"""Perform an action over a vim
action: can be 'list', 'get'/'show', 'delete' or 'create'
item: can be 'tenants' or 'networks'
uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
other parameters:
action: can be 'list', 'get'/'show', 'delete' or 'create'
item: can be 'tenants' or 'networks'
uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
other parameters:
- datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
- descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
+ datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
+ descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
must be a dictionary or a json/yaml text.
name: for created tenant/net Overwrite descriptor name if any
description: tenant descriptor. Overwrite descriptor description if any
must be a dictionary or a json/yaml text.
name: for created tenant/net Overwrite descriptor name if any
description: tenant descriptor. Overwrite descriptor description if any
Return: Raises an exception on error
Obtain a dictionary with format {'tenant':{new_tenant_info}}
"""
Return: Raises an exception on error
Obtain a dictionary with format {'tenant':{new_tenant_info}}
"""
+ session = None # TODO remove when changed to asyncio
if item not in ("tenants", "networks", "images"):
raise ROClientException("Unknown value for item '{}', must be 'tenants', 'nets' or "
if item not in ("tenants", "networks", "images"):
raise ROClientException("Unknown value for item '{}', must be 'tenants', 'nets' or "
- "images".format(str(item)))
+ "images".format(str(item)))
- image_actions = ['list','get','show','delete']
+ image_actions = ['list', 'get', 'show', 'delete']
if item == "images" and action not in image_actions:
raise ROClientException("Only available actions for item '{}' are {}\n"
if item == "images" and action not in image_actions:
raise ROClientException("Only available actions for item '{}' are {}\n"
- "Requested action was '{}'".format(item, ', '.join(image_actions), action))
+ "Requested action was '{}'".format(item, ', '.join(image_actions), action))
if all_tenants:
tenant_text = "/any"
else:
if all_tenants:
tenant_text = "/any"
else:
- tenant_text = "/"+self._get_tenant()
-
+ tenant_text = "/" + self._get_tenant()
+
if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
datacenter = self._get_item_uuid(session, "datacenters", kwargs.get("datacenter"), all_tenants=all_tenants)
else:
datacenter = self.get_datacenter(session)
if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
datacenter = self._get_item_uuid(session, "datacenters", kwargs.get("datacenter"), all_tenants=all_tenants)
else:
datacenter = self.get_datacenter(session)
url = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
url = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
- self.logger.debug("GET %s", url )
+ self.logger.debug("GET %s", url)
mano_response = requests.get(url, headers=self.headers_req)
mano_response = requests.get(url, headers=self.headers_req)
- self.logger.debug("openmano response: %s", mano_response.text )
+ self.logger.debug("RO response: %s", mano_response.text)
content = self._parse_yaml(mano_response.text, response=True)
content = self._parse_yaml(mano_response.text, response=True)
- if mano_response.status_code==200:
+ if mano_response.status_code == 200:
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
- elif action=="get" or action=="show":
+ elif action == "get" or action == "show":
url = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
url = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
- self.logger.debug("GET %s", url )
+ self.logger.debug("GET %s", url)
mano_response = requests.get(url, headers=self.headers_req)
mano_response = requests.get(url, headers=self.headers_req)
- self.logger.debug("openmano response: %s", mano_response.text )
+ self.logger.debug("RO response: %s", mano_response.text)
content = self._parse_yaml(mano_response.text, response=True)
content = self._parse_yaml(mano_response.text, response=True)
- if mano_response.status_code==200:
+ if mano_response.status_code == 200:
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
+ elif action == "delete":
url = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
url = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
- self.logger.debug("DELETE %s", url )
+ self.logger.debug("DELETE %s", url)
mano_response = requests.delete(url, headers=self.headers_req)
mano_response = requests.delete(url, headers=self.headers_req)
- self.logger.debug("openmano response: %s", mano_response.text )
+ self.logger.debug("RO response: %s", mano_response.text)
content = self._parse_yaml(mano_response.text, response=True)
content = self._parse_yaml(mano_response.text, response=True)
- if mano_response.status_code==200:
+ if mano_response.status_code == 200:
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
+ elif action == "create":
if "descriptor" in kwargs:
if isinstance(kwargs["descriptor"], str):
if "descriptor" in kwargs:
if isinstance(kwargs["descriptor"], str):
- descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format") )
+ descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format"))
else:
descriptor = kwargs["descriptor"]
elif "name" in kwargs:
else:
descriptor = kwargs["descriptor"]
elif "name" in kwargs:
- descriptor={item[:-1]: {"name": kwargs["name"]}}
+ descriptor = {item[:-1]: {"name": kwargs["name"]}}
else:
raise ROClientException("Missing descriptor")
else:
raise ROClientException("Missing descriptor")
- if item[:-1] not in descriptor or len(descriptor)!=1:
+ if item[:-1] not in descriptor or len(descriptor) != 1:
raise ROClientException("Descriptor must contain only one 'tenant' field")
if "name" in kwargs:
raise ROClientException("Descriptor must contain only one 'tenant' field")
if "name" in kwargs:
- descriptor[ item[:-1] ]['name'] = kwargs["name"]
+ descriptor[item[:-1]]['name'] = kwargs["name"]
if "description" in kwargs:
if "description" in kwargs:
- descriptor[ item[:-1] ]['description'] = kwargs["description"]
+ descriptor[item[:-1]]['description'] = kwargs["description"]
payload_req = yaml.safe_dump(descriptor)
payload_req = yaml.safe_dump(descriptor)
url = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
url = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
- self.logger.debug("openmano POST %s %s", url, payload_req)
- mano_response = requests.post(url, headers = self.headers_req, data=payload_req)
- self.logger.debug("openmano response: %s", mano_response.text )
+ self.logger.debug("RO POST %s %s", url, payload_req)
+ mano_response = requests.post(url, headers=self.headers_req, data=payload_req)
+ self.logger.debug("RO response: %s", mano_response.text)
content = self._parse_yaml(mano_response.text, response=True)
content = self._parse_yaml(mano_response.text, response=True)
- if mano_response.status_code==200:
+ if mano_response.status_code == 200:
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
else:
return content
else:
raise ROClientException(str(content), http_code=mano_response.status)
else:
- raise ROClientException("Unknown value for action '{}".format(str(action)))
+ raise ROClientException("Unknown value for action '{}".format(str(action)))
if __name__ == '__main__':
if __name__ == '__main__':
tenant_id = True
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
print("tenant", TEST_TENANT, content)
tenant_id = True
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
print("tenant", TEST_TENANT, content)
- content = loop.run_until_complete(myClient.edit("tenant", TEST_TENANT, description="another description"))
+ content = loop.run_until_complete(myClient.edit("tenant", TEST_TENANT, description="another description"))
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
print("tenant edited", TEST_TENANT, content)
myClient["tenant"] = TEST_TENANT
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
print("tenant edited", TEST_TENANT, content)
myClient["tenant"] = TEST_TENANT
- content = loop.run_until_complete(myClient.create("vim", name=TEST_VIM1, type=TEST_TYPE1, vim_url=TEST_URL1, config=TEST_CONFIG1))
+ content = loop.run_until_complete(myClient.create("vim", name=TEST_VIM1, type=TEST_TYPE1, vim_url=TEST_URL1,
+ config=TEST_CONFIG1))
vim_id = True
content = loop.run_until_complete(myClient.get_list("vim"))
print("vim", content)
content = loop.run_until_complete(myClient.show("vim", TEST_VIM1))
print("vim", TEST_VIM1, content)
vim_id = True
content = loop.run_until_complete(myClient.get_list("vim"))
print("vim", content)
content = loop.run_until_complete(myClient.show("vim", TEST_VIM1))
print("vim", TEST_VIM1, content)
- content = loop.run_until_complete(myClient.edit("vim", TEST_VIM1, description="another description",
+ content = loop.run_until_complete(myClient.edit("vim", TEST_VIM1, description="another description",
name=TEST_VIM2, type=TEST_TYPE2, vim_url=TEST_URL2,
config=TEST_CONFIG2))
content = loop.run_until_complete(myClient.show("vim", TEST_VIM2))
name=TEST_VIM2, type=TEST_TYPE2, vim_url=TEST_URL2,
config=TEST_CONFIG2))
content = loop.run_until_complete(myClient.show("vim", TEST_VIM2))
# test VIM_ACCOUNT
content = loop.run_until_complete(myClient.attach_datacenter(TEST_VIM2, vim_username='user',
# test VIM_ACCOUNT
content = loop.run_until_complete(myClient.attach_datacenter(TEST_VIM2, vim_username='user',
- vim_password='pass', vim_tenant_name='vimtenant1', config=TEST_CONFIG1))
+ vim_password='pass', vim_tenant_name='vimtenant1',
+ config=TEST_CONFIG1))
vim_id = True
content = loop.run_until_complete(myClient.get_list("vim_account"))
print("vim_account", content)
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
print("vim_account", TEST_VIM2, content)
vim_id = True
content = loop.run_until_complete(myClient.get_list("vim_account"))
print("vim_account", content)
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
print("vim_account", TEST_VIM2, content)
- content = loop.run_until_complete(myClient.edit("vim_account", TEST_VIM2, vim_username='user2', vim_password='pass2',
- vim_tenant_name="vimtenant2", config=TEST_CONFIG2))
+ content = loop.run_until_complete(myClient.edit("vim_account", TEST_VIM2, vim_username='user2',
+ vim_password='pass2', vim_tenant_name="vimtenant2",
+ config=TEST_CONFIG2))
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
print("vim_account edited", TEST_VIM2, content)
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
print("vim_account edited", TEST_VIM2, content)
logger.error("Error {}".format(e), exc_info=True)
loop.close()
logger.error("Error {}".format(e), exc_info=True)
loop.close()
-version = '0.1.2'
-date_version = '2018-05-16'
+version = '0.1.3'
+date_version = '2018-05-18'
# load configuration
config = self.read_config_file(config_file)
self.config = config
# load configuration
config = self.read_config_file(config_file)
self.config = config
"endpoint_url": "http://{}:{}/openmano".format(config["RO"]["host"], config["RO"]["port"]),
"endpoint_url": "http://{}:{}/openmano".format(config["RO"]["host"], config["RO"]["port"]),
- "tenant": config.get("tenant", "osm"),
+ "tenant": config.get("tenant", "osm"),
"logger_name": "lcm.ROclient",
"loglevel": "ERROR",
}
"logger_name": "lcm.ROclient",
"loglevel": "ERROR",
}
step = "Attach vim to RO tenant"
vim_RO = {"vim_tenant_name": vim_content["vim_tenant_name"],
step = "Attach vim to RO tenant"
vim_RO = {"vim_tenant_name": vim_content["vim_tenant_name"],
- "vim_username": vim_content["vim_user"],
- "vim_password": vim_content["vim_password"],
- "config": vim_content["config"]
- }
- desc = await RO.attach_datacenter(RO_vim_id , descriptor=vim_RO)
+ "vim_username": vim_content["vim_user"],
+ "vim_password": vim_content["vim_password"],
+ "config": vim_content["config"]
+ }
+ desc = await RO.attach_datacenter(RO_vim_id, descriptor=vim_RO)
db_vim["_admin"]["operationalState"] = "ENABLED"
self.update_db("vim_accounts", vim_id, db_vim)
db_vim["_admin"]["operationalState"] = "ENABLED"
self.update_db("vim_accounts", vim_id, db_vim)
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
- db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("vim_accounts", vim_id, db_vim)
async def vim_edit(self, vim_content, order_id):
self.update_db("vim_accounts", vim_id, db_vim)
async def vim_edit(self, vim_content, order_id):
vim_RO.pop("vim_user", None)
vim_RO.pop("vim_password", None)
if vim_RO:
vim_RO.pop("vim_user", None)
vim_RO.pop("vim_password", None)
if vim_RO:
- desc = await RO.edit("vim", RO_vim_id, descriptor=vim_RO)
+ await RO.edit("vim", RO_vim_id, descriptor=vim_RO)
step = "Editing vim-account at RO tenant"
vim_RO = {}
step = "Editing vim-account at RO tenant"
vim_RO = {}
if "vim_user" in vim_content:
vim_content["vim_username"] = vim_content["vim_user"]
if vim_RO:
if "vim_user" in vim_content:
vim_content["vim_username"] = vim_content["vim_user"]
if vim_RO:
- desc = await RO.edit("vim_account", RO_vim_id, descriptor=vim_RO)
+ await RO.edit("vim_account", RO_vim_id, descriptor=vim_RO)
db_vim["_admin"]["operationalState"] = "ENABLED"
self.update_db("vim_accounts", vim_id, db_vim)
db_vim["_admin"]["operationalState"] = "ENABLED"
self.update_db("vim_accounts", vim_id, db_vim)
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
- db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("vim_accounts", vim_id, db_vim)
async def vim_delete(self, vim_id, order_id):
self.update_db("vim_accounts", vim_id, db_vim)
async def vim_delete(self, vim_id, order_id):
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_vim:
db_vim["_admin"]["operationalState"] = "ERROR"
- db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_vim["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("vim_accounts", vim_id, db_vim)
async def sdn_create(self, sdn_content, order_id):
self.update_db("vim_accounts", vim_id, db_vim)
async def sdn_create(self, sdn_content, order_id):
db_sdn["_admin"] = {}
if "deployed" not in db_sdn["_admin"]:
db_sdn["_admin"]["deployed"] = {}
db_sdn["_admin"] = {}
if "deployed" not in db_sdn["_admin"]:
db_sdn["_admin"]["deployed"] = {}
- db_sdn["_admin"]["deployed"]["RO"] = None
+ db_sdn["_admin"]["deployed"]["RO"] = None
step = "Creating sdn at RO"
RO = ROclient.ROClient(self.loop, **self.ro_config)
step = "Creating sdn at RO"
RO = ROclient.ROClient(self.loop, **self.ro_config)
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
- db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("sdns", sdn_id, db_sdn)
async def sdn_edit(self, sdn_content, order_id):
self.update_db("sdns", sdn_id, db_sdn)
async def sdn_edit(self, sdn_content, order_id):
sdn_RO.pop("schema_type", None)
sdn_RO.pop("description", None)
if sdn_RO:
sdn_RO.pop("schema_type", None)
sdn_RO.pop("description", None)
if sdn_RO:
- desc = await RO.edit("sdn", RO_sdn_id, descriptor=sdn_RO)
+ await RO.edit("sdn", RO_sdn_id, descriptor=sdn_RO)
db_sdn["_admin"]["operationalState"] = "ENABLED"
self.update_db("sdns", sdn_id, db_sdn)
db_sdn["_admin"]["operationalState"] = "ENABLED"
self.update_db("sdns", sdn_id, db_sdn)
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
- db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("sdns", sdn_id, db_sdn)
async def sdn_delete(self, sdn_id, order_id):
self.update_db("sdns", sdn_id, db_sdn)
async def sdn_delete(self, sdn_id, order_id):
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
finally:
if exc and db_sdn:
db_sdn["_admin"]["operationalState"] = "ERROR"
- db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step , exc)
+ db_sdn["_admin"]["detailed-status"] = "ERROR {}: {}".format(step, exc)
self.update_db("sdns", sdn_id, db_sdn)
def vnfd2RO(self, vnfd, new_id=None):
self.update_db("sdns", sdn_id, db_sdn)
def vnfd2RO(self, vnfd, new_id=None):
vdu["cloud-init-file"]
)
ci_file = self.fs.file_open(clout_init_file, "r")
vdu["cloud-init-file"]
)
ci_file = self.fs.file_open(clout_init_file, "r")
- # TODO: detect if binary or text. Propose to read as binary and try to decode to utf8. If fails convert to base 64 or similar
+ # TODO: detect if binary or text. Propose to read as binary and try to decode to utf8. If fails
+ # convert to base 64 or similar
clout_init_content = ci_file.read()
ci_file.close()
ci_file = None
clout_init_content = ci_file.read()
ci_file.close()
ci_file = None
if ci_file:
ci_file.close()
if ci_file:
ci_file.close()
- def n2vc_callback(self, model_name, application_name, status, message, db_nsr, db_nslcmop, member_vnf_index, task=None):
+ def n2vc_callback(self, model_name, application_name, status, message, db_nsr, db_nslcmop, member_vnf_index,
+ task=None):
"""
Callback both for charm status change and task completion
:param model_name: Charm model name
"""
Callback both for charm status change and task completion
:param model_name: Charm model name
all_active = False
elif vca_status in ("error", "blocked"):
n2vc_error_text.append("member_vnf_index={} {}: {}".format(member_vnf_index, vca_status,
all_active = False
elif vca_status in ("error", "blocked"):
n2vc_error_text.append("member_vnf_index={} {}: {}".format(member_vnf_index, vca_status,
- vca_info["detailed-status"]))
+ vca_info["detailed-status"]))
- self.logger.debug("[n2vc_callback] ns_instantiate={} vnf_index={} All active".format(nsr_id, member_vnf_index))
+ self.logger.debug("[n2vc_callback] ns_instantiate={} vnf_index={} All active".format(nsr_id,
+ member_vnf_index))
db_nsr["config-status"] = "configured"
db_nsr["detailed-status"] = "done"
db_nslcmop["operationState"] = "COMPLETED"
db_nsr["config-status"] = "configured"
db_nsr["detailed-status"] = "done"
db_nslcmop["operationState"] = "COMPLETED"
:return: The RO ns descriptor
"""
vim_2_RO = {}
:return: The RO ns descriptor
"""
vim_2_RO = {}
def vim_account_2_RO(vim_account):
if vim_account in vim_2_RO:
return vim_2_RO[vim_account]
def vim_account_2_RO(vim_account):
if vim_account in vim_2_RO:
return vim_2_RO[vim_account]
"netmap-use": vim_net,
"datacenter": vim_account_2_RO(vim_account)
})
"netmap-use": vim_net,
"datacenter": vim_account_2_RO(vim_account)
})
- else: #isinstance str
- RO_vld["sites"].append({"netmap-use": vld["vim-network-name"]})
+ else: # isinstance str
+ RO_vld["sites"].append({"netmap-use": vld["vim-network-name"]})
if RO_vld:
RO_ns_params["networks"][vld["name"]] = RO_vld
return RO_ns_params
if RO_vld:
RO_ns_params["networks"][vld["name"]] = RO_vld
return RO_ns_params
step = ns_status_detailed = "Waiting ns ready at RO"
db_nsr["detailed-status"] = ns_status_detailed
self.logger.debug(logging_text + step + " RO_ns_id={}".format(RO_nsr_id))
step = ns_status_detailed = "Waiting ns ready at RO"
db_nsr["detailed-status"] = ns_status_detailed
self.logger.debug(logging_text + step + " RO_ns_id={}".format(RO_nsr_id))
- deployment_timeout = 2*3600 # Two hours
+ deployment_timeout = 2 * 3600 # Two hours
while deployment_timeout > 0:
desc = await RO.show("ns", RO_nsr_id)
ns_status, ns_status_info = RO.check_ns_status(desc)
while deployment_timeout > 0:
desc = await RO.show("ns", RO_nsr_id)
ns_status, ns_status_info = RO.check_ns_status(desc)
# yield from asyncio.wait_for(task, 30.0)
# self.logger.debug("Logged into N2VC!")
# yield from asyncio.wait_for(task, 30.0)
# self.logger.debug("Logged into N2VC!")
- ## await self.n2vc.login()
+ # # await self.n2vc.login()
# Note: The charm needs to exist on disk at the location
# specified by charm_path.
# Note: The charm needs to exist on disk at the location
# specified by charm_path.
- self.logger.debug("Task create_ns={} Passing artifacts path '{}' for {}".format(nsr_id, charm_path, proxy_charm))
+ self.logger.debug("Task create_ns={} Passing artifacts path '{}' for {}".format(nsr_id, charm_path,
+ proxy_charm))
task = asyncio.ensure_future(
self.n2vc.DeployCharms(
model_name, # The network service name
task = asyncio.ensure_future(
self.n2vc.DeployCharms(
model_name, # The network service name
try:
step = db_nsr["detailed-status"] = "Deleting ns at RO"
self.logger.debug(logging_text + step)
try:
step = db_nsr["detailed-status"] = "Deleting ns at RO"
self.logger.debug(logging_text + step)
- desc = await RO.delete("ns", RO_nsr_id)
+ await RO.delete("ns", RO_nsr_id)
nsr_lcm["RO"]["nsr_id"] = None
nsr_lcm["RO"]["nsr_status"] = "DELETED"
except ROclient.ROClientException as e:
nsr_lcm["RO"]["nsr_id"] = None
nsr_lcm["RO"]["nsr_status"] = "DELETED"
except ROclient.ROClientException as e:
nsr_lcm["RO"]["nsr_id"] = None
nsr_lcm["RO"]["nsr_status"] = "DELETED"
self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(RO_nsr_id))
nsr_lcm["RO"]["nsr_id"] = None
nsr_lcm["RO"]["nsr_status"] = "DELETED"
self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(RO_nsr_id))
- elif e.http_code == 409: #conflict
+ elif e.http_code == 409: # conflict
failed_detail.append("RO_ns_id={} delete conflict: {}".format(RO_nsr_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
failed_detail.append("RO_ns_id={} delete conflict: {}".format(RO_nsr_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
if RO_nsd_id:
try:
step = db_nsr["detailed-status"] = "Deleting nsd at RO"
if RO_nsd_id:
try:
step = db_nsr["detailed-status"] = "Deleting nsd at RO"
- desc = await RO.delete("nsd", RO_nsd_id)
+ await RO.delete("nsd", RO_nsd_id)
self.logger.debug(logging_text + "RO_nsd_id={} deleted".format(RO_nsd_id))
nsr_lcm["RO"]["nsd_id"] = None
except ROclient.ROClientException as e:
if e.http_code == 404: # not found
nsr_lcm["RO"]["nsd_id"] = None
self.logger.debug(logging_text + "RO_nsd_id={} already deleted".format(RO_nsd_id))
self.logger.debug(logging_text + "RO_nsd_id={} deleted".format(RO_nsd_id))
nsr_lcm["RO"]["nsd_id"] = None
except ROclient.ROClientException as e:
if e.http_code == 404: # not found
nsr_lcm["RO"]["nsd_id"] = None
self.logger.debug(logging_text + "RO_nsd_id={} already deleted".format(RO_nsd_id))
- elif e.http_code == 409: #conflict
+ elif e.http_code == 409: # conflict
failed_detail.append("RO_nsd_id={} delete conflict: {}".format(RO_nsd_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
failed_detail.append("RO_nsd_id={} delete conflict: {}".format(RO_nsd_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
continue
try:
step = db_nsr["detailed-status"] = "Deleting vnfd={} at RO".format(vnf_id)
continue
try:
step = db_nsr["detailed-status"] = "Deleting vnfd={} at RO".format(vnf_id)
- desc = await RO.delete("vnfd", RO_vnfd_id)
+ await RO.delete("vnfd", RO_vnfd_id)
self.logger.debug(logging_text + "RO_vnfd_id={} deleted".format(RO_vnfd_id))
nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
except ROclient.ROClientException as e:
if e.http_code == 404: # not found
nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
self.logger.debug(logging_text + "RO_vnfd_id={} already deleted ".format(RO_vnfd_id))
self.logger.debug(logging_text + "RO_vnfd_id={} deleted".format(RO_vnfd_id))
nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
except ROclient.ROClientException as e:
if e.http_code == 404: # not found
nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
self.logger.debug(logging_text + "RO_vnfd_id={} already deleted ".format(RO_vnfd_id))
- elif e.http_code == 409: #conflict
+ elif e.http_code == 409: # conflict
failed_detail.append("RO_vnfd_id={} delete conflict: {}".format(RO_vnfd_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
failed_detail.append("RO_vnfd_id={} delete conflict: {}".format(RO_vnfd_id, e))
self.logger.debug(logging_text + failed_detail[-1])
else:
nsr_lcm = db_nsr["_admin"].get("deployed")
vnf_index = db_nslcmop["operationParams"]["member_vnf_index"]
nsr_lcm = db_nsr["_admin"].get("deployed")
vnf_index = db_nslcmop["operationParams"]["member_vnf_index"]
- #TODO check if ns is in a proper status
+ # TODO check if ns is in a proper status
vca_deployed = nsr_lcm["VCA"].get(vnf_index)
if not vca_deployed:
raise LcmException("charm for member_vnf_index={} is not deployed".format(vnf_index))
vca_deployed = nsr_lcm["VCA"].get(vnf_index)
if not vca_deployed:
raise LcmException("charm for member_vnf_index={} is not deployed".format(vnf_index))
"""
if topic == "ns":
lcm_tasks = self.lcm_ns_tasks
"""
if topic == "ns":
lcm_tasks = self.lcm_ns_tasks
- elif topic== "vim_account":
+ elif topic == "vim_account":
lcm_tasks = self.lcm_vim_tasks
lcm_tasks = self.lcm_vim_tasks
lcm_tasks = self.lcm_sdn_tasks
if not lcm_tasks.get(_id):
lcm_tasks = self.lcm_sdn_tasks
if not lcm_tasks.get(_id):
self.pings_not_received = 1
while True:
try:
self.pings_not_received = 1
while True:
try:
- await self.msg.aiowrite("admin", "ping", {"from": "lcm", "to": "lcm"}, self.loop)
+ await self.msg.aiowrite("admin", "ping", {"from": "lcm", "to": "lcm"}, self.loop)
# time between pings are low when it is not received and at starting
wait_time = 5 if not kafka_has_received else 120
if not self.pings_not_received:
# time between pings are low when it is not received and at starting
wait_time = 5 if not kafka_has_received else 120
if not self.pings_not_received:
elif command == "show":
try:
db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
elif command == "show":
try:
db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
- print(
- "nsr:\n _id={}\n operational-status: {}\n config-status: {}\n detailed-status: "
- "{}\n deploy: {}\n tasks: {}".format(
- nsr_id, db_nsr["operational-status"],
- db_nsr["config-status"], db_nsr["detailed-status"],
- db_nsr["_admin"]["deployed"], self.lcm_ns_tasks.get(nsr_id)))
+ print("nsr:\n _id={}\n operational-status: {}\n config-status: {}"
+ "\n detailed-status: {}\n deploy: {}\n tasks: {}"
+ "".format(nsr_id, db_nsr["operational-status"], db_nsr["config-status"],
+ db_nsr["detailed-status"],
+ db_nsr["_admin"]["deployed"], self.lcm_ns_tasks.get(nsr_id)))
except Exception as e:
print("nsr {} not found: {}".format(nsr_id, e))
sys.stdout.flush()
except Exception as e:
print("nsr {} not found: {}".format(nsr_id, e))
sys.stdout.flush()
-c|--config [configuration_file]: loads the configuration file (default: ./nbi.cfg)
-h|--help: shows this help
""".format(sys.argv[0]))
-c|--config [configuration_file]: loads the configuration file (default: ./nbi.cfg)
-h|--help: shows this help
""".format(sys.argv[0]))
- # --log-socket-host HOST: send logs to this host")
- # --log-socket-port PORT: send logs using this port (default: 9022)")
+ # --log-socket-host HOST: send logs to this host")
+ # --log-socket-port PORT: send logs using this port (default: 9022)")
if __name__ == '__main__':
if __name__ == '__main__':
# osm=osm_lcm.lcm:lcm
# ''',
)
# osm=osm_lcm.lcm:lcm
# ''',
)
basepython = python3
deps = flake8
commands =
basepython = python3
deps = flake8
commands =
+ flake8 setup.py --max-line-length 120 --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp --ignore W291,W293
[testenv:build]
basepython = python3
[testenv:build]
basepython = python3