cloud-mu 3.0.0beta → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Inline docs](http://inch-ci.org/github/cloudamatic/mu.svg?branch=master)](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
|