Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding keyfile import, ip association, and execute command functionality to OpenstackCM #71

Merged
merged 2 commits into from Dec 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions cm4/etc/cloudmesh4.yaml
Expand Up @@ -69,9 +69,11 @@ cloudmesh:
OS_USER_DOMAIN_ID: default
OS_VERSION: liberty
OS_REGION_NAME: RegionOne
OS_KEY_PATH: #put your keyfile path here
default:
flavor: m1.small
image: CC-Ubuntu16.04
username: cc
jetstream:
cm:
heading: Jetstream
Expand Down
82 changes: 78 additions & 4 deletions cm4/openstack/OpenstackCM.py
Expand Up @@ -6,10 +6,11 @@
@author: Rui
"""

import os
import subprocess
from cm4.abstractclass.CloudManagerABC import CloudManagerABC
from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver
import os
from cm4.configuration.config import Config


Expand All @@ -20,9 +21,11 @@ def __init__(self, cloud=None):
config = Config()
self.cloud = cloud
self.driver = None
self.key = None
if cloud:
self.os_config = config.get('cloud.{}'.format(cloud))
self.driver = self.get_driver(cloud)
self.key = self.os_config.get('credentials.OS_KEY_PATH') or os.environ['OS_KEY_PATH']
else:
self.os_config = config

Expand All @@ -34,6 +37,8 @@ def _get_obj_list(self,obj_type):
obj_list = self.driver.list_images()
elif obj_type == 'size':
obj_list = self.driver.list_sizes()
elif obj_type == 'ip':
obj_list = self.driver.ex_list_floating_ips()

return obj_list

Expand Down Expand Up @@ -70,14 +75,22 @@ def get_driver_helper(self, cloud):
ex_force_auth_url = credential.get("OS_AUTH_URL"),
ex_force_auth_version='2.0_password',
ex_tenant_name = credential.get("OS_TENANT_NAME"),
ex_force_service_region = credential.get("OS_REGION_NAME")
ex_force_service_region = credential.get("OS_REGION_NAME")
)
return driver


def get_driver(self, cloud):
if not self.driver:
self.driver=self.get_driver_helper(cloud)
return self.driver

def set_cloud(self, cloud):
self.cloud=cloud
self.os_config = Config().get('cloud.{}'.format(cloud))

def _get_public_ip(self):
ips = [x for x in self._get_obj_list('ip') if not x.node_id]
return ips[0] if ips else None

### API hack for new VM class
def ex_start_node(self, info):
Expand All @@ -96,6 +109,55 @@ def list_nodes(self):
return self.driver.list_nodes()

### APIs
def execute(self, name, command):
"""
execute arbitrary shell command on node through ssh
ssh funcionality must available on the local machine

:param name: name of the VM
:param command: shell command

"""
node = self._get_obj_by_name('node', name)
template = 'ssh -i {key} -o StrictHostKeyChecking=no {user}@{host} "{command}"'
kwargs = {'key' : os.path.splitext(self.key)[0],
'user' : self.os_config.get('default.username'),
'host' : node.public_ips[0],
'command': command}

# execute
try:
res = subprocess.check_output(template.format(**kwargs),
shell=True,
input=b'\n',
stderr=subprocess.STDOUT)
return res.decode('utf8')
except Exception as e:
return e

def set_public_ip(self, name, ip_str):
"""
:param name: name of the VM
:param ip_str: ip string
"""
node = self._get_obj_by_name('node', name)
ip_obj = self.driver.ex_get_floating_ip(ip_str)
if ip_obj and not ip_obj.node_id:
self.driver.ex_attach_floating_ip_to_node(node, ip_obj)
elif ip_obj and ip_obj.node_id:
raise EnvironmentError('Public IP has been assigned to another machine. Pick another ip')
else:
raise ValueError('Public IP addresss does not exist!')

def remove_public_ip(self, name):
"""
:param name: name of the VM
:param ip_str: ip string or ip object
"""
node = self._get_obj_by_name('node', name)
for ip in node.public_ips:
self.driver.ex_detach_floating_ip_from_node(node, ip)

def ls(self):
"""
list all nodes
Expand Down Expand Up @@ -141,12 +203,24 @@ def create(self, name, image=None, size=None, **kwargs):
# get defualt if needed
image_name = image if image else self.os_config.get('default').get('image')
size_name = size if size else self.os_config.get('default').get('flavor')


# add to kwargs
kwargs['name'] = name
kwargs['image'] = self._get_obj_by_name('image', image_name)
kwargs['size'] = self._get_obj_by_name('size', size_name)
return self.driver.create_node(**kwargs)
if self.key:
key_pair = self.driver.ex_import_keypair(name, self.key)
kwargs['ex_keyname']=name

# create node
node = self.driver.create_node(**kwargs)

# attach ip if available
ip = self._get_public_ip()
if ip:
self.driver.ex_attach_floating_ip_to_node(node, ip)
return node

def start(self, node_id):
"""
Expand Down