added command-line record editer, a few SFI demo scripts
[sfa.git] / cmdline / genicli.py
1 # command line interface
2
3 import getopt
4 import sys
5 import os
6 from cert import *
7 from geniclient import *
8 from geniticket import *
9
10 long_opts = ["keyfile=", "help", "outfile=", "credfile=", "ticketfile=",
11              "username=", "email=", "ip=", "dns=", "dump_parents", "server=",
12              "filter=", "short"]
13
14 # default command line options
15 username = "client"
16 opname = None
17 type = None
18 hrn = None
19
20 key_file = None
21 cred_file = None
22 cert_file = None
23 out_file = None
24 ticket_file = None
25
26 short = False
27 ip = None
28 dns = None
29 email = None
30 uuid = None
31 gid_pkey_fn = None
32 gid_fn = None
33 filter = None
34
35 dump_fn = None
36
37 dump_parents = False
38
39 leaf_name = None
40 server_url = "https://localhost:12345/"
41
42 def get_leaf(hrn):
43     parts = hrn.split(".")\r
44     return parts[-1]
45
46 def showhelp():
47    print "syntax: cli <options> command <args>"
48    print "options:"
49    print "    --username       ... username (or hrn) of user making call"
50    print "    --outfile       ... save response to a file"
51    print "    --credfile       ... credential of user making call (or 'None')"
52    print "    --keyfile        ... private key file of user making call"
53    print "    --ticketfile     ... filename of ticket (for redeemticket)"
54    print "    --email          ... email address (for registering users)"
55    print "    --ip             ... IP address (for registering nodes)"
56    print "    --dns            ... DNS address (for registering nodes)"
57    print "    --dump_parents   ... dump parents"
58    print "    --server         ... geni server (registry/component) to connect to"
59    print "    --filter <type>  ... filter the results of a list operation (user | slice | node ...)"
60    print "    --short          ... list records in short format (name only)"
61    print "commands:"
62    print "    resolve <hrn>"
63    print "    dumpCredential <filename>"
64    print "    dumpGid <filename>"
65    print "    getCredential <type> <hrn>"
66    print "    list <hrn>"
67    print "    start <hrn>"
68    print "    createKey <filename>"
69    print "    createGid <hrn> <uuid|None> <pubkey_fn>"
70    print "    register <type> <hrn> <gid_filename>"
71    print "    remove <type> <hrn>"
72    print "    update <type> <hrn>"
73    print "    startSlice"
74    print "    stopSlice"
75    print "    listSlices"
76
77 def process_options():
78    global username
79    global opname
80    global type, hrn
81    global cert_file, cred_file
82    global key_file, out_file, ticket_file
83    global uuid, pkey_fn, gid_fn, email, gid_pkey_fn, ip, dns
84    global dump_parents
85    global server_url
86    global filter
87    global short
88    global dump_fn
89
90    (options, args) = getopt.getopt(sys.argv[1:], '', long_opts)
91    for opt in options:
92        name = opt[0]
93        val = opt[1]
94
95        if name == "--help":
96            showhelp()
97            sys.exit(0)
98        elif name == "--username":
99            username = val
100        elif name == "--outfile":
101            out_file = val
102        elif name == "--credfile":
103            cred_file = val
104        elif name == "--certfile":
105            cred_file = val
106        elif name == "--keyfile":
107            key_file = val
108        elif name == "--ticketfile":
109            ticket_file = val
110        elif name == "--email":
111            email = val
112        elif name == "--ip":
113            ip = val
114        elif name == "--dns":
115            dns = val
116        elif name == "--dump_parents":
117            dump_parents = True
118        elif name == "--server":
119            server_url = val
120        elif name == "--filter":
121            filter = val
122        elif name == "--short":
123            short = True
124
125    if not args:
126        print "no operation specified"
127        sys.exit(-1)
128
129    opname = args[0]
130
131    if opname == "resolve":
132        if len(args) < 2:
133            print "syntax: resolve <hrn>"
134            sys.exit(-1)
135        hrn = args[1]
136
137    elif opname == "getCredential":
138        if len(args) < 3:
139            print "syntax: getcredential <type> <hrn>"
140            sys.exit(-1)
141        type = args[1]
142        hrn = args[2]
143
144    elif opname == "list":
145        if len(args) < 2:
146            print "syntax: list <hrn>"
147            sys.exit(-1)
148        hrn = args[1]
149
150
151    elif opname == "createGid":
152        if len(args) < 4:
153            print "syntax: createGid <hrn> <uuid|None> <pubkey_fn>"
154        hrn = args[1]
155        if args[2]=="None":
156            uuid=None
157        else:
158            uuid = int(args[2])
159        gid_pkey_fn = args[3]
160
161    elif opname == "register":
162        if len(args) < 4:
163            print "syntax: register <type> <hrn> <gid_filename>"
164        type = args[1]
165        hrn = args[2]
166        gid_fn = args[3]
167
168    elif opname == "remove":
169        if len(args) < 3:
170            print "syntax: remove <type> <hrn>"
171        type = args[1]
172        hrn = args[2]
173
174    elif opname == "update":
175        if len(args) < 3:
176            print "syntax: update <type> <hrn>"
177        type = args[1]
178        hrn = args[2]
179
180    elif opname == "getTicket":
181        if len(args) < 2:
182            print "syntax: getTicket <hrn>"
183            sys.exit(-1)
184        hrn = args[1]
185
186    elif opname == "dumpGid":
187        if len(args) < 2:
188            print "syntax: dumpGid <filename>"
189            sys.exit(-1)
190        dump_fn = args[1]
191
192    leaf_name = get_leaf(username)
193
194    if cert_file == None:
195        cert_file = leaf_name + ".cert"
196
197    if key_file == None:
198        key_file = leaf_name + ".pkey"
199
200    if cred_file == None:
201        cred_file = leaf_name + ".cred"
202
203 def show_options():
204    print "   server:", server_url
205    print " username:", username
206    print "cert_file:", cert_file
207    print " key_file:", key_file
208    print "cred_file:", cred_file
209    print "operation:", opname
210    print "     type:", type
211    print "      hrn:", hrn
212    print " out_file:", out_file
213
214 def get_authority(x):
215     parts = x.split(".")
216     return ".".join(parts[:3])
217
218 def dumpCredential():
219    pass
220
221 def dumpGid():
222    gid = GID(filename = dump_fn)
223    gid.dump()
224
225 # creates a self-signed certificate and private key
226 def createKey():
227    k = Keypair(create=True)
228
229    self_signed = False
230    if self_signed:
231       ik = k
232       iname = username
233    else:
234       ik = Keypair(create=True)
235       iname = "issuer"
236
237    print "writing private key to", key_file
238    k.save_to_file(key_file)
239
240    #cert = Certificate(subject=username)
241    #cert.set_pubkey(k)
242    #cert.set_issuer(ik, iname)
243    #cert.sign()
244    #print "writing self-signed cert to", cert_file
245    #cert.save_to_file(cert_file)
246
247 def load_publickey_string(fn):
248    f = file(fn,"r")
249    key_string = f.read()
250
251    # if the filename is a private key file, then extract the public key
252    if "PRIVATE KEY" in key_string:
253        outfn = tempfile.mktemp()
254        cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
255        os.system(cmd)
256        f = file(outfn, "r")
257        key_string = f.read()
258        os.remove(outfn)
259
260    return key_string
261
262 def main():
263    process_options()
264    show_options()
265
266    result = None
267
268    # if the operation is not a local operation, then create a geniclient to
269    # talk to the server
270    if (opname != "dumpCredential") and (opname != "help") and (opname != "createKey") and (opname != "dumpGid"):
271        if not os.path.exists(key_file):
272            print "key file", key_file, "does not exist"
273            sys.exit(-1)
274        if not os.path.exists(cert_file):
275            k = Keypair(filename = key_file)
276            cert = Certificate(subject=username)
277            cert.set_pubkey(k)
278            cert.set_issuer(k, username)
279            cert.sign()
280            print "writing self-signed cert to", cert_file
281            cert.save_to_file(cert_file)
282        client = GeniClient(server_url, key_file, cert_file)
283
284    # if a cred_file was specified, then load the credential
285    if (cred_file=="None") or (opname == "help") or (opname == "createKey") or \
286       (opname == "redeemTicket") or (opname == "dumpCredential") or (opname == "dumpGid"):
287       cred = None
288    else:
289       cred = Credential(filename = cred_file)
290
291    if opname == "dumpCredential":
292       dumpCredential()
293
294    elif opname == "dumpGid":
295       dumpGid()
296
297    elif opname == "help":
298       showhelp()
299
300    elif opname == "createKey":
301       createKey()
302
303    elif (opname == "resolve"):
304       result = client.resolve(cred, hrn)
305       if result:
306           for record in result:
307               print "RESULT:"
308               record.dump(dump_parents=dump_parents)
309       else:
310           print "NO RESULT"
311
312    elif (opname == "getCredential"):
313       result = client.get_credential(cred, type, hrn)
314       if result:
315           print "RESULT:"
316           result.dump(dump_parents=dump_parents)
317           if out_file:
318               file(out_file, "w").write(result.save_to_string(save_parents=True))
319       else:
320           print "NO RESULT"
321
322    elif (opname == "list"):
323       result = client.list(cred, hrn)
324       if result:
325           if filter:
326               result = [r for r in result if r.type==filter]
327           print "RESULT:"
328           for record in result:
329               if short:
330                   print "  ", record.get_name()
331               else:
332                   record.dump(dump_parents=dump_parents)
333       else:
334           print "NO RESULT"
335
336    elif (opname == "createGid"):
337        # try loading it from a private or a public key file
338        pkey_string = load_publickey_string(gid_pkey_fn)
339
340        gid = client.create_gid(cred, hrn, uuid, pkey_string)
341        if gid:
342            print "RESULT:"
343            gid.dump(dump_parents=dump_parents)
344            if out_file:
345                file(out_file,"w").write(gid.save_to_string(save_parents=True))
346        else:
347            print "NO RESULT"
348
349    elif (opname == "register"):
350        geni_info = {}
351        if type == "user":
352            if not email:
353                print "ERROR: must specify --email <addr> when registering users"
354            geni_info['email'] = email
355
356        if type == "node":
357            if not ip:
358                print "ERROR: must specify --ip <addr> when registering nodes"
359            geni_info['ip'] = ip
360            if not dns:
361                print "ERROR: must specify --dns <addr> when registering nodes"
362            geni_info['dns'] = dns
363
364        gid = GID(filename=gid_fn)
365        record = GeniRecord(name=hrn, gid=gid, type=type, pointer=-1)
366        record.set_geni_info(geni_info)
367
368        result = client.register(cred, record)
369
370    elif (opname == "remove"):
371        client.remove(cred, type, hrn)
372
373    elif (opname == "update"):
374        record_list = client.resolve(cred, hrn)
375        if not record_list:
376            print "no records match hrn"
377
378        matching_records = []
379        for record in record_list:
380            if record.get_type() == type:
381                matching_records.append(record)
382
383        if not matching_records:
384            print "records match hrn, but no records match type"
385
386        for record in matching_records:
387            geni_info = record.get_geni_info()
388
389            if email:
390                geni_info['email'] = email
391            if ip:
392                geni_info['ip'] = ip
393            if dns:
394                geni_info['dns'] = dns
395
396            client.update(cred, record)
397
398    elif (opname == "stopSlice"):
399        client.stop_slice(cred)
400
401    elif (opname == "startSlice"):
402        client.start_slice(cred)
403
404    elif (opname == "resetSlice"):
405        client.reset_slice(cred)
406
407    elif (opname == "deleteSlice"):
408        client.delete_slice(cred)
409
410    elif (opname == "listSlices"):
411        result = client.list_slices(cred)
412        print "RESULT:"
413        print "\n".join(result)
414        if out_file:
415            file(out_file,"w").write("\n".join(result))
416
417    elif (opname == "getTicket"):
418       result = client.get_ticket(cred, hrn, {})
419       if result:
420           print "RESULT:"
421           result.dump(dump_parents=dump_parents)
422           if out_file:
423               file(out_file,"w").write(result.save_to_string(save_parents=True))
424       else:
425           print "NO RESULT"
426
427    elif (opname == "redeemTicket"):
428        ticket = Ticket(filename = ticket_file)
429        result = client.redeem_ticket(ticket)
430
431    else:
432       print "unknown operation: " + opname
433
434 if __name__=="__main__":
435    main()
436