from __future__ import print_function
from cloudmesh_client.shell.command import command, PluginCommand, CloudPluginCommand
from cloudmesh_client.shell.console import Console
from cloudmesh_client.common.dotdict import dotdict
from cloudmesh_client.default import Default
from pprint import pprint
from cloudmesh_client.cloud.vm import Vm
from cloudmesh_client.cloud.image import Image
from cloudmesh_client.cloud.flavor import Flavor
from cloudmesh_client.cloud.group import Group
from cloudmesh_client.common.Printer import Printer
from cloudmesh_client.common.Shell import Shell
from cloudmesh_client.common.ConfigDict import ConfigDict
import os
from cloudmesh_client.common.util import path_expand
[docs]def boot_from_args(arg):
arg.username = arg.username or Image.guess_username(arg.image)
is_name_provided = arg.name is not None
arg.user = Default.user
for index in range(0, arg.count):
vm_details = dotdict({
"cloud": arg.cloud,
"name": Vm.generate_vm_name(arg.name, index),
"image": arg.image,
"flavor": arg.flavor,
"key": arg.key,
"secgroup": arg.secgroup,
"group": arg.group,
"username": arg.username,
"user": arg.user
})
# correct the username
vm_details.username = Image.guess_username_from_category(
vm_details.cloud,
vm_details.image,
username=arg.username)
try:
if arg.dryrun:
print(Printer.attribute(vm_details, output=arg.format))
msg = "dryrun info. OK."
Console.ok(msg)
else:
vm_id = Vm.boot(**vm_details)
if vm_id is None:
msg = "info. failed."
Console.error(msg, traceflag=False)
return ""
# set name and counter in defaults
Default.set_vm(value=vm_details.name)
if is_name_provided is False:
Default.incr_counter("name")
# Add to group
if vm_id is not None:
Group.add(name=vm_details.group,
species="vm",
member=vm_details.name,
category=vm_details.cloud)
msg = "info. OK."
Console.ok(msg)
except Exception as e:
Console.error("Problem booting instance {name}".format(**vm_details), traceflag=False)
[docs]class ClusterCommand(PluginCommand, CloudPluginCommand):
topics = {"cluster": "notimplemented"}
def __init__(self, context):
self.context = context
if self.context.debug:
print("init command cluster ")
# noinspection PyUnusedLocal
@command
def do_cluster(self, args, arguments):
"""
::
Usage:
cluster list [--format=FORMAT]
cluster list NAME
[--format=FORMAT]
[--column=COLUMN]
[--short]
cluster create NAME
[--count=COUNT]
[--login=USERNAME]
[--cloud=CLOUD]
[--image=IMAGE]
[--flavor=FLAVOR]
[--add]
cluster delete NAME
cluster setup NAME [--username]
cluster inventory NAME
Description:
with the help of the cluster command you can create a number
of virtual machines that are integrated in a named virtual cluster.
You will be able to login between the nodes of the virtual cluster
while using public keys.
cluster setup NAME
sets up the keys between the cluster node as well as the machine that
executes the cm command
cluster inventory NAME
creates an inventory.txt file to be used by ansible in the current directory
cluster create NAME
creates the virtual machines used for the cluster
cluster list NAME
lists selected details of the vms for the cluster
cluster delete NAME
remove the cluster and its VMs
Examples:
cluster list
list the clusters
cluster create NAME --count=COUNT --login=USERNAME [options...]
Start a cluster of VMs, and each of them can log into each other.
CAUTION: you should specify defaults before using this command:
1. select cloud to work on, e.g. cloud select kilo
default cloud=kilo
2. test if you can create a single VM on the cloud to see if
everything is set up
3. set the default key to start VMs, e.g. key default [USERNAME-key]
5. set image of VMs, e.g. default image
6. set flavor of VMs, e.g. default flavor
7. Make sure to use a new unused group name
Arguments:
NAME cluster name or group name
Options:
--count=COUNT give the number of VMs to add into the cluster
--login=USERNAME give a login name for the VMs, e.g. ubuntu
--cloud=CLOUD give a cloud to work on
--flavor=FLAVOR give the name of the flavor or flavor id
--image=IMAGE give the name of the image or image id
--add if a group exists and there are VMs in it
additional vms will be added to this cluster and the
keys will be added to each other so one can login between
them
FORMAT output format: table, json, csv
COLUMN customize what information to display, for example:
--column=status,addresses prints the columns status
and addresses
--detail for table print format, a brief version
is used as default, use this flag to print
detailed table
"""
def get_vms(group_name):
groups = Vm.get_vms_by_group(group_name)
vms = []
for group in groups:
name = group["member"]
print(name)
vm = Vm.get_vm(name)
vm['cluster'] = group_name
vms.append(vm)
return vms
def _print(f):
print (f)
def write(filename, msg):
with open(path_expand(filename), 'w') as f:
output = f.write(msg)
arg = dotdict(arguments)
arg.format = arguments["--format"] or "table"
arg.count = int(arguments["--count"] or 1)
arg.username = arguments["--login"]
arg.cloud = arguments["--cloud"] or Default.cloud
arg.image = arguments["--image"] or Default.get(name="image", category=arg.cloud)
arg.flavor = arguments["--flavor"] or Default.get(name="flavor", category=arg.cloud)
arg.add = arguments["--add"]
arg.group = arg.NAME
arg.name = None
arg.key = Default.key
arg.secgroup = Default.secgroup
arg.group = arg.NAME
arg.short = arguments["--short"]
if arg.create:
boot_from_args(arg)
elif arg.inventory:
group = Vm.get_vms_by_group(arg.group)
result = ""
if arg.format is "table":
result = "[servers]\n"
for element in group:
name = element["member"]
vm = Vm.get_vm(name)[0]
vm['cluster'] = arg.group
result += "{floating_ip}\n".format(**vm)
Console.ok("Writing ips to inventory.txt")
print(result)
write("inventory.txt", result)
Console.ok(".ok")
return ""
elif arg.list and arg.NAME is not None:
if arg.short:
vms = Vm.get_vms_by_group(arg.group)
if vms is None:
Console.error("no vms found for {}".format(arg.group))
else:
print(Printer.list(vms,
header=['Group', 'Vm'],
order=['name', 'member'],
output=arg.format))
else:
groups = Vm.get_vms_by_group(arg.group)
pprint(groups)
vms = []
for group in groups:
name = group["member"]
vm = Vm.get_vm(name)[0]
vm['cluster'] = arg.group
if vm is not None:
vms.append(vm)
pprint(vms)
if vms is None:
Console.error("no vms found for {}".format(arg.group))
else:
print(Printer.list(vms,
order=['name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip'],
output=arg.format))
return ""
elif arg.setup:
def push(from_path, vm):
vm.ip = vm.floating_ip
if vm.ip is not None:
if arg.verbose:
Console.info("Connecting to Instance at IP:" + format(vm.ip))
sshcommand = "scp"
sshcommand += " -o StrictHostKeyChecking=no"
sshcommand += " {:}".format(from_path)
sshcommand += " {username}@{ip}:.ssh/authorized_keys".format(**vm)
print(sshcommand)
os.system(sshcommand)
else:
Console.error("No Public IPs found for the instance", traceflag=False)
groups = Vm.get_vms_by_group(arg.group)
pprint (groups)
vms = []
for group in groups:
name = group["member"]
vm = Vm.get_vm(name)[0]
vm['cluster'] = arg.group
if vm is not None:
vms.append(vm)
pprint(vms)
if vms is None:
Console.error("no vms found for {}".format(arg.group))
else:
print(Printer.list(vms,
order=['name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip'],
output=arg.format))
keys = ""
for vm in vms:
vm = dotdict(vm)
cloud = vm.category
if vm.username is None:
vm.username = arguments["--username"] or Image.guess_username(arg.image)
chameleon = "chameleon" in ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["clouds"][cloud][
"cm_host"]
print ("C", chameleon)
if chameleon:
vm.username = "cc"
elif vm.category == "azure":
vm.username = ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["clouds"]["azure"]["default"][
"username"]
else:
if vm.username is None:
Console.error("Could not guess the username of the vm", traceflag=False)
return
Vm.set_login_user(name=vm.name, cloud=vm.category, username=vm.username)
vm.ip = vm.floating_ip
def execute(commands):
if vm.ip is not None:
if arg.verbose:
Console.info("Connecting to Instance at IP:" + format(vm.ip))
sshcommand = "ssh"
if arg.key is not None:
sshcommand += " -i {:}".format(arg.key)
sshcommand += " -o StrictHostKeyChecking=no"
sshcommand += " {username}@{ip}".format(**vm)
sshcommand += " \'{:}\'".format(commands)
print(sshcommand)
os.system(sshcommand)
else:
Console.error("No Public IPs found for the instance", traceflag=False)
def copy(commands):
if vm.ip is not None:
if arg.verbose:
Console.info("Connecting to Instance at IP:" + format(vm.ip))
sshcommand = "scp"
sshcommand += " -o StrictHostKeyChecking=no"
sshcommand += " {username}@{ip}".format(**vm)
sshcommand += ":{:}".format(commands)
print(sshcommand)
os.system(sshcommand)
else:
Console.error("No Public IPs found for the instance", traceflag=False)
def cat(filename):
with open(path_expand(filename), 'r') as f:
output = f.read()
return output
execute('cat /dev/zero | ssh-keygen -q -N ""')
copy(".ssh/id_rsa.pub ~/.ssh/id_rsa_{name}.pub".format(**vm))
output = "~/.ssh/id_rsa_{name}.pub".format(**vm)
keys = keys + cat(output)
print ("WRITE KEYS")
keys = keys + cat("~/.ssh/id_rsa.pub")
output = "~/.ssh/id_rsa_{group}.pub".format(**arg)
write(output, keys)
print("PUSH KEYS")
for vm in vms:
vm = dotdict(vm)
push("~/.ssh/id_rsa_{group}.pub".format(**arg), vm)
return ""