-
Notifications
You must be signed in to change notification settings - Fork 1
/
serviceaccounts.rb
78 lines (73 loc) · 2.79 KB
/
serviceaccounts.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
require "json"
require "set"
require_relative "workbench"
require_relative "utils/common"
require "tmpdir"
# Entering a service account context ensures that a keyfile exists at the given
# path for the given service account, and that GOOGLE_APPLICATION_CREDENTIALS is
# pointing to it (for application default credentials). Creates this SA key and
# file if necessary, and destroys it when leaving the context.
# The test SA key is a special case for local development, and is initialized
# but not deleted.
class ServiceAccountContext
attr_reader :project, :service_account, :keyfile_path
TEST_SERVICE_ACCOUNTS = Set[
]
SERVICE_ACCOUNT_KEY_PATH = "sa-key.json"
def initialize(project, service_account = nil, keyfile_path = nil)
@project = project
@service_account = service_account
if not service_account
@service_account = "#{@project}@appspot.gserviceaccount.com"
end
@keyfile_path = keyfile_path
if not @keyfile_path
if TEST_SERVICE_ACCOUNTS.include? @service_account
@keyfile_path = File.expand_path(SERVICE_ACCOUNT_KEY_PATH)
else
@keyfile_path = "#{Dir.tmpdir()}/#{@service_account}-key.json"
end
end
end
def existing_file_account(keyfile_path)
if File.exists?(keyfile_path)
begin
return JSON.parse(File.read(keyfile_path))["client_email"]
rescue JSON::ParserError => e
return nil
end
end
return nil
end
def run()
common = Common.new
ENV["GOOGLE_APPLICATION_CREDENTIALS"] = @keyfile_path
if @service_account == existing_file_account(@keyfile_path)
# Don't generate another key if this account is already active. This can
# happen for nested service account contexts, for example.
common.status "Attaching to existing keyfile @ #{@keyfile_path}"
yield(self)
return
end
if TEST_SERVICE_ACCOUNTS.include? @service_account
common.status "Copying key from GCS for #{@service_account} @ #{@keyfile_path}"
common.run_inline %W{gsutil cp gs://#{@project}-credentials/app-engine-default-sa.json
#{@keyfile_path}}
yield(self)
else
common.status "Creating new key for #{@service_account} @ #{@keyfile_path}"
common.run_inline %W{gcloud iam service-accounts keys create #{@keyfile_path}
--iam-account=#{@service_account} --project=#{@project}}
begin
yield(self)
ensure
tmp_private_key = `grep private_key_id #{@keyfile_path} | cut -d\\\" -f4`.strip()
common.run_inline %W{gcloud iam service-accounts keys delete #{tmp_private_key} -q
--iam-account=#{@service_account} --project=#{@project}}
common.run_inline %W{rm #{@keyfile_path}}
end
end
end
end