b789a5ee559c5433a48c1ef117e6597be6b9e717
[arvados.git] / sdk / python / arvados / commands / federation_migrate.py
1 #!/usr/bin/env python3
2 # Copyright (C) The Arvados Authors. All rights reserved.
3 #
4 # SPDX-License-Identifier: Apache-2.0
5
6 import arvados
7 import arvados.util
8 import csv
9 import sys
10 import argparse
11 import hmac
12
13 def main():
14
15     parser = argparse.ArgumentParser(description='Migrate users to federated identity')
16     parser.add_argument('--tokens', type=str)
17     group = parser.add_mutually_exclusive_group()
18     group.add_argument('--report', type=str)
19     group.add_argument('--migrate', type=str)
20     args = parser.parse_args()
21
22     clusters = {}
23
24     with open(args.tokens, "rt") as f:
25         for r in csv.reader(f):
26             host = r[0]
27             token = r[1]
28             arv = arvados.api(host=host, token=token)
29             clusters[arv._rootDesc["uuidPrefix"]] = arv
30             cur = arv.users().current().execute()
31             if not cur["is_admin"]:
32                 raise Exception("Not admin of %s" % host)
33
34     if args.report:
35         users = []
36         for c, arv in clusters.items():
37             ul = arvados.util.list_all(arv.users().list)
38             for l in ul:
39                 if l["uuid"].startswith(c):
40                     users.append(l)
41
42         out = csv.writer(open(args.report, "wt"))
43
44         out.writerow(("email", "user uuid", "primary cluster/user"))
45
46         users = sorted(users, key=lambda u: u["email"]+"::"+u["uuid"])
47
48         accum = []
49         lastemail = None
50         for u in users:
51             if u["uuid"].endswith("-anonymouspublic") or u["uuid"].endswith("-000000000000000"):
52                 continue
53             if lastemail == None:
54                 lastemail = u["email"]
55             if u["email"] == lastemail:
56                 accum.append(u)
57             else:
58                 homeuuid = None
59                 for a in accum:
60                     if homeuuid is None:
61                         homeuuid = a["uuid"]
62                     if a["uuid"] != homeuuid:
63                         homeuuid = ""
64                 for a in accum:
65                     out.writerow((a["email"], a["uuid"], homeuuid[0:5]))
66                 lastemail = u["email"]
67                 accum = [u]
68
69         homeuuid = None
70         for a in accum:
71             if homeuuid is None:
72                 homeuuid = a["uuid"]
73             if a["uuid"] != homeuuid:
74                 homeuuid = ""
75         for a in accum:
76             out.writerow((a["email"], a["uuid"], homeuuid[0:5]))
77
78     if args.migrate:
79         rows = []
80         by_email = {}
81         with open(args.migrate, "rt") as f:
82             for r in csv.reader(f):
83                 if r[0] == "email":
84                     continue
85                 by_email.setdefault(r[0], [])
86                 by_email[r[0]].append(r)
87                 rows.append(r)
88         for r in rows:
89             if r[2] == "":
90                 print("(%s) Skipping %s, no home cluster specified" % (r[0], r[1]))
91             if r[1].startswith(r[2]):
92                 continue
93             candidates = []
94             for b in by_email[r[0]]:
95                 if b[1].startswith(r[2]):
96                     candidates.append(b)
97             if len(candidates) == 0:
98                 print("(%s) No user listed to migrate %s to %s" % (r[0], r[1], r[2]))
99                 continue
100             if len(candidates) > 1:
101                 print("(%s) Multiple users listed to migrate %s to %s, use full uuid" % (r[0], r[1], r[2]))
102                 continue
103             new_user_uuid = candidates[0][1]
104             print("(%s) Will migrate %s to %s" % (r[0], r[1], new_user_uuid))
105             oldcluster = r[1][0:5]
106             newhomecluster = r[2][0:5]
107             homearv = clusters[newhomecluster]
108             # create a token
109             newtok = homearv.api_client_authorizations().create(body={"api_client_authorization": {'owner_uuid': new_user_uuid}}).execute()
110             salted = 'v2/' + newtok["uuid"] + '/' + hmac.new(newtok["api_token"].encode(), msg=oldcluster.encode(), digestmod='sha1').hexdigest()
111             arvados.api(host=arv._rootDesc["rootUrl"][8:-1], token=salted).users().current().execute()
112
113             # now migrate from local user to remote user.
114             arv = clusters[oldcluster]
115
116             grp = arv.groups().create(body={
117                 "owner_uuid": new_user_uuid,
118                 "name": "Migrated from %s (%s)" % (r[0], r[1]),
119                 "group_class": "project"
120             }, ensure_unique_name=True).execute()
121             arv.users().merge(old_user_uuid=r[1],
122                               new_user_uuid=new_user_uuid,
123                               new_owner_uuid=grp["uuid"],
124                               redirect_to_new_user=True).execute()
125
126 if __name__ == "__main__":
127     main()