cloud-mu 3.1.6 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mu-adopt +4 -12
  3. data/bin/mu-azure-tests +57 -0
  4. data/bin/mu-cleanup +2 -4
  5. data/bin/mu-configure +37 -1
  6. data/bin/mu-deploy +3 -3
  7. data/bin/mu-findstray-tests +25 -0
  8. data/bin/mu-gen-docs +2 -4
  9. data/bin/mu-run-tests +23 -10
  10. data/cloud-mu.gemspec +2 -2
  11. data/cookbooks/mu-tools/libraries/helper.rb +1 -1
  12. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  13. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  14. data/extras/generate-stock-images +1 -0
  15. data/modules/mu.rb +82 -95
  16. data/modules/mu/adoption.rb +356 -56
  17. data/modules/mu/cleanup.rb +21 -20
  18. data/modules/mu/cloud.rb +79 -1753
  19. data/modules/mu/cloud/database.rb +49 -0
  20. data/modules/mu/cloud/dnszone.rb +46 -0
  21. data/modules/mu/cloud/machine_images.rb +212 -0
  22. data/modules/mu/cloud/providers.rb +81 -0
  23. data/modules/mu/cloud/resource_base.rb +920 -0
  24. data/modules/mu/cloud/server.rb +40 -0
  25. data/modules/mu/cloud/server_pool.rb +1 -0
  26. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  27. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  28. data/modules/mu/cloud/wrappers.rb +165 -0
  29. data/modules/mu/config.rb +122 -80
  30. data/modules/mu/config/alarm.rb +2 -6
  31. data/modules/mu/config/bucket.rb +1 -1
  32. data/modules/mu/config/cache_cluster.rb +1 -1
  33. data/modules/mu/config/collection.rb +1 -1
  34. data/modules/mu/config/container_cluster.rb +2 -2
  35. data/modules/mu/config/database.rb +83 -104
  36. data/modules/mu/config/database.yml +1 -2
  37. data/modules/mu/config/dnszone.rb +1 -1
  38. data/modules/mu/config/doc_helpers.rb +4 -5
  39. data/modules/mu/config/endpoint.rb +1 -1
  40. data/modules/mu/config/firewall_rule.rb +3 -19
  41. data/modules/mu/config/folder.rb +1 -1
  42. data/modules/mu/config/function.rb +1 -1
  43. data/modules/mu/config/group.rb +1 -1
  44. data/modules/mu/config/habitat.rb +1 -1
  45. data/modules/mu/config/loadbalancer.rb +57 -11
  46. data/modules/mu/config/log.rb +1 -1
  47. data/modules/mu/config/msg_queue.rb +1 -1
  48. data/modules/mu/config/nosqldb.rb +1 -1
  49. data/modules/mu/config/notifier.rb +1 -1
  50. data/modules/mu/config/ref.rb +30 -4
  51. data/modules/mu/config/role.rb +1 -1
  52. data/modules/mu/config/schema_helpers.rb +30 -34
  53. data/modules/mu/config/search_domain.rb +1 -1
  54. data/modules/mu/config/server.rb +4 -12
  55. data/modules/mu/config/server_pool.rb +3 -7
  56. data/modules/mu/config/storage_pool.rb +1 -1
  57. data/modules/mu/config/tail.rb +10 -0
  58. data/modules/mu/config/user.rb +1 -1
  59. data/modules/mu/config/vpc.rb +12 -17
  60. data/modules/mu/defaults/AWS.yaml +32 -32
  61. data/modules/mu/defaults/Azure.yaml +1 -0
  62. data/modules/mu/defaults/Google.yaml +1 -0
  63. data/modules/mu/deploy.rb +16 -15
  64. data/modules/mu/groomer.rb +15 -0
  65. data/modules/mu/groomers/chef.rb +3 -0
  66. data/modules/mu/logger.rb +120 -144
  67. data/modules/mu/master.rb +1 -1
  68. data/modules/mu/mommacat.rb +54 -25
  69. data/modules/mu/mommacat/daemon.rb +10 -7
  70. data/modules/mu/mommacat/naming.rb +82 -3
  71. data/modules/mu/mommacat/search.rb +47 -15
  72. data/modules/mu/mommacat/storage.rb +72 -41
  73. data/modules/mu/{clouds → providers}/README.md +1 -1
  74. data/modules/mu/{clouds → providers}/aws.rb +114 -47
  75. data/modules/mu/{clouds → providers}/aws/alarm.rb +1 -1
  76. data/modules/mu/{clouds → providers}/aws/bucket.rb +2 -2
  77. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +10 -46
  78. data/modules/mu/{clouds → providers}/aws/collection.rb +3 -3
  79. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +15 -33
  80. data/modules/mu/providers/aws/database.rb +1744 -0
  81. data/modules/mu/{clouds → providers}/aws/dnszone.rb +2 -5
  82. data/modules/mu/{clouds → providers}/aws/endpoint.rb +2 -11
  83. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +33 -29
  84. data/modules/mu/{clouds → providers}/aws/folder.rb +0 -0
  85. data/modules/mu/{clouds → providers}/aws/function.rb +2 -10
  86. data/modules/mu/{clouds → providers}/aws/group.rb +9 -13
  87. data/modules/mu/{clouds → providers}/aws/habitat.rb +1 -1
  88. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +41 -33
  89. data/modules/mu/{clouds → providers}/aws/log.rb +2 -2
  90. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +2 -8
  91. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +0 -0
  92. data/modules/mu/{clouds → providers}/aws/notifier.rb +0 -0
  93. data/modules/mu/{clouds → providers}/aws/role.rb +7 -7
  94. data/modules/mu/{clouds → providers}/aws/search_domain.rb +8 -13
  95. data/modules/mu/{clouds → providers}/aws/server.rb +55 -90
  96. data/modules/mu/{clouds → providers}/aws/server_pool.rb +10 -33
  97. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +19 -36
  98. data/modules/mu/{clouds → providers}/aws/user.rb +8 -12
  99. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  100. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  101. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
  102. data/modules/mu/{clouds → providers}/aws/vpc.rb +135 -70
  103. data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
  104. data/modules/mu/{clouds → providers}/azure.rb +4 -1
  105. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  106. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  107. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  108. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  109. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  110. data/modules/mu/{clouds → providers}/azure/server.rb +30 -23
  111. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  112. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  113. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  114. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  115. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  116. data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
  117. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  118. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  119. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  120. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  121. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  122. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  123. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  124. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  125. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  126. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  127. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  128. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  129. data/modules/mu/{clouds → providers}/google.rb +14 -6
  130. data/modules/mu/{clouds → providers}/google/bucket.rb +1 -1
  131. data/modules/mu/{clouds → providers}/google/container_cluster.rb +28 -13
  132. data/modules/mu/{clouds → providers}/google/database.rb +1 -8
  133. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +2 -2
  134. data/modules/mu/{clouds → providers}/google/folder.rb +4 -8
  135. data/modules/mu/{clouds → providers}/google/function.rb +3 -3
  136. data/modules/mu/{clouds → providers}/google/group.rb +8 -16
  137. data/modules/mu/{clouds → providers}/google/habitat.rb +3 -7
  138. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +1 -1
  139. data/modules/mu/{clouds → providers}/google/role.rb +42 -34
  140. data/modules/mu/{clouds → providers}/google/server.rb +25 -10
  141. data/modules/mu/{clouds → providers}/google/server_pool.rb +10 -10
  142. data/modules/mu/{clouds → providers}/google/user.rb +31 -21
  143. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  144. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  145. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  146. data/modules/mu/{clouds → providers}/google/vpc.rb +37 -2
  147. data/modules/tests/centos6.yaml +11 -0
  148. data/modules/tests/centos7.yaml +11 -0
  149. data/modules/tests/centos8.yaml +12 -0
  150. data/modules/tests/rds.yaml +108 -0
  151. data/modules/tests/regrooms/rds.yaml +123 -0
  152. data/spec/mu/clouds/azure_spec.rb +2 -2
  153. metadata +108 -89
  154. data/modules/mu/clouds/aws/database.rb +0 -1974
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 447346eba4a1cd7ee0df18c2c85aea32d1a45af0f4d22474fc902007d1f30a2c
4
- data.tar.gz: 8f44c2cf180c0748c712b9c244d0c21335147c6a3c9f6a1472772546e13a9b85
3
+ metadata.gz: fd9a15a0e94a578919c0cb22bf5c95ee86b5b4a03fcc0ea1c35da2c161e8cf31
4
+ data.tar.gz: 04cdc9d9a70de97fdaf12021166b707921ec981d7ab2dc92cd1ebce491a9e130
5
5
  SHA512:
