Simple maas plugin for the example

From UNamur InfoSec
Revision as of 14:59, 5 December 2021 by Mkuy (talk | contribs) (→‎Source code)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

OSM has include an example dummy VIM implementation here: [1](https://osm.etsi.org/gitweb/?p=osm/RO.git;a=blob;f=RO-plugin/osm_ro_plugin/vim_dummy.py;h=fe3a8115399fffb019ba90fe00698549676d59ed;hb=82954653961d69ce6a44ad26e992fb65db89f9ef)

The dummy VIM is a working VIM but only return dummy data to OSM.

To implement only the minimal deployment, we can extends the dummy VIM and only implement two functions: "new_vminstance", and "refresh_vms_status" functions.

Source code

The source code extends the vim_dummy file instead of vimconn file, and only implement three functions.

With these implementation, we can support deployed simple NS deployment.

import logging
from osm_ro_plugin import vim_dummy
from maas.client import login
import asyncio
from uuid import uuid4
from copy import deepcopy
import yaml

__author__ = ""
__date__ = ""


class vimconnector(vim_dummy.VimDummyConnector):

    def new_vminstance(
            self,
            name,
            description,
            start,
            image_id,
            flavor_id,
            net_list,
            cloud_config=None,
            disk_list=None,
            availability_zone_index=None,
            availability_zone_list=None,
        ):
            _, userdata = self._create_user_data(cloud_config)
            client = self._load_connection()
            flavor = self.get_flavor(flavor_id)
            machine = client.machines.allocate(cpus=flavor["vcpus"], memory=flavor["ram"])
            image = self.images[image_id]
            machine.deploy(user_data=userdata, distro_series=image["name"])
            vm_id = machine.system_id
            vm = {
                "id": vm_id,
                "name": name,
                "status": self._get_mapped_status(machine),
                "description": description,
                "interfaces": self._get_machine_interfaces(machine, net_list),
                "image_id": image_id,
                "flavor_id": flavor_id,
            }
            self.vms[vm_id] = vm
            return vm_id, vm
        
    def refresh_vms_status(self, vm_list):
            vms = {}
            client = self._load_connection()
            for vm_id in vm_list:
                try:
                    machine = client.machines.get(system_id=vm_id)
                    machine.refresh()
                    vm = deepcopy(self.vms[vm_id])
                    status = self._get_mapped_status(machine)
                    vm["vim_info"] = yaml.dump(
                        {"status": status, "name": vm["name"]},
                        default_flow_style=True,
                        width=256,
                    )
                    vm["status"] = status
                    for iface_index, iface in enumerate(vm["interfaces"]):
                        iface["ip_address"] = machine.interfaces[iface_index].links[iface_index].ip_address
                except Exception as e:
                    vm = {"status": "DELETED"}
                vms[vm_id] = vm
            return vms

    def delete_vminstance(self, vm_id, created_items=None):
        client = self._load_connection()
        machine = client.machines.get(system_id=vm_id)
        machine.release()
        self.vms.pop(vm_id)
        return vm_id
    
    def get_image_list(self, filter_dict=None):
        images = []
        image_id = str(uuid4())
        image = deepcopy(filter_dict)
        image["id"] = image_id
        self.images[image_id] = image
        images.append(image)
        return images

    #### private helper functions
    def _load_connection(self):
            try:
                asyncio.get_event_loop()
            except RuntimeError as ex:
                if "There is no current event loop in thread" in str(ex):
                    loop = asyncio.new_event_loop()
                    asyncio.set_event_loop(loop)
            client = login(
                self.url,
                username=self.user, password=self.passwd,
            )
            return client

    def _get_mapped_status(self, machine):
            machine_status = machine.status.name
            power_state = machine.power_state.name
            if (machine_status == "DEPLOYING"):
                return "BUILD"
            if (machine_status == "DEPLOYED"):
                return "ACTIVE"
            return "SUSPENDED"

    def _get_machine_interfaces(self, machine, net_list):
        interfaces = []
        machine.refresh()
        for iface_index, iface in enumerate(net_list):
            iface["vim_id"] = str(iface_index)
            interface = {
                "ip_address": machine.interfaces[iface_index].links[iface_index].ip_address,
                "mac_address": machine.interfaces[iface_index].mac_address,
                "vim_interface_id": str(iface_index),
                "vim_net_id": iface["net_id"],
            }
            interfaces.append(interface)
        return interfaces