from __future__ import print_function
import json
import yaml
from cloudmesh_client.shell.command import command
from cloudmesh_client.shell.console import Console
from cloudmesh_client.common.ConfigDict import Config
from cloudmesh_client.common.Printer import Printer
from cloudmesh_client.common.ConfigDict import ConfigDict
from cloudmesh_client.default import Default
from cloudmesh_client.shell.command import PluginCommand, CloudPluginCommand
from cloudmesh_client.common.Error import Error
from cloudmesh_client.cloud.key import Key
from cloudmesh_client.common.dotdict import dotdict
from pprint import pprint
[docs]class KeyCommand(PluginCommand, CloudPluginCommand):
topics = {"key": "security"}
def __init__(self, context):
self.context = context
if self.context.debug:
print("init command key")
# noinspection PyUnusedLocal
@command
def do_key(self, args, arguments):
"""
::
Usage:
key -h | --help
key list --cloud=CLOUD
key list --source=db [--format=FORMAT]
key list --source=yaml [--format=FORMAT]
key list --source=ssh [--dir=DIR] [--format=FORMAT]
key list --source=git [--format=FORMAT] [--username=USERNAME]
key list
key load [--format=FORMAT]
key add [NAME] [--source=FILENAME]
key add [NAME] [--git]
key add [NAME] [--ssh]
key get NAME
key default --select
key delete (NAME | --select | --all)
key delete NAME --cloud=CLOUD
key upload [NAME] [--cloud=CLOUD]
key upload [NAME] --active
Manages the keys
Arguments:
CLOUD The cloud
NAME The name of the key.
SOURCE db, ssh, all
KEYNAME The name of a key. For key upload it defaults to the default key name.
FORMAT The format of the output (table, json, yaml)
FILENAME The filename with full path in which the key
is located
NAME_ON_CLOUD Typically the name of the keypair on the cloud.
Options:
--dir=DIR the directory with keys [default: ~/.ssh]
--format=FORMAT the format of the output [default: table]
--source=SOURCE the source for the keys [default: db]
--username=USERNAME the source for the keys [default: none]
--name=KEYNAME The name of a key
--all delete all keys
--force delete the key form the cloud
--name_on_cloud=NAME_ON_CLOUD Typically the name of the keypair on the cloud.
Description:
key list --source=git [--username=USERNAME]
lists all keys in git for the specified user. If the
name is not specified it is read from cloudmesh.yaml
key list --source=ssh [--dir=DIR] [--format=FORMAT]
lists all keys in the directory. If the directory is not
specified the default will be ~/.ssh
key list --source=yaml [--dir=DIR] [--format=FORMAT]
lists all keys in cloudmesh.yaml file in the specified directory.
dir is by default ~/.cloudmesh
key list [--format=FORMAT]
list the keys in the giiven format: json, yaml,
table. table is default
key list
Prints list of keys. NAME of the key can be specified
key add ssh
adds the default key with the name id_rsa.pub
key add NAME --source=FILENAME
adds the key specifid by the filename to the key
database
key get NAME
Retrieves the key indicated by the NAME parameter from database
and prints its fingerprint.
key default --select
Select the default key interactively
key delete NAME
deletes a key. In yaml mode it can delete only key that
are not saved in the database
key rename NAME NEW
renames the key from NAME to NEW.
"""
# pprint(arguments)
invalid_names = ['tbd', 'none', "", 'id_rsa']
def _print_dict(d, header=None, format='table'):
msg = Printer.write(d,
order=["name",
"comment",
"uri",
"fingerprint",
"source"],
output=format,
sort_keys=True)
if msg is None:
Console.error("No keys found.", traceflag=False)
return None
else:
return msg
directory = Config.path_expand(arguments["--dir"])
cloud = arguments["--cloud"] or Default.cloud
if arguments['list']:
_format = arguments['--format']
_source = arguments['--source']
_dir = arguments['--dir']
if "--source" not in arguments and "--cloud" not in arguments:
arguments["--source"] = 'db'
if arguments['--cloud']:
#
# get key list from openstack cloud
#
#keys = Key.list(cloud, output=_format)
#keys = Key.list_on_cloud(cloud, live=True, format=_format)
keys = Key.get_from_cloud(cloud, live=True, format=_format)
if keys is None:
Console.ok("The Key list is empty")
else:
print(Printer.write(keys,
order=["name",
"fingerprint"],
output=_format or "table"))
return ""
elif arguments['--source'] == 'ssh':
try:
#sshm = SSHKeyManager()
d = Key.get_from_dir(directory, store=False)
#print("SSS", type(Key.__keys__))
#d = dict(Key.all())
#print(d)
print(Printer.write(d,
order=["name",
"comment",
"uri",
"fingerprint",
"source"],
output="table"))
# d = dict(sshm.__keys__)
# print(_print_dict(d, format=_format))
msg = "info. OK."
Console.ok(msg)
return ""
except Exception as e:
Error.traceback(e)
Console.error("Problem listing keys from ssh")
elif arguments['--source'] in ['cm', 'cloudmesh', 'yaml']:
try:
#sshm = SSHKeyManager()
d = Key.get_from_yaml(load_order=directory, store=False)
print(Printer.write(d,
order=["name",
"comment",
"uri",
"fingerprint",
"source"],
output=_format))
return ""
except Exception as e:
Error.traceback(e)
Console.error("Problem listing keys from `{:}`".format(arguments['--source']))
elif arguments['--source'] in ['git']:
username = arguments["--username"]
# print(username)
if username == 'none':
conf = ConfigDict("cloudmesh.yaml")
username = conf["cloudmesh.github.username"]
#sshm = SSHKeyManager()
try:
d = Key.get_from_git(username, store=False)
print(Printer.write(d,
order=["name",
"comment",
"uri",
"fingerprint",
"source"],
output=_format))
msg = "info. OK."
Console.ok(msg)
except Exception as e:
Error.traceback(e)
Console.error("Problem listing git keys from database")
return ""
elif arguments['--source'] == 'db':
try:
#sshdb = SSHKeyDBManager()
d = Key.all(output='dict')
if d is not None or d != []:
print(Printer.write(d,
order=["name",
"comment",
"uri",
"fingerprint",
"source"],
output=_format))
# print(_print_dict(d, output=arguments['--format']))
msg = "info. OK."
Console.ok(msg)
else:
Console.error("No keys in the database")
except Exception as e:
Error.traceback(e)
Console.error("Problem listing keys from database")
elif arguments['get']:
try:
name = arguments['NAME']
#sshdb = SSHKeyDBManager()
d = Key.all(output="dict")
for key in d:
if key["name"] == name:
print("{:}: {:}".format(key['name'], key['fingerprint']))
msg = "info. OK."
Console.ok(msg)
return ""
else:
pass
Console.error("The key is not in the database")
except Exception as e:
Error.traceback(e)
Console.error("The key is not in the database")
# key add [NAME] [--source=FILENAME]
# key add [NAME] [--git]
elif arguments['add'] and arguments["--git"]:
# Console.error("This feature is not yet implemented", traceflag=False)
# return ""
print('git add')
#sshdb = SSHKeyDBManager()
data = dotdict(arguments)
keyname = data.NAME
#
# get name
#
conf = ConfigDict("cloudmesh.yaml")
data.username = conf["cloudmesh.github.username"]
data.name = arguments['NAME'] or data.username
#
# get git username
#
data.username = ConfigDict("cloudmesh.yaml")["cloudmesh.github.username"]
if str(data.name).lower() in invalid_names:
Console.error("The github user name is not set in the yaml file", traceflag=False)
return ""
try:
Console.msg("Retrieving github ssh keys for user {username}".format(**data))
#sshm = SSHKeyManager()
Key.get_from_git(data.username)
d = Key.all()
# pprint(d)
except Exception as e:
Console.error("Problem adding keys to git for user: {username}".format(**data))
return ""
for key in d:
if key is not None:
key["name"] = key["name"].replace("-", "_")
key["source"] = "git"
key["user"] = data.name
try:
o = dict(key)
o['value'] = key["string"]
Key.add_from_dict(key)
except Exception as e:
Console.error("The key {name} with that finger print already exists".format(**key),
traceflag=False)
elif arguments['add'] and not arguments["--git"]:
# key add [NAME] [--source=FILENAME]
# key add [NAME] [--git]
#sshdb = SSHKeyDBManager()
data = dotdict()
#
# get name
#
conf = ConfigDict("cloudmesh.yaml")
data.username = conf["cloudmesh.profile.user"]
data.name = arguments['NAME'] or data.username
data.filename = arguments['--source']
if data.filename == "db" or data.filename is None:
data.filename = Config.path_expand("~/.ssh/id_rsa.pub")
if str(data.name).lower() in invalid_names:
msg = ("Your choice of keyname {name} is insufficient. \n"
"You must be chosing a keyname that is distingct on all clouds. \n"
"Possible choices are your gmail name, your XSEDE name, or \n"
"some name that is uniqe. "
"Best is also to set this name in \n"
"cloudmesh.profile.user as "
"part of your \n~/cloudmesh/cloudmesh.yaml file.")
Console.error(msg.format(**data), traceflag=False)
return ""
try:
Key.add_from_path(data.filename,
data.name,
source="ssh",
uri="file://" + data.filename)
print("Key {name} successfully added to the database".format(**data))
msg = "info. OK."
Console.ok(msg)
except ValueError as e:
Console.error("A key with this fingerprint already exists".format(**data), traceflag=False)
Console.msg("Please use check with: key list")
return ""
elif arguments['default']:
# print("default")
if arguments['--select']:
keyname = None
try:
#sshdb = SSHKeyDBManager()
select = Key.select()
if select != 'q':
keyname = select.split(':')[0]
print("Setting key: {:} as default.".format(keyname))
Default.key = keyname
msg = "info. OK."
Console.ok(msg)
except Exception as e:
Error.traceback(e)
Console.error("Setting default for selected key {:} failed.".format(keyname))
else:
try:
#sshdb = SSHKeyDBManager()
d = Key.table_dict()
for i in d:
if d[i]["is_default"] == "True":
key = d[i]
print("{:}: {:}".format(key['name'], key['fingerprint']))
msg = "info. OK."
Console.ok(msg)
return ""
else:
pass
Console.error("The key is not in the database")
except Exception as e:
Error.traceback(e)
Console.error("Problem retrieving default key.")
elif arguments['delete'] and arguments["--cloud"]:
key = dotdict({
'cloud': arguments["--cloud"],
'name': arguments["NAME"]
})
try:
Key.delete(key.name, key.cloud)
msg = "info. OK."
Console.ok(msg)
except:
Console.error("Problem deleting the key {name} on the cloud {cloud}".format(**key))
elif arguments['delete']:
# key delete (NAME | --select| --all)
data = dotdict({
'all': arguments['--all'] or False,
'select': arguments['--select'] or False,
'name': arguments['NAME'] or False,
})
pprint(data)
# BUG delete all is not properly implemented
if data.all:
Console.TODO("Delete --all is not yet implemented.")
# Key.delete()
elif data.select:
key = Key.select()
print (key)
else: # name
Key.delete(data.name)
msg = "info. OK."
Console.ok(msg)
elif arguments['upload']:
# pprint(arguments)
try:
#
# get username
#
conf = ConfigDict("cloudmesh.yaml")
username = conf["cloudmesh"]["profile"]["user"]
if username in ['None', 'TBD']:
username = None
#
# get cloudnames
#
clouds = []
if arguments["--active"]:
cloud = 'active'
else:
cloud = arguments["--cloud"] or Default.cloud
if cloud == "all":
config = ConfigDict("cloudmesh.yaml")
clouds = config["cloudmesh"]["clouds"]
elif cloud == 'active':
config = ConfigDict("cloudmesh.yaml")
clouds = config["cloudmesh"]["active"]
else:
clouds.append(cloud)
#
# get keyname
#
for cloud in clouds:
status = 0
#sshdb = SSHKeyDBManager()
#sshm = SSHKeyManager()
keys = Key.all()
for key in keys:
print("upload key {} -> {}".format(key["name"],
cloud))
try:
status = Key.add_key_to_cloud(
username,
key["name"],
cloud)
except Exception as e:
Console.error("problem")
if "already exists" in str(e):
print("key already exists. Skipping upload. OK.")
if status == 1:
print("Problem uploading key {} to {}. failed.".format(key["name"],
cloud))
except Exception as e:
Console.error("Problem adding key to cloud")