############################################################################## # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## from django.contrib.auth.models import User from django.core.files.base import ContentFile from django.utils import timezone import json import re from datetime import timedelta from dashboard.exceptions import InvalidHostnameException from booking.models import Booking from account.models import UserProfile, Lab, LabStatus, VlanManager, PublicNetwork from resource_inventory.models import ( Host, HostProfile, InterfaceProfile, DiskProfile, CpuProfile, Opsys, Image, Scenario, Installer, OPNFVRole, RamProfile, Network, GenericResourceBundle, GenericResource, GenericHost, ConfigBundle, GenericInterface, HostConfiguration, OPNFVConfig, NetworkConnection, HostOPNFVConfig ) from resource_inventory.resource_manager import ResourceManager """ Info for make_booking() function: [topology] argument structure: the [topology] argument should describe the structure of the pod the top level should be a dictionary, with each key being a hostname each value in the top level should be a dictionary with two keys: "type" should map to a host profile instance "nets" should map to a list of interfaces each with a list of dictionaries each defining a network in the format { "name": "netname", "tagged": True|False, "public": True|False } each network is defined if a matching name is not found sample argument structure: topology={ "host1": { "type": instanceOf HostProfile, "role": instanceOf OPNFVRole "image": instanceOf Image "nets": [ 0: [ 0: { "name": "public", "tagged": True, "public": True }, 1: { "name": "private", "tagged": False, "public": False }, ] 1: [] ] } } """ def make_booking(owner=None, start=timezone.now(), end=timezone.now() + timedelta(days=1), lab=None, purpose="my_purpose", project="my_project", collaborators=[], topology={}, installer=None, scenario=None): grb, host_set = make_grb(topology, owner, lab) config_bundle, opnfv_bundle = make_config_bundle(grb, owner, topology, host_set, installer, scenario) resource = ResourceManager.getInstance().convertResourceBundle(grb, config=config_bundle) if not resource: raise Exception("Resource not created") return Booking.objects.create( resource=resource, config_bundle=config_bundle, start=start, end=end, owner=owner, purpose=purpose, project=project, lab=lab, opnfv_config=opnfv_bundle ) def make_config_bundle(grb, owner, topology={}, host_set={}, installer=None, scenario=None): cb = ConfigBundle.objects.create( owner=owner, name="config bundle " + str(ConfigBundle.objects.count()), description="cb generated by make_config_bundle() method", bundle=grb ) scen = scenario or Scenario.objects.first() or make_scenario() inst = installer or Installer.objects.first() or make_installer([scen]) opnfv_config = OPNFVConfig.objects.create( installer=inst, scenario=scen, bundle=cb ) # generate host configurations based on topology and host set for hostname, host_info in topology.items(): host_config = HostConfiguration.objects.create( host=host_set[hostname], image=host_info["image"], bundle=cb, is_head_node=host_info['role'].name.lower() == "jumphost" ) HostOPNFVConfig.objects.create( role=host_info["role"], host_config=host_config, opnfv_config=opnfv_config ) return cb, opnfv_config def make_network(name, lab, grb, public): network = Network(name=name, bundle=grb, is_public=public) if public: public_net = lab.vlan_manager.get_public_vlan() if not public_net: raise Exception("No more public networks available") lab.vlan_manager.reserve_public_vlan(public_net.vlan) network.vlan_id = public_net.vlan else: private_net = lab.vlan_manager.get_vlan() if not private_net: raise Exception("No more generic vlans are available") lab.vlan_manager.reserve_vlans([private_net]) network.vlan_id = private_net network.save() return network def make_grb(topology, owner, lab): grb = GenericResourceBundle.objects.create( owner=owner, lab=lab, name="Generic ResourceBundle " + str(GenericResourceBundle.objects.count()), description="grb generated by make_grb() method" ) networks = {} host_set = {} for hostname, info in topology.items(): host_profile = info["type"] # need to construct host from hostname and type generic_host = make_generic_host(grb, host_profile, hostname) host_set[hostname] = generic_host # set up networks nets = info["nets"] for interface_index, interface_profile in enumerate(host_profile.interfaceprofile.all()): generic_interface = GenericInterface.objects.create(host=generic_host, profile=interface_profile) netconfig = nets[interface_index] for network_info in netconfig: network_name = network_info["name"] if network_name not in networks: networks[network_name] = make_network(network_name, lab, grb, network_info['public']) generic_interface.connections.add(NetworkConnection.objects.create( network=networks[network_name], vlan_is_tagged=network_info["tagged"] )) return grb, host_set def make_generic_host(grb, host_profile, 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") gresource = GenericResource.objects.create(bundle=grb, name=hostname) return GenericHost.objects.create(resource=gresource, profile=host_profile) def make_user(is_superuser=False, username="testuser", password="testpassword", email="default_email@user.com"): user = User.objects.get_or_create(username=username, email=email, password=password)[0] user.is_superuser = is_superuser user.save() return user def make_user_profile(user=None, email_addr="email@email.com", company="company", full_name="John Doe", booking_privledge=True, ssh_file=None): user = user or make_user() profile = UserProfile.objects.get_or_create( email_addr=email_addr, company=company, full_name=full_name, booking_privledge=booking_privledge, user=user )[0] profile.ssh_public_key.save("user_ssh_key", ssh_file if ssh_file else ContentFile("public key content string")) return profile def make_vlan_manager(vlans=None, block_size=20, allow_overlapping=False, reserved_vlans=None): if not vlans: vlans = [vlan % 2 for vlan in range(4095)] if not reserved_vlans: reserved_vlans = [0 for i in range(4095)] return VlanManager.objects.create( vlans=json.dumps(vlans), reserved_vlans=json.dumps(vlans), block_size=block_size, allow_overlapping=allow_overlapping ) def make_lab(user=None, name="Test_Lab_Instance", status=LabStatus.UP, vlan_manager=None, pub_net_count=5): if not vlan_manager: vlan_manager = make_vlan_manager() if not user: user = make_user(username=name + " user") lab = Lab.objects.create( lab_user=user, name=name, contact_email='test_lab@test_site.org', contact_phone='603 123 4567', status=status, vlan_manager=vlan_manager, description='test lab instantiation', api_token='12345678' ) for i in range(pub_net_count): make_public_net(vlan=i * 2 + 1, lab=lab) return lab """ resource_inventory instantiation section for permanent resources """ def make_complete_host_profile(lab, name="test_hostprofile"): host_profile = make_host_profile(lab, name=name) make_disk_profile(host_profile, 500, name=name) make_cpu_profile(host_profile) make_interface_profile(host_profile, name=name) make_ram_profile(host_profile) return host_profile def make_host_profile(lab, host_type=0, name="test hostprofile"): host_profile = HostProfile.objects.create( host_type=host_type, name=name, description='test hostprofile instance' ) host_profile.labs.add(lab) return host_profile def make_ram_profile(host, channels=4, amount=256): return RamProfile.objects.create( host=host, amount=amount, channels=channels ) def make_disk_profile(hostprofile, size=0, media_type="SSD", name="test diskprofile", rotation=0, interface="sata"): return DiskProfile.objects.create( name=name, size=size, media_type=media_type, host=hostprofile, rotation=rotation, interface=interface ) def make_cpu_profile(hostprofile, cores=4, architecture="x86_64", cpus=4,): return CpuProfile.objects.create( cores=cores, architecture=architecture, cpus=cpus, host=hostprofile, cflags='' ) def make_interface_profile(hostprofile, speed=1000, name="test interface profile", nic_type="pcie"): return InterfaceProfile.objects.create( host=hostprofile, name=name, speed=speed, nic_type=nic_type ) def make_image(lab, lab_id, owner, os, host_profile, public=True, name="default image", description="default image"): return Image.objects.create( from_lab=lab, lab_id=lab_id, os=os, host_type=host_profile, public=public, name=name, description=description ) def make_scenario(name="test scenario"): return Scenario.objects.create(name=name) def make_installer(scenarios, name="test installer"): installer = Installer.objects.create(name=name) for scenario in scenarios: installer.sup_scenarios.add(scenario) return installer def make_os(installers=None, name="test OS"): if not installers: installers = [make_installer([make_scenario()])] os = Opsys.objects.create(name=name) for installer in installers: os.sup_installers.add(installer) return os def make_host(host_profile, lab, labid="test_host", name="test_host", booked=False, working=True, config=None, template=None, bundle=None, model="Model 1", vendor="ACME"): return Host.objects.create( lab=lab, profile=host_profile, name=name, booked=booked, working=working, config=config, template=template, bundle=bundle, model=model, vendor=vendor ) def make_opnfv_role(name="Jumphost", description="test opnfvrole"): return OPNFVRole.objects.create( name=name, description=description ) def make_public_net(vlan, lab, in_use=False, cidr="0.0.0.0/0", gateway="0.0.0.0"): return PublicNetwork.objects.create( lab=lab, vlan=vlan, cidr=cidr, gateway=gateway )