6
- metadata.gz: 8008e86471d5596337e3b642f5740a2bfe3b178646dd36a37f23dcfb8e0eacfcfbab4bac148ec5855f74f803543fd333480636249ec938387523e6f0c1fddde8
7
- data.tar.gz: '08466a848ca7b54fc6460e240f472cc812e93730650545f240a92ea67bde875b96a5d8398b770182355721c6628887665f938dcb7a3103209f7e170cffa246b9'
6
+ metadata.gz: adfef4f231a946a3929b7f8026a9e338658dadfef3482942a46e8fdb9b10c4ca7d68aa457d135815a3878882d88a103ec1ebacea4bcb1ae4c45b070d85ceee06
7
+ data.tar.gz: 3a7b04d7d2486b05e8d413b78029b610bb7ba6bd8a33a1c24cf7b8bdf63dabaf9e0a1baab8408a66f995d05df719261248cbf27ee5b230a350109053ddb0420a
@@ -21,12 +21,6 @@ require 'bundler/setup'
21
21
  require 'optimist'
22
22
  require 'mu'
23
23
 
24
- available_clouds = MU::Cloud.supportedClouds
25
- available_clouds.reject! { |cloud|
26
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
27
- cloudclass.listCredentials.nil? or cloudclass.listCredentials.size == 0
28
- }
29
-
30
24
  available_types = MU::Cloud.resource_types.keys.map { |t| t.to_s }
