cloud-mu 2.0.0.pre.alpha → 2.0.0.pre.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/mu-configure +36 -13
- data/cloud-mu.gemspec +1 -1
- data/modules/mu/cleanup.rb +3 -3
- data/modules/mu/cloud.rb +5 -2
- data/modules/mu/clouds/aws/habitat.rb +24 -8
- data/modules/mu/clouds/aws.rb +4 -1
- data/modules/mu/clouds/google.rb +1 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea07140b34d57b4dea2bc06b6a9184896585db834782e6b2b4c40184b6cdee71
|
4
|
+
data.tar.gz: 5382c8d82180c39d6797ccbfabb4903877f29f914f2c968aa4550033c6607db8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4f27d9340d4146cadcd2eeb0a9a2abe650a0822158b136560ff3c8f409975f1a83e8106372c0e8c1f51e35a5868de3764492026f50e6aed9faa410fc133199a
|
7
|
+
data.tar.gz: 411b9b7d3e8db61459dfc480a1d2d874603580d87e3597956d882a0e9e9e41fc0eff61d3af3d01924a4ddd8c6f10916bcb6df8a18576bd3fd5f3a187a2d460b7
|
data/bin/mu-configure
CHANGED
@@ -28,6 +28,11 @@ require 'fileutils'
|
|
28
28
|
require 'erb'
|
29
29
|
require 'tmpdir'
|
30
30
|
|
31
|
+
$IN_GEM = false
|
32
|
+
if Gem.paths and Gem.paths.home and File.dirname(__FILE__).match(/^#{Gem.paths.home}/)
|
33
|
+
$IN_GEM = true
|
34
|
+
end
|
35
|
+
|
31
36
|
GIT_PATTERN = /(((git|ssh|http(s)?)|(git@[\w\.]+))(:(\/\/)?))?([\w\.@\:\/\-~]+)(\.git)?(\/)?/
|
32
37
|
|
33
38
|
# Top-level keys in $MU_CFG for which we'll provide interactive, menu-driven
|
@@ -197,6 +202,11 @@ $CONFIGURABLES = {
|
|
197
202
|
"required" => true,
|
198
203
|
"changes" => ["chefrun"]
|
199
204
|
},
|
205
|
+
"masequerade_as" => {
|
206
|
+
"title" => "GSuite Masquerade User",
|
207
|
+
"required" => false,
|
208
|
+
"desc" => "For Google Cloud projects which are attached to a GSuite domain. GCP service accounts cannot view or manage GSuite resources (groups, users, etc) directly, but must instead masquerade as a GSuite user which has delegated authority to the service account. See also: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority"
|
209
|
+
},
|
200
210
|
"default" => {
|
201
211
|
"title" => "Is Default Account",
|
202
212
|
"default" => false,
|
@@ -281,10 +291,11 @@ end
|
|
281
291
|
|
282
292
|
$INITIALIZE = (!File.size?("#{MU_BASE}/etc/mu.yaml") or $opts[:force])
|
283
293
|
$HAVE_GLOBAL_CONFIG = File.size?("#{MU_BASE}/etc/mu.yaml")
|
284
|
-
if !AMROOT and ($INITIALIZE or !$HAVE_GLOBAL_CONFIG)
|
294
|
+
if !AMROOT and ($INITIALIZE or !$HAVE_GLOBAL_CONFIG) and !$IN_GEM
|
285
295
|
puts "Global configuration has not been initialized or is missing. Must run as root to correct."
|
286
296
|
exit 1
|
287
297
|
end
|
298
|
+
|
288
299
|
if !$HAVE_GLOBAL_CONFIG and $opts[:noninteractive] and (!$opts[:public_address] or !$opts[:mu_admin_email])
|
289
300
|
puts "Specify --public-address and --mu-admin-email on new non-interactive configs"
|
290
301
|
exit 1
|
@@ -315,7 +326,7 @@ begin
|
|
315
326
|
instance_id = open("http://169.254.169.254/metadata/instance/compute").read
|
316
327
|
$IN_AWS = true if !instance_id.nil? and instance_id.size > 0
|
317
328
|
end
|
318
|
-
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH
|
329
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH, Errno::EHOSTUNREACH
|
319
330
|
end
|
320
331
|
|
321
332
|
|
@@ -385,6 +396,7 @@ def assignMenuEntries(tree = $CONFIGURABLES, map = $MENU_MAP)
|
|
385
396
|
"required" => true
|
386
397
|
}
|
387
398
|
map[count.to_s]["#addnew"] = true
|
399
|
+
map[count.to_s]["#title"] = data['title']
|
388
400
|
map[count.to_s]["#key"] = key
|
389
401
|
|
390
402
|
# Now the menu entries for the existing ones
|
@@ -480,7 +492,7 @@ def cloneGitRepo(repo)
|
|
480
492
|
puts "Testing ability to check out Git repository #{repo.bold}"
|
481
493
|
fullrepo = repo
|
482
494
|
if !repo.match(/@|:\/\//) # we try ssh first
|
483
|
-
fullrepo = "git@github.com:"+repo
|
495
|
+
fullrepo = "git@github.com:"+repo
|
484
496
|
puts "Doesn't look like a full URL, trying SSH to #{fullrepo}"
|
485
497
|
end
|
486
498
|
cwd = Dir.pwd
|
@@ -511,7 +523,7 @@ def cloneGitRepo(repo)
|
|
511
523
|
end
|
512
524
|
end
|
513
525
|
if !repo.match(/@|:\/\//)
|
514
|
-
fullrepo = "git://github.com/"+repo
|
526
|
+
fullrepo = "git://github.com/"+repo
|
515
527
|
puts ""
|
516
528
|
puts "No luck there, trying #{fullrepo}".bold
|
517
529
|
puts "/usr/bin/git clone #{fullrepo}"
|
@@ -522,7 +534,7 @@ def cloneGitRepo(repo)
|
|
522
534
|
return fullrepo
|
523
535
|
else
|
524
536
|
puts output.red.on_black
|
525
|
-
fullrepo = "https://github.com/"+repo
|
537
|
+
fullrepo = "https://github.com/"+repo
|
526
538
|
puts "Final attempt, trying #{fullrepo}"
|
527
539
|
puts "/usr/bin/git clone #{fullrepo}"
|
528
540
|
output = %x{/usr/bin/git clone #{fullrepo} 2>&1}
|
@@ -745,8 +757,8 @@ def displayCurrentOpts(tree = $CONFIGURABLES)
|
|
745
757
|
count = 1
|
746
758
|
optlist = []
|
747
759
|
tree.each_pair { |key, data|
|
748
|
-
next if !AMROOT and data['rootonly']
|
749
760
|
next if !data.is_a?(Hash)
|
761
|
+
next if !AMROOT and data['rootonly']
|
750
762
|
if data["title"].nil? or data["#menu"].nil?
|
751
763
|
next
|
752
764
|
end
|
@@ -780,7 +792,7 @@ end
|
|
780
792
|
###############################################################################
|
781
793
|
|
782
794
|
trap("INT"){ puts "" ; exit }
|
783
|
-
importCurrentValues if !$INITIALIZE or $HAVE_GLOBAL_CONFIG
|
795
|
+
importCurrentValues if !$INITIALIZE or $HAVE_GLOBAL_CONFIG or $IN_GEM
|
784
796
|
importCLIValues
|
785
797
|
setDefaults
|
786
798
|
assignMenuEntries # populates $MENU_MAP
|
@@ -821,7 +833,7 @@ def validate(newval, reqs, addnewline = true, in_use: [])
|
|
821
833
|
puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must be true or false)".light_red.on_black
|
822
834
|
puts "\n\n" if addnewline
|
823
835
|
ok = false
|
824
|
-
elsif in_use.size > 0 and in_use.include?(newval)
|
836
|
+
elsif in_use and in_use.size > 0 and in_use.include?(newval)
|
825
837
|
puts "\n##{reqs['title'].bold} #{newval} not available".light_red.on_black
|
826
838
|
puts "\n\n" if addnewline
|
827
839
|
ok = false
|
@@ -830,7 +842,7 @@ def validate(newval, reqs, addnewline = true, in_use: [])
|
|
830
842
|
puts "\nSupplied value for #{reqs['title'].bold} did not pass validation".light_red.on_black
|
831
843
|
puts "\n\n" if addnewline
|
832
844
|
ok = false
|
833
|
-
elsif reqs['negate_pattern']
|
845
|
+
elsif reqs['negate_pattern']
|
834
846
|
if newval.to_s.match(reqs['pattern'])
|
835
847
|
puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must NOT match #{reqs['pattern']})".light_red.on_black
|
836
848
|
puts "\n\n" if addnewline
|
@@ -915,7 +927,9 @@ def menu(tree = $CONFIGURABLES, map = $MENU_MAP, submenu_name = nil, in_use_name
|
|
915
927
|
map[answer],
|
916
928
|
minimap,
|
917
929
|
map[answer]['#title']+" (NEW)",
|
918
|
-
map[answer]['#entries']
|
930
|
+
if map[answer]['#entries']
|
931
|
+
map[answer]['#entries'].keys.reject { |k| k.match(/^#/) }
|
932
|
+
end
|
919
933
|
)
|
920
934
|
if newtree
|
921
935
|
newname = newtree["name"]["value"]
|
@@ -945,7 +959,7 @@ def menu(tree = $CONFIGURABLES, map = $MENU_MAP, submenu_name = nil, in_use_name
|
|
945
959
|
newtree, newmap = menu(
|
946
960
|
map[answer],
|
947
961
|
minimap,
|
948
|
-
map[answer]["#title"],
|
962
|
+
map[answer]["#title"],
|
949
963
|
(map[answer]['#entries'].keys - [map[answer]['#title']])
|
950
964
|
)
|
951
965
|
map[answer] = newtree if newtree
|
@@ -1070,7 +1084,9 @@ if AMROOT
|
|
1070
1084
|
end
|
1071
1085
|
|
1072
1086
|
if $INITIALIZE
|
1073
|
-
|
1087
|
+
if AMROOT
|
1088
|
+
%x{/sbin/service iptables stop} # Chef run will set up correct rules later
|
1089
|
+
end
|
1074
1090
|
$MU_SET_DEFAULTS = setConfigTree
|
1075
1091
|
require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
|
1076
1092
|
else
|
@@ -1093,6 +1109,12 @@ rescue LoadError
|
|
1093
1109
|
require 'mu'
|
1094
1110
|
end
|
1095
1111
|
|
1112
|
+
if $IN_GEM
|
1113
|
+
puts $MU_CFG.to_yaml
|
1114
|
+
saveMuConfig($MU_CFG)
|
1115
|
+
exit
|
1116
|
+
end
|
1117
|
+
|
1096
1118
|
if AMROOT and ($INITIALIZE or $CHANGES.include?("hostname"))
|
1097
1119
|
system("/bin/hostname #{$MU_CFG['hostname']}")
|
1098
1120
|
end
|
@@ -1130,6 +1152,7 @@ def updateChefRbs
|
|
1130
1152
|
user = AMROOT ? "mu" : Etc.getpwuid(Process.uid).name
|
1131
1153
|
chefuser = user.gsub(/\./, "")
|
1132
1154
|
templates = { HOMEDIR+"/.chef/knife.rb" => KNIFE_TEMPLATE }
|
1155
|
+
Dir.mkdir(HOMEDIR+"/.chef") if !Dir.exists?(HOMEDIR+"/.chef")
|
1133
1156
|
if AMROOT
|
1134
1157
|
templates["/etc/chef/client.rb"] = CLIENT_TEMPLATE
|
1135
1158
|
templates["/etc/opscode/pivotal.rb"] = PIVOTAL_TEMPLATE
|
@@ -1252,7 +1275,7 @@ if $INITIALIZE or $CHANGES.include?("vault")
|
|
1252
1275
|
system("chef-client -o 'recipe[mu-master::vault]'")
|
1253
1276
|
end
|
1254
1277
|
|
1255
|
-
if $MU_CFG['ldap']['type'] == "389 Directory Services"
|
1278
|
+
if $MU_CFG['ldap']['type'] == "389 Directory Services"
|
1256
1279
|
begin
|
1257
1280
|
MU::Master::LDAP.listUsers
|
1258
1281
|
rescue Exception => e # XXX lazy exception handling is lazy
|
data/cloud-mu.gemspec
CHANGED
data/modules/mu/cleanup.rb
CHANGED
@@ -61,8 +61,7 @@ module MU
|
|
61
61
|
end
|
62
62
|
|
63
63
|
|
64
|
-
|
65
|
-
types_in_order = ["Collection", "Function", "ServerPool", "ContainerCluster", "SearchDomain", "Server", "MsgQueue", "Database", "CacheCluster", "StoragePool", "LoadBalancer", "FirewallRule", "Alarm", "Notifier", "Log", "VPC", "DNSZone", "Collection"]
|
64
|
+
types_in_order = ["Collection", "Function", "ServerPool", "ContainerCluster", "SearchDomain", "Server", "MsgQueue", "Database", "CacheCluster", "StoragePool", "LoadBalancer", "FirewallRule", "Alarm", "Notifier", "Log", "VPC", "DNSZone", "Collection", "Habitat"]
|
66
65
|
|
67
66
|
# Load up our deployment metadata
|
68
67
|
if !mommacat.nil?
|
@@ -161,6 +160,7 @@ module MU
|
|
161
160
|
|
162
161
|
if @mommacat.nil? or @mommacat.numKittens(types: [t]) > 0
|
163
162
|
begin
|
163
|
+
puts t if t == "Habitat"
|
164
164
|
resclass = Object.const_get("MU").const_get("Cloud").const_get(t)
|
165
165
|
resclass.cleanup(
|
166
166
|
noop: @noop,
|
@@ -184,7 +184,7 @@ module MU
|
|
184
184
|
# XXX move to MU::AWS
|
185
185
|
if provider == "AWS"
|
186
186
|
resp = MU::Cloud::AWS.ec2(region: r, credentials: credset).describe_key_pairs(
|
187
|
-
|
187
|
+
filters: [{name: "key-name", values: [keyname]}]
|
188
188
|
)
|
189
189
|
resp.data.key_pairs.each { |keypair|
|
190
190
|
MU.log "Deleting key pair #{keypair.key_name} from #{r}"
|
data/modules/mu/cloud.rb
CHANGED
@@ -1424,6 +1424,7 @@ MU.log "in dependencies() and findLitterMate gave me "+sib_by_name.to_s+" on beh
|
|
1424
1424
|
# Wrapper for the cleanup class method of underlying cloud object implementations.
|
1425
1425
|
def self.cleanup(*flags)
|
1426
1426
|
params = flags.first
|
1427
|
+
|
1427
1428
|
clouds = MU::Cloud.supportedClouds
|
1428
1429
|
if params[:cloud]
|
1429
1430
|
clouds = [params[:cloud]]
|
@@ -1433,10 +1434,12 @@ MU.log "in dependencies() and findLitterMate gave me "+sib_by_name.to_s+" on beh
|
|
1433
1434
|
begin
|
1434
1435
|
cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
|
1435
1436
|
raise MuCloudResourceNotImplemented if !cloudclass.respond_to?(:cleanup) or cloudclass.method(:cleanup).owner.to_s != "#<Class:#{cloudclass}>"
|
1436
|
-
|
1437
|
+
if cfg_name == "habitat"
|
1438
|
+
MU.log "Invoking #{cloudclass}.cleanup from #{shortname}", MU::WARN, details: flags
|
1439
|
+
end
|
1437
1440
|
cloudclass.cleanup(params)
|
1438
1441
|
rescue MuCloudResourceNotImplemented
|
1439
|
-
MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::
|
1442
|
+
MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::WARN, details: flags
|
1440
1443
|
end
|
1441
1444
|
}
|
1442
1445
|
MU::MommaCat.unlockAll
|
@@ -96,6 +96,16 @@ module MU
|
|
96
96
|
# @param region [String]: The cloud provider region
|
97
97
|
# @return [void]
|
98
98
|
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
99
|
+
puts "IN HABITAT CLEANUP"
|
100
|
+
return if !orgMasterCreds?(credentials)
|
101
|
+
|
102
|
+
resp = MU::Cloud::AWS.orgs(credentials: credentials).list_accounts
|
103
|
+
|
104
|
+
if resp and resp.accounts
|
105
|
+
resp.accounts.each { |acct|
|
106
|
+
pp acct
|
107
|
+
}
|
108
|
+
end
|
99
109
|
end
|
100
110
|
|
101
111
|
# Locate an existing account
|
@@ -121,6 +131,19 @@ module MU
|
|
121
131
|
[toplevel_required, schema]
|
122
132
|
end
|
123
133
|
|
134
|
+
# Figure out what account we're calling from, and then figure out if
|
135
|
+
# it's the organization's master account- the only place from which
|
136
|
+
# we can create accounts, amongst other things.
|
137
|
+
# @param credentials [String]
|
138
|
+
# @return [Boolean]
|
139
|
+
def self.orgMasterCreds?(credentials = nil)
|
140
|
+
user_list = MU::Cloud::AWS.iam(credentials: credentials).list_users.users
|
141
|
+
acct_num = MU::Cloud::AWS.iam(credentials: credentials).list_users.users.first.arn.split(/:/)[4]
|
142
|
+
|
143
|
+
parentorg = MU::Cloud::AWS::Folder.find(credentials: credentials).values.first
|
144
|
+
acct_num == parentorg.master_account_id
|
145
|
+
end
|
146
|
+
|
124
147
|
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::habitats}, bare and unvalidated.
|
125
148
|
# @param habitat [Hash]: The resource to process and validate
|
126
149
|
# @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
@@ -132,14 +155,7 @@ module MU
|
|
132
155
|
MU.log "No email address specified in habitat #{habitat['name']}, and AWS requires a unique contact email. Will generate an alias to #{$MU_CFG['mu_admin_email']} at run time.", MU::NOTICE
|
133
156
|
end
|
134
157
|
|
135
|
-
|
136
|
-
# it's the organization's master account- the only place from which
|
137
|
-
# we can create accounts.
|
138
|
-
user_list = MU::Cloud::AWS.iam(credentials: habitat['credentials']).list_users.users
|
139
|
-
acct_num = MU::Cloud::AWS.iam(credentials: habitat['credentials']).list_users.users.first.arn.split(/:/)[4]
|
140
|
-
|
141
|
-
parentorg = MU::Cloud::AWS::Folder.find(credentials: habitat['credentials']).values.first
|
142
|
-
if acct_num != parentorg.master_account_id
|
158
|
+
if !orgMasterCreds?(habitat['credentials'])
|
143
159
|
MU.log "The Organization master account for habitat #{habitat["name"]} is #{parentorg.master_account_id}, but my credentials (#{ habitat['credentials'] ? habitat['credentials'] : "default"}) are for a non-master account (#{acct_num}). AWS accounts can only be created and managed with credentials from an Organization's master account.", MU::ERR
|
144
160
|
ok = false
|
145
161
|
end
|
data/modules/mu/clouds/aws.rb
CHANGED
@@ -487,7 +487,10 @@ module MU
|
|
487
487
|
# MU.log "Got #{e.inspect} while trying to figure out our account number", MU::WARN, details: caller
|
488
488
|
# end
|
489
489
|
# if user_list.nil? or user_list.size == 0
|
490
|
-
|
490
|
+
resp = MU::Cloud::AWS.getAWSMetaData("network/interfaces/macs/")
|
491
|
+
return nil if !resp
|
492
|
+
|
493
|
+
mac = resp.split(/\n/)[0]
|
491
494
|
acct_num = MU::Cloud::AWS.getAWSMetaData("network/interfaces/macs/#{mac}owner-id")
|
492
495
|
acct_num.chomp!
|
493
496
|
# else
|
data/modules/mu/clouds/google.rb
CHANGED