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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -8
  3. data/ansible/roles/mu-nat/README.md +33 -0
  4. data/ansible/roles/mu-nat/defaults/main.yml +3 -0
  5. data/ansible/roles/mu-nat/handlers/main.yml +2 -0
  6. data/ansible/roles/mu-nat/meta/main.yml +60 -0
  7. data/ansible/roles/mu-nat/tasks/main.yml +65 -0
  8. data/ansible/roles/mu-nat/tests/inventory +2 -0
  9. data/ansible/roles/mu-nat/tests/test.yml +5 -0
  10. data/ansible/roles/mu-nat/vars/main.yml +2 -0
  11. data/bin/mu-cleanup +2 -1
  12. data/bin/mu-configure +950 -948
  13. data/bin/mu-gen-docs +6 -0
  14. data/cloud-mu.gemspec +2 -2
  15. data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
  16. data/modules/mommacat.ru +1 -1
  17. data/modules/mu.rb +31 -39
  18. data/modules/mu/cloud.rb +11 -1
  19. data/modules/mu/clouds/aws.rb +8 -3
  20. data/modules/mu/clouds/aws/alarm.rb +5 -8
  21. data/modules/mu/clouds/aws/bucket.rb +15 -9
  22. data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
  23. data/modules/mu/clouds/aws/collection.rb +4 -4
  24. data/modules/mu/clouds/aws/container_cluster.rb +50 -33
  25. data/modules/mu/clouds/aws/database.rb +25 -21
  26. data/modules/mu/clouds/aws/dnszone.rb +12 -14
  27. data/modules/mu/clouds/aws/endpoint.rb +5 -8
  28. data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
  29. data/modules/mu/clouds/aws/folder.rb +4 -7
  30. data/modules/mu/clouds/aws/function.rb +5 -8
  31. data/modules/mu/clouds/aws/group.rb +5 -8
  32. data/modules/mu/clouds/aws/habitat.rb +2 -5
  33. data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
  34. data/modules/mu/clouds/aws/log.rb +6 -9
  35. data/modules/mu/clouds/aws/msg_queue.rb +16 -19
  36. data/modules/mu/clouds/aws/nosqldb.rb +27 -18
  37. data/modules/mu/clouds/aws/notifier.rb +6 -9
  38. data/modules/mu/clouds/aws/role.rb +4 -7
  39. data/modules/mu/clouds/aws/search_domain.rb +50 -23
  40. data/modules/mu/clouds/aws/server.rb +20 -14
  41. data/modules/mu/clouds/aws/server_pool.rb +22 -12
  42. data/modules/mu/clouds/aws/storage_pool.rb +9 -14
  43. data/modules/mu/clouds/aws/user.rb +5 -8
  44. data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
  45. data/modules/mu/clouds/aws/vpc.rb +16 -14
  46. data/modules/mu/clouds/azure.rb +1 -1
  47. data/modules/mu/clouds/azure/container_cluster.rb +1 -1
  48. data/modules/mu/clouds/azure/server.rb +16 -2
  49. data/modules/mu/clouds/azure/user.rb +1 -1
  50. data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
  51. data/modules/mu/clouds/azure/vpc.rb +32 -13
  52. data/modules/mu/clouds/cloudformation/server.rb +1 -1
  53. data/modules/mu/clouds/google.rb +2 -3
  54. data/modules/mu/clouds/google/container_cluster.rb +9 -1
  55. data/modules/mu/clouds/google/firewall_rule.rb +6 -0
  56. data/modules/mu/clouds/google/role.rb +1 -3
  57. data/modules/mu/clouds/google/server.rb +25 -4
  58. data/modules/mu/clouds/google/user.rb +1 -1
  59. data/modules/mu/clouds/google/userdata/linux.erb +9 -5
  60. data/modules/mu/clouds/google/vpc.rb +102 -21
  61. data/modules/mu/config.rb +250 -49
  62. data/modules/mu/config/alarm.rb +1 -0
  63. data/modules/mu/config/container_cluster.yml +0 -1
  64. data/modules/mu/config/database.yml +4 -1
  65. data/modules/mu/config/search_domain.yml +4 -3
  66. data/modules/mu/config/server.rb +7 -3
  67. data/modules/mu/config/server.yml +4 -1
  68. data/modules/mu/config/server_pool.yml +2 -0
  69. data/modules/mu/config/vpc.rb +42 -29
  70. data/modules/mu/deploy.rb +12 -5
  71. data/modules/mu/groomers/ansible.rb +4 -1
  72. data/modules/mu/groomers/chef.rb +5 -1
  73. data/modules/mu/kittens.rb +60 -11
  74. data/modules/mu/logger.rb +6 -4
  75. data/modules/mu/mommacat.rb +39 -19
  76. data/modules/mu/mu.yaml.rb +276 -0
  77. metadata +13 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6d28f31ace29cfaab6ca01999ae6ac6555e2f997a7bd05a6368d6e3787b67bc
