Source code for cloudmesh_client.shell.plugins.ClusterCommand2

from __future__ import print_function

import sys
from pprint import pprint
from cloudmesh_client.platform.virtual_cluster.cluster import Cluster

from cloudmesh_client.cloud.image import Image
from cloudmesh_client.common.dotdict import dotdict
from cloudmesh_client.db.CloudmeshDatabase import CloudmeshDatabase
from cloudmesh_client.db import SPECIFICATION
from cloudmesh_client.default import Default, Names
from cloudmesh_client.deployer.ansible.inventory import Inventory, Node
from cloudmesh_client.exc import (ClusterNameClashException,
    NoActiveClusterException, UnrecoverableErrorException)
from cloudmesh_client.shell.command import (CloudPluginCommand, PluginCommand,
    command)
from cloudmesh_client.shell.console import Console

db = CloudmeshDatabase


[docs]class Command(object):
[docs] def define(self, clustername=None, **kwargs): """Define a cluster. kwargs are passed to Cluster :returns: a cluster :rtype: :class:`Cluster` """ clustername = clustername or Default.generate_name(Names.CLUSTER_COUNTER) # remove None to defer default definitions to later for k in kwargs.keys(): if kwargs[k] is None: del kwargs[k] try: spec = db.select(SPECIFICATION, name=clustername, type='cluster')[0] spec.update(kwargs) db.updateObj(spec) except IndexError: spec = SPECIFICATION(clustername, 'cluster', kwargs) db.insert(spec) Default.set_specification(clustername) Console.ok('Defined cluster {}'.format(clustername))
[docs] def undefine(self, specname=None, all=False): specs = set() if all: for spec in db.select(SPECIFICATION, type='cluster'): specs.add(spec) try: spec = db.select(SPECIFICATION, type='cluster', name=specname or Default.active_specification)[0] specs.add(spec) except IndexError: pass for spec in specs: try: cluster = db.select(Cluster, specId=spec.cm_id)[0] Console.warning('Cannot undefine allocated cluster {}.'.format(cluster.name)) Console.warning('Please delete the cluster first') continue except IndexError: pass db.delete_(SPECIFICATION, cm_id = spec.cm_id) Console.ok('Undefined specification {}'.format(spec.name)) try: spec = db.select(SPECIFICATION, type='cluster')[0] Default.set_specification(spec.name) except IndexError: pass
[docs] def use(self, specname): """Activate the given specification :param specname: namne of the specification """ spec = db.select(SPECIFICATION, type='cluster', name=specname)[0] Default.set_specification(spec.name) Default.set_cluster(spec.name)
[docs] def avail(self): """Show the available cluster specifications """ specs = db.select(SPECIFICATION, type='cluster') active = Default.active_specification for spec in specs: marker = '>' if spec.name == active else ' ' print('{} {}'.format(marker, spec.name)) for k, v in spec.get().iteritems(): print('{:>4}{:<30}: {}'.format('', k, v))
[docs] def allocate(self, clustername=None): specname = clustername or Default.active_specification try: spec = db.select(SPECIFICATION, name=specname)[0] except IndexError: Console.error('No specification with name={} found'.format(specname)) return 1 defns = spec.get() try: cluster = db.select(Cluster, name=spec.name, specId=spec.cm_id)[0] except IndexError: cluster = Cluster(name=spec.name, specId=spec.cm_id, **defns) Default.set_cluster(cluster.name) Console.ok('Cluster {} is now active'.format(cluster.name)) cluster.create() Console.ok('Cluster {} created'.format(cluster.name)) return cluster
[docs] def cross_ssh(self, clustername=None): clustername = clustername = Default.cluster cluster = db.select(Cluster, name=clustername)[0] cluster.enable_cross_ssh_login()
[docs] def list(self): """List the clusters created The currently active cluster is given as the first element in the tuple, while the remainder are listed in the second position. :returns: a pair: (active, [clusters]) :rtype: :class:`tuple` (:class:`Cluster`, :class:`list` of :class:`Cluster`) :raises: :class:`NoActiveClusterException` if no cluster is active, meaning there are no clusters """ activename = Default.active_cluster.name clusters = db.select(Cluster).all() active = filter(lambda c: c.name == activename, clusters)[0] clusters = filter(lambda c: c.name != activename, clusters) return active, clusters
[docs] def delete(self, clusternames=None, force=False, all=False): """Delete clusters that have these names. If not specified, delete the active cluster. If there is no active cluster, delete the first cluster. :param list clusternames: list of cluster names to delete """ if all: clusters = db.select(Cluster) else: clusternames = clusternames or [Default.cluster] clusters = [db.select(Cluster, name=name).one() for name in clusternames] for cluster in clusters: Console.ok('Deleting cluster {}'.format(cluster.name)) cluster.delete(force=force) Console.ok('Deleted cluster {}: {} nodes' .format(cluster.name, cluster.count)) remaining_clusters = db.select(Cluster).all() if remaining_clusters: name = remaining_clusters[-1].name else: name = None Default.set_cluster(name) Console.ok('Active cluster: {}'.format(name))
[docs] def get(self, property, cluster=None): """Retrieve the property for a cluster/nodes in a cluster. If no cluster is specified, use the currently active cluster. :param str property: name of the property :param Cluster cluster: the cluster (default: currently active) :returns: a list of the values :rtype: :class:`list` """ cluster = cluster or db.select(Cluster, name=Default.cluster).one() # getting from the cluster itself: if hasattr(cluster, property): return [getattr(cluster, property)] # assume it is a property of the instances else: values = [getattr(node, property) for node in cluster] return values
[docs] def nodes(self, cluster=None): """Retrieve the nodes of a cluster If no cluster is specified, use the currently active cluster. :param Cluster cluster: the cluster (default: currently active) :returns: a list of instances :rtype: a VM instance """ try: name = cluster or Default.cluster cluster = Cluster.from_name(name) return cluster.list() except: Console.error('Cluster {} is active. Did you forget to allocate?'.format(name)) return []
[docs] def inventory(self, cluster=None, format=None, path=None): cluster = cluster or Default.active_cluster format = format or 'ansible' if format == 'ansible': inventory = Inventory.from_cluster(cluster) inv_ini = inventory.ini() if not path: print(inv_ini) else: with open(path, 'w') as fd: fd.write(inv_ini) return inventory
[docs]class Cluster2Command(PluginCommand, CloudPluginCommand): topics = {'cluster': 'cluster'} def __init__(self, context): self.context = context if self.context.debug: print("init command cluster2 ") @command def do_cluster(self, args, arguments): """ :: Usage: cluster define [-n NAME] [-c COUNT] [-C CLOUD] [-u NAME] [-i IMAGE] [-f FLAVOR] [-k KEY] [-s NAME] [-AI] cluster undefine [--all] [NAME]... cluster avail cluster use <NAME> cluster allocate cluster cross_ssh cluster list cluster nodes [CLUSTER] cluster delete [--all] [--force] [NAME]... cluster get [-n NAME] PROPERTY cluster inventory [-F NAME] [-o PATH] [NAME] Commands: define Create a cluster specification undefine Delete the active or given specifications avail Show available cluster specifications use Activate the specification with the given name allocate Create a cluster from the active specification nodes Show the nodes of the cluster list List the available clusters inventory Obtain an inventory file delete Delete clusters and associated instances get Get properties of a cluster/nodes in a cluster Arguments: NAME Alphanumeric name COUNT Integer > 0 PATH Path to entry on the filesystem Options: -A --no-activate Don't activate this cluster -I --no-floating-ip Don't assign floating IPs -n NAME --name=NAME Name of the cluster -c COUNT --count=COUNT Number of nodes in the cluster -C NAME --cloud=NAME Name of the cloud -u NAME --username=NAME Name of the image login user -i NAME --image=NAME Name of the image -f NAME --flavor=NAME Name of the flavor -k NAME --key=NAME Name of the key -s NAME --secgroup=NAME NAME of the security group -F NAME --format=NAME Name of the output format -o PATH --path=PATH Output to this path --force --all Inventory File Format: ansible [default] Ansible-compatible inventory """ arguments = dotdict(arguments) cmd = Command() if arguments.define: cmd.define( clustername = arguments['--name'], count=arguments['--count'] or 1, cloud=arguments['--cloud'] or Default.cloud, username=arguments['--username'], image=arguments['--image'] or Default.image, flavor=arguments['--flavor'] or Default.flavor, key=arguments['--key'] or Default.key, secgroup=arguments['--secgroup'] or Default.secgroup, assignFloatingIP=not arguments['--no-floating-ip'], ) elif arguments.undefine: if arguments['NAME']: for specname in arguments['NAME']: cmd.undefine(specname=specname, all=arguments['--all']) else: cmd.undefine(all=arguments['--all']) elif arguments.avail: cmd.avail() elif arguments.use: cmd.use(arguments['<NAME>']) elif arguments.allocate: cmd.allocate() elif arguments.cross_ssh: cmd.cross_ssh() elif arguments.list: try: active, inactive = cmd.list() except NoActiveClusterException: return def show(cluster, isactive=False, stream=sys.stdout): if not cluster: return if isactive: stream.write('> ') else: stream.write(' ') stream.write(cluster.name) stream.write('\n') stream.flush() show(active, isactive=True) map(show, inactive) elif arguments.nodes: nodes = cmd.nodes(cluster=arguments['CLUSTER']) for node in nodes: print(node.name, node.floating_ip) elif arguments.delete: cmd.delete( arguments.NAME, force=arguments['--force'], all=arguments['--all'] ) elif arguments['get']: values = cmd.get(arguments['PROPERTY'], cluster=arguments['--name']) for v in values: print(v) elif arguments.inventory: cmd.inventory( cluster=arguments.NAME, format=arguments['--format'], path=arguments['--path'], )
if __name__ == '__main__': cmd = Cluster2Command() cmd.create( clustername='test3', image='CC-Ubuntu14.04', flavor='m1.medium', key='gambit', count=3, )