Image,
GenericResourceBundle,
ConfigBundle,
- Vlan,
Host,
HostProfile,
HostConfiguration,
GenericHost,
GenericInterface,
OPNFVRole,
- OPNFVConfig
+ OPNFVConfig,
+ Network,
+ NetworkConnection,
+ NetworkRole,
+ HostOPNFVConfig,
)
from resource_inventory.resource_manager import ResourceManager
+from resource_inventory.pdf_templater import PDFTemplater
+from notifier.manager import NotificationHandler
from booking.models import Booking
from dashboard.exceptions import (
InvalidHostnameException,
ResourceAvailabilityException,
- ModelValidationException
+ ModelValidationException,
+ BookingLengthException
)
from api.models import JobFactory
pass
-def create_from_form(form, request):
- quick_booking_id = str(uuid.uuid4())
-
- host_field = form.cleaned_data['filter_field']
- host_json = json.loads(host_field)
- purpose_field = form.cleaned_data['purpose']
- project_field = form.cleaned_data['project']
- users_field = form.cleaned_data['users']
- host_name = form.cleaned_data['hostname']
- length = form.cleaned_data['length']
+class BookingPermissionException(Exception):
+ pass
- image = form.cleaned_data['image']
- scenario = form.cleaned_data['scenario']
- installer = form.cleaned_data['installer']
- # get all initial info we need to validate
+def parse_host_field(host_field_contents):
+ host_json = json.loads(host_field_contents)
lab_dict = host_json['labs'][0]
lab_id = list(lab_dict.keys())[0]
lab_user_id = int(lab_id.split("_")[-1])
profile = HostProfile.objects.get(id=profile_id)
# check validity of field data before trying to apply to models
+ if len(host_json['labs']) != 1:
+ raise NoLabSelectedError("No lab was selected")
if not lab:
raise LabDNE("Lab with provided ID does not exist")
if not profile:
raise HostProfileDNE("Host type with provided ID does not exist")
- # check that hostname is valid
- if not re.match(r"(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})$", host_name):
- raise InvalidHostnameException("Hostname must comply to RFC 952 and all extensions to it until this point")
- # check that image os is compatible with installer
- if installer in image.os.sup_installers.all():
- #if installer not here, we can omit that and not check for scenario
- if not scenario:
- raise IncompatibleScenarioForInstaller("An OPNFV Installer needs a scenario to be chosen to work properly")
- if scenario not in installer.sup_scenarios.all():
- raise IncompatibleScenarioForInstaller("The chosen installer does not support the chosen scenario")
- if image.from_lab != lab:
- raise ImageNotAvailableAtLab("The chosen image is not available at the chosen hosting lab")
- if image.host_type != profile:
- raise IncompatibleImageForHost("The chosen image is not available for the chosen host type")
- if not image.public and image.owner != request.user:
- raise ImageOwnershipInvalid("You are not the owner of the chosen private image")
+ return lab, profile
+
- # check if host type is available
- #ResourceManager.getInstance().acquireHost(ghost, lab.name)
+def check_available_matching_host(lab, hostprofile):
available_host_types = ResourceManager.getInstance().getAvailableHostTypes(lab)
- if not profile in available_host_types:
+ if hostprofile not in available_host_types:
# TODO: handle deleting generic resource in this instance along with grb
- raise HostNotAvailable("Could not book selected host due to changed availability. Try again later")
+ raise HostNotAvailable('Requested host type is not available. Please try again later. Host availability can be viewed in the "Hosts" tab to the left.')
- # check if any hosts with profile at lab are still available
- hostset = Host.objects.filter(lab=lab, profile=profile).filter(booked=False).filter(working=True)
- if not hostset.first():
+ hostset = Host.objects.filter(lab=lab, profile=hostprofile).filter(booked=False).filter(working=True)
+ if not hostset.exists():
raise HostNotAvailable("Couldn't find any matching unbooked hosts")
- # generate GenericResourceBundle
- if len(host_json['labs']) != 1:
- raise NoLabSelectedError("No lab was selected")
+ return True
+
- grbundle = GenericResourceBundle(owner=request.user)
+def generate_grb(owner, lab, common_id):
+ grbundle = GenericResourceBundle(owner=owner)
grbundle.lab = lab
- grbundle.name = "grbundle for quick booking with uid " + quick_booking_id
+ grbundle.name = "grbundle for quick booking with uid " + common_id
grbundle.description = "grbundle created for quick-deploy booking"
grbundle.save()
- # generate GenericResource, GenericHost
- gresource = GenericResource(bundle=grbundle, name=host_name)
+ return grbundle
+
+
+def generate_gresource(bundle, hostname):
+ if not re.match(r"(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})$", hostname):
+ raise InvalidHostnameException("Hostname must comply to RFC 952 and all extensions to it until this point")
+ gresource = GenericResource(bundle=bundle, name=hostname)
gresource.save()
+ return gresource
+
+
+def generate_ghost(generic_resource, host_profile):
ghost = GenericHost()
- ghost.resource = gresource
- ghost.profile = profile
+ ghost.resource = generic_resource
+ ghost.profile = host_profile
ghost.save()
- # generate config bundle
+ return ghost
+
+
+def generate_config_bundle(owner, common_id, grbundle):
cbundle = ConfigBundle()
- cbundle.owner = request.user
- cbundle.name = "configbundle for quick booking with uid " + quick_booking_id
+ cbundle.owner = owner
+ cbundle.name = "configbundle for quick booking with uid " + common_id
cbundle.description = "configbundle created for quick-deploy booking"
cbundle.bundle = grbundle
cbundle.save()
- # generate OPNFVConfig pointing to cbundle
- if installer:
- opnfvconfig = OPNFVConfig()
- opnfvconfig.scenario = scenario
- opnfvconfig.installer = installer
- opnfvconfig.bundle = cbundle
- opnfvconfig.save()
+ return cbundle
+
+
+def generate_opnfvconfig(scenario, installer, config_bundle):
+ opnfvconfig = OPNFVConfig()
+ opnfvconfig.scenario = scenario
+ opnfvconfig.installer = installer
+ opnfvconfig.bundle = config_bundle
+ opnfvconfig.save()
+
+ return opnfvconfig
+
- # generate HostConfiguration pointing to cbundle
+def generate_hostconfig(generic_host, image, config_bundle):
hconf = HostConfiguration()
- hconf.host = ghost
+ hconf.host = generic_host
hconf.image = image
- hconf.opnfvRole = OPNFVRole.objects.get(name="Jumphost")
- if not hconf.opnfvRole:
- raise OPNFVRoleDNE("No jumphost role was found")
- hconf.bundle = cbundle
+ hconf.bundle = config_bundle
+ hconf.is_head_node = True
hconf.save()
- # construct generic interfaces
- for interface_profile in profile.interfaceprofile.all():
- generic_interface = GenericInterface.objects.create(profile=interface_profile, host=ghost)
- generic_interface.save()
- ghost.save()
-
- # get vlan, assign to first interface
- publicnetwork = lab.vlan_manager.get_public_vlan()
- publicvlan = publicnetwork.vlan
- if not publicnetwork:
- raise NoRemainingPublicNetwork("No public networks were available for your pod")
- lab.vlan_manager.reserve_public_vlan(publicvlan)
+ return hconf
- vlan = Vlan.objects.create(vlan_id=publicvlan, tagged=False, public=True)
- vlan.save()
- ghost.generic_interfaces.first().vlans.add(vlan)
- ghost.generic_interfaces.first().save()
- # generate resource bundle
+def generate_hostopnfv(hostconfig, opnfvconfig):
+ config = HostOPNFVConfig()
+ role = None
try:
- resource_bundle = ResourceManager.getInstance().convertResourceBundle(grbundle, config=cbundle)
+ role = OPNFVRole.objects.get(name="Jumphost")
+ except Exception:
+ role = OPNFVRole.objects.create(
+ name="Jumphost",
+ description="Single server jumphost role"
+ )
+ config.role = role
+ config.host_config = hostconfig
+ config.opnfv_config = opnfvconfig
+ config.save()
+ return config
+
+
+def generate_resource_bundle(generic_resource_bundle, config_bundle): # warning: requires cleanup
+ try:
+ resource_manager = ResourceManager.getInstance()
+ resource_bundle = resource_manager.convertResourceBundle(generic_resource_bundle, config=config_bundle)
+ return resource_bundle
except ResourceAvailabilityException:
raise ResourceAvailabilityException("Requested resources not available")
except ModelValidationException:
raise ModelValidationException("Encountered error while saving grbundle")
+
+def check_invariants(request, **kwargs):
+ installer = kwargs['installer']
+ image = kwargs['image']
+ scenario = kwargs['scenario']
+ lab = kwargs['lab']
+ host_profile = kwargs['host_profile']
+ length = kwargs['length']
+ # check that image os is compatible with installer
+ if installer in image.os.sup_installers.all():
+ # if installer not here, we can omit that and not check for scenario
+ if not scenario:
+ raise IncompatibleScenarioForInstaller("An OPNFV Installer needs a scenario to be chosen to work properly")
+ if scenario not in installer.sup_scenarios.all():
+ raise IncompatibleScenarioForInstaller("The chosen installer does not support the chosen scenario")
+ if image.from_lab != lab:
+ raise ImageNotAvailableAtLab("The chosen image is not available at the chosen hosting lab")
+ if image.host_type != host_profile:
+ raise IncompatibleImageForHost("The chosen image is not available for the chosen host type")
+ if not image.public and image.owner != request.user:
+ raise ImageOwnershipInvalid("You are not the owner of the chosen private image")
+ if length < 1 or length > 21:
+ raise BookingLengthException("Booking must be between 1 and 21 days long")
+
+
+def configure_networking(grb, config):
+ # create network
+ net = Network.objects.create(name="public", bundle=grb, is_public=True)
+ # connect network to generic host
+ grb.getHosts()[0].generic_interfaces.first().connections.add(
+ NetworkConnection.objects.create(network=net, vlan_is_tagged=False)
+ )
+ # asign network role
+ role = NetworkRole.objects.create(name="public", network=net)
+ opnfv_config = config.opnfv_config.first()
+ if opnfv_config:
+ opnfv_config.networks.add(role)
+
+
+def create_from_form(form, request):
+ quick_booking_id = str(uuid.uuid4())
+
+ host_field = form.cleaned_data['filter_field']
+ purpose_field = form.cleaned_data['purpose']
+ project_field = form.cleaned_data['project']
+ users_field = form.cleaned_data['users']
+ hostname = form.cleaned_data['hostname']
+ length = form.cleaned_data['length']
+
+ image = form.cleaned_data['image']
+ scenario = form.cleaned_data['scenario']
+ installer = form.cleaned_data['installer']
+
+ lab, host_profile = parse_host_field(host_field)
+ data = form.cleaned_data
+ data['lab'] = lab
+ data['host_profile'] = host_profile
+ check_invariants(request, **data)
+
+ # check booking privileges
+ if Booking.objects.filter(owner=request.user, end__gt=timezone.now()).count() >= 3 and not request.user.userprofile.booking_privledge:
+ raise BookingPermissionException("You do not have permission to have more than 3 bookings at a time.")
+
+ check_available_matching_host(lab, host_profile) # requires cleanup if failure after this point
+
+ grbundle = generate_grb(request.user, lab, quick_booking_id)
+ gresource = generate_gresource(grbundle, hostname)
+ ghost = generate_ghost(gresource, host_profile)
+ cbundle = generate_config_bundle(request.user, quick_booking_id, grbundle)
+ hconf = generate_hostconfig(ghost, image, cbundle)
+
+ # if no installer provided, just create blank host
+ opnfv_config = None
+ if installer:
+ opnfv_config = generate_opnfvconfig(scenario, installer, cbundle)
+ generate_hostopnfv(hconf, opnfv_config)
+
+ # construct generic interfaces
+ for interface_profile in host_profile.interfaceprofile.all():
+ generic_interface = GenericInterface.objects.create(profile=interface_profile, host=ghost)
+ generic_interface.save()
+
+ configure_networking(grbundle, cbundle)
+
+ # generate resource bundle
+ resource_bundle = generate_resource_bundle(grbundle, cbundle)
+
# generate booking
- booking = Booking()
- booking.purpose = purpose_field
- booking.project = project_field
- booking.lab = lab
- booking.owner = request.user
- booking.start = timezone.now()
- booking.end = timezone.now() + timedelta(days=int(length))
- booking.resource = resource_bundle
- booking.pdf = ResourceManager().makePDF(booking.resource)
- booking.save()
- print("users field:")
- print(users_field)
- print(type(users_field))
- #users_field = json.loads(users_field)
+ booking = Booking.objects.create(
+ purpose=purpose_field,
+ project=project_field,
+ lab=lab,
+ owner=request.user,
+ start=timezone.now(),
+ end=timezone.now() + timedelta(days=int(length)),
+ resource=resource_bundle,
+ config_bundle=cbundle,
+ opnfv_config=opnfv_config
+ )
+ booking.pdf = PDFTemplater.makePDF(booking)
+
users_field = users_field[2:-2]
- if users_field: #may be empty after split, if no collaborators entered
+ if users_field: # may be empty after split, if no collaborators entered
users_field = json.loads(users_field)
for collaborator in users_field:
user = User.objects.get(id=collaborator['id'])
booking.collaborators.add(user)
- booking.save()
+
+ booking.save()
# generate job
JobFactory.makeCompleteJob(booking)
+ NotificationHandler.notify_new_booking(booking)
def drop_filter(user):