Merge branch '1692-redesign-dashboard'
[arvados.git] / apps / admin / setup-new-user.rb
1 #!/usr/bin/env ruby
2
3 abort 'Error: Ruby >= 1.9.3 required.' if RUBY_VERSION < '1.9.3'
4
5 require 'logger'
6 require 'trollop'
7 log = Logger.new STDERR
8 log.progname = $0.split('/').last
9
10 opts = Trollop::options do
11   banner ''
12   banner "Usage: #{log.progname} " +
13     "{user_uuid_or_email} {user_and_repo_name} {vm_uuid}"
14   banner ''
15   opt :debug, <<-eos
16 Show debug messages.
17   eos
18   opt :create, <<-eos
19 Create a new user with the given email address if an existing user \
20 is not found.
21   eos
22   opt :openid_prefix, <<-eos, default: 'https://www.google.com/accounts/o8/id'
23 If creating a new user record, require authentication from an OpenID \
24 with this OpenID prefix *and* a matching email address in order to \
25 claim the account.
26   eos
27   opt :force, <<-eos
28 Continue even if sanity checks raise flags: the given user is already \
29 active, the given repository already exists, etc.
30   eos
31   opt :n, 'Do not change anything, just probe'
32 end
33
34 log.level = (ENV['DEBUG'] || opts.debug) ? Logger::DEBUG : Logger::WARN
35     
36 if ARGV.count != 3
37   Trollop::die "required arguments are missing"
38 end
39 user_arg, user_repo_name, vm_uuid = ARGV
40
41 require 'arvados'
42 arv = Arvados.new(api_version: 'v1')
43
44 # Look up the given user by uuid or, failing that, email address.
45 user = begin
46          arv.user.get(uuid: user_arg)
47        rescue Arvados::TransactionFailedError
48          found = arv.user.list(where: {email: ARGV[0]})[:items]
49          if found.count == 0 and opts.create
50            if !opts.force and !user_arg.match(/\w\@\w+\.\w+/)
51              abort "About to create new user, but #{user_arg.inspect} " +
52                "does not look like an email address. Stop."
53            end
54            if opts.n
55              log.info "-n flag given. Stop before creating new user record."
56              exit 0
57            end
58            new_user = arv.user.create(user: {email: user_arg})
59            log.info { "created user: " + new_user[:uuid] }
60            login_perm_props = {identity_url_prefix: opts.openid_prefix }
61            oid_login_perm = arv.link.create(link: {
62                                               link_class: 'permission',
63                                               name: 'can_login',
64                                               tail_kind: 'email',
65                                               tail_uuid: user_arg,
66                                               head_kind: 'arvados#user',
67                                               head_uuid: new_user[:uuid],
68                                               properties: login_perm_props
69                                             })
70            log.info { "openid login permission: " + oid_login_perm[:uuid] }
71            found = [new_user]
72          end
73          if found.count != 1
74            abort "Found #{found.count} users " +
75              "with uuid or email #{user_arg.inspect}. Stop."
76          end
77          found.first
78        end
79 log.info { "user uuid: " + user[:uuid] }
80
81 # Look up the given virtual machine just to make sure it really exists.
82 begin
83   vm = arv.virtual_machine.get(uuid: vm_uuid)
84 rescue
85   abort "Could not look up virtual machine with uuid #{vm_uuid.inspect}. Stop."
86 end
87 log.info { "vm uuid: " + vm[:uuid] }
88
89 # Look up the "all users" group (we expect uuid *-*-fffffffffffffff).
90 group = arv.group.list(where: {name: 'All users'})[:items].select do |g|
91   g[:uuid].match /-f+$/
92 end.first
93 if not group
94   abort "Could not look up virtual machine with uuid #{vm_uuid.inspect}. Stop."
95 end
96 log.info { "\"all users\" group uuid: " + group[:uuid] }
97
98 # Look for signs the user has already been activated / set up.
99
100 if user[:is_active]
101   log.warn "User's is_active flag is already set."
102   need_force = true
103 end
104
105 # Look for existing repository access (perhaps using a different
106 # repository/user name).
107 repo_perms = arv.link.list(where: {
108                              tail_uuid: user[:uuid],
109                              head_kind: 'arvados#repository',
110                              link_class: 'permission',
111                              name: 'can_write'})[:items]
112 if [] != repo_perms
113   log.warn "User already has repository access " +
114     repo_perms.collect { |p| p[:uuid] }.inspect + "."
115   need_force = true
116 end
117
118 # Check for an existing repository with the same name we're about to
119 # use.
120 repo = arv.repository.list(where: {name: user_repo_name})[:items].first
121 if repo
122   log.warn "Repository already exists with name #{user_repo_name.inspect}: " +
123     "#{repo[:uuid]}"
124   need_force = true
125 end
126
127 if opts.n
128   log.info "-n flag given. Done."
129   exit 0
130 end
131
132 if need_force and not opts.force
133   abort "This does not seem to be a new user[name], and -f was not given. Stop."
134 end
135
136 # Everything seems to be in order. Create a repository (if needed) and
137 # add permissions.
138
139 repo ||= arv.repository.create(repository: {name: user_repo_name})
140 log.info { "repo uuid: " + repo[:uuid] }
141
142 repo_perm = arv.link.create(link: {
143                               tail_kind: 'arvados#user',
144                               tail_uuid: user[:uuid],
145                               head_kind: 'arvados#repository',
146                               head_uuid: repo[:uuid],
147                               link_class: 'permission',
148                               name: 'can_write'})
149 log.info { "repo permission: " + repo_perm[:uuid] }
150
151 login_perm = arv.link.create(link: {
152                                tail_kind: 'arvados#user',
153                                tail_uuid: user[:uuid],
154                                head_kind: 'arvados#virtual_machine',
155                                head_uuid: vm[:uuid],
156                                link_class: 'permission',
157                                name: 'can_login',
158                                properties: {username: user_repo_name}})
159 log.info { "login permission: " + login_perm[:uuid] }
160
161 group_perm = arv.link.create(link: {
162                                tail_kind: 'arvados#user',
163                                tail_uuid: user[:uuid],
164                                head_kind: 'arvados#group',
165                                head_uuid: group[:uuid],
166                                link_class: 'permission',
167                                name: 'can_read'})
168 log.info { "group permission: " + group_perm[:uuid] }