31
25
  grouping_options = {
32
26
  "logical" => "Group resources in logical layers (folders and habitats together, users/roles/groups together, network resources together, etc)",
@@ -39,15 +33,17 @@ $opt = Optimist::options do
39
33
  EOS
40
34
  opt :appname, "The overarching name of the application stack we will generate", :required => false, :default => "mu", :type => :string
41
35
  opt :types, "The resource types to scan and import. Valid types: #{available_types.join(", ")}", :required => false, :type => :strings, :default => available_types
42
- opt :clouds, "The cloud providers to scan and import.", :required => false, :type => :strings, :default => available_clouds
36
+ opt :clouds, "The cloud providers to scan and import.", :required => false, :type => :strings, :default => MU::Cloud.availableClouds
43
37
  opt :parent, "Where applicable, resources which reside in the root folder or organization are configured with the specified parent in our target BoK", :required => false, :type => :string
44
38
  opt :billing, "Force-set this billing entity on created resources, instead of copying from the live resources", :required => false, :type => :string
45
39
  opt :sources, "One or more sets of credentials to use when importing resources. By default we will search and import from all sets of available credentials for each cloud provider specified with --clouds", :required => false, :type => :strings
46
40
  opt :credentials, "Override the 'credentials' value in our generated Baskets of Kittens to target a single, specific account. Our default behavior is to set each resource to deploy into the account from which it was sourced.", :required => false, :type => :string
47
41
  opt :savedeploys, "Generate actual deployment metadata in #{MU.dataDir}/deployments, as though the resources we found were created with mu-deploy. If we are generating more than one configuration, and a resource needs to reference another resource (e.g. to declare a VPC in which to reside), this will allow us to reference them as virtual resource, rather than by raw cloud identifier.", :required => false, :type => :boolean, :default => false
48
42
  opt :diff, "List the differences between what we find and an existing, saved deploy from a previous run, if one exists.", :required => false, :type => :boolean
43
+ opt :merge_changes, "When using --diff, merge detected changes into the baseline deploy after reporting on them.", :required => false, :type => :boolean, :default => false
49
44
  opt :grouping, "Methods for grouping found resources into separate Baskets.\n\n"+MU::Adoption::GROUPMODES.keys.map { |g| "* "+g.to_s+": "+MU::Adoption::GROUPMODES[g] }.join("\n")+"\n\n", :required => false, :type => :string, :default => "logical"
50
45
  opt :habitats, "Limit scope of searches to the named accounts/projects/subscriptions, instead of search all habitats visible to our credentials.", :required => false, :type => :strings
46
+ opt :regions, "Restrict to operating on a subset of available regions, instead of all that we know about.", :require => false, :type => :strings
51
47
  opt :scrub, "Whether to set scrub_mu_isms in the BoKs we generate", :default => $MU_CFG.has_key?('adopt_scrub_mu_isms') ? $MU_CFG['adopt_scrub_mu_isms'] : false
52
48
  end
53
49
 
@@ -102,8 +98,7 @@ if !ok
102
98
  exit 1
103
99
  end
104
100
 
105
-
106
- adoption = MU::Adoption.new(clouds: clouds, types: types, parent: $opt[:parent], billing: $opt[:billing], sources: $opt[:sources], credentials: $opt[:credentials], group_by: $opt[:grouping].to_sym, savedeploys: $opt[:savedeploys], diff: $opt[:diff], habitats: $opt[:habitats], scrub_mu_isms: $opt[:scrub])
101
+ adoption = MU::Adoption.new(clouds: clouds, types: types, parent: $opt[:parent], billing: $opt[:billing], sources: $opt[:sources], credentials: $opt[:credentials], group_by: $opt[:grouping].to_sym, savedeploys: $opt[:savedeploys], diff: $opt[:diff], habitats: $opt[:habitats], scrub_mu_isms: $opt[:scrub], regions: $opt[:regions], merge: $opt[:merge_changes])
107
102
  found = adoption.scrapeClouds
108
103
  if found.nil? or found.empty?
109
104
  MU.log "No resources found to adopt", MU::WARN, details: {"clouds" => clouds, "types" => types }
@@ -117,10 +112,7 @@ boks.each_pair { |appname, bok|
117
112
  File.open("#{appname}.yaml", "w") { |f|
118
113
  f.write JSON.parse(JSON.generate(bok)).to_yaml
119
114
  }
120
- conf_engine = MU::Config.new("#{appname}.yaml")
121
- stack_conf = conf_engine.config
122
115
  # puts stack_conf.to_yaml
123
- MU.log "#{appname}.yaml validated successfully", MU::NOTICE
124
116
  MU::Cloud.resource_types.each_pair { |type, cfg|
125
117
  if bok[cfg[:cfg_plural]]
126
118
  MU.log "#{bok[cfg[:cfg_plural]].size.to_s} #{cfg[:cfg_plural]}", MU::NOTICE
@@ -0,0 +1,57 @@
1
+ #!/usr/local/ruby-current/bin/ruby
2
+ # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
3
+ #
4
+ # Licensed under the BSD-3 license (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License in the root of the project or at
7
+ #
8
+ # http://egt-labs.com/mu/LICENSE.html
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'rubygems'
17
+ require 'bundler/setup'
18
+ require 'json'
19
+ require 'erb'
20
+ require 'optimist'
21
+ require 'json-schema'
22
+ require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
23
+ require 'mu'
24
+
25
+ (0..100000).to_a.each { |n|
26
+ retries = 0
27
+ seed = nil
28
+ # begin
29
+ # raise MuError, "Failed to allocate an unused MU-ID after #{retries} tries!" if retries > 70
30
+ # seedsize = 1 + (retries/10).abs
31
+ # seed = (0...seedsize+1).map { ('a'..'z').to_a[rand(26)] }.join
32
+ # end while seed == "mu" or seed[0] == seed[1]
33
+ seed = "nn"
34
+ handle = MU::MommaCat.generateHandle(seed)
35
+ puts handle
36
+ }
37
+ exit
38
+
39
+ #pp MU::Cloud::Azure.listRegions
40
+ #pp MU::Cloud::Azure::Habitat.testcalls
41
+ #pp MU::Cloud::Azure::VPC.find(cloud_id: MU::Cloud::Azure::Id.new(resource_group: "mu", name: "mu-vnet"))
42
+ #pp MU::Cloud::Azure.authorization.role_assignments.list_for_resource_group("AKS-DEV-2019062015-KA-EASTUS")
43
+ #pp MU::Cloud::Azure::Role.find(role_name: "Azure Kubernetes Service Cluster Admin Role")
44
+ #puts MU::Cloud::Azure.default_subscription
45
+ #pp MU::Cloud::Azure.fetchPublicIP("MYVPC-DEV-2019061911-XI-EASTUS", "ip-addr-thingy")
46
+ #pp MU::Cloud::Azure.ensureProvider("egtazure", "Microsoft.ContainerService", force: true)
47
+ pp MU::Cloud::Azure::Server.find(cloud_id: "mu")
48
+ exit
49
+ pp MU::Cloud::Azure::Server.fetchImage("OpenLogic/CentOS/6")
50
+ pp MU::Cloud::Azure::Server.fetchImage("OpenLogic/CentOS/7")
51
+ pp MU::Cloud::Azure::Server.fetchImage("RedHat/RHEL/8")
52
+ pp MU::Cloud::Azure::Server.fetchImage("RedHat/RHEL/7")
53
+ pp MU::Cloud::Azure::Server.fetchImage("RedHat/RHEL/6")
54
+ pp MU::Cloud::Azure::Server.fetchImage("Debian/debian-10/10")
55
+ pp MU::Cloud::Azure::Server.fetchImage("MicrosoftWindowsServer/WindowsServer/2012-R2-Datacenter")
56
+ pp MU::Cloud::Azure::Server.fetchImage("MicrosoftWindowsServer/WindowsServer/2016-Datacenter")
57
+ pp MU::Cloud::Azure::Server.fetchImage("MicrosoftWindowsServer/WindowsServer/2019-Datacenter")
@@ -24,10 +24,8 @@ require 'mu'
24
24
  Dir.chdir(MU.installDir)
25
25
 
26
26
  credentials = []
27
- MU::Cloud.supportedClouds.each { |cloud|
28
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
29
- next if cloudclass.listCredentials.nil? or cloudclass.listCredentials.size == 0
30
- credentials.concat(cloudclass.listCredentials)
27
+ MU::Cloud.availableClouds.each { |cloud|
28
+ credentials.concat(MU::Cloud.cloudClass(cloud).listCredentials)
31
29
  }
32
30
  credentials.uniq!
33
31
 
@@ -113,12 +113,44 @@ $CONFIGURABLES = {
113
113
  "desc" => "Disable the Momma Cat grooming daemon. Nodes which require asynchronous Ansible/Chef bootstraps will not function. This option is only honored in gem-based installations.",
114
114
  "boolean" => true
115
115
  },
116
+ "adopt_change_notify" => {
117
+ "title" => "Adoption Change Notifications",
118
+ "subtree" => {
119
+ "slack" => {
120
+ "title" => "Send to Slack",
121
+ "desc" => "Report modifications to adopted resources, detected by mu-adopt --diff, to the Slack webhook and channel configured under Slack Configuration.",
122
+ "boolean" => true
123
+ },
124
+ "slack_snippet_threshold" => {
125
+ "title" => "Attachment Threshold",
126
+ "desc" => "If a list of details about a modified resources is longer than this number of lines (in JSON), it will be sent as an \"attachment,\" which in Slack means a blockquote that displays a few lines with a \"Show more\" button. The internal default is 5 lines."
127
+ },
128
+ # "email" => {
129
+ # "title" => "Send Email",
130
+ # "desc" => "",
131
+ # "boolean" => true
132
+ # }
133
+ }
134
+ },
116
135
  "adopt_scrub_mu_isms" => {
117
- "title" => "Disable Momma Cat",
136
+ "title" => "Scrub Mu-isms from Baskets of Kittens",
118
137
  "default" => false,
119
138
  "desc" => "Ordinarily, Mu will automatically name, tag and generate auxiliary resources in a standard Mu-ish fashion that allows for deployment of multiple clones of a given stack. Toggling this flag will change the default behavior of mu-adopt, when it creates stack descriptors from found resources, to enable or disable this behavior (see also mu-adopt's --scrub option).",
120
139
  "boolean" => true
121
140
  },
141
+ "slack" => {
142
+ "title" => "Slack Configuration",
143
+ "subtree" => {
144
+ "webhook" => {
145
+ "title" => "Webhook",
146
+ "desc" => "The hooks.slack.com URL for the webook to which we'll send deploy notifications"
147
+ },
148
+ "channel" => {
149
+ "title" => "Channel",
150
+ "desc" => "The channel name (without leading #) to which alerts should be sent."
151
+ }
152
+ }
153
+ },
122
154
  "mommacat_port" => {
123
155
  "title" => "Momma Cat Listen Port",
124
156
  "pattern" => /^[0-9]+$/i,
@@ -247,6 +279,10 @@ $CONFIGURABLES = {
247
279
  "required" => false,
248
280
  "desc" => "For Google Cloud projects which are attached to a GSuite domain. GCP service accounts cannot view or manage GSuite resources (groups, users, etc) directly, but must instead masquerade as a GSuite user which has delegated authority to the service account. See also: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority"
249
281
  },
282
+ "org" => {
283
+ "title" => "Default Org/Domain",
284
+ "desc" => "For credential sets which have access to multiple GSuite or Cloud Identity orgs, you must specify a default organization (e.g. my.domain.com)."
285
+ },
250
286
  "customer_id" => {
251
287
  "title" => "GSuite Customer ID",
252
288
  "required" => false,
@@ -105,7 +105,7 @@ if $opts[:dryrun]
105
105
  Thread.handle_interrupt(MU::Cloud::MuCloudResourceNotImplemented => :never) {
106
106
  begin
107
107
  Thread.handle_interrupt(MU::Cloud::MuCloudResourceNotImplemented => :immediate) {
108
- MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::WARN, verbosity: MU::Logger::NORMAL
108
+ MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::NOTICE, verbosity: MU::Logger::NORMAL
109
109
  Thread.current.exit
110
110
  }
111
111
  ensure
@@ -124,7 +124,7 @@ if $opts[:dryrun]
124
124
  )
125
125
  cost_dummy_deploy.run
126
126
  rescue MU::Cloud::MuCloudResourceNotImplemented, MU::Cloud::MuCloudFlagNotImplemented
127
- MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::WARN, verbosity: MU::Logger::NORMAL
127
+ MU.log "Cost calculator not available for this stack, as it uses a resource not implemented in Mu's CloudFormation layer.", MU::NOTICE, verbosity: MU::Logger::NORMAL
128
128
  end
129
129
  end
130
130
  exit
@@ -135,7 +135,7 @@ if $opts[:update]
135
135
  # TODO consider whether this is useful/valid
136
136
  # old_conf = JSON.parse(File.read(deploy.deploy_dir+"/basket_of_kittens.json"))
137
137
  # stack_conf = old_conf.merge(stack_conf)
138
- deploy.updateBasketofKittens(stack_conf)
138
+ deploy.updateBasketofKittens(stack_conf, skip_validation: true)
139
139
  deployer = MU::Deploy.new(
140
140
  deploy.environment,
141
141
  verbosity: verbosity,
@@ -0,0 +1,25 @@
1
+ #!/usr/local/ruby-current/bin/ruby
2
+ # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
3
+ #
4
+ # Licensed under the BSD-3 license (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License in the root of the project or at
7
+ #
8
+ # http://egt-labs.com/mu/LICENSE.html
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'rubygems'
17
+ require 'bundler/setup'
18
+ require 'json'
19
+ require 'erb'
20
+ require 'optimist'
21
+ require 'json-schema'
22
+ require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb"))
23
+ require 'mu'
24
+
25
+ MU::MommaCat.findStray("AWS", "firewall_rule", region: MU.myRegion, dummy_ok: true, debug: true)
@@ -79,8 +79,7 @@ EOF
79
79
  impl_counts[type] ||= 0
80
80
  [a, b].each { |cloud|
81
81
  begin
82
- myclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
83
- case myclass.quality
82
+ case MU::Cloud.resourceClass(cloud, type).quality
84
83
  when MU::Cloud::RELEASE
85
84
  cloud_is_useful[cloud] = true
86
85
  counts[cloud] += 4
@@ -114,8 +113,7 @@ EOF
114
113
  cloudlist.each { |cloud|
115
114
  readme += "<td><center>"
116
115
  begin
117
- myclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
118
- case myclass.quality
116
+ case MU::Cloud.resourceClass(cloud, type).quality
119
117
  when MU::Cloud::RELEASE
120
118
  readme += "<img src='release.png' style='#{icon_style}' title='Release Quality' alt='[Release Quality]'>"
121
119
  when MU::Cloud::BETA
@@ -42,7 +42,7 @@ only = ARGV
42
42
 
43
43
  files = Dir.glob("*.yaml", base: dir)
44
44
  files.concat(Dir.glob("*.yml", base: dir))
45
- baseclouds = MU::Cloud.supportedClouds.reject { |c| c == "CloudFormation" }
45
+ baseclouds = MU::Cloud.availableClouds.reject { |c| c == "CloudFormation" }
46
46
 
47
47
  commands = {}
48
48
  failures = []
@@ -56,20 +56,33 @@ end
56
56
 
57
57
  files.each { |f|
58
58
  clouds = baseclouds.dup
59
+ groomer_match = true
59
60
  File.open(dir+"/"+f).readlines.each { |l|
60
61
  l.chomp!
61
- next if !l.match(/^\s*#\s*clouds: (.*)/)
62
- clouds = []
63
- cloudstr = Regexp.last_match[1]
64
- cloudstr.split(/\s*,\s*/).each { |c|
65
- baseclouds.each { |cloud|
66
- if cloud.match(/^#{Regexp.quote(c)}$/i)
67
- clouds << cloud
62
+ if l.match(/^\s*#\s*clouds: (.*)/)
63
+ clouds = []
64
+ cloudstr = Regexp.last_match[1]
65
+ cloudstr.split(/\s*,\s*/).each { |c|
66
+ baseclouds.each { |cloud|
67
+ if cloud.match(/^#{Regexp.quote(c)}$/i)
68
+ clouds << cloud
69
+ end
70
+ }
71
+ }
72
+ elsif l.match(/^\s*#\s*groomers: (.*)/)
73
+ groomerstr = Regexp.last_match[1]
74
+ groomerstr.split(/\s*,\s*/).each { |g|
75
+ if !MU::Groomer.availableGroomers.include?(g)
76
+ MU.log "#{f} requires groomer #{g}, which is not available. This test will be skipped.", MU::NOTICE
77
+ groomer_match = false
68
78
  end
69
79
  }
70
- }
71
- break
80
+ end
72
81
  }
82
+ if !groomer_match
83
+ next
84
+ end
85
+
73
86
  clouds.each { |cloud|
74
87
  cmd = "mu-deploy #{f} --cloud #{cloud} #{$opts[:full] ? "" : "--dryrun"}"
75
88
  commands[cmd] = {
@@ -17,8 +17,8 @@ end
17
17
 
18
18
  Gem::Specification.new do |s|
19
19
  s.name = 'cloud-mu'
20
- s.version = '3.1.6'
21
- s.date = '2020-03-20'
20
+ s.version = '3.2.0'
21
+ s.date = '2020-06-16'
22
22
  s.require_paths = ['modules']
23
23
  s.required_ruby_version = '>= 2.4'
24
24
  s.summary = "The eGTLabs Mu toolkit for unified cloud deployments"
@@ -236,7 +236,7 @@ module Mutools
236
236
  response = nil
237
237
  begin
238
238
  secret = get_deploy_secret
239
- if secret.nil?
239
+ if secret.nil? or secret.empty?
240
240
  raise "Failed to fetch deploy secret, and I can't communicate with Momma Cat without it"
241
241
  end
242
242
 
@@ -252,21 +252,21 @@ if !node['application_attributes']['skip_recipes'].include?('apply_security')
252
252
  # end
253
253
  # 6.3 Configure PAM
254
254
  # 6.3.2 Set Password Creation Requirement Parameters Using pam_cracklib
255
- template "/etc/pam.d/password-auth-local" do
256
- source "etc_pamd_password-auth.erb"
257
- mode 0644
258
- end
259
- link "/etc/pam.d/password-auth" do
260
- to "/etc/pam.d/password-auth-local"
261
- end
255
+ # template "/etc/pam.d/password-auth-local" do
256
+ # source "etc_pamd_password-auth.erb"
257
+ # mode 0644
258
+ # end
259
+ # link "/etc/pam.d/password-auth" do
260
+ # to "/etc/pam.d/password-auth-local"
261
+ # end
262
262
  #6.3.3 Set Lockout for Failed Password Attempts
263
- template "/etc/pam.d/system-auth-local" do
264
- source "etc_pamd_system-auth.erb"
265
- mode 0644
266
- end
267
- link "/etc/pam.d/system-auth" do
268
- to "/etc/pam.d/system-auth-local"
269
- end
263
+ # template "/etc/pam.d/system-auth-local" do
264
+ # source "etc_pamd_system-auth.erb"
265
+ # mode 0644
266
+ # end
267
+ # link "/etc/pam.d/system-auth" do
268
+ # to "/etc/pam.d/system-auth-local"
269
+ # end
270
270
 
271
271
  #SV-50303r1_rule/SV-50304r1_rule
272
272
  execute "chown root:root /etc/shadow"
@@ -21,3 +21,12 @@ chef_gem "aws-sdk-core" do
21
21
  version "2.11.24"
22
22
  action :install
23
23
  end
24
+
25
+ if platform_family?("rhel") or platform_family?("amazon")
26
+ if node['platform_version'].to_i == 6
27
+ package "python34-pip"
28
+ execute "/usr/bin/pip3 install awscli" do
29
+ not_if "test -x /usr/bin/aws"
30
+ end
31
+ end
32
+ end
@@ -91,6 +91,7 @@ $opts[:clouds].each { |cloud|
91
91
  end
92
92
  next if !needed
93
93
  end
94
+ MU.log "Loading "+bok_dir+"/"+cloud+"/"+platform+".yaml"
94
95
  conf_engine = MU::Config.new(
95
96
  bok_dir+"/"+cloud+"/"+platform+".yaml",
96
97
  default_credentials: $opts[(cloud.downcase+"_creds").to_sym]
@@ -79,38 +79,40 @@ class Hash
79
79
  }
80
80
  return 0 if self == other # that was easy!
81
81
  # compare elements and decide who's "bigger" based on their totals?
82
- 0
82
+
83
+ # fine, try some brute force and just hope everything implements to_s
84
+ self.flatten.map { |e| e.to_s }.join() <=> other.flatten.map { |e| e.to_s }.join()
83
85
  end
84
86
 
85
- # Recursively compare two hashes
86
- def diff(with, on = self, level: 0, parents: [])
87
+ # Recursively compare two Mu Basket of Kittens hashes and report the differences
88
+ def diff(with, on = self, level: 0, parents: [], report: {}, habitat: nil)
87
89
  return if with.nil? and on.nil?
88
90
  if with.nil? or on.nil? or with.class != on.class
89
91
  return # XXX ...however we're flagging differences
90
92
  end
91
93
  return if on == with
92
94
 
93
- tree = ""
94
- indentsize = 0
95
- parents.each { |p|
96
- tree += (" " * indentsize) + p + " => \n"
97
- indentsize += 2
98
- }
99
- indent = (" " * indentsize)
100
-
101
95
  changes = []
96
+ report ||= {}
102
97
  if on.is_a?(Hash)
103
98
  on_unique = (on.keys - with.keys)
104
99
  with_unique = (with.keys - on.keys)
105
100
  shared = (with.keys & on.keys)
106
101
  shared.each { |k|
107
- diff(with[k], on[k], level: level+1, parents: parents + [k])
102
+
103
+ report_data = diff(with[k], on[k], level: level+1, parents: parents + [k], report: report[k], habitat: habitat)
104
+ if report_data and !report_data.empty?
105
+ report ||= {}
106
+ report[k] = report_data
107
+ end
108
108
  }
109
109
  on_unique.each { |k|
110
- changes << "- ".red+PP.pp({k => on[k] }, '')
110
+ report[k] = { :action => :removed, :parents => parents, :value => on[k].clone }
111
+ report[k][:habitat] = habitat if habitat
111
112
  }
112
113
  with_unique.each { |k|
113
- changes << "+ ".green+PP.pp({k => with[k]}, '')
114
+ report[k] = { :action => :added, :parents => parents, :value => with[k].clone }
115
+ report[k][:habitat] = habitat if habitat
114
116
  }
115
117
  elsif on.is_a?(Array)
116
118
  return if with == on
@@ -122,29 +124,27 @@ class Hash
122
124
  # sorting arrays full of weird, non-primitive types.
123
125
  done = []
124
126
  on.sort.each { |elt|
125
- if elt.is_a?(Hash) and elt['name'] or elt['entity']# or elt['cloud_id']
126
- with.sort.each { |other_elt|
127
- # Figure out what convention this thing is using for resource identification
128
- compare_a, compare_b = if elt['name'].nil? and elt["id"].nil? and !elt["entity"].nil? and !other_elt["entity"].nil?
129
- [elt["entity"], other_elt["entity"]]
130
- else
131
- [elt, other_elt]
132
- end
127
+ if elt.is_a?(Hash) and !MU::MommaCat.getChunkName(elt).first.nil?
128
+ elt_namestr, elt_location, elt_location_list = MU::MommaCat.getChunkName(elt)
133
129
 
134
- if (compare_a['name'] and compare_b['name'] == compare_a['name']) or
135
- (compare_a['name'].nil? and !compare_a["id"].nil? and compare_a["id"] == compare_b["id"])
136
- break if elt == other_elt
130
+ with.sort.each { |other_elt|
131
+ other_elt_namestr, other_elt_location, other_elt_location_list = MU::MommaCat.getChunkName(other_elt)
132
+
133
+ # Case 1: The array element exists in both version of this array
134
+ if elt_namestr and other_elt_namestr and
135
+ elt_namestr == other_elt_namestr and
136
+ (elt_location.nil? or other_elt_location.nil? or
137
+ elt_location == other_elt_location or
138
+ !(elt_location_list & other_elt_location_list).empty?
139
+ )
137
140
  done << elt
138
141
  done << other_elt
139
- namestr = if elt['type']
140
- "#{elt['type']}[#{elt['name']}]"
141
- elsif elt['name']
142
- elt['name']
143
- elsif elt['entity'] and elt["entity"]["id"]
144
- elt['entity']['id']
142
+ break if elt == other_elt # if they're identical, we're done
143
+ report_data = diff(other_elt, elt, level: level+1, parents: parents + [elt_namestr], habitat: (elt_location || habitat))
144
+ if report_data and !report_data.empty?
145
+ report ||= {}
146
+ report[elt_namestr] = report_data
145
147
  end
146
-
147
- diff(other_elt, elt, level: level+1, parents: parents + [namestr])
148
148
  break
149
149
  end
150
150
  }
@@ -152,43 +152,34 @@ class Hash
152
152
  }
153
153
  on_unique = (on - with) - done
154
154
  with_unique = (with - on) - done
155
- # if on_unique.size > 0 or with_unique.size > 0
156
- # if before_a != after_a
157
- # MU.log "A BEFORE", MU::NOTICE, details: before_a
158
- # MU.log "A AFTER", MU::NOTICE, details: after_a
159
- # end
160
- # if before_b != after_b
161
- # MU.log "B BEFORE", MU::NOTICE, details: before_b
162
- # MU.log "B AFTER", MU::NOTICE, details: after_b
163
- # end
164
- # end
155
+
156
+ # Case 2: This array entry exists in the old version, but not the new one
165
157
  on_unique.each { |e|
166
- changes << if e.is_a?(Hash)
167
- "- ".red+PP.pp(Hash.bok_minimize(e), '').gsub(/\n/, "\n "+(indent))
168
- else
169
- "- ".red+e.to_s
170
- end
158
+ namestr, loc = MU::MommaCat.getChunkName(e)
159
+
160
+ report ||= {}
161
+ report[namestr] = { :action => :removed, :parents => parents, :value => e.clone }
162
+ report[namestr][:habitat] = loc if loc
171
163
  }
164
+
165
+ # Case 3: This array entry exists in the new version, but not the old one
172
166
  with_unique.each { |e|
173
- changes << if e.is_a?(Hash)
174
- "+ ".green+PP.pp(Hash.bok_minimize(e), '').gsub(/\n/, "\n "+(indent))
175
- else
176
- "+ ".green+e.to_s
177
- end
167
+ namestr, loc = MU::MommaCat.getChunkName(e)
168
+
169
+ report ||= {}
170
+ report[namestr] = { :action => :added, :parents => parents, :value => e.clone }
171
+ report[namestr][:habitat] = loc if loc
178
172
  }
173
+
174
+ # A plain old leaf node of data
179
175
  else
180
176
  if on != with
181
- changes << "-".red+" #{on.to_s}"
182
- changes << "+".green+" #{with.to_s}"
177
+ report = { :action => :changed, :parents => parents, :oldvalue => on, :value => with.clone }
178
+ report[:habitat] = habitat if habitat
183
179
  end
184
180
  end
185
181
 
186
- if changes.size > 0
187
- puts tree
188
- changes.each { |c|
189
- puts indent+c
190
- }
191
- end
182
+ report.freeze
192
183
  end
193
184
 
194
185
  # Implement a merge! that just updates each hash leaf as needed, not
@@ -212,8 +203,29 @@ class Hash
212
203
  end
213
204
 
214
205
  ENV['HOME'] = Etc.getpwuid(Process.uid).dir
206
+ module MU
207
+
208
+ # For log entries that should only be logged when we're in verbose mode
209
+ DEBUG = 0.freeze
210
+ # For ordinary log entries
211
+ INFO = 1.freeze
212
+ # For more interesting log entries which are not errors
213
+ NOTICE = 2.freeze
214
+ # Log entries for non-fatal errors
215
+ WARN = 3.freeze
216
+ # Log entries for non-fatal errors
217
+ WARNING = 3.freeze
218
+ # Log entries for fatal errors
219
+ ERR = 4.freeze
220
+ # Log entries for fatal errors
221
+ ERROR = 4.freeze
222
+ # Log entries that will be held and displayed/emailed at the end of deploy,
223
+ # cleanup, etc.
224
+ SUMMARY = 5.freeze
225
+ end
215
226
 
216
227
  require 'mu/logger'
228
+
217
229
  module MU
218
230
 
219
231
  # Subclass core thread so we can gracefully handle it when we hit system
@@ -273,8 +285,9 @@ module MU
273
285
  # Wrapper class for fatal Exceptions. Gives our internals something to
274
286
  # inherit that will log an error message appropriately before bubbling up.
275
287
  class MuError < StandardError
276
- def initialize(message = nil, silent: false)
277
- MU.log message, MU::ERR, details: caller[2] if !message.nil? and !silent
288
+ def initialize(message = nil, silent: false, details: nil)
289
+ details ||= caller[2]
290
+ MU.log message, MU::ERR, details: details if !message.nil? and !silent
278
291
  if MU.verbosity == MU::Logger::SILENT
279
292
  super ""
280
293
  else
@@ -620,25 +633,6 @@ module MU
620
633
  @@logger.log(msg, level, details: details, html: html, verbosity: verbosity, color: color)
621
634
  end
622
635
 
623
- # For log entries that should only be logged when we're in verbose mode
624
- DEBUG = 0.freeze
625
- # For ordinary log entries
626
- INFO = 1.freeze
627
- # For more interesting log entries which are not errors
628
- NOTICE = 2.freeze
629
- # Log entries for non-fatal errors
630
- WARN = 3.freeze
631
- # Log entries for non-fatal errors
632
- WARNING = 3.freeze
633
- # Log entries for fatal errors
634
- ERR = 4.freeze
635
- # Log entries for fatal errors
636
- ERROR = 4.freeze
637
- # Log entries that will be held and displayed/emailed at the end of deploy,
638
- # cleanup, etc.
639
- SUMMARY = 5.freeze
640
-
641
-
642
636
  autoload :Cleanup, 'mu/cleanup'
643
637
  autoload :Deploy, 'mu/deploy'
644
638
  autoload :MommaCat, 'mu/mommacat'
@@ -652,7 +646,7 @@ module MU
652
646
  new_cfg = $MU_CFG.dup
653
647
  examples = {}
654
648
  MU::Cloud.supportedClouds.each { |cloud|
655
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
649
+ cloudclass = MU::Cloud.cloudClass(cloud)
656
650
  begin
657
651
  if cloudclass.hosted? and !$MU_CFG[cloud.downcase]
658
652
  cfg_blob = cloudclass.hosted_config
@@ -808,11 +802,7 @@ module MU
808
802
  # @param groomer [String]: The grooming agent to load.
809
803
  # @return [Class]: The class object implementing this groomer agent
810
804
  def self.loadGroomer(groomer)
811
- if !File.size?(MU.myRoot+"/modules/mu/groomers/#{groomer.downcase}.rb")
812
- raise MuError, "Requested to use unsupported grooming agent #{groomer}"
813
- end
814
- require "mu/groomers/#{groomer.downcase}"
815
- return Object.const_get("MU").const_get("Groomer").const_get(groomer)
805
+ MU::Groomer.loadGroomer(groomer)
816
806
  end
817
807
 
818
808
  @@myRegion_var = nil
@@ -966,8 +956,7 @@ module MU
966
956
 
967
957
  @@myCloudDescriptor = nil
968
958
  if MU.myCloud
969
- svrclass = const_get("MU").const_get("Cloud").const_get(MU.myCloud).const_get("Server")
970
- found = svrclass.find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
959
+ found = MU::Cloud.resourceClass(MU.myCloud, "Server").find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
971
960
  # found = MU::MommaCat.findStray(MU.myCloud, "server", cloud_id: @@myInstanceId, dummy_ok: true, region: MU.myRegion)
972
961
  if !found.nil? and found.size == 1
973
962
  @@myCloudDescriptor = found.values.first
@@ -980,8 +969,7 @@ module MU
980
969
  def self.myVPCObj
981
970
  return nil if MU.myCloud.nil?
982
971
  return @@myVPCObj_var if @@myVPCObj_var
983
- cloudclass = const_get("MU").const_get("Cloud").const_get(MU.myCloud)
984
- @@myVPCObj_var ||= cloudclass.myVPCObj
972
+ @@myVPCObj_var ||= MU::Cloud.cloudClass(MU.myCloud).myVPCObj
985
973
  @@myVPCObj_var
986
974
  end
987
975
 
@@ -1106,10 +1094,9 @@ module MU
1106
1094
 
1107
1095
  clouds = platform.nil? ? MU::Cloud.supportedClouds : [platform]
1108
1096
  clouds.each { |cloud|
1109
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
1110
- bucketname = cloudclass.adminBucketName(credentials)
1097
+ bucketname = MU::Cloud.cloudClass(cloud).adminBucketName(credentials)
1111
1098
  begin
1112
- if platform or (cloudclass.hosted? and platform.nil?) or cloud == MU::Config.defaultCloud
1099
+ if platform or (MU::Cloud.cloudClass(cloud).hosted? and platform.nil?) or cloud == MU::Config.defaultCloud
1113
1100
  return bucketname
1114
1101
  end
1115
1102
  end