cloud-mu 2.0.0.pre.alpha → 2.0.0.pre.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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