70a2ad1b145f57cbe644f1c0784801d5d53a8829
[gentoo-keys.git] / gkeyldap / actions.py
1 #
2 #-*- coding:utf-8 -*-
3
4 """
5     Gentoo-keys - gkeyldap/actions.py
6
7     Primary api interface module
8
9     @copyright: 2012 by Brian Dolbec <dol-sen@gentoo.org>
10     @license: GNU GPL2, see COPYING for details.
11 """
12
13 import os
14
15 from gkeys.config import GKEY
16 from gkeys.seed import Seeds
17 from gkeyldap.search import (LdapSearch, UID, gkey2ldap_map, gkey2SEARCH)
18
19
20 # set some defaults
21 KEY_LEN = {
22     'keyid': 8,
23     'longkeyid': 16,
24 }
25
26
27 Avialable_Actions = ['ldapsearch', 'updateseeds']
28
29
30 def get_key_ids(key, info):
31     '''Small utility function to return only keyid (short)
32     or longkeyid's
33
34     @param key: string, the key length desired
35     @param info: list of keysid's to process
36     @return list of the desired key length id's
37     '''
38     result = []
39     for x in info:
40         if x.startswith('0x'):
41             mylen = KEY_LEN[key] + 2
42         else:
43             mylen = KEY_LEN[key]
44         if len(x) == mylen:
45             result.append(x)
46     return result
47
48
49 class Actions(object):
50
51
52     def __init__(self, config, output=None, logger=None):
53         self.config = config
54         self.output = output
55         self.logger = logger
56         self.seeds = None
57
58
59     def ldapsearch(self, args):
60         l = LdapSearch()
61         self.logger.info("Search...establishing connection")
62         self.output("Search...establishing connection")
63         if not l.connect():
64             self.logger.info("Aborting Search...Connection failed")
65             self.output("Aborting Search...Connection failed")
66             return False
67         self.logger.debug("MAIN: _action_ldapsearch; args = %s" % str(args))
68         x, target, search_field = self.get_args(args)
69         results = l.search(target, search_field)
70         devs = l.result2dict(results, gkey2ldap_map[x])
71         for dev in sorted(devs):
72             self.output(dev, devs[dev])
73         self.output("============================================")
74         self.output("Total number of devs in results:", len(devs))
75         return True
76
77
78     def updateseeds(self, args):
79         self.logger.info("Beginning ldap search...")
80         self.output("Beginning ldap search...")
81         l = LdapSearch()
82         if not l.connect():
83             self.output("Aborting Update...Connection failed")
84             return False
85         results = l.search('*', UID)
86         info = l.result2dict(results, 'uid')
87         self.logger.debug(
88             "MAIN: _action_updateseeds; got results :) converted to info")
89         if not self.create_seedfile(info):
90             self.logger.error("Dev seed file update failure: "
91                 "Original seed file is intact & untouched.")
92         old = self.config['dev-seedfile'] + '.old'
93         try:
94             self.output("Backing up existing file...")
95             if os.path.exists(old):
96                 self.logger.debug(
97                     "MAIN: _action_updateseeds; Removing 'old' seed file: %s"
98                     % old)
99                 os.unlink(old)
100             if os.path.exists(self.config['dev-seedfile']):
101                 self.logger.debug(
102                     "MAIN: _action_updateseeds; Renaming current seed file to: "
103                     "%s" % old)
104                 os.rename(self.config['dev-seedfile'], old)
105             self.logger.debug(
106                 "MAIN: _action_updateseeds; Renaming '.new' seed file to: %s"
107                 % self.config['dev-seedfile'])
108             os.rename(self.config['dev-seedfile'] + '.new',
109                 self.config['dev-seedfile'])
110         except IOError:
111             raise
112         self.output("Developer Seed file updated")
113         return True
114
115
116     def create_seedfile(self, devs):
117         self.output("Creating seeds from ldap data...")
118         filename = self.config['dev-seedfile'] + '.new'
119         self.seeds = Seeds(filename)
120         count = 0
121         for dev in sorted(devs):
122             if devs[dev]['gentooStatus'][0] not in ['active']:
123                 continue
124             #self.logger.debug("create_seedfile, dev = "
125             #   "%s, %s" % (str(dev), str(devs[dev])))
126             new_gkey = GKEY._make(self.build_gkeylist(devs[dev]))
127             self.seeds.add(new_gkey)
128             count += 1
129         self.output("Total number of seeds created:", count)
130         self.output("Seeds created...saving file: %s" % filename)
131         return self.seeds.save()
132
133
134     @staticmethod
135     def get_args(args):
136         for x in ['nick', 'name', 'gpgkey', 'fingerprint', 'status']:
137             if x:
138                 target = getattr(args, x)
139                 search_field = gkey2SEARCH[x]
140                 break
141         return (x, target, search_field)
142
143
144
145     def build_gkeydict(self, info):
146         keyinfo = {}
147         for x in GKEY._fields:
148             field = gkey2ldap_map[x]
149             if not field:
150                 continue
151             try:
152                 # strip errant line feeds
153                 values = [y.strip('\n') for y in info[field]]
154                 if values and values in ['uid', 'cn' ]:
155                     value = values[0]
156                 # separate out short/long key id's
157                 elif values and x in ['keyid', 'longkeyid']:
158                     value = get_key_ids(x, values)
159                 else:
160                     value = values
161                 if 'undefined' in values:
162                     self.logger.error('%s = "undefined" for %s, %s'
163                         %(field, info['uid'][0], info['cn'][0]))
164                 if value:
165                     keyinfo[x] = value
166             except KeyError:
167                 pass
168         return keyinfo
169
170
171     def build_gkeylist(self, info):
172         keyinfo = []
173         keyid_found = False
174         keyid_missing = False
175         #self.logger.debug("MAIN: build_gkeylist; info = %s" % str(info))
176         for x in GKEY._fields:
177             field = gkey2ldap_map[x]
178             if not field:
179                 keyinfo.append(None)
180                 continue
181             try:
182                 # strip errant line feeds
183                 values = [y.strip('\n') for y in info[field]]
184                 if values and field in ['uid', 'cn' ]:
185                     value = values[0]
186                 # separate out short/long key id's
187                 elif values and x in ['keyid', 'longkeyid']:
188                     value = get_key_ids(x, values)
189                     if len(value):
190                         keyid_found = True
191                 elif values and x in ['fingerprint']:
192                     value = [v.replace(' ', '') for v in values]
193                 else:
194                     value = values
195                 if 'undefined' in values:
196                     self.logger.error('%s = "undefined" for %s, %s'
197                         %(field, info['uid'][0], info['cn'][0]))
198                 keyinfo.append(value)
199             except KeyError:
200                 self.logger.error("Missing %s (%s) for %s, %s"
201                     %(field, x, info['uid'][0], info['cn'][0]))
202                 if x in ['keyid', 'longkeyid']:
203                     keyid_missing = True
204                 keyinfo.append(None)
205         if not keyid_found and not keyid_missing:
206             try:
207                 gpgkey = info[gkey2ldap_map['longkeyid']]
208             except KeyError:
209                 gpgkey = 'Missing from ldap info'
210             self.logger.error("A valid keyid or longkeyid was not found for")
211             self.logger.error("developer: %s, %s : gpgkey = %s"
212                 %(info['uid'][0], info['cn'][0], gpgkey))
213         else:
214             for x in [2, 3]:
215                 if not keyinfo[x]:
216                     continue
217                 for y in keyinfo[x]:
218                     index = len(y.lstrip('0x'))
219                     if y.lstrip('0x') not in [x[-index:] for x in keyinfo[5]]:
220                         self.logger.error('GPGKey and/or fingerprint error in' +
221                             ' ladap info for: ' + info['uid'][0])
222                         self.logger.error(str(keyinfo))
223         return keyinfo
224