Setting tag myplc-5.3-5
[myplc.git] / support-scripts / renew_reminder.py
1 #!/usr/bin/python
2 #
3 # Notify users of slices that are about to expire
4 #
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2005 The Trustees of Princeton University
7 #
8
9 import os
10 import sys
11 import time
12 from optparse import OptionParser
13
14 # Load shell with default configuration
15 sys.path.append('/usr/share/plc_api')
16 from PLC.Shell import Shell
17 plc = Shell(globals())
18
19 PLC_WWW_HOST = plc.config.PLC_WWW_HOST
20 PLC_NAME = plc.config.PLC_NAME
21
22 LOGFILE = '/var/log/renew_reminder'
23 class Logfile:
24     def __init__(self, filename):
25         self.filename = filename
26     def write(self, data):
27         try:
28             fd = os.open(self.filename, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0644)
29             os.write(fd, '{}'.format(data))
30             os.close(fd)
31         except OSError:
32             sys.stderr.write(data)
33             sys.stderr.flush()
34
35 log = Logfile(LOGFILE)
36
37 # Debug
38 verbose = False;
39
40 # E-mail parameteres
41 slice_url = "https://{PLC_WWW_HOST}/db/slices/index.php?id=".format(**locals())
42
43 parser = OptionParser()
44 parser.add_option("-s", "--slice", action = "append", dest = "slices", default = None,
45                   help = "Slice(s) to check (default: all)")
46 parser.add_option("-x", "--expires", type = "int", default = 5,
47                   help = "Warn if slice expires this many days from now (default: %default)")
48 parser.add_option("-n", "--dryrun", action = "store_true", default = False,
49                   help = "Dry run, do not actually e-mail users (default: %default)")
50 parser.add_option("-f", "--force", action = "store_true", default = False,
51                   help = "Force, send e-mail even if slice is not close to expiring (default: %default)")
52 parser.add_option("-v", "--verbose", action = "store_true", default = False,
53                   help = "Be verbose (default: %default)")
54 (options, args) = parser.parse_args()
55
56 now = int(time.time())
57 expires = now + (options.expires * 24 * 60 * 60)
58
59 if options.verbose:
60     print "Checking for slices that expire before " + time.ctime(expires)
61
62 slice_filter = {'peer_id': None}
63 if options.slices:
64     slice_filter['name'] = options.slices
65
66 # issue one call to GetPersons to gather the sfa_created tag on all persons
67 persons = GetPersons ({'peer_id': None}, ['person_id', 'email', 'sfa_created'])
68 persons_by_id = { p['person_id'] : p for p in persons }
69 if options.verbose:
70     print "retrieved {} persons".format(len(persons))
71
72 slices = GetSlices(slice_filter, ['slice_id', 'name', 'expires', 'description', 'url', 'person_ids'])
73 if options.verbose:
74     print "scanning {} slices".format(len(slices))
75     
76 for slice in slices:
77     # See if slice expires before the specified warning date
78     if not options.force and slice['expires'] > expires:
79         continue
80
81     # Calculate number of whole days left
82     delta = slice['expires'] - now
83     days = delta / 24 / 60 / 60
84     if days == 0:
85         days = "less than a day"
86     else:
87         if days > 1:
88             suffix = "s"
89         else:
90             suffix = ""
91         days = "{days} day{suffix}".format(**locals())
92
93     slice_name = slice['name']
94     slice_id = slice['slice_id']
95
96     message_format = """
97 The {PLC_NAME} slice {slice_name} will expire in {days}.
98 """
99
100     # Explain that slices must have descriptions and URLs
101     if not slice['description'] or not slice['description'].strip() or \
102        not slice['url'] or not slice['url'].strip():
103         message_format += """
104 Before you may renew this slice, you must provide a short description
105 of the slice and a link to a project website.
106 """
107
108     # Provide links to renew or delete the slice
109     message_format += """
110 To update, renew, or delete this slice, visit the URL:
111
112         {slice_url}{slice_id}
113 """
114
115     # compute set of persons but keep federated users (the ones with sfa_created) out 
116     slice_persons    = [ persons_by_id[id] for id in slice['person_ids'] ]
117     recipient_emails = [ person['email'] for person in slice_persons if not person['sfa_created'] ]
118     recipient_ids    = [ person['email'] for person in slice_persons if not person['sfa_created'] ]
119     nb_in_slice      = len(slice_persons)
120     nb_not_sfa       = len(recipient_emails)
121
122     if not recipient_emails:
123         if options.verbose:
124             print """{slice_name} has no recipient 
125 ({nb_in_slice} in slice, {nb_not_sfa} not sfa_created)""".format(**locals())
126         continue
127
128     log_details = [time.ctime(now), slice_name, time.ctime(slice['expires'])]
129     log_data = "{}\t{}".format("\t".join(log_details), ",".join(recipient_emails))
130
131     if options.dryrun:
132         print "-------------------- Found slice to renew {slice_name}".format(**locals())
133         print message_format.format(**locals())
134         print "log >> {}".format(log_data)
135     else:
136         NotifyPersons(slice['person_ids'],
137                       "{PLC_NAME} slice {slice_name} expires in {days}".format(**locals()),
138                       message_format.format(**locals()))
139         print >> log, log_data
140