cloud-mu 3.1.5 → 3.1.6
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/Dockerfile +5 -1
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/tasks/main.yml +16 -0
- data/bin/mu-adopt +2 -1
- data/bin/mu-configure +16 -0
- data/bin/mu-node-manage +15 -16
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/windows-client.rb +25 -22
- data/extras/clean-stock-amis +25 -19
- data/extras/image-generators/AWS/win2k12.yaml +2 -0
- data/extras/image-generators/AWS/win2k16.yaml +2 -0
- data/extras/image-generators/AWS/win2k19.yaml +2 -0
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +6 -5
- data/modules/mu/adoption.rb +19 -4
- data/modules/mu/cleanup.rb +181 -293
- data/modules/mu/cloud.rb +58 -17
- data/modules/mu/clouds/aws.rb +36 -1
- data/modules/mu/clouds/aws/container_cluster.rb +30 -21
- data/modules/mu/clouds/aws/role.rb +1 -1
- data/modules/mu/clouds/aws/vpc.rb +5 -1
- data/modules/mu/clouds/azure.rb +10 -0
- data/modules/mu/clouds/cloudformation.rb +10 -0
- data/modules/mu/clouds/google.rb +18 -4
- data/modules/mu/clouds/google/bucket.rb +2 -2
- data/modules/mu/clouds/google/container_cluster.rb +10 -7
- data/modules/mu/clouds/google/database.rb +3 -3
- data/modules/mu/clouds/google/firewall_rule.rb +3 -3
- data/modules/mu/clouds/google/function.rb +3 -3
- data/modules/mu/clouds/google/loadbalancer.rb +4 -4
- data/modules/mu/clouds/google/role.rb +18 -9
- data/modules/mu/clouds/google/server.rb +16 -14
- data/modules/mu/clouds/google/server_pool.rb +4 -4
- data/modules/mu/clouds/google/user.rb +2 -2
- data/modules/mu/clouds/google/vpc.rb +9 -13
- data/modules/mu/config.rb +1 -1
- data/modules/mu/config/container_cluster.rb +5 -0
- data/modules/mu/config/doc_helpers.rb +1 -1
- data/modules/mu/config/ref.rb +12 -6
- data/modules/mu/config/schema_helpers.rb +8 -3
- data/modules/mu/config/server.rb +7 -0
- data/modules/mu/config/tail.rb +1 -0
- data/modules/mu/config/vpc.rb +15 -7
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +48 -48
- data/modules/mu/deploy.rb +1 -1
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -4
- data/modules/mu/groomers/chef.rb +48 -4
- data/modules/mu/master.rb +75 -3
- data/modules/mu/mommacat.rb +104 -855
- data/modules/mu/mommacat/naming.rb +28 -0
- data/modules/mu/mommacat/search.rb +463 -0
- data/modules/mu/mommacat/storage.rb +185 -183
- data/modules/tests/super_simple_bok.yml +1 -3
- metadata +8 -5
@@ -276,15 +276,20 @@ module MU
|
|
276
276
|
schema_chunk["properties"]["creation_style"] != "existing"
|
277
277
|
schema_chunk["properties"].each_pair { |key, subschema|
|
278
278
|
shortclass = if conf_chunk[key]
|
279
|
-
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key)
|
279
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key, false)
|
280
280
|
shortclass
|
281
281
|
else
|
282
282
|
nil
|
283
283
|
end
|
284
284
|
|
285
285
|
new_val = applySchemaDefaults(conf_chunk[key], subschema, depth+1, conf_chunk, type: shortclass).dup
|
286
|
-
|
287
|
-
|
286
|
+
if !new_val.nil?
|
287
|
+
begin
|
288
|
+
conf_chunk[key] = Marshal.load(Marshal.dump(new_val))
|
289
|
+
rescue TypeError
|
290
|
+
conf_chunk[key] = new_val.clone
|
291
|
+
end
|
292
|
+
end
|
288
293
|
}
|
289
294
|
end
|
290
295
|
elsif schema_chunk["type"] == "array" and conf_chunk.kind_of?(Array)
|
data/modules/mu/config/server.rb
CHANGED
@@ -625,6 +625,13 @@ module MU
|
|
625
625
|
server['vault_access'] << {"vault" => "splunk", "item" => "admin_user"}
|
626
626
|
ok = false if !MU::Config::Server.checkVaultRefs(server)
|
627
627
|
|
628
|
+
server['groomer'] ||= self.defaultGroomer
|
629
|
+
groomclass = MU::Groomer.loadGroomer(server['groomer'])
|
630
|
+
if !groomclass.available?(server['platform'].match(/^win/))
|
631
|
+
MU.log "Groomer #{server['groomer']} for #{server['name']} is missing or has incomplete dependencies", MU::ERR
|
632
|
+
ok = false
|
633
|
+
end
|
634
|
+
|
628
635
|
if server["cloud"] != "Azure"
|
629
636
|
server['dependencies'] << configurator.adminFirewallRuleset(vpc: server['vpc'], region: server['region'], cloud: server['cloud'], credentials: server['credentials'])
|
630
637
|
end
|
data/modules/mu/config/tail.rb
CHANGED
@@ -133,6 +133,7 @@ module MU
|
|
133
133
|
# @param pseudo [<Boolean>]: This is a pseudo-parameter, automatically provided, and not available as user input.
|
134
134
|
# @param runtimecode [<String>]: Actual code to allow the cloud layer to interpret literally in its own idiom, e.g. '"Ref" : "AWS::StackName"' for CloudFormation
|
135
135
|
def getTail(param, value: nil, prettyname: nil, cloudtype: "String", valid_values: [], description: nil, list_of: nil, prefix: "", suffix: "", pseudo: false, runtimecode: nil)
|
136
|
+
param = param.gsub(/[^a-z0-9_]/i, "_")
|
136
137
|
if value.nil?
|
137
138
|
if @@parameters.nil? or !@@parameters.has_key?(param)
|
138
139
|
MU.log "Parameter '#{param}' (#{param.class.name}) referenced in config but not provided (#{caller[0]})", MU::DEBUG, details: @@parameters
|
data/modules/mu/config/vpc.rb
CHANGED
@@ -493,6 +493,7 @@ module MU
|
|
493
493
|
# See if we'll be able to create peering connections
|
494
494
|
can_peer = false
|
495
495
|
already_peered = false
|
496
|
+
|
496
497
|
if MU.myCloud == vpc["cloud"] and MU.myVPCObj
|
497
498
|
if vpc['peers']
|
498
499
|
vpc['peers'].each { |peer|
|
@@ -636,7 +637,7 @@ module MU
|
|
636
637
|
MU.log "VPC peering connections to non-local accounts must specify the vpc_id of the peer.", MU::ERR
|
637
638
|
ok = false
|
638
639
|
end
|
639
|
-
elsif !processReference(peer['vpc'], "vpcs",
|
640
|
+
elsif !processReference(peer['vpc'], "vpcs", vpc, configurator, dflt_region: peer["vpc"]['region'])
|
640
641
|
ok = false
|
641
642
|
end
|
642
643
|
end
|
@@ -735,8 +736,8 @@ module MU
|
|
735
736
|
vpc_block["subnet_pref"] = "all_private" if vpc_block["subnet_pref"] == "private"
|
736
737
|
end
|
737
738
|
|
738
|
-
flags = {}
|
739
|
-
flags["subnet_pref"] = vpc_block["subnet_pref"] if !vpc_block["subnet_pref"].nil?
|
739
|
+
# flags = {}
|
740
|
+
# flags["subnet_pref"] = vpc_block["subnet_pref"] if !vpc_block["subnet_pref"].nil?
|
740
741
|
hab_arg = if vpc_block['habitat']
|
741
742
|
if vpc_block['habitat'].is_a?(MU::Config::Ref)
|
742
743
|
[vpc_block['habitat'].id] # XXX actually, findStray it
|
@@ -770,9 +771,9 @@ MU.log "VPC lookup cache hit", MU::WARN, details: vpc_block
|
|
770
771
|
tag_key: tag_key,
|
771
772
|
tag_value: tag_value,
|
772
773
|
region: vpc_block["region"],
|
773
|
-
flags: flags,
|
774
774
|
habitats: hab_arg,
|
775
|
-
dummy_ok: true
|
775
|
+
dummy_ok: true,
|
776
|
+
subnet_pref: vpc_block["subnet_pref"]
|
776
777
|
)
|
777
778
|
|
778
779
|
found.first if found and found.size == 1
|
@@ -799,7 +800,7 @@ MU.log "VPC lookup cache hit", MU::WARN, details: vpc_block
|
|
799
800
|
@@reference_cache[vpc_block] ||= ext_vpc if ok
|
800
801
|
end
|
801
802
|
rescue StandardError => e
|
802
|
-
raise MuError, e.inspect, e.backtrace
|
803
|
+
raise MuError, e.inspect, [caller, e.backtrace]
|
803
804
|
ensure
|
804
805
|
if !ext_vpc and vpc_block['cloud'] != "CloudFormation"
|
805
806
|
MU.log "Couldn't resolve VPC reference to a unique live VPC in #{parent_type} #{parent['name']} (called by #{caller[0]})", MU::ERR, details: vpc_block
|
@@ -923,7 +924,14 @@ MU.log "VPC lookup cache hit", MU::WARN, details: vpc_block
|
|
923
924
|
ext_vpc.subnets.each { |subnet|
|
924
925
|
next if dflt_region and vpc_block["cloud"] == "Google" and subnet.az != dflt_region
|
925
926
|
if subnet.private? and (vpc_block['subnet_pref'] != "all_public" and vpc_block['subnet_pref'] != "public")
|
926
|
-
private_subnets << {
|
927
|
+
private_subnets << {
|
928
|
+
"subnet_id" => configurator.getTail(
|
929
|
+
"#{parent['name']} Private Subnet #{priv}",
|
930
|
+
value: subnet.cloud_id,
|
931
|
+
prettyname: "#{parent['name']} Private Subnet #{priv}",
|
932
|
+
cloudtype: "AWS::EC2::Subnet::Id"),
|
933
|
+
"az" => subnet.az
|
934
|
+
}
|
927
935
|
private_subnets_map[subnet.cloud_id] = subnet
|
928
936
|
priv = priv + 1
|
929
937
|
elsif !subnet.private? and vpc_block['subnet_pref'] != "all_private" and vpc_block['subnet_pref'] != "private"
|
data/modules/mu/config/vpc.yml
CHANGED
@@ -73,56 +73,56 @@ ubuntu14:
|
|
73
73
|
ap-southeast-1: ami-2855964b
|
74
74
|
ap-southeast-2: ami-d19fc4b2
|
75
75
|
win2k12r2: &1
|
76
|
-
us-east-1: ami-
|
77
|
-
us-east-2: ami-
|
78
|
-
ca-central-1: ami-
|
79
|
-
us-west-2: ami-
|
80
|
-
us-west-1: ami-
|
81
|
-
eu-west-1: ami-
|
82
|
-
eu-west-2: ami-
|
83
|
-
eu-west-3: ami-
|
84
|
-
eu-north-1: ami-
|
85
|
-
sa-east-1: ami-
|
86
|
-
eu-central-1: ami-
|
87
|
-
ap-northeast-1: ami-
|
88
|
-
ap-south-1: ami-
|
89
|
-
ap-northeast-2: ami-
|
90
|
-
ap-southeast-1: ami-
|
91
|
-
ap-southeast-2: ami-
|
76
|
+
us-east-1: ami-003aea65bc2e7136a
|
77
|
+
us-east-2: ami-0163293e39ba504c2
|
78
|
+
ca-central-1: ami-055689dd92f29d2aa
|
79
|
+
us-west-2: ami-0ce87dda2c9244e57
|
80
|
+
us-west-1: ami-00d9cf64bd2fafa44
|
81
|
+
eu-west-1: ami-026d7427b9fadad40
|
82
|
+
eu-west-2: ami-036a22c0780551794
|
83
|
+
eu-west-3: ami-05e3d9b79bdc10861
|
84
|
+
eu-north-1: ami-063eb48504c7d73f1
|
85
|
+
sa-east-1: ami-0a8c1829a5e650bc5
|
86
|
+
eu-central-1: ami-0ea20cef52335b008
|
87
|
+
ap-northeast-1: ami-08db2dc67228dbb90
|
88
|
+
ap-south-1: ami-012241411db3f09c3
|
89
|
+
ap-northeast-2: ami-0368c224de1d20502
|
90
|
+
ap-southeast-1: ami-028ef74e1edc3943a
|
91
|
+
ap-southeast-2: ami-09e03eab1b1bc151b
|
92
92
|
win2k16: &5
|
93
|
-
us-east-1: ami-
|
94
|
-
us-east-2: ami-
|
95
|
-
ca-central-1: ami-
|
96
|
-
us-west-2: ami-
|
97
|
-
eu-west-1: ami-
|
98
|
-
us-west-1: ami-
|
99
|
-
eu-west-2: ami-
|
100
|
-
eu-west-3: ami-
|
101
|
-
eu-central-1: ami-
|
102
|
-
sa-east-1: ami-
|
103
|
-
ap-northeast-1: ami-
|
104
|
-
ap-south-1: ami-
|
105
|
-
ap-northeast-2: ami-
|
106
|
-
ap-southeast-2: ami-
|
107
|
-
ap-southeast-1: ami-
|
108
|
-
eu-north-1: ami-
|
93
|
+
us-east-1: ami-02801a2c8dcbfb883
|
94
|
+
us-east-2: ami-0ca4f779a2a58a7ea
|
95
|
+
ca-central-1: ami-05d3854d9d6e9bcc5
|
96
|
+
us-west-2: ami-091f4a88ce32d28b6
|
97
|
+
eu-west-1: ami-0b938c9b23ed7d18c
|
98
|
+
us-west-1: ami-0fd744c3fbe8260f2
|
99
|
+
eu-west-2: ami-071a89b959c5eda27
|
100
|
+
eu-west-3: ami-0b206e3dbda9ff9eb
|
101
|
+
eu-central-1: ami-0dd9bdad31dd0d3ce
|
102
|
+
sa-east-1: ami-0d69b8d6c0f9a7bae
|
103
|
+
ap-northeast-1: ami-02eb4a6f519bc3190
|
104
|
+
ap-south-1: ami-0666fd543ac8b5501
|
105
|
+
ap-northeast-2: ami-01277c81f9b91cf77
|
106
|
+
ap-southeast-2: ami-0426a246f9b0ccadd
|
107
|
+
ap-southeast-1: ami-07ecb0d55c2eb7247
|
108
|
+
eu-north-1: ami-047811530583b6d08
|
109
109
|
win2k19:
|
110
|
-
us-east-1: ami-
|
111
|
-
us-east-2: ami-
|
112
|
-
ca-central-1: ami-
|
113
|
-
us-west-2: ami-
|
114
|
-
eu-west-2: ami-
|
115
|
-
us-west-1: ami-
|
116
|
-
eu-west-1: ami-
|
117
|
-
eu-central-1: ami-
|
118
|
-
eu-west-3: ami-
|
119
|
-
eu-north-1: ami-
|
120
|
-
sa-east-1: ami-
|
121
|
-
ap-northeast-2: ami-
|
122
|
-
ap-northeast-1: ami-
|
123
|
-
ap-southeast-1: ami-
|
124
|
-
ap-southeast-2: ami-
|
125
|
-
ap-south-1: ami-
|
110
|
+
us-east-1: ami-00820419bf212df7e
|
111
|
+
us-east-2: ami-0a7916b90aa4629d5
|
112
|
+
ca-central-1: ami-0d704529661e19185
|
113
|
+
us-west-2: ami-0ee6a198d7ac35eb1
|
114
|
+
eu-west-2: ami-0f6ac1634bd7add92
|
115
|
+
us-west-1: ami-039e3816b4cac1e27
|
116
|
+
eu-west-1: ami-03a771d99091199b7
|
117
|
+
eu-central-1: ami-03b648d5b45f51a4f
|
118
|
+
eu-west-3: ami-068839907c18c3a6e
|
119
|
+
eu-north-1: ami-0db851ee76f7deefb
|
120
|
+
sa-east-1: ami-0c2cc60c62159f87c
|
121
|
+
ap-northeast-2: ami-06bdf8ae9ae9add92
|
122
|
+
ap-northeast-1: ami-02306d959c7f175b9
|
123
|
+
ap-southeast-1: ami-0d5b4a3d73e0f471f
|
124
|
+
ap-southeast-2: ami-00fa88caff4f64937
|
125
|
+
ap-south-1: ami-0b44feae4bb9f497a
|
126
126
|
amazon:
|
127
127
|
us-east-1: ami-b73b63a0
|
128
128
|
us-east-2: ami-58277d3d
|
data/modules/mu/deploy.rb
CHANGED
@@ -394,7 +394,7 @@ module MU
|
|
394
394
|
Thread.handle_interrupt(MU::Cloud::MuCloudResourceNotImplemented => :never) {
|
395
395
|
begin
|
396
396
|
Thread.handle_interrupt(MU::Cloud::MuCloudResourceNotImplemented => :immediate) {
|
397
|
-
MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::
|
397
|
+
MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::DEBUG, verbosity: MU::Logger::NORMAL
|
398
398
|
Thread.current.exit
|
399
399
|
}
|
400
400
|
ensure
|
data/modules/mu/groomer.rb
CHANGED
@@ -24,6 +24,10 @@ module MU
|
|
24
24
|
class NoAnsibleExecError < MuError;
|
25
25
|
end
|
26
26
|
|
27
|
+
# One or more Python dependencies missing
|
28
|
+
class AnsibleLibrariesError < MuError;
|
29
|
+
end
|
30
|
+
|
27
31
|
# Location in which we'll find our Ansible executables. This only applies
|
28
32
|
# to full-grown Mu masters; minimalist gem installs will have to make do
|
29
33
|
# with whatever Ansible executables they can find in $PATH.
|
@@ -40,6 +44,10 @@ module MU
|
|
40
44
|
@ansible_path = node.deploy.deploy_dir+"/ansible"
|
41
45
|
@ansible_execs = MU::Groomer::Ansible.ansibleExecDir
|
42
46
|
|
47
|
+
if !MU::Groomer::Ansible.checkPythonDependencies(@server.windows?)
|
48
|
+
raise AnsibleLibrariesError, "One or more python dependencies not available"
|
49
|
+
end
|
50
|
+
|
43
51
|
if !@ansible_execs or @ansible_execs.empty?
|
44
52
|
raise NoAnsibleExecError, "No Ansible executables found in visible paths"
|
45
53
|
end
|
@@ -54,6 +62,10 @@ module MU
|
|
54
62
|
installRoles
|
55
63
|
end
|
56
64
|
|
65
|
+
# Are Ansible executables and key libraries present and accounted for?
|
66
|
+
def self.available?(windows = false)
|
67
|
+
MU::Groomer::Ansible.checkPythonDependencies(windows)
|
68
|
+
end
|
57
69
|
|
58
70
|
# Indicate whether our server has been bootstrapped with Ansible
|
59
71
|
def haveBootstrapped?
|
@@ -245,7 +257,7 @@ module MU
|
|
245
257
|
"#{@server.config['name']}.yml"
|
246
258
|
end
|
247
259
|
|
248
|
-
cmd = %Q{cd #{@ansible_path} && echo "#{purpose}" && #{@ansible_execs}/ansible-playbook -i hosts #{playbook} --limit=#{@server.mu_name} --vault-password-file #{pwfile} --timeout=30 --vault-password-file #{@ansible_path}/.vault_pw -u #{ssh_user}}
|
260
|
+
cmd = %Q{cd #{@ansible_path} && echo "#{purpose}" && #{@ansible_execs}/ansible-playbook -i hosts #{playbook} --limit=#{@server.windows? ? @server.canonicalIP : @server.mu_name} --vault-password-file #{pwfile} --timeout=30 --vault-password-file #{@ansible_path}/.vault_pw -u #{ssh_user}}
|
249
261
|
|
250
262
|
retries = 0
|
251
263
|
begin
|
@@ -294,7 +306,7 @@ module MU
|
|
294
306
|
# Bootstrap our server with Ansible- basically, just make sure this node
|
295
307
|
# is listed in our deployment's Ansible inventory.
|
296
308
|
def bootstrap
|
297
|
-
@inventory.add(@server.config['name'], @server.mu_name)
|
309
|
+
@inventory.add(@server.config['name'], @server.windows? ? @server.canonicalIP : @server.mu_name)
|
298
310
|
play = {
|
299
311
|
"hosts" => @server.config['name']
|
300
312
|
}
|
@@ -387,11 +399,18 @@ module MU
|
|
387
399
|
allvars['deployment']
|
388
400
|
end
|
389
401
|
|
402
|
+
# Nuke everything associated with a deploy. Since we're just some files
|
403
|
+
# in the deploy directory, this doesn't have to do anything.
|
404
|
+
def self.cleanup(deploy_id, noop = false)
|
405
|
+
# deploy = MU::MommaCat.new(MU.deploy_id)
|
406
|
+
# inventory = Inventory.new(deploy)
|
407
|
+
end
|
408
|
+
|
390
409
|
# Expunge Ansible resources associated with a node.
|
391
410
|
# @param node [String]: The Mu name of the node in question.
|
392
411
|
# @param _vaults_to_clean [Array<Hash>]: Dummy argument, part of this method's interface but not used by the Ansible layer
|
393
412
|
# @param noop [Boolean]: Skip actual deletion, just state what we'd do
|
394
|
-
def self.
|
413
|
+
def self.purge(node, _vaults_to_clean = [], noop = false)
|
395
414
|
deploy = MU::MommaCat.new(MU.deploy_id)
|
396
415
|
inventory = Inventory.new(deploy)
|
397
416
|
# ansible_path = deploy.deploy_dir+"/ansible"
|
@@ -427,6 +446,50 @@ module MU
|
|
427
446
|
output
|
428
447
|
end
|
429
448
|
|
449
|
+
# Hunt down and return a path for a Python executable
|
450
|
+
# @return [String]
|
451
|
+
def self.pythonExecDir
|
452
|
+
path = nil
|
453
|
+
|
454
|
+
if File.exist?(BINDIR+"/python")
|
455
|
+
path = BINDIR
|
456
|
+
else
|
457
|
+
paths = [ansibleExecDir]
|
458
|
+
paths.concat(ENV['PATH'].split(/:/))
|
459
|
+
paths << "/usr/bin" # not always in path, esp in pared-down Docker images
|
460
|
+
paths.reject! { |p| p.nil? }
|
461
|
+
paths.uniq.each { |bindir|
|
462
|
+
if File.exist?(bindir+"/python")
|
463
|
+
path = bindir
|
464
|
+
break
|
465
|
+
end
|
466
|
+
}
|
467
|
+
end
|
468
|
+
path
|
469
|
+
end
|
470
|
+
|
471
|
+
# Make sure what's in our Python requirements.txt is reflected in the
|
472
|
+
# Python we're about to run for Ansible
|
473
|
+
def self.checkPythonDependencies(windows = false)
|
474
|
+
return nil if !ansibleExecDir
|
475
|
+
|
476
|
+
execline = File.readlines(ansibleExecDir+"/ansible-playbook").first.chomp.sub(/^#!/, '')
|
477
|
+
if !execline
|
478
|
+
MU.log "Unable to extract a Python executable from #{ansibleExecDir}/ansible-playbook", MU::ERR
|
479
|
+
return false
|
480
|
+
end
|
481
|
+
|
482
|
+
require 'tempfile'
|
483
|
+
f = Tempfile.new("pythoncheck")
|
484
|
+
f.puts "import ansible"
|
485
|
+
f.puts "import winrm" if windows
|
486
|
+
f.close
|
487
|
+
|
488
|
+
system(%Q{#{execline} #{f.path}})
|
489
|
+
f.unlink
|
490
|
+
$?.exitstatus == 0 ? true : false
|
491
|
+
end
|
492
|
+
|
430
493
|
# Hunt down and return a path for Ansible executables
|
431
494
|
# @return [String]
|
432
495
|
def self.ansibleExecDir
|
@@ -434,7 +497,9 @@ module MU
|
|
434
497
|
if File.exist?(BINDIR+"/ansible-playbook")
|
435
498
|
path = BINDIR
|
436
499
|
else
|
437
|
-
ENV['PATH'].split(/:/)
|
500
|
+
paths = ENV['PATH'].split(/:/)
|
501
|
+
paths << "/usr/bin"
|
502
|
+
paths.uniq.each { |bindir|
|
438
503
|
if File.exist?(bindir+"/ansible-playbook")
|
439
504
|
path = bindir
|
440
505
|
if !File.exist?(bindir+"/ansible-vault")
|
data/modules/mu/groomers/chef.rb
CHANGED
@@ -35,6 +35,12 @@ module MU
|
|
35
35
|
end
|
36
36
|
}
|
37
37
|
|
38
|
+
# Are the Chef libraries present and accounted for?
|
39
|
+
def self.available?(windows = false)
|
40
|
+
loadChefLib
|
41
|
+
@chefloaded
|
42
|
+
end
|
43
|
+
|
38
44
|
@chefloaded = false
|
39
45
|
@chefload_semaphore = Mutex.new
|
40
46
|
# Autoload is too brain-damaged to get Chef's subclasses/submodules, so
|
@@ -362,7 +368,7 @@ module MU
|
|
362
368
|
}
|
363
369
|
|
364
370
|
if resp.exitcode == 1 and output_lines.join("\n").match(/Chef Client finished/)
|
365
|
-
MU.log
|
371
|
+
MU.log output_lines.last
|
366
372
|
elsif resp.exitcode != 0
|
367
373
|
raise MU::Cloud::BootstrapTempFail if resp.exitcode == 35 or output_lines.join("\n").match(/REBOOT_SCHEDULED| WARN: Reboot requested:|Rebooting server at a recipe's request|Chef::Exceptions::Reboot/)
|
368
374
|
raise MU::Groomer::RunError, output_lines.slice(output_lines.length-50, output_lines.length).join("")
|
@@ -619,15 +625,16 @@ module MU
|
|
619
625
|
kb.name_args = [@server.mu_name]
|
620
626
|
kb.config[:manual] = true
|
621
627
|
kb.config[:winrm_transport] = :ssl
|
622
|
-
kb.config[:host] = @server.mu_name
|
623
628
|
kb.config[:winrm_port] = 5986
|
624
629
|
kb.config[:session_timeout] = timeout
|
625
630
|
kb.config[:operation_timeout] = timeout
|
626
631
|
if retries % 2 == 0
|
632
|
+
kb.config[:host] = canonical_addr
|
627
633
|
kb.config[:winrm_authentication_protocol] = :basic
|
628
634
|
kb.config[:winrm_user] = @server.config['windows_admin_username']
|
629
635
|
kb.config[:winrm_password] = @server.getWindowsAdminPassword
|
630
636
|
else
|
637
|
+
kb.config[:host] = @server.mu_name
|
631
638
|
kb.config[:winrm_authentication_protocol] = :cert
|
632
639
|
kb.config[:winrm_client_cert] = "#{MU.mySSLDir}/#{@server.mu_name}-winrm.crt"
|
633
640
|
kb.config[:winrm_client_key] = "#{MU.mySSLDir}/#{@server.mu_name}-winrm.key"
|
@@ -681,7 +688,7 @@ module MU
|
|
681
688
|
preClean(false) # it's ok for this to fail
|
682
689
|
rescue StandardError => e
|
683
690
|
end
|
684
|
-
MU::Groomer::Chef.
|
691
|
+
MU::Groomer::Chef.purge(@server.mu_name, nodeonly: true)
|
685
692
|
@config['forced_preclean'] = true
|
686
693
|
@server.reboot if @server.windows? # *sigh*
|
687
694
|
end
|
@@ -798,12 +805,49 @@ retry
|
|
798
805
|
end
|
799
806
|
end
|
800
807
|
|
808
|
+
def self.cleanup(deploy_id, noop = false)
|
809
|
+
return nil if deploy_id.nil? or deploy_id.empty?
|
810
|
+
begin
|
811
|
+
if File.exist?(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
812
|
+
::Chef::Config.from_file(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
813
|
+
end
|
814
|
+
deadnodes = []
|
815
|
+
::Chef::Config[:environment] ||= MU.environment
|
816
|
+
q = ::Chef::Search::Query.new
|
817
|
+
begin
|
818
|
+
q.search("node", "tags_MU-ID:#{deploy_id}").each { |item|
|
819
|
+
next if item.is_a?(Integer)
|
820
|
+
item.each { |node|
|
821
|
+
deadnodes << node.name
|
822
|
+
}
|
823
|
+
}
|
824
|
+
rescue Net::HTTPServerException
|
825
|
+
end
|
826
|
+
|
827
|
+
begin
|
828
|
+
q.search("node", "name:#{deploy_id}-*").each { |item|
|
829
|
+
next if item.is_a?(Integer)
|
830
|
+
item.each { |node|
|
831
|
+
deadnodes << node.name
|
832
|
+
}
|
833
|
+
}
|
834
|
+
rescue Net::HTTPServerException
|
835
|
+
end
|
836
|
+
MU.log "Missed some Chef resources in node cleanup, purging now", MU::NOTICE if deadnodes.size > 0
|
837
|
+
deadnodes.uniq.each { |node|
|
838
|
+
MU::Groomer::Chef.purge(node, [], noop)
|
839
|
+
}
|
840
|
+
rescue LoadError
|
841
|
+
end
|
842
|
+
|
843
|
+
end
|
844
|
+
|
801
845
|
# Expunge Chef resources associated with a node.
|
802
846
|
# @param node [String]: The Mu name of the node in question.
|
803
847
|
# @param vaults_to_clean [Array<Hash>]: Some vaults to expunge
|
804
848
|
# @param noop [Boolean]: Skip actual deletion, just state what we'd do
|
805
849
|
# @param nodeonly [Boolean]: Just delete the node and its keys, but leave other artifacts
|
806
|
-
def self.
|
850
|
+
def self.purge(node, vaults_to_clean = [], noop = false, nodeonly: false)
|
807
851
|
loadChefLib
|
808
852
|
MU.log "Deleting Chef resources associated with #{node}"
|
809
853
|
if !nodeonly
|