1# Copyright 2013 OpenStack Foundation 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# not use this file except in compliance with the License. You may obtain 5# a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations 13# under the License. 14# 15 16"""Keypair action implementations""" 17 18import io 19import logging 20import os 21import sys 22 23from osc_lib.command import command 24from osc_lib import exceptions 25from osc_lib import utils 26 27from openstackclient.i18n import _ 28 29 30LOG = logging.getLogger(__name__) 31 32 33class CreateKeypair(command.ShowOne): 34 _description = _("Create new public or private key for server ssh access") 35 36 def get_parser(self, prog_name): 37 parser = super(CreateKeypair, self).get_parser(prog_name) 38 parser.add_argument( 39 'name', 40 metavar='<name>', 41 help=_("New public or private key name") 42 ) 43 key_group = parser.add_mutually_exclusive_group() 44 key_group.add_argument( 45 '--public-key', 46 metavar='<file>', 47 help=_("Filename for public key to add. If not used, " 48 "creates a private key.") 49 ) 50 key_group.add_argument( 51 '--private-key', 52 metavar='<file>', 53 help=_("Filename for private key to save. If not used, " 54 "print private key in console.") 55 ) 56 return parser 57 58 def take_action(self, parsed_args): 59 compute_client = self.app.client_manager.compute 60 61 public_key = parsed_args.public_key 62 if public_key: 63 try: 64 with io.open(os.path.expanduser(parsed_args.public_key)) as p: 65 public_key = p.read() 66 except IOError as e: 67 msg = _("Key file %(public_key)s not found: %(exception)s") 68 raise exceptions.CommandError( 69 msg % {"public_key": parsed_args.public_key, 70 "exception": e} 71 ) 72 73 keypair = compute_client.keypairs.create( 74 parsed_args.name, 75 public_key=public_key, 76 ) 77 78 private_key = parsed_args.private_key 79 # Save private key into specified file 80 if private_key: 81 try: 82 with io.open( 83 os.path.expanduser(parsed_args.private_key), 'w+' 84 ) as p: 85 p.write(keypair.private_key) 86 except IOError as e: 87 msg = _("Key file %(private_key)s can not be saved: " 88 "%(exception)s") 89 raise exceptions.CommandError( 90 msg % {"private_key": parsed_args.private_key, 91 "exception": e} 92 ) 93 # NOTE(dtroyer): how do we want to handle the display of the private 94 # key when it needs to be communicated back to the user 95 # For now, duplicate nova keypair-add command output 96 info = {} 97 if public_key or private_key: 98 info.update(keypair._info) 99 if 'public_key' in info: 100 del info['public_key'] 101 if 'private_key' in info: 102 del info['private_key'] 103 return zip(*sorted(info.items())) 104 else: 105 sys.stdout.write(keypair.private_key) 106 return ({}, {}) 107 108 109class DeleteKeypair(command.Command): 110 _description = _("Delete public or private key(s)") 111 112 def get_parser(self, prog_name): 113 parser = super(DeleteKeypair, self).get_parser(prog_name) 114 parser.add_argument( 115 'name', 116 metavar='<key>', 117 nargs='+', 118 help=_("Name of key(s) to delete (name only)") 119 ) 120 return parser 121 122 def take_action(self, parsed_args): 123 compute_client = self.app.client_manager.compute 124 result = 0 125 for n in parsed_args.name: 126 try: 127 data = utils.find_resource( 128 compute_client.keypairs, n) 129 compute_client.keypairs.delete(data.name) 130 except Exception as e: 131 result += 1 132 LOG.error(_("Failed to delete key with name " 133 "'%(name)s': %(e)s"), {'name': n, 'e': e}) 134 135 if result > 0: 136 total = len(parsed_args.name) 137 msg = (_("%(result)s of %(total)s keys failed " 138 "to delete.") % {'result': result, 'total': total}) 139 raise exceptions.CommandError(msg) 140 141 142class ListKeypair(command.Lister): 143 _description = _("List key fingerprints") 144 145 def take_action(self, parsed_args): 146 compute_client = self.app.client_manager.compute 147 columns = ( 148 "Name", 149 "Fingerprint" 150 ) 151 data = compute_client.keypairs.list() 152 153 return (columns, 154 (utils.get_item_properties( 155 s, columns, 156 ) for s in data)) 157 158 159class ShowKeypair(command.ShowOne): 160 _description = _("Display key details") 161 162 def get_parser(self, prog_name): 163 parser = super(ShowKeypair, self).get_parser(prog_name) 164 parser.add_argument( 165 'name', 166 metavar='<key>', 167 help=_("Public or private key to display (name only)") 168 ) 169 parser.add_argument( 170 '--public-key', 171 action='store_true', 172 default=False, 173 help=_("Show only bare public key paired with the generated key") 174 ) 175 return parser 176 177 def take_action(self, parsed_args): 178 compute_client = self.app.client_manager.compute 179 keypair = utils.find_resource(compute_client.keypairs, 180 parsed_args.name) 181 182 info = {} 183 info.update(keypair._info) 184 if not parsed_args.public_key: 185 del info['public_key'] 186 return zip(*sorted(info.items())) 187 else: 188 # NOTE(dtroyer): a way to get the public key in a similar form 189 # as the private key in the create command 190 sys.stdout.write(keypair.public_key) 191 return ({}, {}) 192