- Service Function Path (OSM) -> Port Chain (Neutron)
"""
-from osm_ro_plugin import vimconn
-
-# import json
+import copy
+from http.client import HTTPException
import logging
-import netaddr
-import time
-import yaml
+from pprint import pformat
import random
import re
-import copy
-from pprint import pformat
-from novaclient import client as nClient, exceptions as nvExceptions
-from keystoneauth1.identity import v2, v3
+import time
+
+from cinderclient import client as cClient
+from glanceclient import client as glClient
+import glanceclient.exc as gl1Exceptions
from keystoneauth1 import session
+from keystoneauth1.identity import v2, v3
import keystoneclient.exceptions as ksExceptions
-import keystoneclient.v3.client as ksClient_v3
import keystoneclient.v2_0.client as ksClient_v2
-from glanceclient import client as glClient
-import glanceclient.exc as gl1Exceptions
-from cinderclient import client as cClient
-
-# TODO py3 check that this base exception matches python2 httplib.HTTPException
-from http.client import HTTPException
-from neutronclient.neutron import client as neClient
+import keystoneclient.v3.client as ksClient_v3
+import netaddr
from neutronclient.common import exceptions as neExceptions
+from neutronclient.neutron import client as neClient
+from novaclient import client as nClient, exceptions as nvExceptions
+from osm_ro_plugin import vimconn
from requests.exceptions import ConnectionError
+import yaml
__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor D.C., Eduardo Sousa"
__date__ = "$22-sep-2017 23:59:59$"
flavor_dict["ram"],
flavor_dict["vcpus"],
flavor_dict["disk"],
+ flavor_dict.get("ephemeral", 0),
+ flavor_dict.get("swap", 0),
)
# numa=None
extended = flavor_dict.get("extended", {})
continue
# TODO
- flavor_data = (flavor.ram, flavor.vcpus, flavor.disk)
+ flavor_data = (
+ flavor.ram,
+ flavor.vcpus,
+ flavor.disk,
+ flavor.ephemeral,
+ flavor.swap if isinstance(flavor.swap, int) else 0,
+ )
if flavor_data == flavor_target:
return flavor.id
elif (
extended.get("disk-io-quota"), "disk_io", extra_specs
)
+ # Set the mempage size as specified in the descriptor
+ if extended.get("mempage-size"):
+ if extended.get("mempage-size") == "LARGE":
+ extra_specs["hw:mem_page_size"] = "large"
+ elif extended.get("mempage-size") == "SMALL":
+ extra_specs["hw:mem_page_size"] = "small"
+ elif extended.get("mempage-size") == "SIZE_2MB":
+ extra_specs["hw:mem_page_size"] = "2MB"
+ elif extended.get("mempage-size") == "SIZE_1GB":
+ extra_specs["hw:mem_page_size"] = "1GB"
+ elif extended.get("mempage-size") == "PREFER_LARGE":
+ extra_specs["hw:mem_page_size"] = "any"
+ else:
+ # The validations in NBI should make reaching here not possible.
+ # If this message is shown, check validations
+ self.logger.debug(
+ "Invalid mempage-size %s. Will be ignored",
+ extended.get("mempage-size"),
+ )
+
# create flavor
new_flavor = self.nova.flavors.create(
- name,
- ram,
- vcpus,
- flavor_data.get("disk", 0),
+ name=name,
+ ram=ram,
+ vcpus=vcpus,
+ disk=flavor_data.get("disk", 0),
+ ephemeral=flavor_data.get("ephemeral", 0),
+ swap=flavor_data.get("swap", 0),
is_public=flavor_data.get("is_public", True),
)
# add metadata
start,
image_id,
flavor_id,
+ affinity_group_list,
net_list,
cloud_config=None,
disk_list=None,
"""Adds a VM instance to VIM
Params:
start: indicates if VM must start or boot in pause mode. Ignored
- image_id,flavor_id: iamge and flavor uuid
+ image_id,flavor_id: image and flavor uuid
+ affinity_group_list: list of affinity groups, each one is a dictionary.
+ Ignore if empty.
net_list: list of interfaces, each one is a dictionary with:
name:
net_id: network uuid to connect
# cloud config
config_drive, userdata = self._create_user_data(cloud_config)
+ # get availability Zone
+ vm_av_zone = self._get_vm_availability_zone(
+ availability_zone_index, availability_zone_list
+ )
+
# Create additional volumes in case these are present in disk_list
base_disk_index = ord("b")
+ boot_volume_id = None
if disk_list:
block_device_mapping = {}
for disk in disk_list:
]
else:
if "image_id" in disk:
+ base_disk_index = ord("a")
volume = self.cinder.volumes.create(
size=disk["size"],
name=name + "_vd" + chr(base_disk_index),
imageRef=disk["image_id"],
+ # Make sure volume is in the same AZ as the VM to be attached to
+ availability_zone=vm_av_zone,
)
+ boot_volume_id = volume.id
else:
volume = self.cinder.volumes.create(
size=disk["size"],
name=name + "_vd" + chr(base_disk_index),
+ # Make sure volume is in the same AZ as the VM to be attached to
+ availability_zone=vm_av_zone,
)
created_items["volume:" + str(volume.id)] = True
"Timeout creating volumes for instance " + name,
http_code=vimconn.HTTP_Request_Timeout,
)
+ if boot_volume_id:
+ self.cinder.volumes.set_bootable(boot_volume_id, True)
- # get availability Zone
- vm_av_zone = self._get_vm_availability_zone(
- availability_zone_index, availability_zone_list
- )
+ # Manage affinity groups/server groups
+ server_group_id = None
+ scheduller_hints = {}
+
+ if affinity_group_list:
+ # Only first id on the list will be used. Openstack restriction
+ server_group_id = affinity_group_list[0]["affinity_group_id"]
+ scheduller_hints["group"] = server_group_id
self.logger.debug(
"nova.servers.create({}, {}, {}, nics={}, security_groups={}, "
"availability_zone={}, key_name={}, userdata={}, config_drive={}, "
- "block_device_mapping={})".format(
+ "block_device_mapping={}, server_group={})".format(
name,
image_id,
flavor_id,
userdata,
config_drive,
block_device_mapping,
+ server_group_id,
)
)
server = self.nova.servers.create(
userdata=userdata,
config_drive=config_drive,
block_device_mapping=block_device_mapping,
+ scheduler_hints=scheduller_hints,
) # , description=description)
vm_start_time = time.time()
classification_dict[classification_id] = classification
return classification_dict
+
+ def new_affinity_group(self, affinity_group_data):
+ """Adds a server group to VIM
+ affinity_group_data contains a dictionary with information, keys:
+ name: name in VIM for the server group
+ type: affinity or anti-affinity
+ scope: Only nfvi-node allowed
+ Returns the server group identifier"""
+ self.logger.debug("Adding Server Group '%s'", str(affinity_group_data))
+
+ try:
+ name = affinity_group_data["name"]
+ policy = affinity_group_data["type"]
+
+ self._reload_connection()
+ new_server_group = self.nova.server_groups.create(name, policy)
+
+ return new_server_group.id
+ except (
+ ksExceptions.ClientException,
+ nvExceptions.ClientException,
+ ConnectionError,
+ KeyError,
+ ) as e:
+ self._format_exception(e)
+
+ def get_affinity_group(self, affinity_group_id):
+ """Obtain server group details from the VIM. Returns the server group detais as a dict"""
+ self.logger.debug("Getting flavor '%s'", affinity_group_id)
+ try:
+ self._reload_connection()
+ server_group = self.nova.server_groups.find(id=affinity_group_id)
+
+ return server_group.to_dict()
+ except (
+ nvExceptions.NotFound,
+ nvExceptions.ClientException,
+ ksExceptions.ClientException,
+ ConnectionError,
+ ) as e:
+ self._format_exception(e)
+
+ def delete_affinity_group(self, affinity_group_id):
+ """Deletes a server group from the VIM. Returns the old affinity_group_id"""
+ self.logger.debug("Getting server group '%s'", affinity_group_id)
+ try:
+ self._reload_connection()
+ self.nova.server_groups.delete(affinity_group_id)
+
+ return affinity_group_id
+ except (
+ nvExceptions.NotFound,
+ ksExceptions.ClientException,
+ nvExceptions.ClientException,
+ ConnectionError,
+ ) as e:
+ self._format_exception(e)