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