import os
from pprint import pprint
from uuid import UUID
import re
from cloudmesh_client.cloud.iaas.CloudProviderBase import CloudProviderBase
from cloudmesh_client.common.todo import TODO
from cloudmesh_client.common.ConfigDict import Config, ConfigDict
from cloudmesh_client.common.LibcloudDict import LibcloudDict
from libcloud.compute.base import NodeAuthPassword, NodeAuthSSHKey
from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver
import libcloud.security
from cloudmesh_client.shell.console import Console
[docs]class CloudProviderLibcloud(CloudProviderBase):
debug = True
def _print(self, o):
if self.debug:
pprint(o)
for element in o:
pprint(element.__dict__)
def __init__(self, cloud_name, cloud_details, user=None, flat=True):
super(CloudProviderLibcloud, self).__init__(cloud_name, user=user)
self.flat = flat
self.cloud_type = "libcloud"
self.kind = ["image", "flavor", "vm", "key"]
self.dbobject = ["libcloud_image", "libcloud_flavor", "libcloud_vm", "key"]
self.default_image = None
self.default_flavor = None
self.cloud = None
self.config = None
self.provider = None
def _list(self, f, cloudname, **kwargs):
nodes = self.provider.f()
self._print(nodes)
d = self._to_dict(nodes)
return d
[docs] def list_key(self, cloudname, **kwargs):
Console.info("In list_key")
keys = self.provider.list_key_pairs()
#Console.info(keys)
#self._print(keys)
keys_dict = self._to_dict(keys)
#print (keys_dict)
return keys_dict
[docs] def list_vm(self, cloudname, **kwargs):
# return self.list(self.provider.list_nodes, cloudnames, kwargs)
Console.info("In list_vm")
nodes = self.provider.list_nodes()
self._print(nodes)
vm_dict = self._to_dict(nodes)
return vm_dict
[docs] def list_image(self, cloudname, **kwargs):
# return self.list(self.provider.list_images, cloudnames, kwargs)
Console.info("In list_images of libcloud")
images = self.provider.list_images()
self._print(images)
image_dict = self._to_dict(images)
return image_dict
[docs] def list_flavor(self, cloudname, **kwargs):
# return self.list(self.provider.list_sizes, cloudnames, kwargs)
Console.info("In list_flavor of libcloud")
sizes = self.provider.list_sizes()
self._print(sizes)
sizes_dict = self._to_dict(sizes)
return sizes_dict
# TODO: deprecated
[docs] def list_size(self, cloudname, **kwargs):
Console.info("In list_sizes of libcloud")
sizes = self.provider.list_sizes()
self._print(sizes)
sizes_dict = self._to_dict(sizes)
return sizes_dict
def _to_dict(self, libcloud_result):
d = {}
result_type = ""
if len(libcloud_result) > 0:
name = libcloud_result[0].__class__.__name__
#print("RRRR", name)
if name in ["Node", "NodeImage", "NodeSize", "KeyPair"]:
result_type = name
Console.info("{} type object received".format(name))
# pprint(libcloud_result[0])
for index, obj in enumerate(libcloud_result):
if result_type == "Node":
d[index] = dict(LibcloudDict.convert_libcloud_vm_to_dict(obj))
elif result_type == "NodeImage":
d[index] = dict(LibcloudDict.handle_vm_image_details(obj))
elif result_type == "NodeSize":
d[index] = dict(LibcloudDict.handle_vm_size_details(obj))
# pprint("Index:"+str(index))
elif result_type == "KeyPair":
d[index] = dict(LibcloudDict.handle_key_details(obj))
return d
[docs] def attributes(self, kind):
layout = {
'flavor': {
'order': [
'id',
'name',
'user',
'cpu',
'ram',
'bandwidth',
'price',
'category',
'uuid',
'updated_at'
],
'header': [
'Id',
'Name',
'User',
'cpu',
'RAM',
'bandwidth',
'price',
'Cloud',
'UUID',
'Updated'
]
},
'image': {
'order': [
'id',
'name',
'category',
'image_type',
'state',
'uuid',
'updated_at',
'owner_id'
],
'header': [
'id',
'name',
'cloud',
'image_type',
'state',
'uuid',
'updated_at',
'owner_id'
]
},
'vm': {
'order': [
'id',
'uuid',
'label',
'status',
'public_ips',
'private_ips',
'image_name',
'key',
'availability',
'instance_type',
'user',
'category',
'updated_at'
],
'header': [
'id',
'uuid',
'label',
'status',
'public_ips',
'private_ips',
'image_name',
'key',
'availability',
'instance_type',
'user',
'cloud',
'updated'
]
},
'floating_ip': {
'order': [
"instance_name",
"ip",
"pool",
"fixed_ip",
"id",
"instance_id",
'cloud',
'updated'
],
'header': [
"instance_name",
"floating_ip",
"floating_ip_pool",
"fixed_ip",
"floating_ip_id",
"instance_id",
'cloud',
'updated'
],
},
'floating_ip_pool': {
'order': [
"name"
],
'header': [
"floating_ip_pool"
],
},
'clouds': {
'order': [
"cloud",
"status"
],
'header': [
"cloud",
"status"
],
},
'limits': {
'order': [
'Name',
'Value'
],
'header': [
'Name',
'Value'
]
},
'quota': {
'order': [
'Quota',
'Limit'
],
'header': [
'Quota',
'Limit'
]
},
'secgroup': {
'order': [
'id',
'name',
'category',
'user',
'project',
'uuid'
],
'header': [
'id',
'secgroup_name',
'category',
'user',
'tenant_id',
'secgroup_uuid'
]
},
'default': {
'order': [
'user',
'cloud',
'name',
'value',
'created_at',
'updated_at'
],
'header': [
'user',
'cloud',
'name',
'value',
'created',
'updated'
],
}
}
# TODO: bug, this only returns some og the attributes, but not all
if kind in ["vm", "image", "flavor"]:
order = layout[kind]['order']
header = layout[kind]['header']
else:
order = None
header = None
return order, header
[docs] def boot_vm(self,
name,
image=None,
flavor=None,
cloud=None,
key=None,
secgroup=None,
meta=None,
nics=None,
**kwargs):
"""
Spawns a VM instance on the cloud.
If image and flavor passed as none, it would consider the defaults specified in cloudmesh.yaml.
:param name: Name of the instance to be started
:param image: Image id to be used for the instance
:param flavor: Flavor to be used for the instance
:param cloud: Cloud on which to spawn the machine. Defaults to 'India'.
:param key: Key to be used for the instance
:param secgroup: Security group for the instance
:param nics: TODO: fixme
:param meta: A dict of arbitrary key/value metadata to store for this server
"""
Console.info("boot_vm() called")
if cloud is None:
Console.error("Cloud is not specified")
return
auth = NodeAuthPassword('mysecretpassword')
# self.provider.create_node("test_node", auth=auth)
if image is not None:
image = self.get_image_by_id(image)
Console.info("Image Id & Name: {0}, {1}".format(image.id, image.name))
else:
Console.error("Image Id not found")
if flavor is not None:
flavor = self.get_size_by_id(flavor)
Console.info("Flavor: {0}, {1}".format(flavor.id, flavor.name))
else:
Console.error("valid Flavor Id not found")
# flavor = self.provider.list_sizes()[2]
# location = self.provider.list_locations()[0]
# pprint(self.provider.features['create_node'])
# create_args = dict()
# create_args['image'] = image
# Console.info("Demo start a VM:")
# Console.info("Image selected :"+image.name)
# Console.info("Flavor selected :"+flavor.name)
# Console.info("Key :")
# pprint(key)
vm = self.provider.create_node(name=name, image=image, size=flavor, ex_keyname=key)
Console.info("EC2 Instance {0} started".format(vm.id))
# vm info returned
return vm
[docs] def delete_vm(self, name, group=None, force=None):
"""
Delete a VM instance whose instance name is given by name
:param name:
:param group:
:param force:
:return:
"""
Console.info("Delete VM for " + name)
nodes_list = self.provider.list_nodes()
node_obj = None
for node in nodes_list:
if node.name == name:
node_obj = node
break
if node_obj is not None:
self.provider.destroy_node(node_obj)
Console.info("VM delete success.ok.")
else:
Console.error("No valid node found with the name "+name)
[docs] def add_key_to_cloud(self, name, public_key):
"""
Method to add key to libcloud based clouds, typically a keypair for AWS EC2.
:param name: Name of the keypair.
:param public_key: public key string.
:return:
"""
keypair = self.provider.import_key_pair_from_string(name, key_material=public_key)
Console.info("Uploading the key to libcloud. ok.")
return keypair
[docs] def get_image_by_id(self, image_id):
image_list = self.provider.list_images()
for image in image_list:
if image.id == image_id:
return image
raise ValueError("image id not found")
return None
[docs] def get_size_by_id(self, size_id):
size_list = self.provider.list_sizes()
for size in size_list:
if size.id == size_id:
return size
raise ValueError("flavor id not found")
# return None
[docs] def create_sec_group(self, cloud, secgroup_name='default'):
try:
self.provider.ex_create_security_group(secgroup_name, "Default Security Group")
except Exception as e:
Console.info("create_sec_group exception." + e.args[0])
[docs] def enable_ssh(self, cloud, secgroup_name='default'):
if cloud == "aws":
params = {'Action': 'AuthorizeSecurityGroupIngress',
'GroupName': secgroup_name,
'IpProtocol': 'tcp',
'FromPort': '22',
'ToPort': '22',
'CidrIp': '0.0.0.0/0'}
try:
self.provider.connection.request(self.provider.path, params=params).object
Console.info("Permission added.ok")
except Exception as e:
if e.args[0].find("InvalidPermission.Duplicate") == -1:
Console.info("Permission already exists.ok")
else:
Console.error("Enable SSH not implemented for others")