4
- data.tar.gz: da3c08bb506f6952cb74a07710436d6c698acafa6c4f3fc5eeb3ac3cdaff58b4
3
+ metadata.gz: ec38717ba0e001faf5500c971fad6d2ce978302e11c9b7dfc587b4d7f1e7c7a3
4
+ data.tar.gz: 57a212554afb4c30752e471211b515252524dc5a4e4cddabafe29f66bd6a377f
5
5
  SHA512:
6
- metadata.gz: 3b6adb59f7ead95071f134ba9059042ff493cad6259fd19c1f0e32f78bbfb1e856403e7272c980a5cede5aae8fdf53bfe2c810ade5e23d2a045cad2f4264ab20
7
- data.tar.gz: 283566f81d55c6a34871edb57ae895855bbf1ed3f2a8e6946ca40319839e780802bc0228f6c2b5d1ca2a0dffc10b2cd107b48770133a88b72144ad3478043800
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
- **mu** is the deployer and developer toolset for the Cloudamatic complete cloud deployment solution, designed to provision, orchestrate and manage complex platforms and applications. mu provides Cloudamatic deployers and developers with the tools and commands to automate any arbitrarily complex application, platform or combination on a wide range of infrastructure targets, starting with AWS Cloud and including other clouds, virtualized environments and bare iron.
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
- For general information on Cloudamatic, see the [cloudamatic repository](https://github.com/cloudamatic/cloudamatic)
11
+ **Install instructions and tutorials**: https://github.com/cloudamatic/mu/wiki
12
12
 
13
- For more detailed information on Cloudamatic architecture and mu tooling usage, see our [yard docs](https://cloudamatic.gitlab.io/mu/).
13
+ **API and configuration language documentation**: https://cloudamatic.gitlab.io/mu/
14
14
 
15
- The mu tooling is currently supported on RHEL or CentOS 6/7.
15
+ # Quick Start
16
16
 
17
- ## Installation
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
- ## Usage
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,3 @@
1
+ ---
2
+ mu:
3
+ nat_ip_block: 10.0.0.0/16
@@ -0,0 +1,2 @@
1
+ ---
2
+ # handlers file for mu-installer
@@ -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
@@ -0,0 +1,2 @@
1
+ localhost
2
+
@@ -0,0 +1,5 @@
1
+ ---
2
+ - hosts: localhost
3
+ remote_user: root
4
+ roles:
5
+ - mu-installer
@@ -0,0 +1,2 @@
1
+ ---
2
+ # vars file for mu-installer
@@ -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("You must specify a deploy id!", MU::ERR, html: $opts[:web])
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]
@@ -345,301 +345,292 @@ def importCurrentValues
345
345
  }
346
346
  end
347
347
 
