RIFT OSM R1 Initial Submission
[osm/SO.git] / rwcal / plugins / vala / rwcal_aws / rwcal_aws.py
diff --git a/rwcal/plugins/vala/rwcal_aws/rwcal_aws.py b/rwcal/plugins/vala/rwcal_aws/rwcal_aws.py
new file mode 100644 (file)
index 0000000..4f212d7
--- /dev/null
@@ -0,0 +1,1111 @@
+
+# 
+#   Copyright 2016 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+import time
+import os
+import subprocess
+import logging
+import rift.rwcal.aws as aws_drv
+import rw_status
+import rift.cal.rwcal_status as rwcal_status
+import rwlogger
+import rift.rwcal.aws.exceptions as exceptions
+from gi import require_version
+require_version('RwCal', '1.0')
+
+from gi.repository import (
+    GObject,
+    RwCal,
+    RwTypes,
+    RwcalYang)
+
+
+PREPARE_VM_CMD = "prepare_vm.py --aws_key {key} --aws_secret {secret} --aws_region {region} --server_id {server_id}"
+DELETE_VM_CMD =  "delete_vm.py --aws_key {key} --aws_secret {secret} --aws_region {region} --server_id {server_id}"
+
+rwstatus_exception_map = {IndexError: RwTypes.RwStatus.NOTFOUND,
+                          KeyError: RwTypes.RwStatus.NOTFOUND,
+                          NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,
+                          AttributeError: RwTypes.RwStatus.FAILURE,
+                          exceptions.RWErrorNotFound: RwTypes.RwStatus.NOTFOUND,
+                          exceptions.RWErrorDuplicate: RwTypes.RwStatus.DUPLICATE,
+                          exceptions.RWErrorExists: RwTypes.RwStatus.EXISTS,
+                          exceptions.RWErrorNotConnected: RwTypes.RwStatus.NOTCONNECTED,
+                          }
+
+rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
+rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
+
+class RwcalAWSPlugin(GObject.Object, RwCal.Cloud):
+    """This class implements the CAL VALA methods for AWS."""
+
+    flavor_id = 1;
+    instance_num = 1
+    def __init__(self):
+        GObject.Object.__init__(self)
+        self._driver_class = aws_drv.AWSDriver
+        self._flavor_list = []
+        self.log = logging.getLogger('rwcal.aws.%s' % RwcalAWSPlugin.instance_num)
+        self.log.setLevel(logging.DEBUG)
+
+        RwcalAWSPlugin.instance_num += 1
+
+    def _get_driver(self, account):
+        return self._driver_class(key     = account.aws.key,
+                                  secret  = account.aws.secret,
+                                  region  = account.aws.region,
+                                  ssh_key = account.aws.ssh_key,
+                                  vpcid   = account.aws.vpcid,
+                                  availability_zone = account.aws.availability_zone,
+                                  default_subnet_id = account.aws.default_subnet_id)
+
+    @rwstatus
+    def do_init(self, rwlog_ctx):
+        self.log.addHandler(
+                rwlogger.RwLogger(
+                    category="rw-cal-log",
+                    subcategory="aws",
+                    log_hdl=rwlog_ctx,
+                    )
+                )
+
+    @rwstatus(ret_on_failure=[None])
+    def do_validate_cloud_creds(self, account):
+        """
+        Validates the cloud account credentials for the specified account.
+        Performs an access to the resources using underlying API. If creds
+        are not valid, returns an error code & reason string
+        Arguments:
+            account - a cloud account to validate
+
+        Returns:
+            Validation Code and Details String
+        """
+        status = RwcalYang.CloudConnectionStatus(
+                status="success",
+                details="AWS Cloud Account validation not implemented yet"
+                )
+
+        return status
+
+    @rwstatus(ret_on_failure=[""])
+    def do_get_management_network(self, account):
+        """
+        Returns the management network associated with the specified account.
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            The management network
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_tenant(self, account, name):
+        """Create a new tenant.
+
+        Arguments:
+            account - a cloud account
+            name - name of the tenant
+
+        Returns:
+            The tenant id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_tenant(self, account, tenant_id):
+        """delete a tenant.
+
+        Arguments:
+            account - a cloud account
+            tenant_id - id of the tenant
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_tenant_list(self, account):
+        """List tenants.
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List of tenants
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_role(self, account, name):
+        """Create a new user.
+
+        Arguments:
+            account - a cloud account
+            name - name of the user
+
+        Returns:
+            The user id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_role(self, account, role_id):
+        """Delete a user.
+
+        Arguments:
+            account - a cloud account
+            role_id - id of the user
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_role_list(self, account):
+        """List roles.
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List of roles
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_image(self, account, image):
+        """Create an image
+
+        Arguments:
+            account - a cloud account
+            image - a description of the image to create
+
+        Returns:
+            The image id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_image(self, account, image_id):
+        """Delete a vm image.
+
+        Arguments:
+            account - a cloud account
+            image_id - id of the image to delete
+        """
+        raise NotImplementedError
+
+    @staticmethod
+    def _fill_image_info(img_info):
+        """Create a GI object from image info dictionary
+
+        Converts image information dictionary object returned by AWS
+        driver into Protobuf Gi Object
+
+        Arguments:
+            account - a cloud account
+            img_info - image information dictionary object from AWS
+
+        Returns:
+            The ImageInfoItem
+        """
+        img = RwcalYang.ImageInfoItem()
+        img.name = img_info.name
+        img.id   = img_info.id
+
+        #tag_fields = ['checksum']
+        # Look for any properties
+        if img_info.tags:
+            for tag in img_info.tags:
+                if tag['Key'] == 'checksum':
+                    setattr(img, tag['Key'], tag['Value'])
+        img.disk_format  = 'ami'
+        if img_info.state == 'available':
+            img.state = 'active'
+        else:
+            img.state = 'inactive'
+        return img
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_image_list(self, account):
+        """Return a list of the names of all available images.
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            The the list of images in VimResources object
+        """
+        response = RwcalYang.VimResources()
+        images = self._get_driver(account).list_images()
+        for img in images:
+            response.imageinfo_list.append(RwcalAWSPlugin._fill_image_info(img))
+        return response
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_image(self, account, image_id):
+        """Return a image information.
+
+        Arguments:
+            account - a cloud account
+            image_id - an id of the image
+
+        Returns:
+            ImageInfoItem object containing image information.
+        """
+        image = self._get_driver(account).get_image(image_id)
+        return RwcalAWSPlugin._fill_image_info(image)
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_vm(self, account, vminfo):
+        """Create a new virtual machine.
+
+        Arguments:
+            account - a cloud account
+            vminfo - information that defines the type of VM to create
+
+        Returns:
+            The image id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_start_vm(self, account, vm_id):
+        """Start an existing virtual machine.
+
+        Arguments:
+            account - a cloud account
+            vm_id - an id of the VM
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_stop_vm(self, account, vm_id):
+        """Stop a running virtual machine.
+
+        Arguments:
+            account - a cloud account
+            vm_id - an id of the VM
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_vm(self, account, vm_id):
+        """Delete a virtual machine.
+
+        Arguments:
+            account - a cloud account
+            vm_id - an id of the VM
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_reboot_vm(self, account, vm_id):
+        """Reboot a virtual machine.
+
+        Arguments:
+            account - a cloud account
+            vm_id - an id of the VM
+        """
+        raise NotImplementedError
+
+    @staticmethod
+    def _fill_vm_info(vm_info):
+        """Create a GI object from vm info dictionary
+
+        Converts VM information dictionary object returned by openstack
+        driver into Protobuf Gi Object
+
+        Arguments:
+            vm_info - VM information from AWS
+
+        Returns:
+            Protobuf Gi object for VM
+        """
+        vm = RwcalYang.VMInfoItem()
+        vm.vm_id     = vm_info.id
+        vm.image_id  = vm_info.image_id
+        vm.flavor_id = vm_info.instance_type
+        if vm_info.state['Name'] == 'running':
+            vm.state = 'active'
+        else:
+            vm.state = 'inactive'
+        for network_intf in vm_info.network_interfaces:
+            if 'Attachment' in network_intf and network_intf['Attachment']['DeviceIndex'] == 0:
+                if 'Association' in network_intf and 'PublicIp' in network_intf['Association']:
+                    vm.public_ip = network_intf['Association']['PublicIp']
+                vm.management_ip = network_intf['PrivateIpAddress']
+            else:
+                addr = vm.private_ip_list.add()
+                addr.ip_address = network_intf['PrivateIpAddress']
+                if 'Association' in network_intf and 'PublicIp' in network_intf['Association']:
+                    addr = vm.public_ip_list.add()
+                    addr.ip_address = network_intf['Association']['PublicIp']
+
+        if vm_info.placement and 'AvailabilityZone' in vm_info.placement:
+            vm.availability_zone = vm_info.placement['AvailabilityZone']
+        if vm_info.tags:
+            for tag in vm_info.tags:
+                if tag['Key'] == 'Name':
+                    vm.vm_name   = tag['Value']
+                elif tag['Key'] in vm.user_tags.fields:
+                    setattr(vm.user_tags,tag['Key'],tag['Value'])
+        return vm
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_vm_list(self, account):
+        """Return a list of the VMs as vala boxed objects
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List containing VM information
+        """
+        response = RwcalYang.VimResources()
+        vms = self._get_driver(account).list_instances()
+        for vm in vms:
+            response.vminfo_list.append(RwcalAWSPlugin._fill_vm_info(vm))
+        return response
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_vm(self, account, id):
+        """Return vm information.
+
+        Arguments:
+            account - a cloud account
+            id - an id for the VM
+
+        Returns:
+            VM information
+        """
+        vm = self._get_driver(account).get_instance(id)
+        return RwcalAWSPlugin._fill_vm_info(vm)
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_flavor(self, account, flavor):
+        """Create new flavor.
+           AWS has fixed set of AWS types and so we map flavor to existing instance type
+           and create local flavor for the same.
+
+        Arguments:
+            account - a cloud account
+            flavor - flavor of the VM
+
+        Returns:
+            flavor id (with EC2 instance type included in id)
+        """
+        drv = self._get_driver(account)
+        inst_type = drv.map_flavor_to_instance_type(ram       = flavor.vm_flavor.memory_mb,
+                                vcpus     = flavor.vm_flavor.vcpu_count,
+                                disk      = flavor.vm_flavor.storage_gb)
+
+        new_flavor = RwcalYang.FlavorInfoItem()
+        new_flavor.name = flavor.name
+        new_flavor.vm_flavor.memory_mb = flavor.vm_flavor.memory_mb
+        new_flavor.vm_flavor.vcpu_count = flavor.vm_flavor.vcpu_count
+        new_flavor.vm_flavor.storage_gb = flavor.vm_flavor.storage_gb
+        new_flavor.id = inst_type + '-' + str(RwcalAWSPlugin.flavor_id)
+        RwcalAWSPlugin.flavor_id = RwcalAWSPlugin.flavor_id+1
+        self._flavor_list.append(new_flavor)
+        return new_flavor.id
+
+    @rwstatus
+    def do_delete_flavor(self, account, flavor_id):
+        """Delete flavor.
+
+        Arguments:
+            account - a cloud account
+            flavor_id - id flavor of the VM
+        """
+
+        flavor = [flav for flav in self._flavor_list if flav.id == flavor_id]
+        self._flavor_list.delete(flavor[0])
+
+    @staticmethod
+    def _fill_flavor_info(flavor_info):
+        """Create a GI object from flavor info dictionary
+
+        Converts Flavor information dictionary object returned by openstack
+        driver into Protobuf Gi Object
+
+        Arguments:
+            flavor_info: Flavor information from openstack
+
+        Returns:
+             Object of class FlavorInfoItem
+        """
+        flavor = RwcalYang.FlavorInfoItem()
+        flavor.name                       = flavor_info.name
+        flavor.id                         = flavor_info.id
+        flavor.vm_flavor.memory_mb = flavor_info.vm_flavor.memory_mb
+        flavor.vm_flavor.vcpu_count = flavor_info.vm_flavor.vcpu_count
+        flavor.vm_flavor.storage_gb = flavor_info.vm_flavor.storage_gb
+        return flavor
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_flavor_list(self, account):
+        """Return flavor information.
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List of flavors
+        """
+        response = RwcalYang.VimResources()
+        for flv in self._flavor_list:
+            response.flavorinfo_list.append(RwcalAWSPlugin._fill_flavor_info(flv))
+        return response
+
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_flavor(self, account, id):
+        """Return flavor information.
+
+        Arguments:
+            account - a cloud account
+            id - an id for the flavor
+
+        Returns:
+            Flavor info item
+        """
+        flavor = [flav for flav in self._flavor_list if flav.id == id]
+        return (RwcalAWSPlugin._fill_flavor_info(flavor[0]))
+
+    def _fill_network_info(self, network_info, account):
+        """Create a GI object from network info dictionary
+
+        Converts Network information dictionary object returned by AWS
+        driver into Protobuf Gi Object
+
+        Arguments:
+            network_info - Network information from AWS
+            account - a cloud account
+
+        Returns:
+            Network info item
+        """
+        network                  = RwcalYang.NetworkInfoItem()
+        network.network_id       = network_info.subnet_id
+        network.subnet           = network_info.cidr_block
+        if network_info.tags:
+            for tag in network_info.tags:
+                if tag['Key'] == 'Name':
+                    network.network_name   = tag['Value']
+        return network
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_network_list(self, account):
+        """Return a list of networks
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List of networks
+        """
+        response = RwcalYang.VimResources()
+        networks = self._get_driver(account).get_subnet_list()
+        for network in networks:
+            response.networkinfo_list.append(self._fill_network_info(network, account))
+        return response
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_network(self, account, id):
+        """Return a network
+
+        Arguments:
+            account - a cloud account
+            id - an id for the network
+
+        Returns:
+            Network info item
+        """
+        network = self._get_driver(account).get_subnet(id)
+        return self._fill_network_info(network, account)
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_network(self, account, network):
+        """Create a new network
+
+        Arguments:
+            account - a cloud account
+            network - Network object
+
+        Returns:
+            Network id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_network(self, account, network_id):
+        """Delete a network
+
+        Arguments:
+            account - a cloud account
+            network_id - an id for the network
+        """
+        raise NotImplementedError
+
+    @staticmethod
+    def _fill_port_info(port_info):
+        """Create a GI object from port info dictionary
+
+        Converts Port information dictionary object returned by AWS
+        driver into Protobuf Gi Object
+
+        Arguments:
+            port_info - Port/Network interface information from AWS
+
+        Returns:
+            Port info item
+        """
+        port = RwcalYang.PortInfoItem()
+
+        port.port_id    = port_info.id
+        port.network_id = port_info.subnet_id
+        if port_info.attachment and 'InstanceId' in port_info.attachment:
+            port.vm_id = port_info.attachment['InstanceId']
+        port.ip_address = port_info.private_ip_address
+        if port_info.status == 'in-use':
+            port.port_state = 'active'
+        elif port_info.status == 'available':
+            port.port_state = 'inactive'
+        else:
+            port.port_state = 'unknown'
+        if port_info.tag_set:
+            for tag in port_info.tag_set:
+                if tag['Key'] == 'Name':
+                    port.port_name   = tag['Value']
+        return port
+
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_port(self, account, port_id):
+        """Return a port
+
+        Arguments:
+            account - a cloud account
+            port_id - an id for the port
+
+        Returns:
+            Port info item
+        """
+        port = self._get_driver(account).get_network_interface(port_id)
+        return RwcalAWSPlugin._fill_port_info(port)
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_port_list(self, account):
+        """Return a list of ports
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            Port info list
+        """
+        response = RwcalYang.VimResources()
+        ports = self._get_driver(account).get_network_interface_list()
+        for port in ports:
+            response.portinfo_list.append(RwcalAWSPlugin._fill_port_info(port))
+        return response
+
+    @rwstatus(ret_on_failure=[""])
+    def do_create_port(self, account, port):
+        """Create a new port
+
+        Arguments:
+            account - a cloud account
+            port - port object
+
+        Returns:
+            Port id
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_delete_port(self, account, port_id):
+        """Delete a port
+
+        Arguments:
+            account - a cloud account
+            port_id - an id for port
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[""])
+    def do_add_host(self, account, host):
+        """Add a new host
+
+        Arguments:
+            account - a cloud account
+            host - a host object
+
+        Returns:
+            An id for the host
+        """
+        raise NotImplementedError
+
+    @rwstatus
+    def do_remove_host(self, account, host_id):
+        """Remove a host
+
+        Arguments:
+            account - a cloud account
+            host_id - an id for the host
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_host(self, account, host_id):
+        """Return a host
+
+        Arguments:
+            account - a cloud account
+            host_id - an id for host
+
+        Returns:
+            Host info item
+        """
+        raise NotImplementedError
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_host_list(self, account):
+        """Return a list of hosts
+
+        Arguments:
+            account - a cloud account
+
+        Returns:
+            List of hosts
+        """
+        raise NotImplementedError
+
+    @rwcalstatus(ret_on_failure=[""])
+    def do_create_virtual_link(self, account, link_params):
+        """Create a new virtual link
+
+        Arguments:
+            account     - a cloud account
+            link_params - information that defines the type of VDU to create
+
+        Returns:
+            The vdu_id
+        """
+        drv = self._get_driver(account)
+        kwargs = {}
+        kwargs['CidrBlock'] = link_params.subnet
+
+        subnet =  drv.create_subnet(**kwargs)
+        if link_params.name:
+            subnet.create_tags(Tags=[{'Key': 'Name','Value':link_params.name}])
+        if link_params.associate_public_ip:
+              drv.modify_subnet(SubnetId=subnet.id,MapPublicIpOnLaunch=link_params.associate_public_ip)
+        return subnet.id
+
+    @rwstatus
+    def do_delete_virtual_link(self, account, link_id):
+        """Delete a virtual link
+
+        Arguments:
+            account - a cloud account
+            link_id - id for the virtual-link to be deleted
+
+        Returns:
+            None
+        """
+        drv = self._get_driver(account)
+        port_list = drv.get_network_interface_list(SubnetId=link_id)
+        for port in port_list:
+            if port  and port.association and 'AssociationId' in port.association:
+                drv.disassociate_public_ip_from_network_interface(NetworkInterfaceId=port.id)
+            if port and port.attachment and 'AttachmentId' in port.attachment:
+                drv.detach_network_interface(AttachmentId = port.attachment['AttachmentId'],Force=True) #force detach as otherwise delete fails
+                #detach instance takes time; so poll to check port is not in-use
+                port = drv.get_network_interface(NetworkInterfaceId=port.id)
+                retries = 0
+                while port.status == 'in-use' and retries < 10:
+                    time.sleep(5)
+                    port = drv.get_network_interface(NetworkInterfaceId=port.id)
+            drv.delete_network_interface(NetworkInterfaceId=port.id)
+        drv.delete_subnet(link_id)
+
+    @staticmethod
+    def _fill_connection_point_info(c_point, port_info):
+        """Create a GI object for RwcalYang.VDUInfoParams_ConnectionPoints()
+
+        Converts EC2.NetworkInterface object returned by AWS driver into
+        Protobuf Gi Object
+
+        Arguments:
+            port_info - Network Interface information from AWS
+        Returns:
+            Protobuf Gi object for RwcalYang.VDUInfoParams_ConnectionPoints
+        """
+        c_point.virtual_link_id = port_info.subnet_id
+        c_point.connection_point_id = port_info.id
+        if port_info.attachment:
+            c_point.vdu_id = port_info.attachment['InstanceId']
+        c_point.ip_address = port_info.private_ip_address
+        if port_info.association and 'PublicIp' in port_info.association:
+                c_point.public_ip = port_info.association['PublicIp']
+        if port_info.tag_set:
+            for tag in port_info.tag_set:
+                if tag['Key'] == 'Name':
+                    c_point.name   = tag['Value']
+        if port_info.status == 'in-use':
+            c_point.state = 'active'
+        elif port_info.status == 'available':
+            c_point.state = 'inactive'
+        else:
+            c_point.state = 'unknown'
+
+    @staticmethod
+    def _fill_virtual_link_info(network_info, port_list):
+        """Create a GI object for VirtualLinkInfoParams
+
+        Converts Subnet and NetworkInterface object
+        returned by AWS driver into Protobuf Gi Object
+
+        Arguments:
+            network_info - Subnet information from AWS
+            port_list - A list of network interface information from openstack
+        Returns:
+            Protobuf Gi object for VirtualLinkInfoParams
+        """
+        link = RwcalYang.VirtualLinkInfoParams()
+        if network_info.state == 'available':
+            link.state = 'active'
+        else:
+            link.state = 'inactive'
+        link.virtual_link_id = network_info.subnet_id
+        link.subnet = network_info.cidr_block
+        if network_info.tags:
+            for tag in network_info.tags:
+                if tag['Key'] == 'Name':
+                    link.name   = tag['Value']
+        for port in port_list:
+            c_point = link.connection_points.add()
+            RwcalAWSPlugin._fill_connection_point_info(c_point, port)
+
+        return link
+
+    @staticmethod
+    def _fill_vdu_info(vm_info, port_list):
+        """Create a GI object for VDUInfoParams
+
+        Converts VM information dictionary object returned by AWS
+        driver into Protobuf Gi Object
+
+        Arguments:
+            vm_info - EC2 instance information from AWS
+            port_list - A list of network interface information from AWS
+        Returns:
+            Protobuf Gi object for VDUInfoParams
+        """
+        vdu = RwcalYang.VDUInfoParams()
+        vdu.vdu_id = vm_info.id
+        mgmt_port = [port for port in port_list if port.attachment and port.attachment['DeviceIndex'] == 0]
+        assert(len(mgmt_port) == 1)
+        vdu.management_ip = mgmt_port[0].private_ip_address
+        if mgmt_port[0].association and 'PublicIp' in mgmt_port[0].association:
+            vdu.public_ip = mgmt_port[0].association['PublicIp']
+            #For now set managemnet ip also to public ip
+            #vdu.management_ip = vdu.public_ip
+        if vm_info.tags:
+            for tag in vm_info.tags:
+                if tag['Key'] == 'Name':
+                    vdu.name   = tag['Value']
+                elif tag['Key'] == 'node_id':
+                    vdu.node_id = tag['Value']
+        vdu.image_id = vm_info.image_id
+        vdu.flavor_id = vm_info.instance_type
+        if vm_info.state['Name'] == 'running':
+            vdu.state = 'active'
+        else:
+            vdu.state = 'inactive'
+        #if vm_info.placement and 'AvailabilityZone' in vm_info.placement:
+        #    vdu.availability_zone = vm_info.placement['AvailabilityZone']
+        # Fill the port information
+        cp_port_list = [port for port in port_list if port.attachment and port.attachment['DeviceIndex'] != 0]
+
+        for port in cp_port_list:
+            c_point = vdu.connection_points.add()
+            RwcalAWSPlugin._fill_connection_point_info(c_point, port)
+        return vdu
+
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_virtual_link(self, account, link_id):
+        """Get information about virtual link.
+
+        Arguments:
+            account  - a cloud account
+            link_id  - id for the virtual-link
+
+        Returns:
+            Object of type RwcalYang.VirtualLinkInfoParams
+        """
+        drv = self._get_driver(account)
+        network = drv.get_subnet(SubnetId=link_id)
+        port_list = drv.get_network_interface_list(SubnetId=link_id)
+        virtual_link = RwcalAWSPlugin._fill_virtual_link_info(network, port_list)
+        return virtual_link
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_virtual_link_list(self, account):
+        """Get information about all the virtual links
+
+        Arguments:
+            account  - a cloud account
+
+        Returns:
+            A list of objects of type RwcalYang.VirtualLinkInfoParams
+        """
+        vnf_resources = RwcalYang.VNFResources()
+        drv = self._get_driver(account)
+        networks = drv.get_subnet_list()
+        for network in networks:
+            port_list = drv.get_network_interface_list(SubnetId=network.id)
+            virtual_link = RwcalAWSPlugin._fill_virtual_link_info(network, port_list)
+            vnf_resources.virtual_link_info_list.append(virtual_link)
+        return vnf_resources
+
+    def _create_connection_point(self, account, c_point):
+        """
+        Create a connection point
+        Arguments:
+           account  - a cloud account
+           c_point  - connection_points
+        """
+        drv = self._get_driver(account)
+        port     = drv.create_network_interface(SubnetId=c_point.virtual_link_id)
+        if c_point.name:
+            port.create_tags(Tags=[{'Key': 'Name','Value':c_point.name}])
+        if c_point.associate_public_ip:
+                drv.associate_public_ip_to_network_interface(NetworkInterfaceId = port.id)
+        return port
+
+    def prepare_vdu_on_boot(self, account, server_id,vdu_init_params,vdu_port_list = None):
+        cmd = PREPARE_VM_CMD.format(key     = account.aws.key,
+                                  secret  = account.aws.secret,
+                                  region  = account.aws.region,
+                                  server_id = server_id)
+        if vdu_init_params.has_field('name'):
+            cmd += (" --vdu_name "+ vdu_init_params.name)
+        if vdu_init_params.has_field('node_id'):
+            cmd += (" --vdu_node_id "+ vdu_init_params.node_id)
+        if vdu_port_list is not None:
+            for port_id in vdu_port_list:
+                cmd += (" --vdu_port_list "+ port_id)
+
+        exec_path = 'python3 ' + os.path.dirname(aws_drv.__file__)
+        exec_cmd = exec_path+'/'+cmd
+        self.log.info("Running command: %s" %(exec_cmd))
+        subprocess.call(exec_cmd, shell=True)
+
+    @rwcalstatus(ret_on_failure=[""])
+    def do_create_vdu(self, account, vdu_init):
+        """Create a new virtual deployment unit
+
+        Arguments:
+            account     - a cloud account
+            vdu_init  - information about VDU to create (RwcalYang.VDUInitParams)
+
+        Returns:
+            The vdu_id
+        """
+        drv = self._get_driver(account)
+        ### First create required number of ports aka connection points
+        port_list = []
+
+        ### Now Create VM
+        kwargs = {}
+        kwargs['ImageId'] = vdu_init.image_id
+        if vdu_init.has_field('flavor_id'):
+            #Get instance type from flavor id which is of form c3.xlarge-1
+            inst_type =  vdu_init.flavor_id.split('-')[0]
+        else:
+            inst_type = drv.map_flavor_to_instance_type(ram       = vdu_init.vm_flavor.memory_mb,
+                                vcpus     = vdu_init.vm_flavor.vcpu_count,
+                                disk      = vdu_init.vm_flavor.storage_gb)
+
+        kwargs['InstanceType'] = inst_type
+        if vdu_init.vdu_init and vdu_init.vdu_init.userdata:
+            kwargs['UserData'] = vdu_init.vdu_init.userdata
+
+        #If we need to allocate public IP address create network interface and associate elastic
+        #ip  to interface
+        if vdu_init.allocate_public_address:
+           port_id     = drv.create_network_interface(SubnetId=drv.default_subnet_id)
+           drv.associate_public_ip_to_network_interface(NetworkInterfaceId = port_id.id)
+           network_interface  = {'NetworkInterfaceId':port_id.id,'DeviceIndex':0}
+           kwargs['NetworkInterfaces'] = [network_interface]
+
+        #AWS Driver will use default subnet id to create first network interface
+        # if network interface is not specified and will also have associate public ip
+        # if enabled for the subnet
+        vm_inst = drv.create_instance(**kwargs)
+
+        # Wait for instance to get to running state before attaching network interface
+        # to instance
+        #vm_inst[0].wait_until_running()
+
+        #if vdu_init.name:
+            #vm_inst[0].create_tags(Tags=[{'Key': 'Name','Value':vdu_init.name}])
+        #if vdu_init.node_id is not None:
+            #vm_inst[0].create_tags(Tags=[{'Key':'node_id','Value':vdu_init.node_id}])
+
+        # Create the connection points
+        port_list = []
+        for index,c_point in enumerate(vdu_init.connection_points):
+            port_id = self._create_connection_point(account, c_point)
+            port_list.append(port_id.id)
+            #drv.attach_network_interface(NetworkInterfaceId = port_id.id,InstanceId = vm_inst[0].id,DeviceIndex=index+1)
+
+        # We wait for instance to get to running state and update name,node_id and attach network intfs
+        self.prepare_vdu_on_boot(account, vm_inst[0].id, vdu_init, port_list)
+
+        return vm_inst[0].id
+
+    @rwstatus
+    def do_modify_vdu(self, account, vdu_modify):
+        """Modify Properties of existing virtual deployment unit
+
+        Arguments:
+            account     -  a cloud account
+            vdu_modify  -  Information about VDU Modification (RwcalYang.VDUModifyParams)
+        """
+        ### First create required number of ports aka connection points
+        drv = self._get_driver(account)
+        port_list = []
+
+        vm_inst = drv.get_instance(vdu_modify.vdu_id)
+
+        if vm_inst.state['Name'] != 'running':
+            self.log.error("RWCAL-AWS: VM with id %s is not in running state during modify VDU",vdu_modify.vdu_id)
+            raise exceptions.RWErrorFailure("RWCAL-AWS: VM with id %s is not in running state during modify VDU",vdu_modify.vdu_id)
+
+        port_list = drv.get_network_interface_list(InstanceId = vdu_modify.vdu_id)
+        used_device_indexs = [port.attachment['DeviceIndex'] for port in port_list if port.attachment]
+
+        device_index = 1
+        for c_point in vdu_modify.connection_points_add:
+            #Get unused device index
+            while device_index in used_device_indexs:
+                device_index = device_index+1
+            port_id = self._create_connection_point(account, c_point)
+            drv.attach_network_interface(NetworkInterfaceId = port_id.id,InstanceId = vdu_modify.vdu_id,DeviceIndex =device_index)
+
+        ### Detach the requested connection_points
+        for c_point in vdu_modify.connection_points_remove:
+            port = drv.get_network_interface(NetworkInterfaceId=c_point.connection_point_id)
+            #Check if elastic IP is associated with interface and release it
+            if port  and port.association and 'AssociationId' in port.association:
+                drv.disassociate_public_ip_from_network_interface(NetworkInterfaceId=port.id)
+            if port and port.attachment and port.attachment['DeviceIndex'] != 0:
+                drv.detach_network_interface(AttachmentId = port.attachment['AttachmentId'],Force=True) #force detach as otherwise delete fails
+            else:
+                self.log.error("RWCAL-AWS: Cannot modify connection port at index 0")
+
+        # Delete the connection points. Interfaces take time to get detached from instance and so
+        # we check status before doing delete network interface
+        for c_point in vdu_modify.connection_points_remove:
+            port = drv.get_network_interface(NetworkInterfaceId=c_point.connection_point_id)
+            retries = 0
+            if port and port.attachment and port.attachment['DeviceIndex'] == 0:
+                self.log.error("RWCAL-AWS: Cannot modify connection port at index 0")
+                continue
+            while port.status == 'in-use' and retries < 10:
+                time.sleep(5)
+                port = drv.get_network_interface(NetworkInterfaceId=c_point.connection_point_id)
+            drv.delete_network_interface(port.id)
+
+    def cleanup_vdu_on_term(self, account, server_id,vdu_port_list = None):
+        cmd = DELETE_VM_CMD.format(key    = account.aws.key,
+                                  secret  = account.aws.secret,
+                                  region  = account.aws.region,
+                                  server_id = server_id)
+        if vdu_port_list is not None:
+            for port_id in vdu_port_list:
+                cmd += (" --vdu_port_list "+ port_id)
+
+        exec_path = 'python3 ' + os.path.dirname(aws_drv.__file__)
+        exec_cmd = exec_path+'/'+cmd
+        self.log.info("Running command: %s" %(exec_cmd))
+        subprocess.call(exec_cmd, shell=True)
+
+    @rwstatus
+    def do_delete_vdu(self, account, vdu_id):
+        """Delete a virtual deployment unit
+
+        Arguments:
+            account - a cloud account
+            vdu_id  - id for the vdu to be deleted
+
+        Returns:
+            None
+        """
+        drv = self._get_driver(account)
+        ### Get list of port on VM and delete them.
+        #vm_inst = drv.get_instance(vdu_id)
+
+        port_list = drv.get_network_interface_list(InstanceId = vdu_id)
+        delete_port_list = [port.id for port in port_list if port.attachment and port.attachment['DeleteOnTermination'] is False]
+        drv.terminate_instance(vdu_id)
+
+        self.cleanup_vdu_on_term(account,vdu_id,delete_port_list)
+
+
+    @rwstatus(ret_on_failure=[None])
+    def do_get_vdu(self, account, vdu_id):
+        """Get information about a virtual deployment unit.
+
+        Arguments:
+            account - a cloud account
+            vdu_id  - id for the vdu
+
+        Returns:
+            Object of type RwcalYang.VDUInfoParams
+        """
+        drv = self._get_driver(account)
+
+        ### Get list of ports excluding the one for management network
+        vm = drv.get_instance(vdu_id)
+        port_list = drv.get_network_interface_list(InstanceId = vdu_id)
+        return RwcalAWSPlugin._fill_vdu_info(vm,port_list)
+
+
+    @rwstatus(ret_on_failure=[[]])
+    def do_get_vdu_list(self, account):
+        """Get information about all the virtual deployment units
+
+        Arguments:
+            account     - a cloud account
+
+        Returns:
+            A list of objects of type RwcalYang.VDUInfoParams
+        """
+        vnf_resources = RwcalYang.VNFResources()
+        drv = self._get_driver(account)
+        vms = drv.list_instances()
+        for vm in vms:
+            ### Get list of ports excluding one for management network
+            port_list = [p for p in drv.get_network_interface_list(InstanceId = vm.id)]
+            vdu = RwcalAWSPlugin._fill_vdu_info(vm,
+                                                port_list)
+            vnf_resources.vdu_info_list.append(vdu)
+        return vnf_resources