diff --git a/README.rst b/README.rst index 663864bb1..af07bfca6 100644 --- a/README.rst +++ b/README.rst @@ -96,6 +96,9 @@ You'll find complete documentation on the shell by running ipgroup-delete Delete an IP group. ipgroup-list Show IP groups. ipgroup-show Show details about a particular IP group. + keypair-add Create a new key pair for use with instances + keypair-delete Delete keypair by its id + keypair-list Show a list of keypairs for a user list List active servers. migrate Migrate a server to a new host in the same zone. reboot Reboot a server. @@ -135,6 +138,7 @@ You'll find complete documentation on the shell by running zone-info Show the capabilities for this Zone. zone-list List all the immediate Child Zones. + Optional arguments: --username USERNAME Defaults to env[NOVA_USERNAME]. --apikey APIKEY Defaults to env[NOVA_API_KEY]. diff --git a/novaclient/v1_1/keypairs.py b/novaclient/v1_1/keypairs.py index 76b65a80c..3ee8d8b49 100644 --- a/novaclient/v1_1/keypairs.py +++ b/novaclient/v1_1/keypairs.py @@ -16,6 +16,7 @@ """ Keypair interface (1.1 extension). """ +import os from novaclient import base diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py index 9de20f6fd..773365a20 100644 --- a/novaclient/v1_1/shell.py +++ b/novaclient/v1_1/shell.py @@ -61,7 +61,14 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): except IOError, e: raise exceptions.CommandError("Can't open '%s': %s" % (src, e)) - if args.key is AUTO_KEY: + # use the os-keypair extension + key_name = None + if args.key_name is not None: + key_name = args.key_name + + # or use file injection functionality (independent of os-keypair extension) + keyfile = None + elif args.key_path is AUTO_KEY: possible_keys = [os.path.join(os.path.expanduser('~'), '.ssh', k) for k in ('id_dsa.pub', 'id_rsa.pub')] for k in possible_keys: @@ -71,10 +78,8 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): else: raise exceptions.CommandError("Couldn't find a key file: tried " "~/.ssh/id_dsa.pub or ~/.ssh/id_rsa.pub") - elif args.key: - keyfile = args.key - else: - keyfile = None + elif args.key_path: + keyfile = args.key_path if keyfile: try: @@ -100,7 +105,7 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): security_groups = args.security_groups.split(',') else: security_groups = None - return (args.name, image, flavor, metadata, files, + return (args.name, image, flavor, metadata, files, key_name, reservation_id, min_count, max_count, user_data, \ availability_zone, security_groups) @@ -126,13 +131,17 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): default=[], help="Store arbitrary files from <src-path> locally to <dst-path> "\ "on the new server. You may store up to 5 files.") -@utils.arg('--key', - metavar='<path>', +@utils.arg('--key_path', + metavar='<key_path>', nargs='?', const=AUTO_KEY, help="Key the server with an SSH keypair. "\ "Looks in ~/.ssh for a key, "\ - "or takes an explicit <path> to one.") + "or takes an explicit <path> to one. (uses --file functionality)") +@utils.arg('--key_name', + metavar='<key_name>', + help="Key name of keypair that should be created earlier with \ + the command keypair-add") @utils.arg('name', metavar='<name>', help='Name for the new server') @utils.arg('--user_data', default=None, @@ -148,7 +157,7 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): help="comma separated list of security group names.") def do_boot(cs, args): """Boot a new server.""" - name, image, flavor, metadata, files, reservation_id, \ + name, image, flavor, metadata, files, key_name, reservation_id, \ min_count, max_count, user_data, availability_zone, \ security_groups = _boot(cs, args) @@ -159,7 +168,8 @@ def do_boot(cs, args): max_count=max_count, userdata=user_data, availability_zone=availability_zone, - security_groups=security_groups) + security_groups=security_groups, + key_name=key_name) info = server._info @@ -243,7 +253,7 @@ def do_zone_boot(cs, args): min_count=min_count, max_count=max_count) print "Reservation ID=", reservation_id - + def _translate_flavor_keys(collection): convert = [('ram', 'memory_mb'), ('disk', 'local_gb')] @@ -1025,3 +1035,39 @@ def do_secgroup_delete_group_rule(cs, args): return cs.security_group_rules.delete(rule['id']) raise exceptions.CommandError("Rule not found") + + +@utils.arg('name', metavar='<name>', help='Name of key.') +@utils.arg('--pub_key', metavar='<pub_key>', help='Path to a public ssh key.', default=None) +def do_keypair_add(cs, args): + """Create a new key pair for use with instances""" + name = args.name + pub_key = args.pub_key + + if pub_key: + try: + with open(pub_key) as f: + pub_key = f.read() + except IOError, e: + raise exceptions.CommandError("Can't open or read '%s': %s" % (pub_key, e)) + + keypair = cs.keypairs.create(name, pub_key) + + if not pub_key: + private_key = keypair.private_key + print private_key + + +@utils.arg('name', metavar='<name>', help='Keypair name to delete.') +def do_keypair_delete(cs, args): + """Delete keypair by its id""" + name = args.name + cs.keypairs.delete(name) + + +def do_keypair_list(cs, args): + """Print a list of keypairs for a user""" + keypairs = cs.keypairs.list() + columns = ['Name', 'Fingerprint'] + utils.print_list(keypairs, columns) +