348
- AMROOT = Process.uid == 0
349
- HOMEDIR = Etc.getpwuid(Process.uid).dir
350
-
351
- $opts = Optimist::options do
352
- banner <<-EOS
353
- EOS
354
- required = []
355
- 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
356
- $CONFIGURABLES.each_pair { |key, data|
357
- next if !AMROOT and data['rootonly']
358
- if data.has_key?("subtree")
359
- data["subtree"].each_pair { |subkey, subdata|
360
- next if !AMROOT and subdata['rootonly']
361
- subdata['cli-opt'] = (key+"-"+subkey).gsub(/_/, "-")
362
- opt subdata['cli-opt'].to_sym, subdata["desc"], :require => false, :type => (subdata["boolean"] ? :boolean : :string)
363
- required << subdata['cli-opt'] if subdata['required']
364
- }
365
- elsif data["array"]
366
- data['cli-opt'] = key.gsub(/_/, "-")
367
- opt data['cli-opt'].to_sym, data["desc"], :require => false, :type => (data["boolean"] ? :booleans : :strings)
368
- required << data['cli-opt'] if data['required']
369
- else
370
- data['cli-opt'] = key.gsub(/_/, "-")
371
- opt data['cli-opt'].to_sym, data["desc"], :require => false, :type => (data["boolean"] ? :boolean : :string)
372
- required << data['cli-opt'] if data['required']
373
- end
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
- opt :force, "Run all rebuild actions, whether or not our configuration is changed.", :require => false, :default => false, :type => :boolean if AMROOT
377
- 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
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
- MU_BASE = ENV["MU_INSTALLDIR"]
382
- else
383
- MU_BASE = "/opt/mu"
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
- home = Etc.getpwuid(Process.uid).dir
388
- username = Etc.getpwuid(Process.uid).name
389
- if Process.uid == 0
390
- if ENV.include?('MU_INSTALLDIR')
391
- ENV['MU_INSTALLDIR']+"/etc/mu.yaml"
392
- elsif Dir.exist?("/opt/mu")
393
- "/opt/mu/etc/mu.yaml"
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
- $HAVE_GLOBAL_CONFIG = File.size?("#{MU_BASE}/etc/mu.yaml")
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
- if !$HAVE_GLOBAL_CONFIG and $opts[:noninteractive] and (!$opts[:"public-address"] or !$opts[:"mu-admin-email"])
411
- if $IN_GEM
412
- importCurrentValues # maybe we're in local-only mode
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
- $IN_AWS = false
421
- begin
422
- Timeout.timeout(2) do
423
- instance_id = open("http://169.254.169.254/latest/meta-data/instance-id").read
424
- $IN_AWS = true if !instance_id.nil? and instance_id.size > 0
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
- rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH
427
- end
428
- $IN_GOOGLE = false
429
- begin
430
- Timeout.timeout(2) do
431
- instance_id = open(
432
- "http://metadata.google.internal/computeMetadata/v1/instance/name",
433
- "Metadata-Flavor" => "Google"
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
- rescue OpenURI::HTTPError, Timeout::Error, SocketError, Errno::ENETUNREACH
438
- end
439
- $IN_AZURE = false
440
- begin
441
- Timeout.timeout(2) do
442
- instance = open("http://169.254.169.254/metadata/instance/compute?api-version=2017-08-01","Metadata"=>"true").read
443
- $IN_AZURE = true if !instance.nil? and instance.size > 0
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
- count = 1
487
- tree.each_pair { |key, data|
488
- next if !data.is_a?(Hash)
489
- next if !AMROOT and data['rootonly']
490
- if data.has_key?("subtree")
491
- letters = ("a".."z").to_a
492
- lettercount = 0
493
- if data['named_subentries']
494
- # Generate a stub entry for adding a new item
495
- map[count.to_s] = cloneHash(data["subtree"])
496
- map[count.to_s].each_pair { |k, v| v.delete("value") } # use defaults
497
- map[count.to_s]["name"] = {
498
- "title" => "Name",
499
- "desc" => "A name/alias for this account.",
500
- "required" => true
501
- }
502
- map[count.to_s]["#addnew"] = true
503
- map[count.to_s]["#title"] = data['title']
504
- map[count.to_s]["#key"] = key
505
-
506
- # Now the menu entries for the existing ones
507
- if data['subtree']['#entries']
508
- data['subtree']['#entries'].each_pair { |nameentry, subdata|
509
- next if data['readonly']
510
- next if !subdata.is_a?(Hash)
511
- subdata["#menu"] = count.to_s+letters[lettercount]
512
- subdata["#title"] = nameentry
513
- subdata["#key"] = key
514
- subdata["#entries"] = cloneHash(data["subtree"]["#entries"])
515
- subdata["is_submenu"] = true
516
- map[count.to_s+letters[lettercount]] = tree[key]["subtree"]['#entries'][nameentry]
517
- map[count.to_s+letters[lettercount]]['#entries'] ||= cloneHash(data["subtree"]["#entries"])
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
- end
531
- tree[key]["#menu"] = count.to_s
532
- tree[key]["#key"] = key
533
- map[count.to_s] ||= tree[key]
534
- count = count + 1
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
- puts "/usr/bin/git clone #{repo}"
577
- output = %x{/usr/bin/git clone #{repo} 2>&1}
578
- if $?.exitstatus == 0
579
- puts "Successfully cloned #{repo}".green.on_black
580
- return true
581
- else
582
- puts output.red.on_black
583
- if cfgbackup
584
- puts "Restoring #{HOMEDIR}/.ssh/config"
585
- File.rename(cfgbackup, "#{HOMEDIR}/.ssh/config")
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
- if deletekey
588
- puts "Removing #{keypath}"
589
- File.unlink(keypath)
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
- end
592
- return false
593
- end
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
- def cloneGitRepo(repo)
596
- puts "Testing ability to check out Git repository #{repo.bold}"
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 #{fullrepo}".green.on_black
609
- Dir.chdir(cwd)
610
- return fullrepo
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 $opts[:"ssh-keys-given"]
615
- $opts[:"ssh-keys"].each { |keypath|
616
- if trySSHKeyWithGit(fullrepo, keypath)
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 !$opts[:noninteractive]
623
- if trySSHKeyWithGit(fullrepo)
624
- Dir.chdir(cwd)
625
- return fullrepo
626
- end
588
+ if deletekey
589
+ puts "Removing #{keypath}"
590
+ File.unlink(keypath)
627
591
  end
628
592
  end
629
- if !repo.match(/@|:\/\//)
630
- fullrepo = "git://github.com/"+repo
631
- puts ""
632
- puts "No luck there, trying #{fullrepo}".bold
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
- else
612
+ elsif $?.exitstatus != 0 and output.match(/permission denied/i)
613
+ puts ""
640
614
  puts output.red.on_black
641
- fullrepo = "https://github.com/"+repo
642
- puts "Final attempt, trying #{fullrepo}"
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
- else
654
- puts "No other methods I can think to try, giving up on #{repo.bold}".red.on_black
655
- end
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
- ips = []
664
- if $IN_AWS
665
- ["public-ipv4", "local-ipv4"].each { |addr|
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
- Timeout.timeout(2) do
668
- ip = open("http://169.254.169.254/latest/meta-data/#{addr}").read
669
- ips << ip if !ip.nil? and ip.size > 0
670
- end
671
- rescue OpenURI::HTTPError, Timeout::Error, SocketError
672
- # these are ok to ignore
673
- end
674
- }
675
- elsif $IN_GOOGLE
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
- $CONFIGURABLES["allow_invade_foreign_vpcs"]["default"] = false
692
- $CONFIGURABLES["public_address"]["default"] = $possible_addresses.first
693
- $CONFIGURABLES["hostname"]["default"] = Socket.gethostname
694
- $CONFIGURABLES["banner"]["default"] = "Mu Master at #{$CONFIGURABLES["public_address"]["default"]}"
695
- if $IN_AWS
696
- # XXX move this crap to a callback hook for puttering around in the AWS submenu
697
- aws = JSON.parse(open("http://169.254.169.254/latest/dynamic/instance-identity/document").read)
698
- iam = nil
699
- begin
700
- iam = open("http://169.254.169.254/latest/meta-data/iam/security-credentials").read
701
- rescue OpenURI::HTTPError, SocketError
702
- end
703
- # $CONFIGURABLES["aws"]["subtree"]["account_number"]["default"] = aws["accountId"]
704
- $CONFIGURABLES["aws"]["subtree"]["region"]["default"] = aws["region"]
705
- if iam and iam.size > 0
706
- # XXX can we think of a good way to test our permission set?
707
- $CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] = $CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] + ". Not necessary if IAM Profile #{iam.bold} has sufficient API access."
708
- $CONFIGURABLES["aws"]["subtree"]["access_secret"]["desc"] = $CONFIGURABLES["aws"]["subtree"]["access_key"]["desc"] + ". Not necessary if IAM Profile #{iam.bold} has sufficient API access."
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
- if desc['array']
718
- if desc["callback"]
719
- newval = []
720
- val.each { |v|
721
- v = send(desc["callback"].to_sym, v)
722
- newval << v if !v.nil?
723
- }
724
- val = newval
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
- elsif desc["callback"]
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
- if !data['named_subentries']
738
- data["subtree"].each_pair { |subkey, subdata|
739
- next if !AMROOT and subdata['rootonly']
740
- if $opts[(subdata['cli-opt'].+"_given").to_sym]
741
- newval = runValueCallback(subdata, $opts[subdata['cli-opt'].to_sym])
742
- subdata["value"] = newval if !newval.nil?
743
- $CHANGES.concat(subdata['changes']) if subdata['changes']
744
- end
745
- }
746
- # Honor CLI adds for named trees (credentials, etc) if there are no
747
- # entries in them yet.
748
- elsif data["#entries"].nil? or data["#entries"].empty?
749
- newvals = false
750
- data["subtree"].each_pair { |subkey, subdata|
751
- next if !AMROOT and subdata['rootonly']
752
- next if !subdata['cli-opt']
753
- if $opts[(subdata['cli-opt']+"_given").to_sym]
754
- newval = runValueCallback(subdata, $opts[subdata['cli-opt'].to_sym])
755
- if !newval.nil?
756
- subdata["value"] = newval
757
- newvals = true
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
- else
770
- if $opts[(data['cli-opt']+"_given").to_sym]
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
- valid = true
782
- valid = validate(data["value"], data, false) if data["value"]
781
+ def printVal(data)
782
+ valid = true
783
+ valid = validate(data["value"], data, false) if data["value"]
783
784
 
784
- value = if data["value"] and data["value"] != ""
785
- data["value"]
786
- elsif data["default"] and data["default"] != ""
787
- data["default"]
788
- end
789
- if data['readonly'] and value
790
- print " - "+value.to_s.cyan.on_black
791
- elsif !valid
792
- print " "+data["value"].to_s.red.on_black
793
- print " (consider default of #{data["default"].to_s.bold})" if data["default"]
794
- elsif !data["value"].nil?
795
- print " - "+data["value"].to_s.green.on_black
796
- elsif data["required"]
797
- print " - "+"REQUIRED".red.on_black
798
- elsif !data["default"].nil?
799
- print " - "+data["default"].to_s.yellow.on_black+" (DEFAULT)"
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
- cfg = {}
807
- tree.each_pair { |key, data|
808
- next if !AMROOT and data['rootonly']
809
- if data.has_key?("subtree")
810
- if data["named_subentries"]
811
- if data["subtree"]["#entries"]
812
- data["subtree"]["#entries"].each_pair { |name, block|
813
-
814
- next if !block.is_a?(Hash)
815
- block.each_pair { |subkey, subdata|
816
- next if subkey.match(/^#/) or !subdata.is_a?(Hash)
817
- cfg[key] ||= {}
818
- cfg[key][name] ||= {}
819
- cfg[key][name][subkey] = subdata['value'] if subdata['value']
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
- else
824
- data["subtree"].each_pair { |subkey, subdata|
825
- if !subdata["value"].nil?
826
- cfg[key] ||= {}
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
- elsif !data["value"].nil?
835
- cfg[key] = data["value"]
836
- elsif !data["default"].nil? and !$HAVE_GLOBAL_CONFIG or ($MU_CFG and !$MU_CFG[key])
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
- count = 1
845
- optlist = []
846
- tree.each_pair { |key, data|
847
- next if !data.is_a?(Hash)
848
- next if !AMROOT and data['rootonly']
849
- if data["title"].nil? or data["#menu"].nil?
850
- next
851
- end
852
- print data["#menu"].bold+") "+data["title"]
853
- if data.has_key?("subtree")
854
- puts ""
855
- if data["named_subentries"]
856
- if data['subtree']['#entries']
857
- data['subtree']['#entries'].each_pair { |nameentry, subdata|
858
- next if nameentry.match(/^#/)
859
- puts " "+subdata["#menu"].bold+". "+nameentry.green.on_black
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["subtree"].each_pair { |subkey, subdata|
864
- next if !AMROOT and subdata['rootonly']
865
- print " "+subdata["#menu"].bold+". "+subdata["title"]
866
- printVal(subdata)
867
- puts ""
868
- }
872
+ printVal(data)
873
+ puts ""
869
874
  end
870
- else
871
- printVal(data)
872
- puts ""
873
- end
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
- puts ""
889
- puts (desc['required'] ? "REQUIRED".red.on_black : "OPTIONAL".yellow.on_black)+" - "+desc["desc"]
890
- puts "Enter one or more values, separated by commas".yellow.on_black if desc['array']
891
- puts "Enter 0 or false, 1 or true".yellow.on_black if desc['boolean']
892
- prompt = desc["title"].bold + "> "
893
- current = desc['value'] || desc['default']
894
- if current
895
- current = current.join(", ") if desc['array'] and current.is_a?(Array)
896
- Readline.pre_input_hook = -> do
897
- Readline.insert_text current.to_s
898
- Readline.redisplay
899
- Readline.pre_input_hook = nil
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
- val = Readline.readline(prompt, false)
903
- if desc['array'] and !val.nil?
904
- val = val.strip.split(/\s*,\s*/)
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
- if reqs['boolean'] and newval != true and newval != false and newval != nil
920
- puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must be true or false)".light_red.on_black
921
- puts "\n\n" if addnewline
922
- ok = false
923
- elsif in_use and in_use.size > 0 and in_use.include?(newval)
924
- puts "\n##{reqs['title'].bold} #{newval} not available".light_red.on_black
925
- puts "\n\n" if addnewline
926
- ok = false
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['negate_pattern']
933
- if newval.to_s.match(reqs['pattern'])
934
- puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (must NOT match #{reqs['pattern']})".light_red.on_black
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
- if reqs['array']
948
- if !newval.is_a?(Array)
949
- puts "\nInvalid value '#{newval.bold}' for #{reqs['title'].bold} (should be an array)".light_red.on_black
950
- puts "\n\n" if addnewline
951
- ok = false
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.each { |v|
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
- else
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
- ok = true
968
- $CONFIGURABLES.each_pair { |key, data|
969
- next if !AMROOT and data['rootonly']
970
- if data.has_key?("subtree")
971
- data["subtree"].each_pair { |subkey, subdata|
972
- next if !AMROOT and subdata['rootonly']
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
- else
977
- next if !data["value"]
978
- ok = false if !validate(data["value"], data, false)
979
- end
980
- }
981
- ok
982
- end
980
+ end
981
+ }
982
+ ok
983
+ end
983
984
 
984
- def generateMiniMenu(srctree)
985
- map = {}
986
- tree = cloneHash(srctree)
987
- return [tree, map]
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
- if submenu_name
995
- print "Enter an option to change, "+"O".bold+" to save #{submenu_name.bold}, or "+"q".bold+" to return.\n> "
996
- else
997
- print "Enter an option to change, "+"O".bold+" to save this config, or "+"^D".bold+" to quit.\n> "
998
- end
999
- answer = gets
1000
- if answer.nil?
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
- if map.has_key?(answer) and map[answer]["#addnew"]
1011
- minimap = {}
1012
- assignMenuEntries(map[answer], minimap)
1013
- newtree, newmap = menu(
1014
- map[answer],
1015
- minimap,
1016
- map[answer]['#title']+" (NEW)",
1017
- if map[answer]['#entries']
1018
- map[answer]['#entries'].keys.reject { |k| k.match(/^#/) }
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
- newname = newtree["name"]["value"]
1023
- newtree.delete("#addnew")
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
- tree[parentname]['subtree'] ||= {}
1027
- tree[parentname]['subtree']['#entries'] ||= {}
1028
- # if we're in cloud land and just added a 2nd entry, set the original
1029
- # one to 'default'
1030
- if tree[parentname]['subtree']['#entries'].size == 1
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
- tree[parentname]['subtree']['#entries'][newname] = cloneHash(newtree)
1033
-
1034
- map = {} # rebuild the menu map to include new entries
1035
- assignMenuEntries(tree, map)
1036
- end
1037
- # exit
1038
- # map[answer] = newtree if newtree
1039
- elsif map.has_key?(answer) and map[answer]["is_submenu"]
1040
- minimap = {}
1041
- parentname = map[answer]['#key']
1042
- entryname = map[answer]['#title']
1043
- puts PP.pp(map[answer], '').yellow
1044
- puts PP.pp(tree[parentname]['subtree']['#entries'][entryname], '').red
1045
- assignMenuEntries(tree[parentname]['subtree']['#entries'][entryname], minimap)
1046
- newtree, newmap = menu(
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
- next
1058
- end
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
- changed = true
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
- return [tree, map]
1081
- end
1081
+ return [tree, map]
1082
+ end
1082
1083
 
1083
- if !$opts[:noninteractive]
1084
- $CONFIGURABLES, $MENU_MAP = menu
1085
- $MU_CFG = setConfigTree
1086
- else
1087
- $MU_CFG = setConfigTree
1088
- if !entireConfigValid?
1089
- puts "Configuration had validation errors, exiting.\nRe-invoke #{$0} to correct."
1090
- exit 1
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
- newcfg = cloneHash($MU_CFG)
1096
- require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
1097
- newcfg['multiuser'] = true
1098
- saveMuConfig(newcfg)
1099
- $MU_CFG = loadMuConfig($MU_SET_DEFAULTS)
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
- require 'mu'
1104
- credlist = {
1105
- "bind_creds" => {
1106
- "user" => "CN=mu_bind_creds,#{$MU_CFG["ldap"]['user_ou']}"
1107
- },
1108
- "join_creds" => {
1109
- "user" => "CN=mu_join_creds,#{$MU_CFG["ldap"]['user_ou']}"
1110
- },
1111
- "cfg_directory_adm" => {
1112
- "user" => "admin"
1113
- },
1114
- "root_dn_user" => {
1115
- "user" => "CN=root_dn_user"
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
- credlist.each_pair { |creds, cfg|
1119
- begin
1120
- data = nil
1121
- if $MU_CFG["ldap"].has_key?(creds)
1122
- data = MU::Groomer::Chef.getSecret(
1123
- vault: $MU_CFG["ldap"][creds]["vault"],
1124
- item: $MU_CFG["ldap"][creds]["item"]
1125
- )
1126
- MU::Groomer::Chef.grantSecretAccess("MU-MASTER", $MU_CFG["ldap"][creds]["vault"], $MU_CFG["ldap"][creds]["item"])
1127
- else
1128
- data = MU::Groomer::Chef.getSecret(vault: "mu_ldap", item: creds)
1129
- MU::Groomer::Chef.grantSecretAccess("MU-MASTER", "mu_ldap", creds)
1130
- end
1131
- rescue MU::Groomer::MuNoSuchSecret
1132
- user = cfg["user"]
1133
- pw = Password.pronounceable(14..16)
1134
- if $MU_CFG["ldap"].has_key?(creds)
1135
- data = {
1136
- $MU_CFG["ldap"][creds]["username_field"] => user,
1137
- $MU_CFG["ldap"][creds]["password_field"] => pw
1138
- }
1139
- MU::Groomer::Chef.saveSecret(
1140
- vault: $MU_CFG["ldap"][creds]["vault"],
1141
- item: $MU_CFG["ldap"][creds]["item"],
1142
- data: data,
1143
- permissions: "name:MU-MASTER"
1144
- )
1145
- else
1146
- MU::Groomer::Chef.saveSecret(
1147
- vault: "mu_ldap",
1148
- item: creds,
1149
- data: { "username" => user, "password" => pw },
1150
- permissions: "name:MU-MASTER"
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
- %x{/sbin/service iptables stop} # Chef run will set up correct rules later
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
- $MU_SET_DEFAULTS = setConfigTree
1177
- require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
1178
- saveMuConfig($MU_SET_DEFAULTS)
1179
- else
1180
- if AMROOT
1181
- $NEW_CFG = $MU_CFG.merge(setConfigTree)
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
- $NEW_CFG = setConfigTree
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
- saveMuConfig($NEW_CFG)
1186
- $MU_CFG = $MU_CFG.merge(setConfigTree)
1187
- require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
1188
- end
1189
- begin
1190
- require 'mu'
1191
- rescue MU::MuError => e
1192
- puts "Correct the above error before proceeding. To retry, run:\n\n#{$0.bold} #{ARGV.join(" ").bold}"
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 AMROOT and ($INITIALIZE or $CHANGES.include?("hostname"))
1212
- system("/bin/hostname #{$MU_CFG['hostname']}")
1213
- end
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
- # Do some more basic-but-Chef-dependent configuration *before* we meddle with
1216
- # the Chef Server configuration, which depends on some of this (SSL certs and
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
- if $INITIALIZE and AMROOT
1232
- MU.log "Force open key firewall holes", MU::NOTICE
1233
- system("chef-client -o 'recipe[mu-master::firewall-holes]'")
1234
- end
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
- MU.log "Checking internal SSL signing authority and certificates", MU::NOTICE
1238
- if !system("chef-client -o 'recipe[mu-master::ssl-certs]'") and $INITIALIZE
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
- templates["/etc/chef/client.rb"] = CLIENT_TEMPLATE
1251
- templates["/etc/opscode/pivotal.rb"] = PIVOTAL_TEMPLATE
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
- templates.each_pair { |file, template|
1254
- erb = ERB.new(template)
1255
- processed = erb.result(binding)
1256
- tmpfile = file+".tmp."+Process.pid.to_s
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 processed
1278
+ f.puts updated_server_cfg
1259
1279
  }
1260
- if !File.size?(file) or File.read(tmpfile) != File.read(file)
1261
- File.rename(tmpfile, file)
1262
- MU.log "Updated #{file}", MU::NOTICE
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 $INITIALIZE or $CHANGES.include?("chefcerts")
1317
- system("rm -f #{HOMEDIR}/.chef/trusted_certs/* ; knife ssl fetch -c #{HOMEDIR}/.chef/knife.rb")
1318
- if AMROOT
1319
- system("rm -f /etc/chef/trusted_certs/* ; knife ssl fetch -c /etc/chef/client.rb")
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
- # knife ssl fetch isn't bright enough to nab our intermediate certs, which
1324
- # ironically becomes a problem when we use one from the real world. Jam it
1325
- # into knife and chef-client's faces thusly:
1326
- if $MU_CFG['ssl'] and $MU_CFG['ssl']['chain'] and File.size?($MU_CFG['ssl']['chain'])
1327
- cert = File.basename($MU_CFG['ssl']['chain'])
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
- if $MU_CFG['repos'] and $MU_CFG['repos'].size > 0
1337
- $MU_CFG['repos'].each { |repo|
1338
- repo.match(/\/([^\/]+?)(\.git)?$/)
1339
- shortname = Regexp.last_match(1)
1340
- repodir = MU.dataDir + "/" + shortname
1341
- if !Dir.exist?(repodir)
1342
- MU.log "Cloning #{repo} into #{repodir}", MU::NOTICE
1343
- Dir.chdir(MU.dataDir)
1344
- system("/usr/bin/git clone #{repo}")
1345
- $CHANGES << "chefartifacts"
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 !AMROOT
1351
- exit
1352
- end
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
- begin
1355
- MU::Groomer::Chef.getSecret(vault: "secrets", item: "consul")
1356
- rescue MU::Groomer::MuNoSuchSecret
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::Master::LDAP.listUsers
1377
- rescue Exception => e # XXX lazy exception handling is lazy
1378
- $CHANGES << "389ds"
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?("389ds")
1381
- File.unlink("/root/389ds.tmp/389-directory-setup.inf") if File.exist?("/root/389ds.tmp/389-directory-setup.inf")
1382
- MU.log "Configuring 389 Directory Services", MU::NOTICE
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
- # Figure out if our run list is dumb
1393
- MU.log "Verifying MU-MASTER's Chef run list", MU::NOTICE
1394
- MU::Groomer::Chef.loadChefLib
1395
- chef_node = ::Chef::Node.load("MU-MASTER")
1396
- run_list = ["role[mu-master]"]
1397
- run_list.concat($MU_CFG['master_runlist_extras']) if $MU_CFG['master_runlist_extras'].is_a?(Array)
1398
- set_runlist = false
1399
- run_list.each { |rl|
1400
- set_runlist = true if !chef_node.run_list?(rl)
1401
- }
1402
- if set_runlist
1403
- MU.log "Updating MU-MASTER run_list", MU::NOTICE, details: run_list
1404
- chef_node.run_list(run_list)
1405
- chef_node.save
1406
- $CHANGES << "chefrun"
1407
- else
1408
- MU.log "Chef run list looks correct", MU::NOTICE, details: run_list
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
- # TODO here are some things we don't do yet but should
1412
- # accommodate running as a non-root user
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
- if $INITIALIZE
1415
- MU::Config.emitSchemaAsRuby
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
- output = %x{/opt/chef/bin/knife vault show scratchpad 2>&1}
1441
- if $?.exitstatus != 0 or output.match(/is not a chef-vault/)
1442
- MU::Groomer::Chef.saveSecret(
1443
- vault: "scratchpad",
1444
- item: "placeholder",
1445
- data: { "secret" => "DO NOT DELETE", "timestamp" => "9999999999" },
1446
- permissions: "name:MU-MASTER"
1447
- )
1448
- end
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
- MU.log "Regenerating documentation in /var/www/html/docs"
1451
- %x{#{MU_BASE}/lib/bin/mu-gen-docs}
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
- if $INITIALIZE
1454
- MU.log "Setting initial password for admin user 'mu', for logging into Nagios and other built-in services.", MU::NOTICE
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 !ENV['PATH'].match(/(^|:)#{Regexp.quote(MU_BASE)}\/bin(:|$)/)
1461
- MU.log "I added some entries to your $PATH, run this to import them:", MU::NOTICE
1462
- puts "source #{HOMEDIR}/.bashrc".bold
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