685d055cc48369fbe15ee6aeac717e95e710922e
[myplc.git] / support-scripts / renew_reminder.py
1 #!/usr/bin/env python3
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 # pylint: disable=c0326
9
10 import sys
11 import time
12 from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
13
14 # Load shell with default configuration
15 sys.path.append('/usr/share/plc_api')
16 from PLC.Shell import Shell
17
18 def main():
19
20     plc = Shell(globals())
21
22     PLC_WWW_HOST = plc.config.PLC_WWW_HOST
23     PLC_NAME = plc.config.PLC_NAME
24
25     # E-mail parameteres
26     slice_url = f"https://{PLC_WWW_HOST}/db/slices/index.php?id="
27
28
29     parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
30     parser.add_argument("-s", "--slice", action="append", dest="slices", default=None,
31                         help="Slice(s) to check (default: all)")
32     parser.add_argument("-x", "--expires", type=int, default=5,
33                         help="Warn if slice expires this many days from now")
34     parser.add_argument("-n", "--dry-run", action="store_true", default=False,
35                         help="Dry run, do not actually e-mail users")
36     parser.add_argument("-f", "--force", action="store_true", default=False,
37                         help="Force, send e-mail even if slice is not close to expiring")
38     parser.add_argument("-v", "--verbose", action="store_true", default=False,
39                         help="Be verbose")
40     args = parser.parse_args()
41
42     now = int(time.time())
43     expires = now + (args.expires * 24 * 60 * 60)
44
45     if args.verbose:
46         print("Checking for slices that expire before " + time.ctime(expires))
47
48     slice_filter = {'peer_id': None}
49     if args.slices:
50         slice_filter['name'] = args.slices
51
52     # issue one call to GetPersons to gather the sfa_created tag on all persons
53     persons = GetPersons({'peer_id': None}, ['person_id', 'email', 'sfa_created'])
54     persons_by_id = { p['person_id'] : p for p in persons }
55     if args.verbose:
56         print("retrieved {} persons".format(len(persons)))
57
58     slices = GetSlices(
59         slice_filter,
60         ['slice_id', 'name', 'expires', 'description', 'url', 'person_ids'])
61     if args.verbose:
62         print("scanning {} slices".format(len(slices)))
63
64     for slice in slices:
65         # See if slice expires before the specified warning date
66         if not args.force and slice['expires'] > expires:
67             continue
68
69         # Calculate number of whole days left
70         delta = slice['expires'] - now
71         days = delta // (24 * 60 * 60)
72         if days == 0:
73             days = "less than a day"
74         else:
75             if days > 1:
76                 suffix = "s"
77             else:
78                 suffix = ""
79             days = f"{days} day{suffix}"
80
81         slice_name = slice['name']
82         slice_id = slice['slice_id']
83
84         message = f"""
85     The {PLC_NAME} slice {slice_name} will expire in {days}.
86     """
87
88         # Explain that slices must have descriptions and URLs
89         if not slice['description'] or not slice['description'].strip() or \
90            not slice['url'] or not slice['url'].strip():
91             message += f"""
92     Before you may renew this slice, you must provide a short description
93     of the slice and a link to a project website.
94     """
95
96         # Provide links to renew or delete the slice
97         message += f"""
98     To update, renew, or delete this slice, visit the URL:
99
100             {slice_url}{slice_id}
101     """
102
103         # compute set of persons but keep federated users (the ones with sfa_created) out
104         slice_persons    = [persons_by_id[id] for id in slice['person_ids']]
105         recipient_emails = [person['email'] for person in slice_persons
106                             if not person['sfa_created']]
107         nb_in_slice      = len(slice_persons)
108         nb_not_sfa       = len(recipient_emails)
109
110         if not recipient_emails:
111             if args.verbose:
112                 print(f"""{slice_name} has no recipient
113     ({nb_in_slice} in slice, {nb_not_sfa} not sfa_created)""")
114             continue
115
116         log_details = [time.ctime(now), slice_name, time.ctime(slice['expires'])]
117         details = "\t".join(log_details)
118         recipients = ",".join(recipient_emails)
119         log_data = f"{details}\t{recipients}"
120
121         extras = GetMessages({'message_id': "renew_reminder_addition"})
122         if extras:
123             message += extras[0]['template']
124
125         if args.dry_run:
126             print(f"-------------------- Found slice to renew {slice_name}")
127             print(message)
128             print(f"---- log_data\n{log_data}")
129         else:
130             NotifyPersons(slice['person_ids'],
131                           f"{PLC_NAME}: slice {slice_name} expires in {days}",
132                           message)
133             print(log_data)
134
135 if __name__ == '__main__':
136     main()