cloud-mu 3.0.0beta → 3.0.0
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/README.md +17 -8
- data/ansible/roles/mu-nat/README.md +33 -0
- data/ansible/roles/mu-nat/defaults/main.yml +3 -0
- data/ansible/roles/mu-nat/handlers/main.yml +2 -0
- data/ansible/roles/mu-nat/meta/main.yml +60 -0
- data/ansible/roles/mu-nat/tasks/main.yml +65 -0
- data/ansible/roles/mu-nat/tests/inventory +2 -0
- data/ansible/roles/mu-nat/tests/test.yml +5 -0
- data/ansible/roles/mu-nat/vars/main.yml +2 -0
- data/bin/mu-cleanup +2 -1
- data/bin/mu-configure +950 -948
- data/bin/mu-gen-docs +6 -0
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +31 -39
- data/modules/mu/cloud.rb +11 -1
- data/modules/mu/clouds/aws.rb +8 -3
- data/modules/mu/clouds/aws/alarm.rb +5 -8
- data/modules/mu/clouds/aws/bucket.rb +15 -9
- data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
- data/modules/mu/clouds/aws/collection.rb +4 -4
- data/modules/mu/clouds/aws/container_cluster.rb +50 -33
- data/modules/mu/clouds/aws/database.rb +25 -21
- data/modules/mu/clouds/aws/dnszone.rb +12 -14
- data/modules/mu/clouds/aws/endpoint.rb +5 -8
- data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
- data/modules/mu/clouds/aws/folder.rb +4 -7
- data/modules/mu/clouds/aws/function.rb +5 -8
- data/modules/mu/clouds/aws/group.rb +5 -8
- data/modules/mu/clouds/aws/habitat.rb +2 -5
- data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
- data/modules/mu/clouds/aws/log.rb +6 -9
- data/modules/mu/clouds/aws/msg_queue.rb +16 -19
- data/modules/mu/clouds/aws/nosqldb.rb +27 -18
- data/modules/mu/clouds/aws/notifier.rb +6 -9
- data/modules/mu/clouds/aws/role.rb +4 -7
- data/modules/mu/clouds/aws/search_domain.rb +50 -23
- data/modules/mu/clouds/aws/server.rb +20 -14
- data/modules/mu/clouds/aws/server_pool.rb +22 -12
- data/modules/mu/clouds/aws/storage_pool.rb +9 -14
- data/modules/mu/clouds/aws/user.rb +5 -8
- data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
- data/modules/mu/clouds/aws/vpc.rb +16 -14
- data/modules/mu/clouds/azure.rb +1 -1
- data/modules/mu/clouds/azure/container_cluster.rb +1 -1
- data/modules/mu/clouds/azure/server.rb +16 -2
- data/modules/mu/clouds/azure/user.rb +1 -1
- data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
- data/modules/mu/clouds/azure/vpc.rb +32 -13
- data/modules/mu/clouds/cloudformation/server.rb +1 -1
- data/modules/mu/clouds/google.rb +2 -3
- data/modules/mu/clouds/google/container_cluster.rb +9 -1
- data/modules/mu/clouds/google/firewall_rule.rb +6 -0
- data/modules/mu/clouds/google/role.rb +1 -3
- data/modules/mu/clouds/google/server.rb +25 -4
- data/modules/mu/clouds/google/user.rb +1 -1
- data/modules/mu/clouds/google/userdata/linux.erb +9 -5
- data/modules/mu/clouds/google/vpc.rb +102 -21
- data/modules/mu/config.rb +250 -49
- data/modules/mu/config/alarm.rb +1 -0
- data/modules/mu/config/container_cluster.yml +0 -1
- data/modules/mu/config/database.yml +4 -1
- data/modules/mu/config/search_domain.yml +4 -3
- data/modules/mu/config/server.rb +7 -3
- data/modules/mu/config/server.yml +4 -1
- data/modules/mu/config/server_pool.yml +2 -0
- data/modules/mu/config/vpc.rb +42 -29
- data/modules/mu/deploy.rb +12 -5
- data/modules/mu/groomers/ansible.rb +4 -1
- data/modules/mu/groomers/chef.rb +5 -1
- data/modules/mu/kittens.rb +60 -11
- data/modules/mu/logger.rb +6 -4
- data/modules/mu/mommacat.rb +39 -19
- data/modules/mu/mu.yaml.rb +276 -0
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec38717ba0e001faf5500c971fad6d2ce978302e11c9b7dfc587b4d7f1e7c7a3
|
4
|
+
data.tar.gz: 57a212554afb4c30752e471211b515252524dc5a4e4cddabafe29f66bd6a377f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fa39a5ac28414a186e1a1b620e2f097d3d662989dfd0501e02f01ad8f406f289e397a9b506c79c3511c3a659a316a1920d8ca1b8ecc5995bfe8e5f076e98f6c
|
7
|
+
data.tar.gz: 663202c112b0cf2c816a578da15c1d82724ddd577077b7d15075d0e1c6c683b8048dbf216f044a6a623cf82d3ba2ce370ff87a66627c052e9fd996a3b372244e
|
data/README.md
CHANGED
@@ -6,17 +6,26 @@ mu -- Cloudamatic Automation Tooling
|
|
6
6
|
[](http://inch-ci.org/github/cloudamatic/mu)
|
7
7
|
|
8
8
|
# About mu
|
9
|
-
**
|
9
|
+
**Mu** is the deployer and developer toolset for the Cloudamatic suite of services, designed to provision, orchestrate and manage complex platforms and applications. At [eGT Labs](https://www.eglobaltech.com/egt-labs/), we use mu for rapid prototyping of cloud migration efforts for federal customers, for managing cloud applications throughout their lifecycles, and as a tools library for cloud maintenance tasks.
|
10
10
|
|
11
|
-
|
11
|
+
**Install instructions and tutorials**: https://github.com/cloudamatic/mu/wiki
|
12
12
|
|
13
|
-
|
13
|
+
**API and configuration language documentation**: https://cloudamatic.gitlab.io/mu/
|
14
14
|
|
15
|
-
|
15
|
+
# Quick Start
|
16
16
|
|
17
|
-
|
18
|
-
See the [README](../master/install) in the install folder for mu master installation instructions
|
17
|
+
1. `gem install cloud-mu` - Install the toolkit in your Ruby 2.4+ ecosystem. See our [install wiki](https://github.com/cloudamatic/mu/wiki/Install) for other installation options
|
19
18
|
|
20
|
-
|
21
|
-
See the [Usage](https://github.com/cloudamatic/mu/wiki/Usage) section of our Wiki for an overview of how to use the mu tooling for deployment
|
19
|
+
2. `mu-configure` - Set up credentials to your cloud provider of choice. See the [mu-configure manual](https://github.com/cloudamatic/mu/wiki/Configuration) for more.
|
22
20
|
|
21
|
+
3. `mu-deploy` - Build something! This will make a complete public/private VPC:
|
22
|
+
|
23
|
+
```
|
24
|
+
cat <<EOF > myvpc.yaml
|
25
|
+
---
|
26
|
+
appname: myvpc
|
27
|
+
- vpcs:
|
28
|
+
name: thisvpc
|
29
|
+
EOF
|
30
|
+
mu-deploy myvpc.yaml
|
31
|
+
```
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Role Name
|
2
|
+
=========
|
3
|
+
|
4
|
+
Configure a basic iptables-based NAT
|
5
|
+
|
6
|
+
Requirements
|
7
|
+
------------
|
8
|
+
|
9
|
+
CentOS 7, RHEL 7, or Amazon Linux 2
|
10
|
+
|
11
|
+
License
|
12
|
+
-------
|
13
|
+
|
14
|
+
Copyright:: Copyright (c) 2019 eGlobalTech, Inc., all rights reserved
|
15
|
+
|
16
|
+
Licensed under the BSD-3 license (the "License");
|
17
|
+
you may not use this file except in compliance with the License.
|
18
|
+
You may obtain a copy of the License in the root of the project or at
|
19
|
+
|
20
|
+
http://egt-labs.com/mu/LICENSE.html
|
21
|
+
|
22
|
+
Unless required by applicable law or agreed to in writing, software
|
23
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
24
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
25
|
+
See the License for the specific language governing permissions and
|
26
|
+
limitations under the License.
|
27
|
+
|
28
|
+
Author Information
|
29
|
+
------------------
|
30
|
+
|
31
|
+
Current developers: John Stange, Robert Patt-Corner, Ryan Bolyard, Zach Rowe
|
32
|
+
|
33
|
+
egt-labs-admins@egt-labs.com
|
@@ -0,0 +1,60 @@
|
|
1
|
+
galaxy_info:
|
2
|
+
author: your name
|
3
|
+
description: your description
|
4
|
+
company: your company (optional)
|
5
|
+
|
6
|
+
# If the issue tracker for your role is not on github, uncomment the
|
7
|
+
# next line and provide a value
|
8
|
+
# issue_tracker_url: http://example.com/issue/tracker
|
9
|
+
|
10
|
+
# Some suggested licenses:
|
11
|
+
# - BSD (default)
|
12
|
+
# - MIT
|
13
|
+
# - GPLv2
|
14
|
+
# - GPLv3
|
15
|
+
# - Apache
|
16
|
+
# - CC-BY
|
17
|
+
license: license (GPLv2, CC-BY, etc)
|
18
|
+
|
19
|
+
min_ansible_version: 2.4
|
20
|
+
|
21
|
+
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
22
|
+
# min_ansible_container_version:
|
23
|
+
|
24
|
+
# Optionally specify the branch Galaxy will use when accessing the GitHub
|
25
|
+
# repo for this role. During role install, if no tags are available,
|
26
|
+
# Galaxy will use this branch. During import Galaxy will access files on
|
27
|
+
# this branch. If Travis integration is configured, only notifications for this
|
28
|
+
# branch will be accepted. Otherwise, in all cases, the repo's default branch
|
29
|
+
# (usually master) will be used.
|
30
|
+
#github_branch:
|
31
|
+
|
32
|
+
#
|
33
|
+
# Provide a list of supported platforms, and for each platform a list of versions.
|
34
|
+
# If you don't wish to enumerate all versions for a particular platform, use 'all'.
|
35
|
+
# To view available platforms and versions (or releases), visit:
|
36
|
+
# https://galaxy.ansible.com/api/v1/platforms/
|
37
|
+
#
|
38
|
+
# platforms:
|
39
|
+
# - name: Fedora
|
40
|
+
# versions:
|
41
|
+
# - all
|
42
|
+
# - 25
|
43
|
+
# - name: SomePlatform
|
44
|
+
# versions:
|
45
|
+
# - all
|
46
|
+
# - 1.0
|
47
|
+
# - 7
|
48
|
+
# - 99.99
|
49
|
+
|
50
|
+
galaxy_tags: []
|
51
|
+
# List tags for your role here, one per line. A tag is a keyword that describes
|
52
|
+
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
53
|
+
# remove the '[]' above, if you add tags to this list.
|
54
|
+
#
|
55
|
+
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
56
|
+
# Maximum 20 tags per role.
|
57
|
+
|
58
|
+
dependencies: []
|
59
|
+
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
60
|
+
# if you add dependencies to this list.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
---
|
2
|
+
- name: remove firewalld
|
3
|
+
package:
|
4
|
+
name: firewalld
|
5
|
+
state: absent
|
6
|
+
|
7
|
+
- name: make sure iptables is available
|
8
|
+
package:
|
9
|
+
name: iptables-services
|
10
|
+
state: present
|
11
|
+
|
12
|
+
- name: Enable ip_forward
|
13
|
+
sysctl:
|
14
|
+
name: net.ipv4.ip_forward
|
15
|
+
value: '1'
|
16
|
+
state: present
|
17
|
+
|
18
|
+
- name: Disable send_redirects
|
19
|
+
sysctl:
|
20
|
+
name: net.ipv4.conf.eth0.send_redirects
|
21
|
+
value: '0'
|
22
|
+
state: present
|
23
|
+
|
24
|
+
- name: NAT postrouting
|
25
|
+
iptables:
|
26
|
+
table: nat
|
27
|
+
chain: POSTROUTING
|
28
|
+
out_interface: eth0
|
29
|
+
source: "{{ mu['nat_ip_block'] }}"
|
30
|
+
jump: MASQUERADE
|
31
|
+
|
32
|
+
- name: NAT stateful connections
|
33
|
+
iptables:
|
34
|
+
chain: INPUT
|
35
|
+
ctstate: ESTABLISHED,RELATED
|
36
|
+
jump: ACCEPT
|
37
|
+
|
38
|
+
- name: allow inbound from NAT network
|
39
|
+
iptables:
|
40
|
+
chain: INPUT
|
41
|
+
source: "{{ mu['nat_ip_block'] }}"
|
42
|
+
jump: ACCEPT
|
43
|
+
|
44
|
+
- name: flushy
|
45
|
+
iptables:
|
46
|
+
chain: FORWARD
|
47
|
+
flush: yes
|
48
|
+
|
49
|
+
- name: allow forward of NAT network (outbound)
|
50
|
+
iptables:
|
51
|
+
chain: FORWARD
|
52
|
+
source: "{{ mu['nat_ip_block'] }}"
|
53
|
+
jump: ACCEPT
|
54
|
+
|
55
|
+
- name: allow forward of NAT network (inbound)
|
56
|
+
iptables:
|
57
|
+
chain: FORWARD
|
58
|
+
destination: "{{ mu['nat_ip_block'] }}"
|
59
|
+
ctstate: ESTABLISHED,RELATED
|
60
|
+
jump: ACCEPT
|
61
|
+
|
62
|
+
- name: Default forwarding policy to ACCEPT
|
63
|
+
iptables:
|
64
|
+
chain: FORWARD
|
65
|
+
policy: DROP
|
data/bin/mu-cleanup
CHANGED
@@ -59,7 +59,8 @@ end
|
|
59
59
|
MU.setLogging(verbosity, $opts[:web])
|
60
60
|
|
61
61
|
if (!ARGV[0] or ARGV[0].empty?) and !$opts[:deploy]
|
62
|
-
MU.log
|
62
|
+
MU.log "Must specify a deploy id. Visible deploys:", MU::WARN
|
63
|
+
puts MU::MommaCat.listDeploys.sort.join("\n")
|
63
64
|
exit 1
|
64
65
|
else
|
65
66
|
$opts[:deploy] = ARGV[0]
|
data/bin/mu-configure
CHANGED
@@ -345,301 +345,292 @@ def importCurrentValues
|
|
345
345
|
}
|
346
346
|
end
|
347
347
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
data
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
data[
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
348
|
+
if !$NOOP
|
349
|
+
AMROOT = Process.uid == 0
|
350
|
+
HOMEDIR = Etc.getpwuid(Process.uid).dir
|
351
|
+
|
352
|
+
$opts = Optimist::options do
|
353
|
+
banner <<-EOS
|
354
|
+
EOS
|
355
|
+
required = []
|
356
|
+
opt :noninteractive, "Skip menu-based configuration prompts. If there is no existing configuration, the following flags are required: #{required.map{|x|"--"+x}.join(", ")}", :require => false, :default => false, :type => :boolean
|
357
|
+
$CONFIGURABLES.each_pair { |key, data|
|
358
|
+
next if !AMROOT and data['rootonly']
|
359
|
+
if data.has_key?("subtree")
|
360
|
+
data["subtree"].each_pair { |subkey, subdata|
|
361
|
+
next if !AMROOT and subdata['rootonly']
|
362
|
+
subdata['cli-opt'] = (key+"-"+subkey).gsub(/_/, "-")
|
363
|
+
opt subdata['cli-opt'].to_sym, subdata["desc"], :require => false, :type => (subdata["boolean"] ? :boolean : :string)
|
364
|
+
required << subdata['cli-opt'] if subdata['required']
|
365
|
+
}
|
366
|
+
elsif data["array"]
|
367
|
+
data['cli-opt'] = key.gsub(/_/, "-")
|
368
|
+
opt data['cli-opt'].to_sym, data["desc"], :require => false, :type => (data["boolean"] ? :booleans : :strings)
|
369
|
+
required << data['cli-opt'] if data['required']
|
370
|
+
else
|
371
|
+
data['cli-opt'] = key.gsub(/_/, "-")
|
372
|
+
opt data['cli-opt'].to_sym, data["desc"], :require => false, :type => (data["boolean"] ? :boolean : :string)
|
373
|
+
required << data['cli-opt'] if data['required']
|
374
|
+
end
|
375
|
+
}
|
375
376
|
|
376
|
-
|
377
|
-
|
378
|
-
end
|
377
|
+
opt :force, "Run all rebuild actions, whether or not our configuration is changed.", :require => false, :default => false, :type => :boolean if AMROOT
|
378
|
+
opt :ssh_keys, "One or more paths to SSH private keys, which we can try to use for SSH-based Git clone operations", :require => false, :type => :strings
|
379
|
+
end
|
379
380
|
|
380
|
-
if ENV.has_key?("MU_INSTALLDIR")
|
381
|
-
|
382
|
-
else
|
383
|
-
|
384
|
-
end
|
381
|
+
if ENV.has_key?("MU_INSTALLDIR")
|
382
|
+
MU_BASE = ENV["MU_INSTALLDIR"]
|
383
|
+
else
|
384
|
+
MU_BASE = "/opt/mu"
|
385
|
+
end
|
385
386
|
|
386
|
-
def cfgPath
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
387
|
+
def cfgPath
|
388
|
+
home = Etc.getpwuid(Process.uid).dir
|
389
|
+
username = Etc.getpwuid(Process.uid).name
|
390
|
+
if Process.uid == 0
|
391
|
+
if ENV.include?('MU_INSTALLDIR')
|
392
|
+
ENV['MU_INSTALLDIR']+"/etc/mu.yaml"
|
393
|
+
elsif Dir.exist?("/opt/mu")
|
394
|
+
"/opt/mu/etc/mu.yaml"
|
395
|
+
else
|
396
|
+
"#{home}/.mu.yaml"
|
397
|
+
end
|
394
398
|
else
|
395
399
|
"#{home}/.mu.yaml"
|
396
400
|
end
|
397
|
-
else
|
398
|
-
"#{home}/.mu.yaml"
|
399
401
|
end
|
400
|
-
end
|
401
|
-
|
402
|
-
$INITIALIZE = (!File.size?(cfgPath) or $opts[:force])
|
403
402
|
|
404
|
-
$
|
405
|
-
if !AMROOT and !$HAVE_GLOBAL_CONFIG and !$IN_GEM and Dir.exist?("/opt/mu/lib")
|
406
|
-
puts "Global configuration has not been initialized or is missing. Must run as root to correct."
|
407
|
-
exit 1
|
408
|
-
end
|
403
|
+
$INITIALIZE = (!File.size?(cfgPath) or $opts[:force])
|
409
404
|
|
410
|
-
|
411
|
-
if
|
412
|
-
|
413
|
-
end
|
414
|
-
if !$MU_CFG or !$MU_CFG['mu_admin_email'] or !$MU_CFG['mu_admin_name']
|
415
|
-
puts "Specify --public-address and --mu-admin-email on new non-interactive configs"
|
405
|
+
$HAVE_GLOBAL_CONFIG = File.size?("#{MU_BASE}/etc/mu.yaml")
|
406
|
+
if !AMROOT and !$HAVE_GLOBAL_CONFIG and !$IN_GEM and Dir.exist?("/opt/mu/lib")
|
407
|
+
puts "Global configuration has not been initialized or is missing. Must run as root to correct."
|
416
408
|
exit 1
|
417
409
|
end
|
418
|
-
end
|
419
410
|
|
420
|
-
$
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
411
|
+
if !$HAVE_GLOBAL_CONFIG and $opts[:noninteractive] and (!$opts[:"public-address"] or !$opts[:"mu-admin-email"])
|
412
|
+
if $IN_GEM
|
413
|
+
importCurrentValues # maybe we're in local-only mode
|
414
|
+
end
|
415
|
+
if !$MU_CFG or !$MU_CFG['mu_admin_email'] or !$MU_CFG['mu_admin_name']
|
416
|
+
puts "Specify --public-address and --mu-admin-email on new non-interactive configs"
|
417
|
+
exit 1
|
418
|
+
end
|
425
419
|
end
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
).read
|
435
|
-
$IN_GOOGLE = true if !instance_id.nil? and instance_id.size > 0
|
420
|
+
|
421
|
+
$IN_AWS = false
|
422
|
+
begin
|
423
|
+
Timeout.timeout(2) do
|
424
|
+
instance_id = open("http://169.254.169.254/latest/meta-data/instance-id").read
|
425
|
+
$IN_AWS = true if !instance_id.nil? and instance_id.size > 0
|
426
|
+
end
|
427
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH
|
436
428
|
end
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
429
|
+
$IN_GOOGLE = false
|
430
|
+
begin
|
431
|
+
Timeout.timeout(2) do
|
432
|
+
instance_id = open(
|
433
|
+
"http://metadata.google.internal/computeMetadata/v1/instance/name",
|
434
|
+
"Metadata-Flavor" => "Google"
|
435
|
+
).read
|
436
|
+
$IN_GOOGLE = true if !instance_id.nil? and instance_id.size > 0
|
437
|
+
end
|
438
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH
|
439
|
+
end
|
440
|
+
$IN_AZURE = false
|
441
|
+
begin
|
442
|
+
Timeout.timeout(2) do
|
443
|
+
instance = open("http://169.254.169.254/metadata/instance/compute?api-version=2017-08-01","Metadata"=>"true").read
|
444
|
+
$IN_AZURE = true if !instance.nil? and instance.size > 0
|
445
|
+
end
|
446
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH, Errno::EHOSTUNREACH
|
444
447
|
end
|
445
|
-
rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH, Errno::EHOSTUNREACH
|
446
|
-
end
|
447
448
|
|
448
|
-
KNIFE_TEMPLATE = "log_level :info
|
449
|
-
log_location STDOUT
|
450
|
-
node_name '<%= chefuser %>'
|
451
|
-
client_key '<%= MU_BASE %>/var/users/<%= user %>/<%= chefuser %>.user.key'
|
452
|
-
validation_client_name 'mu-validator'
|
453
|
-
validation_key '<%= MU_BASE %>/var/orgs/<%= user %>/<%= chefuser %>.org.key'
|
454
|
-
chef_server_url 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= chefuser %>'
|
455
|
-
chef_server_root 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= chefuser %>'
|
456
|
-
syntax_check_cache_path '<%= HOMEDIR %>/.chef/syntax_check_cache'
|
457
|
-
cookbook_path [ '<%= HOMEDIR %>/.chef/cookbooks', '<%= HOMEDIR %>/.chef/site_cookbooks' ]
|
458
|
-
<% if $MU_CFG.has_key?('ssl') and $MU_CFG['ssl'].has_key?('chain') %>
|
459
|
-
ssl_ca_path '<%= File.dirname($MU_CFG['ssl']['chain']) %>'
|
460
|
-
ssl_ca_file '<%= File.basename($MU_CFG['ssl']['chain']) %>'
|
461
|
-
<% end %>
|
462
|
-
knife[:vault_mode] = 'client'
|
463
|
-
knife[:vault_admins] = ['<%= chefuser %>']"
|
464
|
-
|
465
|
-
CLIENT_TEMPLATE = "chef_server_url 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= user %>'
|
466
|
-
validation_client_name 'mu-validator'
|
467
|
-
log_location STDOUT
|
468
|
-
node_name 'MU-MASTER'
|
469
|
-
verify_api_cert false
|
470
|
-
ssl_verify_mode :verify_none
|
471
|
-
"
|
472
|
-
|
473
|
-
PIVOTAL_TEMPLATE = "node_name 'pivotal'
|
474
|
-
chef_server_url 'https://<%= MU.mu_public_addr %>:7443'
|
475
|
-
chef_server_root 'https://<%= MU.mu_public_addr %>:7443'
|
476
|
-
no_proxy '<%= MU.mu_public_addr %>'
|
477
|
-
client_key '/etc/opscode/pivotal.pem'
|
478
|
-
ssl_verify_mode :verify_none
|
479
|
-
"
|
480
|
-
|
481
|
-
$CHANGES = []
|
482
|
-
|
483
|
-
|
484
|
-
$MENU_MAP = {}
|
485
|
-
def assignMenuEntries(tree = $CONFIGURABLES, map = $MENU_MAP)
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
449
|
+
KNIFE_TEMPLATE = "log_level :info
|
450
|
+
log_location STDOUT
|
451
|
+
node_name '<%= chefuser %>'
|
452
|
+
client_key '<%= MU_BASE %>/var/users/<%= user %>/<%= chefuser %>.user.key'
|
453
|
+
validation_client_name 'mu-validator'
|
454
|
+
validation_key '<%= MU_BASE %>/var/orgs/<%= user %>/<%= chefuser %>.org.key'
|
455
|
+
chef_server_url 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= chefuser %>'
|
456
|
+
chef_server_root 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= chefuser %>'
|
457
|
+
syntax_check_cache_path '<%= HOMEDIR %>/.chef/syntax_check_cache'
|
458
|
+
cookbook_path [ '<%= HOMEDIR %>/.chef/cookbooks', '<%= HOMEDIR %>/.chef/site_cookbooks' ]
|
459
|
+
<% if $MU_CFG.has_key?('ssl') and $MU_CFG['ssl'].has_key?('chain') %>
|
460
|
+
ssl_ca_path '<%= File.dirname($MU_CFG['ssl']['chain']) %>'
|
461
|
+
ssl_ca_file '<%= File.basename($MU_CFG['ssl']['chain']) %>'
|
462
|
+
<% end %>
|
463
|
+
knife[:vault_mode] = 'client'
|
464
|
+
knife[:vault_admins] = ['<%= chefuser %>']"
|
465
|
+
|
466
|
+
CLIENT_TEMPLATE = "chef_server_url 'https://<%= MU.mu_public_addr %>:7443/organizations/<%= user %>'
|
467
|
+
validation_client_name 'mu-validator'
|
468
|
+
log_location STDOUT
|
469
|
+
node_name 'MU-MASTER'
|
470
|
+
verify_api_cert false
|
471
|
+
ssl_verify_mode :verify_none
|
472
|
+
"
|
473
|
+
|
474
|
+
PIVOTAL_TEMPLATE = "node_name 'pivotal'
|
475
|
+
chef_server_url 'https://<%= MU.mu_public_addr %>:7443'
|
476
|
+
chef_server_root 'https://<%= MU.mu_public_addr %>:7443'
|
477
|
+
no_proxy '<%= MU.mu_public_addr %>'
|
478
|
+
client_key '/etc/opscode/pivotal.pem'
|
479
|
+
ssl_verify_mode :verify_none
|
480
|
+
"
|
481
|
+
|
482
|
+
$CHANGES = []
|
483
|
+
|
484
|
+
|
485
|
+
$MENU_MAP = {}
|
486
|
+
def assignMenuEntries(tree = $CONFIGURABLES, map = $MENU_MAP)
|
487
|
+
count = 1
|
488
|
+
tree.each_pair { |key, data|
|
489
|
+
next if !data.is_a?(Hash)
|
490
|
+
next if !AMROOT and data['rootonly']
|
491
|
+
if data.has_key?("subtree")
|
492
|
+
letters = ("a".."z").to_a
|
493
|
+
lettercount = 0
|
494
|
+
if data['named_subentries']
|
495
|
+
# Generate a stub entry for adding a new item
|
496
|
+
map[count.to_s] = cloneHash(data["subtree"])
|
497
|
+
map[count.to_s].each_pair { |k, v| v.delete("value") } # use defaults
|
498
|
+
map[count.to_s]["name"] = {
|
499
|
+
"title" => "Name",
|
500
|
+
"desc" => "A name/alias for this account.",
|
501
|
+
"required" => true
|
502
|
+
}
|
503
|
+
map[count.to_s]["#addnew"] = true
|
504
|
+
map[count.to_s]["#title"] = data['title']
|
505
|
+
map[count.to_s]["#key"] = key
|
506
|
+
|
507
|
+
# Now the menu entries for the existing ones
|
508
|
+
if data['subtree']['#entries']
|
509
|
+
data['subtree']['#entries'].each_pair { |nameentry, subdata|
|
510
|
+
next if data['readonly']
|
511
|
+
next if !subdata.is_a?(Hash)
|
512
|
+
subdata["#menu"] = count.to_s+letters[lettercount]
|
513
|
+
subdata["#title"] = nameentry
|
514
|
+
subdata["#key"] = key
|
515
|
+
subdata["#entries"] = cloneHash(data["subtree"]["#entries"])
|
516
|
+
subdata["is_submenu"] = true
|
517
|
+
map[count.to_s+letters[lettercount]] = tree[key]["subtree"]['#entries'][nameentry]
|
518
|
+
map[count.to_s+letters[lettercount]]['#entries'] ||= cloneHash(data["subtree"]["#entries"])
|
519
|
+
lettercount = lettercount + 1
|
520
|
+
}
|
521
|
+
end
|
522
|
+
else
|
523
|
+
data["subtree"].each_pair { |subkey, subdata|
|
524
|
+
next if !AMROOT and subdata['rootonly']
|
525
|
+
tree[key]["subtree"][subkey]["#menu"] = count.to_s+letters[lettercount]
|
526
|
+
tree[key]["subtree"][subkey]["#key"] = subkey
|
527
|
+
map[count.to_s+letters[lettercount]] = tree[key]["subtree"][subkey]
|
518
528
|
lettercount = lettercount + 1
|
519
529
|
}
|
520
530
|
end
|
521
|
-
else
|
522
|
-
data["subtree"].each_pair { |subkey, subdata|
|
523
|
-
next if !AMROOT and subdata['rootonly']
|
524
|
-
tree[key]["subtree"][subkey]["#menu"] = count.to_s+letters[lettercount]
|
525
|
-
tree[key]["subtree"][subkey]["#key"] = subkey
|
526
|
-
map[count.to_s+letters[lettercount]] = tree[key]["subtree"][subkey]
|
527
|
-
lettercount = lettercount + 1
|
528
|
-
}
|
529
531
|
end
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
map#.freeze
|
537
|
-
end
|
538
|
-
|
539
|
-
def trySSHKeyWithGit(repo, keypath = nil)
|
540
|
-
cfgbackup = nil
|
541
|
-
deletekey = false
|
542
|
-
repo.match(/^([^@]+?)@([^:]+?):/)
|
543
|
-
ssh_user = Regexp.last_match(1)
|
544
|
-
ssh_host = Regexp.last_match(2)
|
545
|
-
if keypath.nil?
|
546
|
-
response = nil
|
547
|
-
puts "Would you like to provide a private ssh key for #{repo} and try again?"
|
548
|
-
begin
|
549
|
-
response = Readline.readline("Y/N> ".bold, false)
|
550
|
-
end while !response and !response.match(/^(y|n)$/i)
|
551
|
-
if response == "y" or response == "Y"
|
552
|
-
Dir.mkdir("#{HOMEDIR}/.ssh", 0700) if !Dir.exist?("#{HOMEDIR}/.ssh")
|
553
|
-
keynamestr = repo.gsub(/[^a-z0-9\-]/i, "-") + Process.pid.to_s
|
554
|
-
keypath = "#{HOMEDIR}/.ssh/#{keynamestr}"
|
555
|
-
puts "Paste a complete SSH private key for #{ssh_user.bold}@#{ssh_host.bold} below, then ^D"
|
556
|
-
system("cat > #{keypath}")
|
557
|
-
File.chmod(0600, keypath)
|
558
|
-
puts "Key saved to "+keypath.bold
|
559
|
-
deletekey = true
|
560
|
-
else
|
561
|
-
return false
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
if File.exist?("#{HOMEDIR}/.ssh/config")
|
566
|
-
FileUtils.cp("#{HOMEDIR}/.ssh/config", "#{HOMEDIR}/.ssh/config.bak.#{Process.pid.to_s}")
|
567
|
-
cfgbackup = "#{HOMEDIR}/.ssh/config.bak.#{Process.pid.to_s}"
|
532
|
+
tree[key]["#menu"] = count.to_s
|
533
|
+
tree[key]["#key"] = key
|
534
|
+
map[count.to_s] ||= tree[key]
|
535
|
+
count = count + 1
|
536
|
+
}
|
537
|
+
map#.freeze
|
568
538
|
end
|
569
|
-
File.open("#{HOMEDIR}/.ssh/config", "a", 0600){ |f|
|
570
|
-
f.puts "Host "+ssh_host
|
571
|
-
f.puts " User "+ssh_user
|
572
|
-
f.puts " IdentityFile "+keypath
|
573
|
-
f.puts " StrictHostKeyChecking no"
|
574
|
-
}
|
575
539
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
puts "
|
585
|
-
|
540
|
+
def trySSHKeyWithGit(repo, keypath = nil)
|
541
|
+
cfgbackup = nil
|
542
|
+
deletekey = false
|
543
|
+
repo.match(/^([^@]+?)@([^:]+?):/)
|
544
|
+
ssh_user = Regexp.last_match(1)
|
545
|
+
ssh_host = Regexp.last_match(2)
|
546
|
+
if keypath.nil?
|
547
|
+
response = nil
|
548
|
+
puts "Would you like to provide a private ssh key for #{repo} and try again?"
|
549
|
+
begin
|
550
|
+
response = Readline.readline("Y/N> ".bold, false)
|
551
|
+
end while !response and !response.match(/^(y|n)$/i)
|
552
|
+
if response == "y" or response == "Y"
|
553
|
+
Dir.mkdir("#{HOMEDIR}/.ssh", 0700) if !Dir.exist?("#{HOMEDIR}/.ssh")
|
554
|
+
keynamestr = repo.gsub(/[^a-z0-9\-]/i, "-") + Process.pid.to_s
|
555
|
+
keypath = "#{HOMEDIR}/.ssh/#{keynamestr}"
|
556
|
+
puts "Paste a complete SSH private key for #{ssh_user.bold}@#{ssh_host.bold} below, then ^D"
|
557
|
+
system("cat > #{keypath}")
|
558
|
+
File.chmod(0600, keypath)
|
559
|
+
puts "Key saved to "+keypath.bold
|
560
|
+
deletekey = true
|
561
|
+
else
|
562
|
+
return false
|
563
|
+
end
|
586
564
|
end
|
587
|
-
|
588
|
-
|
589
|
-
|
565
|
+
|
566
|
+
if File.exist?("#{HOMEDIR}/.ssh/config")
|
567
|
+
FileUtils.cp("#{HOMEDIR}/.ssh/config", "#{HOMEDIR}/.ssh/config.bak.#{Process.pid.to_s}")
|
568
|
+
cfgbackup = "#{HOMEDIR}/.ssh/config.bak.#{Process.pid.to_s}"
|
590
569
|
end
|
591
|
-
|
592
|
-
|
593
|
-
|
570
|
+
File.open("#{HOMEDIR}/.ssh/config", "a", 0600){ |f|
|
571
|
+
f.puts "Host "+ssh_host
|
572
|
+
f.puts " User "+ssh_user
|
573
|
+
f.puts " IdentityFile "+keypath
|
574
|
+
f.puts " StrictHostKeyChecking no"
|
575
|
+
}
|
594
576
|
|
595
|
-
|
596
|
-
|
597
|
-
fullrepo = repo
|
598
|
-
if !repo.match(/@|:\/\//) # we try ssh first
|
599
|
-
fullrepo = "git@github.com:"+repo
|
600
|
-
puts "Doesn't look like a full URL, trying SSH to #{fullrepo}"
|
601
|
-
end
|
602
|
-
cwd = Dir.pwd
|
603
|
-
Dir.mktmpdir("mu-git-test-") { |dir|
|
604
|
-
Dir.chdir(dir)
|
605
|
-
puts "/usr/bin/git clone #{fullrepo}"
|
606
|
-
output = %x{/usr/bin/git clone #{fullrepo} 2>&1}
|
577
|
+
puts "/usr/bin/git clone #{repo}"
|
578
|
+
output = %x{/usr/bin/git clone #{repo} 2>&1}
|
607
579
|
if $?.exitstatus == 0
|
608
|
-
puts "Successfully cloned #{
|
609
|
-
|
610
|
-
|
611
|
-
elsif $?.exitstatus != 0 and output.match(/permission denied/i)
|
612
|
-
puts ""
|
580
|
+
puts "Successfully cloned #{repo}".green.on_black
|
581
|
+
return true
|
582
|
+
else
|
613
583
|
puts output.red.on_black
|
614
|
-
if
|
615
|
-
|
616
|
-
|
617
|
-
Dir.chdir(cwd)
|
618
|
-
return fullrepo
|
619
|
-
end
|
620
|
-
}
|
584
|
+
if cfgbackup
|
585
|
+
puts "Restoring #{HOMEDIR}/.ssh/config"
|
586
|
+
File.rename(cfgbackup, "#{HOMEDIR}/.ssh/config")
|
621
587
|
end
|
622
|
-
if
|
623
|
-
|
624
|
-
|
625
|
-
return fullrepo
|
626
|
-
end
|
588
|
+
if deletekey
|
589
|
+
puts "Removing #{keypath}"
|
590
|
+
File.unlink(keypath)
|
627
591
|
end
|
628
592
|
end
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
593
|
+
return false
|
594
|
+
end
|
595
|
+
|
596
|
+
def cloneGitRepo(repo)
|
597
|
+
puts "Testing ability to check out Git repository #{repo.bold}"
|
598
|
+
fullrepo = repo
|
599
|
+
if !repo.match(/@|:\/\//) # we try ssh first
|
600
|
+
fullrepo = "git@github.com:"+repo
|
601
|
+
puts "Doesn't look like a full URL, trying SSH to #{fullrepo}"
|
602
|
+
end
|
603
|
+
cwd = Dir.pwd
|
604
|
+
Dir.mktmpdir("mu-git-test-") { |dir|
|
605
|
+
Dir.chdir(dir)
|
633
606
|
puts "/usr/bin/git clone #{fullrepo}"
|
634
607
|
output = %x{/usr/bin/git clone #{fullrepo} 2>&1}
|
635
608
|
if $?.exitstatus == 0
|
636
609
|
puts "Successfully cloned #{fullrepo}".green.on_black
|
637
610
|
Dir.chdir(cwd)
|
638
611
|
return fullrepo
|
639
|
-
|
612
|
+
elsif $?.exitstatus != 0 and output.match(/permission denied/i)
|
613
|
+
puts ""
|
640
614
|
puts output.red.on_black
|
641
|
-
|
642
|
-
|
615
|
+
if $opts[:"ssh-keys-given"]
|
616
|
+
$opts[:"ssh-keys"].each { |keypath|
|
617
|
+
if trySSHKeyWithGit(fullrepo, keypath)
|
618
|
+
Dir.chdir(cwd)
|
619
|
+
return fullrepo
|
620
|
+
end
|
621
|
+
}
|
622
|
+
end
|
623
|
+
if !$opts[:noninteractive]
|
624
|
+
if trySSHKeyWithGit(fullrepo)
|
625
|
+
Dir.chdir(cwd)
|
626
|
+
return fullrepo
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
if !repo.match(/@|:\/\//)
|
631
|
+
fullrepo = "git://github.com/"+repo
|
632
|
+
puts ""
|
633
|
+
puts "No luck there, trying #{fullrepo}".bold
|
643
634
|
puts "/usr/bin/git clone #{fullrepo}"
|
644
635
|
output = %x{/usr/bin/git clone #{fullrepo} 2>&1}
|
645
636
|
if $?.exitstatus == 0
|
@@ -648,816 +639,827 @@ def cloneGitRepo(repo)
|
|
648
639
|
return fullrepo
|
649
640
|
else
|
650
641
|
puts output.red.on_black
|
642
|
+
fullrepo = "https://github.com/"+repo
|
643
|
+
puts "Final attempt, trying #{fullrepo}"
|
644
|
+
puts "/usr/bin/git clone #{fullrepo}"
|
645
|
+
output = %x{/usr/bin/git clone #{fullrepo} 2>&1}
|
646
|
+
if $?.exitstatus == 0
|
647
|
+
puts "Successfully cloned #{fullrepo}".green.on_black
|
648
|
+
Dir.chdir(cwd)
|
649
|
+
return fullrepo
|
650
|
+
else
|
651
|
+
puts output.red.on_black
|
652
|
+
end
|
651
653
|
end
|
654
|
+
else
|
655
|
+
puts "No other methods I can think to try, giving up on #{repo.bold}".red.on_black
|
652
656
|
end
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
Dir.chdir(cwd)
|
658
|
-
nil
|
659
|
-
end
|
657
|
+
}
|
658
|
+
Dir.chdir(cwd)
|
659
|
+
nil
|
660
|
+
end
|
660
661
|
|
661
|
-
# Rustle up some sensible default values, if this is our first time
|
662
|
-
def setDefaults
|
663
|
-
|
664
|
-
|
665
|
-
|
662
|
+
# Rustle up some sensible default values, if this is our first time
|
663
|
+
def setDefaults
|
664
|
+
ips = []
|
665
|
+
if $IN_AWS
|
666
|
+
["public-ipv4", "local-ipv4"].each { |addr|
|
667
|
+
begin
|
668
|
+
Timeout.timeout(2) do
|
669
|
+
ip = open("http://169.254.169.254/latest/meta-data/#{addr}").read
|
670
|
+
ips << ip if !ip.nil? and ip.size > 0
|
671
|
+
end
|
672
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError
|
673
|
+
# these are ok to ignore
|
674
|
+
end
|
675
|
+
}
|
676
|
+
elsif $IN_GOOGLE
|
677
|
+
base_url = "http://metadata.google.internal/computeMetadata/v1"
|
666
678
|
begin
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
base_url = "http://metadata.google.internal/computeMetadata/v1"
|
677
|
-
begin
|
678
|
-
Timeout.timeout(2) do
|
679
|
-
# TODO iterate across multiple interfaces/access-configs
|
680
|
-
ip = open("#{base_url}/instance/network-interfaces/0/ip", "Metadata-Flavor" => "Google").read
|
681
|
-
ips << ip if !ip.nil? and ip.size > 0
|
682
|
-
ip = open("#{base_url}/instance/network-interfaces/0/access-configs/0/external-ip", "Metadata-Flavor" => "Google").read
|
683
|
-
ips << ip if !ip.nil? and ip.size > 0
|
679
|
+
Timeout.timeout(2) do
|
680
|
+
# TODO iterate across multiple interfaces/access-configs
|
681
|
+
ip = open("#{base_url}/instance/network-interfaces/0/ip", "Metadata-Flavor" => "Google").read
|
682
|
+
ips << ip if !ip.nil? and ip.size > 0
|
683
|
+
ip = open("#{base_url}/instance/network-interfaces/0/access-configs/0/external-ip", "Metadata-Flavor" => "Google").read
|
684
|
+
ips << ip if !ip.nil? and ip.size > 0
|
685
|
+
end
|
686
|
+
rescue OpenURI::HTTPError, Timeout::Error, SocketError => e
|
687
|
+
# This is fairly normal, just handle it gracefully
|
684
688
|
end
|
685
|
-
rescue OpenURI::HTTPError, Timeout::Error, SocketError => e
|
686
|
-
# This is fairly normal, just handle it gracefully
|
687
689
|
end
|
688
|
-
end
|
689
690
|
|
690
691
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
# XXX move this crap to a callback hook for puttering around in the AWS submenu
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
# $CONFIGURABLES["aws"]["subtree"]["account_number"]["default"] = aws["accountId"]
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
692
|
+
$CONFIGURABLES["allow_invade_foreign_vpcs"]["default"] = false
|
693
|
+
$CONFIGURABLES["public_address"]["default"] = $possible_addresses.first
|
694
|
+
$CONFIGURABLES["hostname"]["default"] = Socket.gethostname
|
695
|
+
$CONFIGURABLES["banner"]["default"] = "Mu Master at #{$CONFIGURABLES["public_address"]["default"]}"
|
696
|
+
if $IN_AWS
|
697
|
+
# XXX move this crap to a callback hook for puttering around in the AWS submenu
|
698
|
+
aws = JSON.parse(open("http://169.254.169.254/latest/dynamic/instance-identity/document").read)
|
699
|
+
iam = nil
|
700
|
+
begin
|
701
|
+
iam = open("http://169.254.169.254/latest/meta-data/iam/security-credentials").read
|
702
|
+
rescue OpenURI::HTTPError, SocketError
|
703
|
+
end
|
704
|
+
# $CONFIGURABLES["aws"]["subtree"]["account_number"]["default"] = aws["accountId"]
|
705
|
+
$CONFIGURABLES["aws"]["subtree"]["region"]["default"] = aws["region"]
|
706
|
+
if iam and iam.size > 0
|
707
|
+
# XXX can we think of a good way to test our permission set?
|
708
|
+
$CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] = $CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] + ". Not necessary if IAM Profile #{iam.bold} has sufficient API access."
|
709
|
+
$CONFIGURABLES["aws"]["subtree"]["access_secret"]["desc"] = $CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] + ". Not necessary if IAM Profile #{iam.bold} has sufficient API access."
|
710
|
+
end
|
709
711
|
end
|
712
|
+
$CONFIGURABLES["aws"]["subtree"]["log_bucket_name"]["default"] = $CONFIGURABLES["hostname"]["default"]
|
713
|
+
$CONFIGURABLES["google"]["subtree"]["log_bucket_name"]["default"] = $CONFIGURABLES["hostname"]["default"]
|
710
714
|
end
|
711
|
-
$CONFIGURABLES["aws"]["subtree"]["log_bucket_name"]["default"] = $CONFIGURABLES["hostname"]["default"]
|
712
|
-
$CONFIGURABLES["google"]["subtree"]["log_bucket_name"]["default"] = $CONFIGURABLES["hostname"]["default"]
|
713
|
-
end
|
714
715
|
|
715
716
|
|
716
|
-
def runValueCallback(desc, val)
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
717
|
+
def runValueCallback(desc, val)
|
718
|
+
if desc['array']
|
719
|
+
if desc["callback"]
|
720
|
+
newval = []
|
721
|
+
val.each { |v|
|
722
|
+
v = send(desc["callback"].to_sym, v)
|
723
|
+
newval << v if !v.nil?
|
724
|
+
}
|
725
|
+
val = newval
|
726
|
+
end
|
727
|
+
elsif desc["callback"]
|
728
|
+
val = send(desc["callback"].to_sym, val)
|
725
729
|
end
|
726
|
-
|
727
|
-
val = send(desc["callback"].to_sym, val)
|
730
|
+
val
|
728
731
|
end
|
729
|
-
val
|
730
|
-
end
|
731
|
-
|
732
|
-
def importCLIValues
|
733
|
-
$CONFIGURABLES.each_pair { |key, data|
|
734
|
-
next if !AMROOT and data['rootonly']
|
735
|
-
if data.has_key?("subtree")
|
736
732
|
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
733
|
+
def importCLIValues
|
734
|
+
$CONFIGURABLES.each_pair { |key, data|
|
735
|
+
next if !AMROOT and data['rootonly']
|
736
|
+
if data.has_key?("subtree")
|
737
|
+
|
738
|
+
if !data['named_subentries']
|
739
|
+
data["subtree"].each_pair { |subkey, subdata|
|
740
|
+
next if !AMROOT and subdata['rootonly']
|
741
|
+
if $opts[(subdata['cli-opt'].+"_given").to_sym]
|
742
|
+
newval = runValueCallback(subdata, $opts[subdata['cli-opt'].to_sym])
|
743
|
+
subdata["value"] = newval if !newval.nil?
|
744
|
+
$CHANGES.concat(subdata['changes']) if subdata['changes']
|
745
|
+
end
|
746
|
+
}
|
747
|
+
# Honor CLI adds for named trees (credentials, etc) if there are no
|
748
|
+
# entries in them yet.
|
749
|
+
elsif data["#entries"].nil? or data["#entries"].empty?
|
750
|
+
newvals = false
|
751
|
+
data["subtree"].each_pair { |subkey, subdata|
|
752
|
+
next if !AMROOT and subdata['rootonly']
|
753
|
+
next if !subdata['cli-opt']
|
754
|
+
if $opts[(subdata['cli-opt']+"_given").to_sym]
|
755
|
+
newval = runValueCallback(subdata, $opts[subdata['cli-opt'].to_sym])
|
756
|
+
if !newval.nil?
|
757
|
+
subdata["value"] = newval
|
758
|
+
newvals = true
|
759
|
+
end
|
758
760
|
end
|
759
|
-
end
|
760
|
-
}
|
761
|
-
if newvals
|
762
|
-
newtree = data["subtree"].dup
|
763
|
-
newtree['default']['value'] = true if newtree['default']
|
764
|
-
data['subtree']['#entries'] = {
|
765
|
-
"default" => newtree
|
766
761
|
}
|
762
|
+
if newvals
|
763
|
+
newtree = data["subtree"].dup
|
764
|
+
newtree['default']['value'] = true if newtree['default']
|
765
|
+
data['subtree']['#entries'] = {
|
766
|
+
"default" => newtree
|
767
|
+
}
|
768
|
+
end
|
769
|
+
end
|
770
|
+
else
|
771
|
+
if $opts[(data['cli-opt']+"_given").to_sym]
|
772
|
+
newval = runValueCallback(data, $opts[data['cli-opt'].to_sym])
|
773
|
+
data["value"] = newval if !newval.nil?
|
774
|
+
$CHANGES.concat(data['changes']) if data['changes']
|
767
775
|
end
|
768
776
|
end
|
769
|
-
|
770
|
-
|
771
|
-
newval = runValueCallback(data, $opts[data['cli-opt'].to_sym])
|
772
|
-
data["value"] = newval if !newval.nil?
|
773
|
-
$CHANGES.concat(data['changes']) if data['changes']
|
774
|
-
end
|
775
|
-
end
|
776
|
-
}
|
777
|
-
end
|
777
|
+
}
|
778
|
+
end
|
778
779
|
|
779
780
|
|
780
|
-
def printVal(data)
|
781
|
-
|
782
|
-
|
781
|
+
def printVal(data)
|
782
|
+
valid = true
|
783
|
+
valid = validate(data["value"], data, false) if data["value"]
|
783
784
|
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
785
|
+
value = if data["value"] and data["value"] != ""
|
786
|
+
data["value"]
|
787
|
+
elsif data["default"] and data["default"] != ""
|
788
|
+
data["default"]
|
789
|
+
end
|
790
|
+
if data['readonly'] and value
|
791
|
+
print " - "+value.to_s.cyan.on_black
|
792
|
+
elsif !valid
|
793
|
+
print " "+data["value"].to_s.red.on_black
|
794
|
+
print " (consider default of #{data["default"].to_s.bold})" if data["default"]
|
795
|
+
elsif !data["value"].nil?
|
796
|
+
print " - "+data["value"].to_s.green.on_black
|
797
|
+
elsif data["required"]
|
798
|
+
print " - "+"REQUIRED".red.on_black
|
799
|
+
elsif !data["default"].nil?
|
800
|
+
print " - "+data["default"].to_s.yellow.on_black+" (DEFAULT)"
|
801
|
+
end
|
800
802
|
end
|
801
|
-
end
|
802
803
|
|
803
|
-
# Converts the current $CONFIGURABLES object to a Hash suitable for merging
|
804
|
-
# with $MU_CFG.
|
805
|
-
def setConfigTree(tree = $CONFIGURABLES)
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
804
|
+
# Converts the current $CONFIGURABLES object to a Hash suitable for merging
|
805
|
+
# with $MU_CFG.
|
806
|
+
def setConfigTree(tree = $CONFIGURABLES)
|
807
|
+
cfg = {}
|
808
|
+
tree.each_pair { |key, data|
|
809
|
+
next if !AMROOT and data['rootonly']
|
810
|
+
if data.has_key?("subtree")
|
811
|
+
if data["named_subentries"]
|
812
|
+
if data["subtree"]["#entries"]
|
813
|
+
data["subtree"]["#entries"].each_pair { |name, block|
|
814
|
+
|
815
|
+
next if !block.is_a?(Hash)
|
816
|
+
block.each_pair { |subkey, subdata|
|
817
|
+
next if subkey.match(/^#/) or !subdata.is_a?(Hash)
|
818
|
+
cfg[key] ||= {}
|
819
|
+
cfg[key][name] ||= {}
|
820
|
+
cfg[key][name][subkey] = subdata['value'] if subdata['value']
|
821
|
+
}
|
820
822
|
}
|
823
|
+
end
|
824
|
+
else
|
825
|
+
data["subtree"].each_pair { |subkey, subdata|
|
826
|
+
if !subdata["value"].nil?
|
827
|
+
cfg[key] ||= {}
|
828
|
+
cfg[key][subkey] = subdata["value"]
|
829
|
+
elsif !subdata["default"].nil? and !$HAVE_GLOBAL_CONFIG or ($MU_CFG and (!$MU_CFG[key] or !$MU_CFG[key][subkey]))
|
830
|
+
cfg[key] ||= {}
|
831
|
+
cfg[key][subkey] = subdata["default"]
|
832
|
+
end
|
821
833
|
}
|
822
834
|
end
|
823
|
-
|
824
|
-
data["
|
825
|
-
|
826
|
-
|
827
|
-
cfg[key][subkey] = subdata["value"]
|
828
|
-
elsif !subdata["default"].nil? and !$HAVE_GLOBAL_CONFIG or ($MU_CFG and (!$MU_CFG[key] or !$MU_CFG[key][subkey]))
|
829
|
-
cfg[key] ||= {}
|
830
|
-
cfg[key][subkey] = subdata["default"]
|
831
|
-
end
|
832
|
-
}
|
835
|
+
elsif !data["value"].nil?
|
836
|
+
cfg[key] = data["value"]
|
837
|
+
elsif !data["default"].nil? and !$HAVE_GLOBAL_CONFIG or ($MU_CFG and !$MU_CFG[key])
|
838
|
+
cfg[key] = data["default"]
|
833
839
|
end
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
cfg[key] = data["default"]
|
838
|
-
end
|
839
|
-
}
|
840
|
-
cfg
|
841
|
-
end
|
840
|
+
}
|
841
|
+
cfg
|
842
|
+
end
|
842
843
|
|
843
|
-
def displayCurrentOpts(tree = $CONFIGURABLES)
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
844
|
+
def displayCurrentOpts(tree = $CONFIGURABLES)
|
845
|
+
count = 1
|
846
|
+
optlist = []
|
847
|
+
tree.each_pair { |key, data|
|
848
|
+
next if !data.is_a?(Hash)
|
849
|
+
next if !AMROOT and data['rootonly']
|
850
|
+
if data["title"].nil? or data["#menu"].nil?
|
851
|
+
next
|
852
|
+
end
|
853
|
+
print data["#menu"].bold+") "+data["title"]
|
854
|
+
if data.has_key?("subtree")
|
855
|
+
puts ""
|
856
|
+
if data["named_subentries"]
|
857
|
+
if data['subtree']['#entries']
|
858
|
+
data['subtree']['#entries'].each_pair { |nameentry, subdata|
|
859
|
+
next if nameentry.match(/^#/)
|
860
|
+
puts " "+subdata["#menu"].bold+". "+nameentry.green.on_black
|
861
|
+
}
|
862
|
+
end
|
863
|
+
else
|
864
|
+
data["subtree"].each_pair { |subkey, subdata|
|
865
|
+
next if !AMROOT and subdata['rootonly']
|
866
|
+
print " "+subdata["#menu"].bold+". "+subdata["title"]
|
867
|
+
printVal(subdata)
|
868
|
+
puts ""
|
860
869
|
}
|
861
870
|
end
|
862
871
|
else
|
863
|
-
data
|
864
|
-
|
865
|
-
print " "+subdata["#menu"].bold+". "+subdata["title"]
|
866
|
-
printVal(subdata)
|
867
|
-
puts ""
|
868
|
-
}
|
872
|
+
printVal(data)
|
873
|
+
puts ""
|
869
874
|
end
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
count = count + 1
|
875
|
-
}
|
876
|
-
optlist
|
877
|
-
end
|
875
|
+
count = count + 1
|
876
|
+
}
|
877
|
+
optlist
|
878
|
+
end
|
878
879
|
|
879
|
-
###############################################################################
|
880
|
-
|
881
|
-
trap("INT"){ puts "" ; exit }
|
882
|
-
importCurrentValues if !$INITIALIZE or $HAVE_GLOBAL_CONFIG or $IN_GEM
|
883
|
-
importCLIValues
|
884
|
-
setDefaults
|
885
|
-
assignMenuEntries # populates $MENU_MAP
|
886
|
-
|
887
|
-
def ask(desc)
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
880
|
+
###############################################################################
|
881
|
+
|
882
|
+
trap("INT"){ puts "" ; exit }
|
883
|
+
importCurrentValues if !$INITIALIZE or $HAVE_GLOBAL_CONFIG or $IN_GEM
|
884
|
+
importCLIValues
|
885
|
+
setDefaults
|
886
|
+
assignMenuEntries # populates $MENU_MAP
|
887
|
+
|
888
|
+
def ask(desc)
|
889
|
+
puts ""
|
890
|
+
puts (desc['required'] ? "REQUIRED".red.on_black : "OPTIONAL".yellow.on_black)+" - "+desc["desc"]
|
891
|
+
puts "Enter one or more values, separated by commas".yellow.on_black if desc['array']
|
892
|
+
puts "Enter 0 or false, 1 or true".yellow.on_black if desc['boolean']
|
893
|
+
prompt = desc["title"].bold + "> "
|
894
|
+
current = desc['value'] || desc['default']
|
895
|
+
if current
|
896
|
+
current = current.join(", ") if desc['array'] and current.is_a?(Array)
|
897
|
+
Readline.pre_input_hook = -> do
|
898
|
+
Readline.insert_text current.to_s
|
899
|
+
Readline.redisplay
|
900
|
+
Readline.pre_input_hook = nil
|
901
|
+
end
|
902
|
+
end
|
903
|
+
val = Readline.readline(prompt, false)
|
904
|
+
if desc['array'] and !val.nil?
|
905
|
+
val = val.strip.split(/\s*,\s*/)
|
900
906
|
end
|
907
|
+
if desc['boolean']
|
908
|
+
val = false if ["0", "false", "FALSE"].include?(val)
|
909
|
+
val = true if ["1", "true", "TRUE"].include?(val)
|
901
910
|
end
|
902
|
-
|
903
|
-
|
904
|
-
val
|
905
|
-
end
|
906
|
-
if desc['boolean']
|
907
|
-
val = false if ["0", "false", "FALSE"].include?(val)
|
908
|
-
val = true if ["1", "true", "TRUE"].include?(val)
|
911
|
+
val = runValueCallback(desc, val)
|
912
|
+
val = current if val.nil? and desc['value']
|
913
|
+
val
|
909
914
|
end
|
910
|
-
val = runValueCallback(desc, val)
|
911
|
-
val = current if val.nil? and desc['value']
|
912
|
-
val
|
913
|
-
end
|
914
915
|
|
915
|
-
def validate(newval, reqs, addnewline = true, in_use: [])
|
916
|
-
ok = true
|
917
|
-
def validate_individual_value(newval, reqs, addnewline, in_use: [])
|
916
|
+
def validate(newval, reqs, addnewline = true, in_use: [])
|
918
917
|
ok = true
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
elsif reqs['pattern']
|
928
|
-
if newval.nil?
|
929
|
-
puts "\nSupplied value for #{reqs['title'].bold} did not pass validation".light_red.on_black
|
918
|
+
def validate_individual_value(newval, reqs, addnewline, in_use: [])
|
919
|
+
ok = true
|
920
|
+
if reqs['boolean'] and newval != true and newval != false and newval != nil
|
921
|
+
puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must be true or false)".light_red.on_black
|
922
|
+
puts "\n\n" if addnewline
|
923
|
+
ok = false
|
924
|
+
elsif in_use and in_use.size > 0 and in_use.include?(newval)
|
925
|
+
puts "\n##{reqs['title'].bold} #{newval} not available".light_red.on_black
|
930
926
|
puts "\n\n" if addnewline
|
931
927
|
ok = false
|
932
|
-
elsif reqs['
|
933
|
-
if newval.
|
934
|
-
puts "\
|
928
|
+
elsif reqs['pattern']
|
929
|
+
if newval.nil?
|
930
|
+
puts "\nSupplied value for #{reqs['title'].bold} did not pass validation".light_red.on_black
|
931
|
+
puts "\n\n" if addnewline
|
932
|
+
ok = false
|
933
|
+
elsif reqs['negate_pattern']
|
934
|
+
if newval.to_s.match(reqs['pattern'])
|
935
|
+
puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must NOT match #{reqs['pattern']})".light_red.on_black
|
936
|
+
puts "\n\n" if addnewline
|
937
|
+
ok = false
|
938
|
+
end
|
939
|
+
elsif !newval.to_s.match(reqs['pattern'])
|
940
|
+
puts "\nInvalid value '#{newval.bold}' #{reqs['title'].bold} (must match #{reqs['pattern']})".light_red.on_black
|
935
941
|
puts "\n\n" if addnewline
|
936
942
|
ok = false
|
937
943
|
end
|
938
|
-
elsif !newval.to_s.match(reqs['pattern'])
|
939
|
-
puts "\nInvalid value '#{newval.bold}' #{reqs['title'].bold} (must match #{reqs['pattern']})".light_red.on_black
|
940
|
-
puts "\n\n" if addnewline
|
941
|
-
ok = false
|
942
944
|
end
|
945
|
+
ok
|
943
946
|
end
|
944
|
-
ok
|
945
|
-
end
|
946
947
|
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
948
|
+
if reqs['array']
|
949
|
+
if !newval.is_a?(Array)
|
950
|
+
puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (should be an array)".light_red.on_black
|
951
|
+
puts "\n\n" if addnewline
|
952
|
+
ok = false
|
953
|
+
else
|
954
|
+
newval.each { |v|
|
955
|
+
ok = false if !validate_individual_value(v, reqs, addnewline, in_use: in_use)
|
956
|
+
}
|
957
|
+
end
|
952
958
|
else
|
953
|
-
newval
|
954
|
-
ok = false if !validate_individual_value(v, reqs, addnewline, in_use: in_use)
|
955
|
-
}
|
959
|
+
ok = false if !validate_individual_value(newval, reqs, addnewline, in_use: in_use)
|
956
960
|
end
|
957
|
-
|
958
|
-
ok = false if !validate_individual_value(newval, reqs, addnewline, in_use: in_use)
|
961
|
+
ok
|
959
962
|
end
|
960
|
-
ok
|
961
|
-
end
|
962
963
|
|
963
|
-
answer = nil
|
964
|
-
changed = false
|
964
|
+
answer = nil
|
965
|
+
changed = false
|
965
966
|
|
966
|
-
def entireConfigValid?
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
967
|
+
def entireConfigValid?
|
968
|
+
ok = true
|
969
|
+
$CONFIGURABLES.each_pair { |key, data|
|
970
|
+
next if !AMROOT and data['rootonly']
|
971
|
+
if data.has_key?("subtree")
|
972
|
+
data["subtree"].each_pair { |subkey, subdata|
|
973
|
+
next if !AMROOT and subdata['rootonly']
|
974
|
+
next if !data["value"]
|
975
|
+
ok = false if !validate(data["value"], data, false)
|
976
|
+
}
|
977
|
+
else
|
973
978
|
next if !data["value"]
|
974
979
|
ok = false if !validate(data["value"], data, false)
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
end
|
980
|
-
}
|
981
|
-
ok
|
982
|
-
end
|
980
|
+
end
|
981
|
+
}
|
982
|
+
ok
|
983
|
+
end
|
983
984
|
|
984
|
-
def generateMiniMenu(srctree)
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
end
|
985
|
+
def generateMiniMenu(srctree)
|
986
|
+
map = {}
|
987
|
+
tree = cloneHash(srctree)
|
988
|
+
return [tree, map]
|
989
|
+
end
|
989
990
|
|
990
|
-
def menu(tree = $CONFIGURABLES, map = $MENU_MAP, submenu_name = nil, in_use_names = [])
|
991
|
-
begin
|
992
|
-
optlist = displayCurrentOpts(tree)
|
991
|
+
def menu(tree = $CONFIGURABLES, map = $MENU_MAP, submenu_name = nil, in_use_names = [])
|
993
992
|
begin
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
993
|
+
optlist = displayCurrentOpts(tree)
|
994
|
+
begin
|
995
|
+
if submenu_name
|
996
|
+
print "Enter an option to change, "+"O".bold+" to save #{submenu_name.bold}, or "+"q".bold+" to return.\n> "
|
997
|
+
else
|
998
|
+
print "Enter an option to change, "+"O".bold+" to save this config, or "+"^D".bold+" to quit.\n> "
|
999
|
+
end
|
1000
|
+
answer = gets
|
1001
|
+
if answer.nil?
|
1002
|
+
puts ""
|
1003
|
+
exit 0
|
1004
|
+
end
|
1005
|
+
answer.strip!
|
1006
|
+
rescue EOFError
|
1001
1007
|
puts ""
|
1002
1008
|
exit 0
|
1003
1009
|
end
|
1004
|
-
answer.strip!
|
1005
|
-
rescue EOFError
|
1006
|
-
puts ""
|
1007
|
-
exit 0
|
1008
|
-
end
|
1009
1010
|
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1011
|
+
if map.has_key?(answer) and map[answer]["#addnew"]
|
1012
|
+
minimap = {}
|
1013
|
+
assignMenuEntries(map[answer], minimap)
|
1014
|
+
newtree, newmap = menu(
|
1015
|
+
map[answer],
|
1016
|
+
minimap,
|
1017
|
+
map[answer]['#title']+" (NEW)",
|
1018
|
+
if map[answer]['#entries']
|
1019
|
+
map[answer]['#entries'].keys.reject { |k| k.match(/^#/) }
|
1020
|
+
end
|
1021
|
+
)
|
1022
|
+
if newtree
|
1023
|
+
newname = newtree["name"]["value"]
|
1024
|
+
newtree.delete("#addnew")
|
1025
|
+
parentname = map[answer]['#key']
|
1026
|
+
|
1027
|
+
tree[parentname]['subtree'] ||= {}
|
1028
|
+
tree[parentname]['subtree']['#entries'] ||= {}
|
1029
|
+
# if we're in cloud land and just added a 2nd entry, set the original
|
1030
|
+
# one to 'default'
|
1031
|
+
if tree[parentname]['subtree']['#entries'].size == 1
|
1032
|
+
end
|
1033
|
+
tree[parentname]['subtree']['#entries'][newname] = cloneHash(newtree)
|
1034
|
+
|
1035
|
+
map = {} # rebuild the menu map to include new entries
|
1036
|
+
assignMenuEntries(tree, map)
|
1019
1037
|
end
|
1020
|
-
|
1021
|
-
if newtree
|
1022
|
-
|
1023
|
-
|
1038
|
+
# exit
|
1039
|
+
# map[answer] = newtree if newtree
|
1040
|
+
elsif map.has_key?(answer) and map[answer]["is_submenu"]
|
1041
|
+
minimap = {}
|
1024
1042
|
parentname = map[answer]['#key']
|
1025
|
-
|
1026
|
-
|
1027
|
-
tree[parentname]['subtree']['#entries']
|
1028
|
-
#
|
1029
|
-
|
1030
|
-
|
1043
|
+
entryname = map[answer]['#title']
|
1044
|
+
puts PP.pp(map[answer], '').yellow
|
1045
|
+
puts PP.pp(tree[parentname]['subtree']['#entries'][entryname], '').red
|
1046
|
+
assignMenuEntries(tree[parentname]['subtree']['#entries'][entryname], minimap)
|
1047
|
+
newtree, newmap = menu(
|
1048
|
+
map[answer],
|
1049
|
+
minimap,
|
1050
|
+
map[answer]["#title"],
|
1051
|
+
(map[answer]['#entries'].keys - [map[answer]['#title']])
|
1052
|
+
)
|
1053
|
+
map[answer] = newtree if newtree
|
1054
|
+
elsif map.has_key?(answer) and !map[answer].has_key?("subtree")
|
1055
|
+
newval = ask(map[answer])
|
1056
|
+
if !validate(newval, map[answer], in_use: in_use_names)
|
1057
|
+
sleep 1
|
1058
|
+
next
|
1031
1059
|
end
|
1032
|
-
|
1033
|
-
|
1034
|
-
map
|
1035
|
-
|
1036
|
-
|
1037
|
-
#
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
map[answer],
|
1048
|
-
minimap,
|
1049
|
-
map[answer]["#title"],
|
1050
|
-
(map[answer]['#entries'].keys - [map[answer]['#title']])
|
1051
|
-
)
|
1052
|
-
map[answer] = newtree if newtree
|
1053
|
-
elsif map.has_key?(answer) and !map[answer].has_key?("subtree")
|
1054
|
-
newval = ask(map[answer])
|
1055
|
-
if !validate(newval, map[answer], in_use: in_use_names)
|
1060
|
+
map[answer]['value'] = newval == "" ? nil : newval
|
1061
|
+
tree[map[answer]['#key']]['value'] = newval
|
1062
|
+
$CHANGES.concat(map[answer]['changes']) if map[answer].include?("changes")
|
1063
|
+
if map[answer]['title'] == "Local Hostname"
|
1064
|
+
# $CONFIGURABLES["aws"]["subtree"]["log_bucket_name"]["default"] = newval
|
1065
|
+
# $CONFIGURABLES["google"]["subtree"]["log_bucket_name"]["default"] = newval
|
1066
|
+
elsif map[answer]['title'] == "Public Address"
|
1067
|
+
$CONFIGURABLES["banner"]["default"] = "Mu Master at #{newval}"
|
1068
|
+
end
|
1069
|
+
changed = true
|
1070
|
+
puts ""
|
1071
|
+
elsif ["q", "Q"].include?(answer)
|
1072
|
+
return nil
|
1073
|
+
elsif !["", "0", "O", "o"].include?(answer)
|
1074
|
+
puts "\nInvalid option '#{answer.bold}'".light_red.on_black+"\n\n"
|
1056
1075
|
sleep 1
|
1057
|
-
|
1058
|
-
|
1059
|
-
map[answer]['value'] = newval == "" ? nil : newval
|
1060
|
-
tree[map[answer]['#key']]['value'] = newval
|
1061
|
-
$CHANGES.concat(map[answer]['changes']) if map[answer].include?("changes")
|
1062
|
-
if map[answer]['title'] == "Local Hostname"
|
1063
|
-
# $CONFIGURABLES["aws"]["subtree"]["log_bucket_name"]["default"] = newval
|
1064
|
-
# $CONFIGURABLES["google"]["subtree"]["log_bucket_name"]["default"] = newval
|
1065
|
-
elsif map[answer]['title'] == "Public Address"
|
1066
|
-
$CONFIGURABLES["banner"]["default"] = "Mu Master at #{newval}"
|
1076
|
+
else
|
1077
|
+
answer = nil if !entireConfigValid?
|
1067
1078
|
end
|
1068
|
-
|
1069
|
-
puts ""
|
1070
|
-
elsif ["q", "Q"].include?(answer)
|
1071
|
-
return nil
|
1072
|
-
elsif !["", "0", "O", "o"].include?(answer)
|
1073
|
-
puts "\nInvalid option '#{answer.bold}'".light_red.on_black+"\n\n"
|
1074
|
-
sleep 1
|
1075
|
-
else
|
1076
|
-
answer = nil if !entireConfigValid?
|
1077
|
-
end
|
1078
|
-
end while answer != "0" and answer != "O" and answer != "o"
|
1079
|
+
end while answer != "0" and answer != "O" and answer != "o"
|
1079
1080
|
|
1080
|
-
|
1081
|
-
end
|
1081
|
+
return [tree, map]
|
1082
|
+
end
|
1082
1083
|
|
1083
|
-
if !$opts[:noninteractive]
|
1084
|
-
|
1085
|
-
|
1086
|
-
else
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1084
|
+
if !$opts[:noninteractive]
|
1085
|
+
$CONFIGURABLES, $MENU_MAP = menu
|
1086
|
+
$MU_CFG = setConfigTree
|
1087
|
+
else
|
1088
|
+
$MU_CFG = setConfigTree
|
1089
|
+
if !entireConfigValid?
|
1090
|
+
puts "Configuration had validation errors, exiting.\nRe-invoke #{$0} to correct."
|
1091
|
+
exit 1
|
1092
|
+
end
|
1091
1093
|
end
|
1092
|
-
end
|
1093
1094
|
|
1094
|
-
if AMROOT
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
end
|
1095
|
+
if AMROOT
|
1096
|
+
newcfg = cloneHash($MU_CFG)
|
1097
|
+
require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
|
1098
|
+
newcfg['multiuser'] = true
|
1099
|
+
saveMuConfig(newcfg)
|
1100
|
+
$MU_CFG = loadMuConfig($MU_SET_DEFAULTS)
|
1101
|
+
end
|
1101
1102
|
|
1102
|
-
def set389DSCreds
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1103
|
+
def set389DSCreds
|
1104
|
+
require 'mu'
|
1105
|
+
credlist = {
|
1106
|
+
"bind_creds" => {
|
1107
|
+
"user" => "CN=mu_bind_creds,#{$MU_CFG["ldap"]['user_ou']}"
|
1108
|
+
},
|
1109
|
+
"join_creds" => {
|
1110
|
+
"user" => "CN=mu_join_creds,#{$MU_CFG["ldap"]['user_ou']}"
|
1111
|
+
},
|
1112
|
+
"cfg_directory_adm" => {
|
1113
|
+
"user" => "admin"
|
1114
|
+
},
|
1115
|
+
"root_dn_user" => {
|
1116
|
+
"user" => "CN=root_dn_user"
|
1117
|
+
}
|
1116
1118
|
}
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1119
|
+
credlist.each_pair { |creds, cfg|
|
1120
|
+
begin
|
1121
|
+
data = nil
|
1122
|
+
if $MU_CFG["ldap"].has_key?(creds)
|
1123
|
+
data = MU::Groomer::Chef.getSecret(
|
1124
|
+
vault: $MU_CFG["ldap"][creds]["vault"],
|
1125
|
+
item: $MU_CFG["ldap"][creds]["item"]
|
1126
|
+
)
|
1127
|
+
MU::Groomer::Chef.grantSecretAccess("MU-MASTER", $MU_CFG["ldap"][creds]["vault"], $MU_CFG["ldap"][creds]["item"])
|
1128
|
+
else
|
1129
|
+
data = MU::Groomer::Chef.getSecret(vault: "mu_ldap", item: creds)
|
1130
|
+
MU::Groomer::Chef.grantSecretAccess("MU-MASTER", "mu_ldap", creds)
|
1131
|
+
end
|
1132
|
+
rescue MU::Groomer::MuNoSuchSecret
|
1133
|
+
user = cfg["user"]
|
1134
|
+
pw = Password.pronounceable(14..16)
|
1135
|
+
if $MU_CFG["ldap"].has_key?(creds)
|
1136
|
+
data = {
|
1137
|
+
$MU_CFG["ldap"][creds]["username_field"] => user,
|
1138
|
+
$MU_CFG["ldap"][creds]["password_field"] => pw
|
1139
|
+
}
|
1140
|
+
MU::Groomer::Chef.saveSecret(
|
1141
|
+
vault: $MU_CFG["ldap"][creds]["vault"],
|
1142
|
+
item: $MU_CFG["ldap"][creds]["item"],
|
1143
|
+
data: data,
|
1144
|
+
permissions: "name:MU-MASTER"
|
1145
|
+
)
|
1146
|
+
else
|
1147
|
+
MU::Groomer::Chef.saveSecret(
|
1148
|
+
vault: "mu_ldap",
|
1149
|
+
item: creds,
|
1150
|
+
data: { "username" => user, "password" => pw },
|
1151
|
+
permissions: "name:MU-MASTER"
|
1152
|
+
)
|
1153
|
+
end
|
1152
1154
|
end
|
1153
|
-
end
|
1154
|
-
}
|
1155
|
-
end
|
1156
|
-
|
1157
|
-
if AMROOT and !$IN_GEM
|
1158
|
-
cur_chef_version = `/bin/rpm -q chef`.sub(/^chef-(\d+\.\d+\.\d+-\d+)\..*/, '\1').chomp
|
1159
|
-
pref_chef_version = File.read("#{MU_BASE}/var/mu-chef-client-version").chomp
|
1160
|
-
if (cur_chef_version != pref_chef_version and cur_chef_version.sub(/\-\d+$/, "") != pref_chef_version) or cur_chef_version.match(/is not installed/)
|
1161
|
-
puts "Updating MU-MASTER's Chef Client to '#{pref_chef_version}' from '#{cur_chef_version}'"
|
1162
|
-
chef_installer = open("https://omnitruck.chef.io/install.sh").read
|
1163
|
-
File.open("#{HOMEDIR}/chef-install.sh", File::CREAT|File::TRUNC|File::RDWR, 0644){ |f|
|
1164
|
-
f.puts chef_installer
|
1165
1155
|
}
|
1166
|
-
system("/bin/rm -rf /opt/chef ; sh #{HOMEDIR}/chef-install.sh -v #{pref_chef_version}");
|
1167
|
-
# This will go fix gems, permissions, etc
|
1168
|
-
system("/opt/chef/bin/chef-apply #{MU_BASE}/lib/cookbooks/mu-master/recipes/init.rb");
|
1169
1156
|
end
|
1170
|
-
end
|
1171
1157
|
|
1172
|
-
if $INITIALIZE
|
1173
1158
|
if AMROOT and !$IN_GEM
|
1174
|
-
|
1159
|
+
cur_chef_version = `/bin/rpm -q chef`.sub(/^chef-(\d+\.\d+\.\d+-\d+)\..*/, '\1').chomp
|
1160
|
+
pref_chef_version = File.read("#{MU_BASE}/var/mu-chef-client-version").chomp
|
1161
|
+
if (cur_chef_version != pref_chef_version and cur_chef_version.sub(/\-\d+$/, "") != pref_chef_version) or cur_chef_version.match(/is not installed/)
|
1162
|
+
puts "Updating MU-MASTER's Chef Client to '#{pref_chef_version}' from '#{cur_chef_version}'"
|
1163
|
+
chef_installer = open("https://omnitruck.chef.io/install.sh").read
|
1164
|
+
File.open("#{HOMEDIR}/chef-install.sh", File::CREAT|File::TRUNC|File::RDWR, 0644){ |f|
|
1165
|
+
f.puts chef_installer
|
1166
|
+
}
|
1167
|
+
system("/bin/rm -rf /opt/chef ; sh #{HOMEDIR}/chef-install.sh -v #{pref_chef_version}");
|
1168
|
+
# This will go fix gems, permissions, etc
|
1169
|
+
system("/opt/chef/bin/chef-apply #{MU_BASE}/lib/cookbooks/mu-master/recipes/init.rb");
|
1170
|
+
end
|
1175
1171
|
end
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
$
|
1172
|
+
|
1173
|
+
if $INITIALIZE
|
1174
|
+
if AMROOT and !$IN_GEM
|
1175
|
+
%x{/sbin/service iptables stop} # Chef run will set up correct rules later
|
1176
|
+
end
|
1177
|
+
$MU_SET_DEFAULTS = setConfigTree
|
1178
|
+
require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
|
1179
|
+
saveMuConfig($MU_SET_DEFAULTS)
|
1182
1180
|
else
|
1183
|
-
|
1181
|
+
if AMROOT
|
1182
|
+
$NEW_CFG = $MU_CFG.merge(setConfigTree)
|
1183
|
+
else
|
1184
|
+
$NEW_CFG = setConfigTree
|
1185
|
+
end
|
1186
|
+
saveMuConfig($NEW_CFG)
|
1187
|
+
$MU_CFG = $MU_CFG.merge(setConfigTree)
|
1188
|
+
require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
|
1184
1189
|
end
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
exit 1
|
1194
|
-
rescue LoadError
|
1195
|
-
system("cd #{MU_BASE}/lib/modules && umask 0022 && /usr/local/ruby-current/bin/bundle install")
|
1196
|
-
require 'mu'
|
1197
|
-
end
|
1198
|
-
exit
|
1199
|
-
if $IN_GEM
|
1200
|
-
if $INITIALIZE
|
1201
|
-
$MU_CFG = MU.detectCloudProviders
|
1190
|
+
begin
|
1191
|
+
require 'mu'
|
1192
|
+
rescue MU::MuError => e
|
1193
|
+
puts "Correct the above error before proceeding. To retry, run:\n\n#{$0.bold} #{ARGV.join(" ").bold}"
|
1194
|
+
exit 1
|
1195
|
+
rescue LoadError
|
1196
|
+
system("cd #{MU_BASE}/lib/modules && umask 0022 && /usr/local/ruby-current/bin/bundle install")
|
1197
|
+
require 'mu'
|
1202
1198
|
end
|
1203
|
-
require 'mu/master/ssl'
|
1204
|
-
MU::Master::SSL.bootstrap
|
1205
|
-
puts $MU_CFG.to_yaml
|
1206
|
-
saveMuConfig($MU_CFG)
|
1207
|
-
MU::MommaCat.restart
|
1208
|
-
exit
|
1209
|
-
end
|
1210
1199
|
|
1211
|
-
if
|
1212
|
-
|
1213
|
-
|
1200
|
+
if $IN_GEM
|
1201
|
+
if $INITIALIZE
|
1202
|
+
$MU_CFG = MU.detectCloudProviders
|
1203
|
+
end
|
1204
|
+
require 'mu/master/ssl'
|
1205
|
+
MU::Master::SSL.bootstrap
|
1206
|
+
puts $MU_CFG.to_yaml
|
1207
|
+
saveMuConfig($MU_CFG)
|
1208
|
+
MU::MommaCat.restart
|
1209
|
+
exit
|
1210
|
+
end
|
1214
1211
|
|
1215
|
-
|
1216
|
-
|
1217
|
-
# local firewall ports).
|
1218
|
-
if AMROOT and ($INITIALIZE or $CHANGES.include?("chefartifacts"))
|
1219
|
-
MU.log "Purging and re-uploading all Chef artifacts", MU::NOTICE
|
1220
|
-
%x{/sbin/service iptables stop} if $INITIALIZE
|
1221
|
-
output = %x{MU_INSTALLDIR=#{MU_BASE} MU_LIBDIR=#{MU_BASE}/lib MU_DATADIR=#{MU_BASE}/var #{MU_BASE}/lib/bin/mu-upload-chef-artifacts}
|
1222
|
-
if $?.exitstatus != 0
|
1223
|
-
puts output
|
1224
|
-
MU.log "mu-upload-chef-artifacts failed, can't proceed", MU::ERR
|
1225
|
-
%x{/sbin/service iptables start} if !$INITIALIZE
|
1226
|
-
exit 1
|
1212
|
+
if AMROOT and ($INITIALIZE or $CHANGES.include?("hostname"))
|
1213
|
+
system("/bin/hostname #{$MU_CFG['hostname']}")
|
1227
1214
|
end
|
1228
|
-
%x{/sbin/service iptables start} if !$INITIALIZE
|
1229
|
-
end
|
1230
1215
|
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1216
|
+
# Do some more basic-but-Chef-dependent configuration *before* we meddle with
|
1217
|
+
# the Chef Server configuration, which depends on some of this (SSL certs and
|
1218
|
+
# local firewall ports).
|
1219
|
+
if AMROOT and ($INITIALIZE or $CHANGES.include?("chefartifacts"))
|
1220
|
+
MU.log "Purging and re-uploading all Chef artifacts", MU::NOTICE
|
1221
|
+
%x{/sbin/service iptables stop} if $INITIALIZE
|
1222
|
+
output = %x{MU_INSTALLDIR=#{MU_BASE} MU_LIBDIR=#{MU_BASE}/lib MU_DATADIR=#{MU_BASE}/var #{MU_BASE}/lib/bin/mu-upload-chef-artifacts}
|
1223
|
+
if $?.exitstatus != 0
|
1224
|
+
puts output
|
1225
|
+
MU.log "mu-upload-chef-artifacts failed, can't proceed", MU::ERR
|
1226
|
+
%x{/sbin/service iptables start} if !$INITIALIZE
|
1227
|
+
exit 1
|
1228
|
+
end
|
1229
|
+
%x{/sbin/service iptables start} if !$INITIALIZE
|
1230
|
+
end
|
1235
1231
|
|
1236
|
-
if AMROOT
|
1237
|
-
|
1238
|
-
|
1239
|
-
MU.log "Got bad exit code trying to run recipe[mu-master::ssl-certs]', aborting", MU::ERR
|
1240
|
-
exit 1
|
1232
|
+
if $INITIALIZE and AMROOT
|
1233
|
+
MU.log "Force open key firewall holes", MU::NOTICE
|
1234
|
+
system("chef-client -o 'recipe[mu-master::firewall-holes]'")
|
1241
1235
|
end
|
1242
|
-
end
|
1243
1236
|
|
1244
|
-
def updateChefRbs
|
1245
|
-
user = AMROOT ? "mu" : Etc.getpwuid(Process.uid).name
|
1246
|
-
chefuser = user.gsub(/\./, "")
|
1247
|
-
templates = { HOMEDIR+"/.chef/knife.rb" => KNIFE_TEMPLATE }
|
1248
|
-
Dir.mkdir(HOMEDIR+"/.chef") if !Dir.exist?(HOMEDIR+"/.chef")
|
1249
1237
|
if AMROOT
|
1250
|
-
|
1251
|
-
|
1238
|
+
MU.log "Checking internal SSL signing authority and certificates", MU::NOTICE
|
1239
|
+
if !system("chef-client -o 'recipe[mu-master::ssl-certs]'") and $INITIALIZE
|
1240
|
+
MU.log "Got bad exit code trying to run recipe[mu-master::ssl-certs]', aborting", MU::ERR
|
1241
|
+
exit 1
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
def updateChefRbs
|
1246
|
+
user = AMROOT ? "mu" : Etc.getpwuid(Process.uid).name
|
1247
|
+
chefuser = user.gsub(/\./, "")
|
1248
|
+
templates = { HOMEDIR+"/.chef/knife.rb" => KNIFE_TEMPLATE }
|
1249
|
+
Dir.mkdir(HOMEDIR+"/.chef") if !Dir.exist?(HOMEDIR+"/.chef")
|
1250
|
+
if AMROOT
|
1251
|
+
templates["/etc/chef/client.rb"] = CLIENT_TEMPLATE
|
1252
|
+
templates["/etc/opscode/pivotal.rb"] = PIVOTAL_TEMPLATE
|
1253
|
+
end
|
1254
|
+
templates.each_pair { |file, template|
|
1255
|
+
erb = ERB.new(template)
|
1256
|
+
processed = erb.result(binding)
|
1257
|
+
tmpfile = file+".tmp."+Process.pid.to_s
|
1258
|
+
File.open(tmpfile, File::CREAT|File::TRUNC|File::RDWR, 0644){ |f|
|
1259
|
+
f.puts processed
|
1260
|
+
}
|
1261
|
+
if !File.size?(file) or File.read(tmpfile) != File.read(file)
|
1262
|
+
File.rename(tmpfile, file)
|
1263
|
+
MU.log "Updated #{file}", MU::NOTICE
|
1264
|
+
$CHANGES << "chefcerts"
|
1265
|
+
else
|
1266
|
+
File.unlink(tmpfile)
|
1267
|
+
end
|
1268
|
+
}
|
1252
1269
|
end
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1270
|
+
|
1271
|
+
|
1272
|
+
if AMROOT
|
1273
|
+
erb = ERB.new(File.read("#{MU_BASE}/lib/cookbooks/mu-master/templates/default/chef-server.rb.erb"))
|
1274
|
+
updated_server_cfg = erb.result(binding)
|
1275
|
+
cfgpath = "/etc/opscode/chef-server.rb"
|
1276
|
+
tmpfile = "/etc/opscode/chef-server.rb.#{Process.pid}"
|
1257
1277
|
File.open(tmpfile, File::CREAT|File::TRUNC|File::RDWR, 0644){ |f|
|
1258
|
-
f.puts
|
1278
|
+
f.puts updated_server_cfg
|
1259
1279
|
}
|
1260
|
-
if !File.size?(
|
1261
|
-
File.rename(tmpfile,
|
1262
|
-
|
1280
|
+
if !File.size?(cfgpath) or File.read(tmpfile) != File.read(cfgpath)
|
1281
|
+
File.rename(tmpfile, cfgpath)
|
1282
|
+
# Opscode can't seem to get things right with their postgres socket
|
1283
|
+
Dir.mkdir("/var/run/postgresql", 0755) if !Dir.exist?("/var/run/postgresql")
|
1284
|
+
if File.exist?("/tmp/.s.PGSQL.5432") and !File.exist?("/var/run/postgresql/.s.PGSQL.5432")
|
1285
|
+
File.symlink("/tmp/.s.PGSQL.5432", "/var/run/postgresql/.s.PGSQL.5432")
|
1286
|
+
elsif !File.exist?("/tmp/.s.PGSQL.5432") and File.exist?("/var/run/postgresql/.s.PGSQL.5432")
|
1287
|
+
File.symlink("/var/run/postgresql/.s.PGSQL.5432", "/tmp/.s.PGSQL.5432")
|
1288
|
+
end
|
1289
|
+
MU.log "Chef Server config was modified, reconfiguring...", MU::NOTICE
|
1290
|
+
# XXX Some undocumented port Chef needs only on startup is being blocked by
|
1291
|
+
# iptables. Something rabbitmq-related. Dopey workaround.
|
1292
|
+
%x{/sbin/service iptables stop}
|
1293
|
+
system("/opt/opscode/bin/chef-server-ctl reconfigure")
|
1294
|
+
system("/opt/opscode/bin/chef-server-ctl restart")
|
1295
|
+
%x{/sbin/service iptables start} if !$INITIALIZE
|
1296
|
+
updateChefRbs
|
1263
1297
|
$CHANGES << "chefcerts"
|
1264
1298
|
else
|
1265
1299
|
File.unlink(tmpfile)
|
1300
|
+
updateChefRbs
|
1266
1301
|
end
|
1267
|
-
}
|
1268
|
-
end
|
1269
|
-
|
1270
|
-
|
1271
|
-
if AMROOT
|
1272
|
-
erb = ERB.new(File.read("#{MU_BASE}/lib/cookbooks/mu-master/templates/default/chef-server.rb.erb"))
|
1273
|
-
updated_server_cfg = erb.result(binding)
|
1274
|
-
cfgpath = "/etc/opscode/chef-server.rb"
|
1275
|
-
tmpfile = "/etc/opscode/chef-server.rb.#{Process.pid}"
|
1276
|
-
File.open(tmpfile, File::CREAT|File::TRUNC|File::RDWR, 0644){ |f|
|
1277
|
-
f.puts updated_server_cfg
|
1278
|
-
}
|
1279
|
-
if !File.size?(cfgpath) or File.read(tmpfile) != File.read(cfgpath)
|
1280
|
-
File.rename(tmpfile, cfgpath)
|
1281
|
-
# Opscode can't seem to get things right with their postgres socket
|
1282
|
-
Dir.mkdir("/var/run/postgresql", 0755) if !Dir.exist?("/var/run/postgresql")
|
1283
|
-
if File.exist?("/tmp/.s.PGSQL.5432") and !File.exist?("/var/run/postgresql/.s.PGSQL.5432")
|
1284
|
-
File.symlink("/tmp/.s.PGSQL.5432", "/var/run/postgresql/.s.PGSQL.5432")
|
1285
|
-
elsif !File.exist?("/tmp/.s.PGSQL.5432") and File.exist?("/var/run/postgresql/.s.PGSQL.5432")
|
1286
|
-
File.symlink("/var/run/postgresql/.s.PGSQL.5432", "/tmp/.s.PGSQL.5432")
|
1287
|
-
end
|
1288
|
-
MU.log "Chef Server config was modified, reconfiguring...", MU::NOTICE
|
1289
|
-
# XXX Some undocumented port Chef needs only on startup is being blocked by
|
1290
|
-
# iptables. Something rabbitmq-related. Dopey workaround.
|
1291
|
-
%x{/sbin/service iptables stop}
|
1292
|
-
system("/opt/opscode/bin/chef-server-ctl reconfigure")
|
1293
|
-
system("/opt/opscode/bin/chef-server-ctl restart")
|
1294
|
-
%x{/sbin/service iptables start} if !$INITIALIZE
|
1295
|
-
updateChefRbs
|
1296
|
-
$CHANGES << "chefcerts"
|
1297
1302
|
else
|
1298
|
-
File.unlink(tmpfile)
|
1299
1303
|
updateChefRbs
|
1300
1304
|
end
|
1301
|
-
else
|
1302
|
-
updateChefRbs
|
1303
|
-
end
|
1304
|
-
|
1305
|
-
if $IN_AWS and AMROOT
|
1306
|
-
system("#{MU_BASE}/lib/bin/mu-aws-setup --dns --sg --logs --ephemeral")
|
1307
|
-
# XXX --ip? Do we really care?
|
1308
|
-
end
|
1309
|
-
if $IN_GOOGLE and AMROOT
|
1310
|
-
system("#{MU_BASE}/lib/bin/mu-gcp-setup --sg --logs")
|
1311
|
-
end
|
1312
|
-
if $IN_AZURE and AMROOT
|
1313
|
-
system("#{MU_BASE}/lib/bin/mu-azure-setup --sg")
|
1314
|
-
end
|
1315
1305
|
|
1316
|
-
if $
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1306
|
+
if $IN_AWS and AMROOT
|
1307
|
+
system("#{MU_BASE}/lib/bin/mu-aws-setup --dns --sg --logs --ephemeral")
|
1308
|
+
# XXX --ip? Do we really care?
|
1309
|
+
end
|
1310
|
+
if $IN_GOOGLE and AMROOT
|
1311
|
+
system("#{MU_BASE}/lib/bin/mu-gcp-setup --sg --logs")
|
1312
|
+
end
|
1313
|
+
if $IN_AZURE and AMROOT
|
1314
|
+
system("#{MU_BASE}/lib/bin/mu-azure-setup --sg")
|
1320
1315
|
end
|
1321
|
-
end
|
1322
1316
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
FileUtils.cp($MU_CFG['ssl']['chain'], HOMEDIR+"/.chef/trusted_certs/#{cert}")
|
1329
|
-
File.chmod(0600, HOMEDIR+"/.chef/trusted_certs/#{cert}")
|
1330
|
-
if AMROOT
|
1331
|
-
File.chmod(0644, $MU_CFG['ssl']['chain'])
|
1332
|
-
FileUtils.cp($MU_CFG['ssl']['chain'], "/etc/chef/trusted_certs/#{cert}")
|
1317
|
+
if $INITIALIZE or $CHANGES.include?("chefcerts")
|
1318
|
+
system("rm -f #{HOMEDIR}/.chef/trusted_certs/* ; knife ssl fetch -c #{HOMEDIR}/.chef/knife.rb")
|
1319
|
+
if AMROOT
|
1320
|
+
system("rm -f /etc/chef/trusted_certs/* ; knife ssl fetch -c /etc/chef/client.rb")
|
1321
|
+
end
|
1333
1322
|
end
|
1334
|
-
end
|
1335
1323
|
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
$
|
1324
|
+
# knife ssl fetch isn't bright enough to nab our intermediate certs, which
|
1325
|
+
# ironically becomes a problem when we use one from the real world. Jam it
|
1326
|
+
# into knife and chef-client's faces thusly:
|
1327
|
+
if $MU_CFG['ssl'] and $MU_CFG['ssl']['chain'] and File.size?($MU_CFG['ssl']['chain'])
|
1328
|
+
cert = File.basename($MU_CFG['ssl']['chain'])
|
1329
|
+
FileUtils.cp($MU_CFG['ssl']['chain'], HOMEDIR+"/.chef/trusted_certs/#{cert}")
|
1330
|
+
File.chmod(0600, HOMEDIR+"/.chef/trusted_certs/#{cert}")
|
1331
|
+
if AMROOT
|
1332
|
+
File.chmod(0644, $MU_CFG['ssl']['chain'])
|
1333
|
+
FileUtils.cp($MU_CFG['ssl']['chain'], "/etc/chef/trusted_certs/#{cert}")
|
1346
1334
|
end
|
1347
|
-
|
1348
|
-
end
|
1335
|
+
end
|
1349
1336
|
|
1350
|
-
if
|
1351
|
-
|
1352
|
-
|
1337
|
+
if $MU_CFG['repos'] and $MU_CFG['repos'].size > 0
|
1338
|
+
$MU_CFG['repos'].each { |repo|
|
1339
|
+
repo.match(/\/([^\/]+?)(\.git)?$/)
|
1340
|
+
shortname = Regexp.last_match(1)
|
1341
|
+
repodir = MU.dataDir + "/" + shortname
|
1342
|
+
if !Dir.exist?(repodir)
|
1343
|
+
MU.log "Cloning #{repo} into #{repodir}", MU::NOTICE
|
1344
|
+
Dir.chdir(MU.dataDir)
|
1345
|
+
system("/usr/bin/git clone #{repo}")
|
1346
|
+
$CHANGES << "chefartifacts"
|
1347
|
+
end
|
1348
|
+
}
|
1349
|
+
end
|
1353
1350
|
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
data = {
|
1358
|
-
"private_key" => File.read("#{MU_BASE}/var/ssl/consul.key"),
|
1359
|
-
"certificate" => File.read("#{MU_BASE}/var/ssl/consul.crt"),
|
1360
|
-
"ca_certificate" => File.read("#{MU_BASE}/var/ssl/Mu_CA.pem")
|
1361
|
-
}
|
1362
|
-
MU::Groomer::Chef.saveSecret(
|
1363
|
-
vault: "secrets",
|
1364
|
-
item: "consul",
|
1365
|
-
data: data,
|
1366
|
-
permissions: "name:MU-MASTER"
|
1367
|
-
)
|
1368
|
-
end
|
1369
|
-
if $INITIALIZE or $CHANGES.include?("vault")
|
1370
|
-
MU.log "Setting up Hashicorp Vault", MU::NOTICE
|
1371
|
-
system("chef-client -o 'recipe[mu-master::vault]'")
|
1372
|
-
end
|
1351
|
+
if !AMROOT
|
1352
|
+
exit
|
1353
|
+
end
|
1373
1354
|
|
1374
|
-
if $MU_CFG['ldap']['type'] == "389 Directory Services"
|
1375
1355
|
begin
|
1376
|
-
MU::
|
1377
|
-
rescue
|
1378
|
-
|
1356
|
+
MU::Groomer::Chef.getSecret(vault: "secrets", item: "consul")
|
1357
|
+
rescue MU::Groomer::MuNoSuchSecret
|
1358
|
+
data = {
|
1359
|
+
"private_key" => File.read("#{MU_BASE}/var/ssl/consul.key"),
|
1360
|
+
"certificate" => File.read("#{MU_BASE}/var/ssl/consul.crt"),
|
1361
|
+
"ca_certificate" => File.read("#{MU_BASE}/var/ssl/Mu_CA.pem")
|
1362
|
+
}
|
1363
|
+
MU::Groomer::Chef.saveSecret(
|
1364
|
+
vault: "secrets",
|
1365
|
+
item: "consul",
|
1366
|
+
data: data,
|
1367
|
+
permissions: "name:MU-MASTER"
|
1368
|
+
)
|
1379
1369
|
end
|
1380
|
-
if $INITIALIZE or $CHANGES.include?("
|
1381
|
-
|
1382
|
-
|
1383
|
-
set389DSCreds
|
1384
|
-
system("chef-client -o 'recipe[mu-master::389ds]'")
|
1385
|
-
exit 1 if $? != 0
|
1386
|
-
MU::Master::LDAP.initLocalLDAP
|
1387
|
-
system("chef-client -o 'recipe[mu-master::sssd]'")
|
1388
|
-
exit 1 if $? != 0
|
1370
|
+
if $INITIALIZE or $CHANGES.include?("vault")
|
1371
|
+
MU.log "Setting up Hashicorp Vault", MU::NOTICE
|
1372
|
+
system("chef-client -o 'recipe[mu-master::vault]'")
|
1389
1373
|
end
|
1390
|
-
end
|
1391
1374
|
|
1392
|
-
|
1393
|
-
|
1394
|
-
MU::
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
end
|
1375
|
+
if $MU_CFG['ldap']['type'] == "389 Directory Services"
|
1376
|
+
begin
|
1377
|
+
MU::Master::LDAP.listUsers
|
1378
|
+
rescue Exception => e # XXX lazy exception handling is lazy
|
1379
|
+
$CHANGES << "389ds"
|
1380
|
+
end
|
1381
|
+
if $INITIALIZE or $CHANGES.include?("389ds")
|
1382
|
+
File.unlink("/root/389ds.tmp/389-directory-setup.inf") if File.exist?("/root/389ds.tmp/389-directory-setup.inf")
|
1383
|
+
MU.log "Configuring 389 Directory Services", MU::NOTICE
|
1384
|
+
set389DSCreds
|
1385
|
+
system("chef-client -o 'recipe[mu-master::389ds]'")
|
1386
|
+
exit 1 if $? != 0
|
1387
|
+
MU::Master::LDAP.initLocalLDAP
|
1388
|
+
system("chef-client -o 'recipe[mu-master::sssd]'")
|
1389
|
+
exit 1 if $? != 0
|
1390
|
+
end
|
1391
|
+
end
|
1410
1392
|
|
1411
|
-
#
|
1412
|
-
|
1393
|
+
# Figure out if our run list is dumb
|
1394
|
+
MU.log "Verifying MU-MASTER's Chef run list", MU::NOTICE
|
1395
|
+
MU::Groomer::Chef.loadChefLib
|
1396
|
+
chef_node = ::Chef::Node.load("MU-MASTER")
|
1397
|
+
run_list = ["role[mu-master]"]
|
1398
|
+
run_list.concat($MU_CFG['master_runlist_extras']) if $MU_CFG['master_runlist_extras'].is_a?(Array)
|
1399
|
+
set_runlist = false
|
1400
|
+
run_list.each { |rl|
|
1401
|
+
set_runlist = true if !chef_node.run_list?(rl)
|
1402
|
+
}
|
1403
|
+
if set_runlist
|
1404
|
+
MU.log "Updating MU-MASTER run_list", MU::NOTICE, details: run_list
|
1405
|
+
chef_node.run_list(run_list)
|
1406
|
+
chef_node.save
|
1407
|
+
$CHANGES << "chefrun"
|
1408
|
+
else
|
1409
|
+
MU.log "Chef run list looks correct", MU::NOTICE, details: run_list
|
1410
|
+
end
|
1413
1411
|
|
1414
|
-
|
1415
|
-
|
1416
|
-
MU.log "Generating YARD documentation in /var/www/html/docs (see http://#{$MU_CFG['public_address']}/docs/frames.html)"
|
1417
|
-
File.umask(0022)
|
1418
|
-
system("cd #{MU.myRoot} && umask 0022 && env -i PATH=#{ENV['PATH']} HOME=#{HOMEDIR} /usr/local/ruby-current/bin/yard doc modules -m markdown -o /var/www/html/docs && chcon -R -h -t httpd_sys_script_exec_t /var/www/html/")
|
1419
|
-
end
|
1412
|
+
# TODO here are some things we don't do yet but should
|
1413
|
+
# accommodate running as a non-root user
|
1420
1414
|
|
1415
|
+
if $INITIALIZE
|
1416
|
+
MU::Config.emitSchemaAsRuby
|
1417
|
+
MU.log "Generating YARD documentation in /var/www/html/docs (see http://#{$MU_CFG['public_address']}/docs/frames.html)"
|
1418
|
+
File.umask(0022)
|
1419
|
+
system("cd #{MU.myRoot} && umask 0022 && env -i PATH=#{ENV['PATH']} HOME=#{HOMEDIR} /usr/local/ruby-current/bin/yard doc modules -m markdown -o /var/www/html/docs && chcon -R -h -t httpd_sys_script_exec_t /var/www/html/")
|
1420
|
+
end
|
1421
1421
|
|
1422
|
-
MU.log "Running chef-client on MU-MASTER", MU::NOTICE
|
1423
|
-
system("chef-client -o '#{run_list.join(",")}'")
|
1424
1422
|
|
1423
|
+
MU.log "Running chef-client on MU-MASTER", MU::NOTICE
|
1424
|
+
system("chef-client -o '#{run_list.join(",")}'")
|
1425
1425
|
|
1426
|
-
if !File.exist?("#{MU_BASE}/var/users/mu/email") or !File.exist?("#{MU_BASE}/var/users/mu/realname")
|
1427
|
-
MU.log "Finalizing the 'mu' Chef/LDAP account", MU::NOTICE
|
1428
|
-
MU.setLogging(MU::Logger::SILENT)
|
1429
|
-
MU::Master.manageUser(
|
1430
|
-
"mu",
|
1431
|
-
name: $MU_CFG['mu_admin_name'],
|
1432
|
-
email: $MU_CFG['mu_admin_email'],
|
1433
|
-
admin: true,
|
1434
|
-
password: MU.generateWindowsPassword # we'll just overwrite this and do it with mu-user-manage below, which can do smart things with Scratchpad
|
1435
|
-
)
|
1436
|
-
MU.setLogging(MU::Logger::NORMAL)
|
1437
|
-
sleep 3 # avoid LDAP lag for mu-user-manage
|
1438
|
-
end
|
1439
1426
|
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1427
|
+
if !File.exist?("#{MU_BASE}/var/users/mu/email") or !File.exist?("#{MU_BASE}/var/users/mu/realname")
|
1428
|
+
MU.log "Finalizing the 'mu' Chef/LDAP account", MU::NOTICE
|
1429
|
+
MU.setLogging(MU::Logger::SILENT)
|
1430
|
+
MU::Master.manageUser(
|
1431
|
+
"mu",
|
1432
|
+
name: $MU_CFG['mu_admin_name'],
|
1433
|
+
email: $MU_CFG['mu_admin_email'],
|
1434
|
+
admin: true,
|
1435
|
+
password: MU.generateWindowsPassword # we'll just overwrite this and do it with mu-user-manage below, which can do smart things with Scratchpad
|
1436
|
+
)
|
1437
|
+
MU.setLogging(MU::Logger::NORMAL)
|
1438
|
+
sleep 3 # avoid LDAP lag for mu-user-manage
|
1439
|
+
end
|
1449
1440
|
|
1450
|
-
|
1451
|
-
|
1441
|
+
output = %x{/opt/chef/bin/knife vault show scratchpad 2>&1}
|
1442
|
+
if $?.exitstatus != 0 or output.match(/is not a chef-vault/)
|
1443
|
+
MU::Groomer::Chef.saveSecret(
|
1444
|
+
vault: "scratchpad",
|
1445
|
+
item: "placeholder",
|
1446
|
+
data: { "secret" => "DO NOT DELETE", "timestamp" => "9999999999" },
|
1447
|
+
permissions: "name:MU-MASTER"
|
1448
|
+
)
|
1449
|
+
end
|
1452
1450
|
|
1453
|
-
|
1454
|
-
|
1455
|
-
puts %x{#{MU_BASE}/lib/bin/mu-user-manage -g mu -n "#{$MU_CFG['mu_admin_name']}"}
|
1456
|
-
MU.log "If Scratchpad web interface is not accessible, try the following:", MU::NOTICE
|
1457
|
-
puts "#{MU_BASE}/lib/bin/mu-user-manage -g --no-scratchpad mu".bold
|
1458
|
-
end
|
1451
|
+
MU.log "Regenerating documentation in /var/www/html/docs"
|
1452
|
+
%x{#{MU_BASE}/lib/bin/mu-gen-docs}
|
1459
1453
|
|
1460
|
-
if
|
1461
|
-
|
1462
|
-
|
1454
|
+
if $INITIALIZE
|
1455
|
+
MU.log "Setting initial password for admin user 'mu', for logging into Nagios and other built-in services.", MU::NOTICE
|
1456
|
+
puts %x{#{MU_BASE}/lib/bin/mu-user-manage -g mu -n "#{$MU_CFG['mu_admin_name']}"}
|
1457
|
+
MU.log "If Scratchpad web interface is not accessible, try the following:", MU::NOTICE
|
1458
|
+
puts "#{MU_BASE}/lib/bin/mu-user-manage -g --no-scratchpad mu".bold
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
if !ENV['PATH'].match(/(^|:)#{Regexp.quote(MU_BASE)}\/bin(:|$)/)
|
1462
|
+
MU.log "I added some entries to your $PATH, run this to import them:", MU::NOTICE
|
1463
|
+
puts "source #{HOMEDIR}/.bashrc".bold
|
1464
|
+
end
|
1463
1465
|
end
|