3 from PLC.Faults import *
4 from PLC.Parameter import Parameter
5 from PLC.Filter import Filter
6 from PLC.Debug import profile
7 from PLC.Table import Row, Table
8 from PLC.KeyTypes import KeyType, KeyTypes
9 from PLC.NovaTable import NovaObject, NovaTable
11 class Key(NovaObject):
13 Representation of a row in the keys table. To use, instantiate with a
14 dict of values. Update as you would a dict. Commit to the database
19 primary_key = 'key_id'
20 join_tables = ['person_key', 'peer_key']
22 'key_id': Parameter(str, "Key identifier"),
23 'key_type': Parameter(str, "Key type"),
24 'key': Parameter(str, "Key value", max = 4096),
25 'person_id': Parameter(int, "User to which this key belongs", nullok = True),
26 'peer_id': Parameter(int, "Peer to which this key belongs", nullok = True),
27 'peer_key_id': Parameter(int, "Foreign key identifier at peer", nullok = True),
30 def validate_key_type(self, key_type):
31 key_types = [row['key_type'] for row in KeyTypes(self.api)]
32 if key_type not in key_types:
33 raise PLCInvalidArgument, "Invalid key type"
36 def validate_key(self, key):
37 # Key must not be blacklisted
38 rows = self.api.db.selectall("SELECT 1 from keys" \
39 " WHERE key = %(key)s" \
40 " AND is_blacklisted IS True",
43 raise PLCInvalidArgument, "Key is blacklisted and cannot be used"
54 if self['key_type'] == 'ssh':
55 # Accept only SSH version 2 keys without options. From
58 # Each protocol version 2 public key consists of: options,
59 # keytype, base64 encoded key, comment. The options field
60 # is optional...The comment field is not used for anything
61 # (but may be convenient for the user to identify the
62 # key). For protocol version 2 the keytype is ``ssh-dss''
65 good_ssh_key = r'^.*(?:ssh-dss|ssh-rsa)[ ]+[A-Za-z0-9+/=]+(?: .*)?$'
66 if not re.match(good_ssh_key, key, re.IGNORECASE):
67 raise PLCInvalidArgument, "Invalid SSH version 2 public key"
69 def blacklist(self, commit = True):
71 Permanently blacklist key (and all other identical keys),
72 preventing it from ever being added again. Because this could
73 affect multiple keys associated with multiple accounts, it
77 assert 'key_id' in self
80 # Get all matching keys
81 rows = self.api.db.selectall("SELECT key_id FROM keys WHERE key = %(key)s",
83 key_ids = [row['key_id'] for row in rows]
85 assert self['key_id'] in key_ids
87 # Keep the keys in the table
88 self.api.db.do("UPDATE keys SET is_blacklisted = True" \
89 " WHERE key_id IN (%s)" % ", ".join(map(str, key_ids)))
91 # But disassociate them from all join tables
92 for table in self.join_tables:
93 self.api.db.do("DELETE FROM %s WHERE key_id IN (%s)" % \
94 (table, ", ".join(map(str, key_ids))))
99 class Keys(NovaTable):
101 Representation of row(s) from the keys table in the
105 def __init__(self, api, key_filter = None, columns = None):
107 keysManager = self.api.client_shell.nova.keypairs
110 if key_filter is not None:
111 if isinstance(key_filter, (list, tuple, set, int, long)):
112 keyPairs = filter(lambda kp: kp.uuid in key_filter,
113 keysManager.findall())
114 elif isinstance(key_filter, dict):
115 keyPairs = keysManager.findall(**key_filter)
116 elif isinstnace(key_filter, StringTypes):
117 keyPairs = keyManagers.findall(uuid = key_filter)
119 raise PLCInvalidArgument, "Wrong key filter %r"%key_filter
121 self.extend(keyPairs)