b506f644f1c41c505c51d539ba04f28abbcdec6a
[gentoo-keys.git] / gkeyldap / cli.py
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4
5
6 import sys
7 import os
8 import argparse
9
10 from gkeys import log
11 log.set_logger('gkeyldap')
12 from gkeys.log import logger
13
14 from gkeys.config import GKeysConfig, GKEY
15 from gkeys.seed import Seeds
16 from gkeyldap.search import (LdapSearch, UID, gkey2ldap_map, gkey2SEARCH)
17
18
19 # set debug level to min
20 logger.setLevel(0)
21
22
23 class Main(object):
24     '''Main command line interface class'''
25
26
27     def __init__(self, root=None, config=None, print_results=True):
28         """ Main class init function.
29
30         @param root: string, root path to use
31         """
32         self.root = root or "/"
33         self.config = config or GKeysConfig(root=root)
34         self.print_results = print_results
35         self.args = None
36         self.seeds = None
37
38
39     def __call__(self, args=None):
40         if args:
41             self.run(self.parse_args(args))
42         else:
43             self.run(self.parse_args(sys.argv[1:]))
44
45
46     def parse_args(self, args):
47         '''Parse a list of aruments
48
49         @param args: list
50         @returns argparse.Namespace object
51         '''
52         #logger.debug('MAIN: parse_args; args: %s' % args)
53         actions = ['ldapsearch', 'updateseeds']
54         parser = argparse.ArgumentParser(
55             prog='gkeys',
56             description='Gentoo-keys manager program',
57             epilog='''Caution: adding untrusted keys to these keyrings can
58                 be hazardous to your system!''')
59         # actions
60         parser.add_argument('action', choices=actions, nargs='?',
61             default='ldapsearch', help='Search ldap or update the seed file')
62         # options
63         parser.add_argument('-c', '--config', dest='config', default=None,
64             help='The path to an alternate config file')
65         parser.add_argument('-d', '--dest', dest='destination', default=None,
66             help='The destination db file path')
67         parser.add_argument('-N', '--name', dest='name', default=None,
68             help='The name to search for')
69         parser.add_argument('-n', '--nick', dest='nick', default=None,
70             help='The nick or user id (uid) to search for')
71         parser.add_argument('-m', '--mail', dest='mail', default=None,
72             help='The email address to search for')
73         parser.add_argument('-k', '--keyid', dest='keyid', default=None,
74             help='The gpg keyid to search for')
75         parser.add_argument('-f', '--fingerprint', dest='fingerprint', default=None,
76             help='The gpg fingerprint to search for')
77         parser.add_argument('-S', '--status', default=False,
78             help='The seedfile path to use')
79         parser.add_argument('-D', '--debug', default=0,
80             help='The logging level to use and report with')
81
82         return parser.parse_args(args)
83
84
85     def run(self, args):
86         '''Run the args passed in
87
88         @param args: list or argparse.Namespace object
89         '''
90         if not args:
91             logger.error("Main: run; invalid args argument passed in")
92         if isinstance(args, list):
93             args = self.parse_args(args)
94         if args.debug:
95             logger.setLevel(int(args.debug))
96             logger.debug("MAIN: run; Found alternate debug setting: %s" % str(args.debug))
97         if args.config:
98             logger.debug("Main: run; Found alternate config request: %s"
99                 % args.config)
100             self.config.defaults['config'] = args.config
101         # now make it load the config file
102         self.config.read_config()
103
104         func = getattr(self, '_action_%s' % args.action)
105         logger.debug('Main: run; Found action: %s' % args.action)
106         results = func(args)
107         return results
108
109
110     def _action_ldapsearch(self, args):
111         l = LdapSearch()
112         if not l.connect():
113             print("Aborting Search...Connection failed")
114             return False
115         logger.debug("MAIN: _action_ldapsearch; args = %s" % str(args))
116         x, target, search_field = self.get_args(args)
117         results = l.search(target, search_field)
118         devs = l.result2dict(results, gkey2ldap_map[x])
119         for dev in sorted(devs):
120             print(dev, devs[dev])
121         print("============================================")
122         print("Total number of devs in results:", len(devs))
123         return True
124
125
126     def _action_updateseeds(self, args):
127         print("Beginning ldap search...")
128         l = LdapSearch()
129         if not l.connect():
130             print("Aborting Update...Connection failed")
131             return False
132         results = l.search('*', UID)
133         info = l.result2dict(results, 'uid')
134         logger.debug(
135             "MAIN: _action_updateseeds; got results :) converted to info")
136         if not self.create_seedfile(info):
137             logger.error("Dev seed file update failure: "
138                 "Original seed file is intact & untouched.")
139         old = self.config['dev-seedfile'] + '.old'
140         try:
141             print("Backing up existing file...")
142             if os.path.exists(old):
143                 logger.debug(
144                     "MAIN: _action_updateseeds; Removing 'old' seed file: %s"
145                     % old)
146                 os.unlink(old)
147             if os.path.exists(self.config['dev-seedfile']):
148                 logger.debug(
149                     "MAIN: _action_updateseeds; Renaming current seed file to: "
150                     "%s" % old)
151                 os.rename(self.config['dev-seedfile'], old)
152             logger.debug(
153                 "MAIN: _action_updateseeds; Renaming '.new' seed file to: %s"
154                 % self.config['dev-seedfile'])
155             os.rename(self.config['dev-seedfile'] + '.new',
156                 self.config['dev-seedfile'])
157         except IOError:
158             raise
159         print("Developer Seed file updated")
160         return True
161
162
163     def create_seedfile(self, devs):
164         print("Creating seeds from ldap data...")
165         filename = self.config['dev-seedfile'] + '.new'
166         self.seeds = Seeds(filename)
167         count = 0
168         for dev in sorted(devs):
169             if devs[dev]['gentooStatus'][0] not in ['active']:
170                 continue
171             #logger.debug("create_seedfile, dev = "
172             #   "%s, %s" % (str(dev), str(devs[dev])))
173             new_gkey = GKEY._make(self.build_gkeylist(devs[dev]))
174             self.seeds.add(new_gkey)
175             count += 1
176         print("Total number of seeds created:", count)
177         print("Seeds created...saving file: %s" % filename)
178         return self.seeds.save()
179
180
181     @staticmethod
182     def get_args(args):
183         for x in ['nick', 'name', 'gpgkey', 'fingerprint', 'status']:
184             if x:
185                 target = getattr(args, x)
186                 search_field = gkey2SEARCH[x]
187                 break
188         return (x, target, search_field)
189
190
191
192     @staticmethod
193     def build_gkeydict(info):
194         keyinfo = {}
195         for x in GKEY._fields:
196             field = gkey2ldap_map[x]
197             if not field:
198                 continue
199             try:
200                 values = info[field]
201                 if values and values in ['uid', 'cn' ]:
202                     value = values[0]
203                 else:
204                     value = values
205                 if value:
206                     keyinfo[x] = value
207             except KeyError:
208                 pass
209         return keyinfo
210
211
212     @staticmethod
213     def build_gkeylist(info):
214         keyinfo = []
215         #logger.debug("MAIN: build_gkeylist; info = %s" % str(info))
216         for x in GKEY._fields:
217             field = gkey2ldap_map[x]
218             if not field:
219                 keyinfo.append(None)
220                 continue
221             try:
222                 values = info[field]
223                 if values and field in ['uid', 'cn' ]:
224                     value = values[0]
225                 else:
226                     value = values
227                 if 'undefined' in values:
228                     logger.error('%s = "undefined" for %s, %s'
229                         %(field, info['uid'][0], info['cn'][0]))
230                 keyinfo.append(value)
231             except KeyError:
232                 logger.error("Missing %s for %s, %s"
233                     %(field, info['uid'][0], info['cn'][0]))
234                 keyinfo.append(None)
235         return keyinfo
236
237
238 if __name__ == '__main__':
239
240     Main()
241
242
243