cloud-mu 3.5.0 → 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +5 -2
  3. data/Berksfile.lock +135 -0
  4. data/ansible/roles/mu-base/README.md +33 -0
  5. data/ansible/roles/mu-base/defaults/main.yml +2 -0
  6. data/ansible/roles/mu-base/files/check_apm.cfg +1 -0
  7. data/ansible/roles/mu-base/files/check_apm.sh +18 -0
  8. data/ansible/roles/mu-base/files/check_disk.cfg +1 -0
  9. data/ansible/roles/mu-base/files/check_elastic_shards.cfg +1 -0
  10. data/ansible/roles/mu-base/files/check_elastic_shards.sh +12 -0
  11. data/ansible/roles/mu-base/files/check_logstash.cfg +1 -0
  12. data/ansible/roles/mu-base/files/check_logstash.sh +14 -0
  13. data/ansible/roles/mu-base/files/check_mem.cfg +1 -0
  14. data/ansible/roles/mu-base/files/check_updates.cfg +1 -0
  15. data/ansible/roles/mu-base/files/logrotate.conf +35 -0
  16. data/ansible/roles/mu-base/files/nrpe-apm-sudo +1 -0
  17. data/ansible/roles/mu-base/files/nrpe-elasticshards-sudo +2 -0
  18. data/ansible/roles/mu-base/handlers/main.yml +5 -0
  19. data/ansible/roles/mu-base/meta/main.yml +53 -0
  20. data/ansible/roles/mu-base/tasks/main.yml +113 -0
  21. data/ansible/roles/mu-base/templates/nrpe.cfg.j2 +231 -0
  22. data/ansible/roles/mu-base/tests/inventory +2 -0
  23. data/ansible/roles/mu-base/tests/test.yml +5 -0
  24. data/ansible/roles/mu-base/vars/main.yml +1 -0
  25. data/ansible/roles/mu-compliance/README.md +33 -0
  26. data/ansible/roles/mu-compliance/defaults/main.yml +2 -0
  27. data/ansible/roles/mu-compliance/files/U_MS_Windows_Server_2016_V2R1_STIG_SCAP_1-2_Benchmark.xml +15674 -0
  28. data/ansible/roles/mu-compliance/files/U_MS_Windows_Server_2019_V2R1_STIG_SCAP_1-2_Benchmark.xml +17553 -0
  29. data/ansible/roles/mu-compliance/handlers/main.yml +2 -0
  30. data/ansible/roles/mu-compliance/meta/main.yml +53 -0
  31. data/ansible/roles/mu-compliance/tasks/main.yml +45 -0
  32. data/ansible/roles/mu-compliance/tests/inventory +2 -0
  33. data/ansible/roles/mu-compliance/tests/test.yml +5 -0
  34. data/ansible/roles/mu-compliance/vars/main.yml +4 -0
  35. data/ansible/roles/mu-elastic/README.md +51 -0
  36. data/ansible/roles/mu-elastic/defaults/main.yml +2 -0
  37. data/ansible/roles/mu-elastic/files/jvm.options +93 -0
  38. data/ansible/roles/mu-elastic/handlers/main.yml +10 -0
  39. data/ansible/roles/mu-elastic/meta/main.yml +52 -0
  40. data/ansible/roles/mu-elastic/tasks/main.yml +186 -0
  41. data/ansible/roles/mu-elastic/templates/elasticsearch.yml.j2 +110 -0
  42. data/ansible/roles/mu-elastic/templates/kibana.yml.j2 +131 -0
  43. data/ansible/roles/mu-elastic/templates/password_set.expect.j2 +19 -0
  44. data/ansible/roles/mu-elastic/tests/inventory +2 -0
  45. data/ansible/roles/mu-elastic/tests/test.yml +5 -0
  46. data/ansible/roles/mu-elastic/vars/main.yml +2 -0
  47. data/ansible/roles/mu-logstash/README.md +51 -0
  48. data/ansible/roles/mu-logstash/defaults/main.yml +2 -0
  49. data/ansible/roles/mu-logstash/files/02-beats-input.conf +5 -0
  50. data/ansible/roles/mu-logstash/files/10-rails-filter.conf +16 -0
  51. data/ansible/roles/mu-logstash/files/jvm.options +84 -0
  52. data/ansible/roles/mu-logstash/files/logstash.yml +304 -0
  53. data/ansible/roles/mu-logstash/handlers/main.yml +20 -0
  54. data/ansible/roles/mu-logstash/meta/main.yml +52 -0
  55. data/ansible/roles/mu-logstash/tasks/main.yml +254 -0
  56. data/ansible/roles/mu-logstash/templates/20-cloudtrail.conf.j2 +28 -0
  57. data/ansible/roles/mu-logstash/templates/30-elasticsearch-output.conf.j2 +19 -0
  58. data/ansible/roles/mu-logstash/templates/apm-server.yml.j2 +33 -0
  59. data/ansible/roles/mu-logstash/templates/heartbeat.yml.j2 +29 -0
  60. data/ansible/roles/mu-logstash/templates/nginx/apm.conf.j2 +25 -0
  61. data/ansible/roles/mu-logstash/templates/nginx/default.conf.j2 +56 -0
  62. data/ansible/roles/mu-logstash/templates/nginx/elastic.conf.j2 +27 -0
  63. data/ansible/roles/mu-logstash/tests/inventory +2 -0
  64. data/ansible/roles/mu-logstash/tests/test.yml +5 -0
  65. data/ansible/roles/mu-logstash/vars/main.yml +2 -0
  66. data/ansible/roles/mu-rdp/README.md +33 -0
  67. data/ansible/roles/mu-rdp/meta/main.yml +53 -0
  68. data/ansible/roles/mu-rdp/tasks/main.yml +9 -0
  69. data/ansible/roles/mu-rdp/tests/inventory +2 -0
  70. data/ansible/roles/mu-rdp/tests/test.yml +5 -0
  71. data/ansible/roles/mu-windows/tasks/main.yml +3 -0
  72. data/bin/mu-ansible-secret +1 -1
  73. data/bin/mu-aws-setup +4 -3
  74. data/bin/mu-azure-setup +5 -5
  75. data/bin/mu-configure +25 -17
  76. data/bin/mu-firewall-allow-clients +1 -0
  77. data/bin/mu-gcp-setup +3 -3
  78. data/bin/mu-load-config.rb +1 -0
  79. data/bin/mu-node-manage +66 -33
  80. data/bin/mu-self-update +2 -2
  81. data/bin/mu-upload-chef-artifacts +6 -1
  82. data/bin/mu-user-manage +1 -1
  83. data/cloud-mu.gemspec +25 -23
  84. data/cookbooks/firewall/CHANGELOG.md +417 -224
  85. data/cookbooks/firewall/LICENSE +202 -0
  86. data/cookbooks/firewall/README.md +153 -126
  87. data/cookbooks/firewall/TODO.md +6 -0
  88. data/cookbooks/firewall/attributes/firewalld.rb +7 -0
  89. data/cookbooks/firewall/attributes/iptables.rb +3 -3
  90. data/cookbooks/firewall/chefignore +115 -0
  91. data/cookbooks/firewall/libraries/helpers.rb +5 -0
  92. data/cookbooks/firewall/libraries/helpers_firewalld.rb +1 -1
  93. data/cookbooks/firewall/libraries/helpers_firewalld_dbus.rb +72 -0
  94. data/cookbooks/firewall/libraries/helpers_iptables.rb +3 -3
  95. data/cookbooks/firewall/libraries/helpers_nftables.rb +170 -0
  96. data/cookbooks/firewall/libraries/helpers_ufw.rb +7 -0
  97. data/cookbooks/firewall/libraries/helpers_windows.rb +8 -9
  98. data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +9 -9
  99. data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +7 -7
  100. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +12 -8
  101. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +13 -9
  102. data/cookbooks/firewall/libraries/provider_firewall_rule.rb +1 -1
  103. data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +5 -5
  104. data/cookbooks/firewall/libraries/provider_firewall_windows.rb +4 -4
  105. data/cookbooks/firewall/libraries/resource_firewall_rule.rb +3 -3
  106. data/cookbooks/firewall/metadata.json +40 -1
  107. data/cookbooks/firewall/metadata.rb +15 -0
  108. data/cookbooks/firewall/recipes/default.rb +7 -7
  109. data/cookbooks/firewall/recipes/disable_firewall.rb +1 -1
  110. data/cookbooks/firewall/recipes/firewalld.rb +87 -0
  111. data/cookbooks/firewall/renovate.json +18 -0
  112. data/cookbooks/firewall/resources/firewalld.rb +28 -0
  113. data/cookbooks/firewall/resources/firewalld_config.rb +39 -0
  114. data/cookbooks/firewall/resources/firewalld_helpers.rb +106 -0
  115. data/cookbooks/firewall/resources/firewalld_icmptype.rb +88 -0
  116. data/cookbooks/firewall/resources/firewalld_ipset.rb +104 -0
  117. data/cookbooks/firewall/resources/firewalld_policy.rb +115 -0
  118. data/cookbooks/firewall/resources/firewalld_service.rb +98 -0
  119. data/cookbooks/firewall/resources/firewalld_zone.rb +118 -0
  120. data/cookbooks/firewall/resources/nftables.rb +71 -0
  121. data/cookbooks/firewall/resources/nftables_rule.rb +113 -0
  122. data/cookbooks/mu-activedirectory/Berksfile +1 -1
  123. data/cookbooks/mu-activedirectory/metadata.rb +1 -1
  124. data/cookbooks/mu-firewall/metadata.rb +2 -2
  125. data/cookbooks/mu-master/Berksfile +4 -3
  126. data/cookbooks/mu-master/attributes/default.rb +5 -2
  127. data/cookbooks/mu-master/files/default/check_elastic.sh +761 -0
  128. data/cookbooks/mu-master/files/default/check_kibana.rb +45 -0
  129. data/cookbooks/mu-master/libraries/mu.rb +24 -0
  130. data/cookbooks/mu-master/metadata.rb +5 -5
  131. data/cookbooks/mu-master/recipes/default.rb +31 -20
  132. data/cookbooks/mu-master/recipes/firewall-holes.rb +5 -0
  133. data/cookbooks/mu-master/recipes/init.rb +58 -19
  134. data/cookbooks/mu-master/recipes/update_nagios_only.rb +251 -178
  135. data/cookbooks/mu-master/templates/default/nagios.conf.erb +5 -11
  136. data/cookbooks/mu-master/templates/default/web_app.conf.erb +3 -0
  137. data/cookbooks/mu-php54/Berksfile +1 -1
  138. data/cookbooks/mu-php54/metadata.rb +2 -2
  139. data/cookbooks/mu-tools/Berksfile +2 -3
  140. data/cookbooks/mu-tools/attributes/default.rb +3 -4
  141. data/cookbooks/mu-tools/files/amazon/etc/bashrc +90 -0
  142. data/cookbooks/mu-tools/files/amazon/etc/login.defs +292 -0
  143. data/cookbooks/mu-tools/files/amazon/etc/profile +77 -0
  144. data/cookbooks/mu-tools/files/amazon/etc/security/limits.conf +63 -0
  145. data/cookbooks/mu-tools/files/amazon/etc/sysconfig/init +19 -0
  146. data/cookbooks/mu-tools/files/amazon/etc/sysctl.conf +82 -0
  147. data/cookbooks/mu-tools/files/amazon-2023/etc/login.defs +294 -0
  148. data/cookbooks/mu-tools/files/default/logrotate.conf +35 -0
  149. data/cookbooks/mu-tools/files/default/nrpe_conf_d.pp +0 -0
  150. data/cookbooks/mu-tools/libraries/helper.rb +21 -9
  151. data/cookbooks/mu-tools/metadata.rb +4 -4
  152. data/cookbooks/mu-tools/recipes/apply_security.rb +3 -2
  153. data/cookbooks/mu-tools/recipes/aws_api.rb +23 -5
  154. data/cookbooks/mu-tools/recipes/base_repositories.rb +4 -1
  155. data/cookbooks/mu-tools/recipes/gcloud.rb +56 -56
  156. data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
  157. data/cookbooks/mu-tools/recipes/nrpe.rb +20 -2
  158. data/cookbooks/mu-tools/recipes/rsyslog.rb +12 -1
  159. data/cookbooks/mu-tools/recipes/set_local_fw.rb +1 -1
  160. data/data_bags/nagios_services/apm_backend_connect.json +5 -0
  161. data/data_bags/nagios_services/apm_listen.json +5 -0
  162. data/data_bags/nagios_services/elastic_shards.json +5 -0
  163. data/data_bags/nagios_services/logstash.json +5 -0
  164. data/data_bags/nagios_services/rhel7_updates.json +8 -0
  165. data/extras/image-generators/AWS/centos7.yaml +1 -0
  166. data/extras/image-generators/AWS/rhel7.yaml +21 -0
  167. data/extras/image-generators/AWS/win2k12r2.yaml +1 -0
  168. data/extras/image-generators/AWS/win2k16.yaml +1 -0
  169. data/extras/image-generators/AWS/win2k19.yaml +1 -0
  170. data/extras/list-stock-amis +0 -0
  171. data/extras/ruby_rpm/muby.spec +8 -5
  172. data/extras/vault_tools/export_vaults.sh +1 -1
  173. data/extras/vault_tools/recreate_vaults.sh +0 -0
  174. data/extras/vault_tools/test_vaults.sh +0 -0
  175. data/install/deprecated-bash-library.sh +1 -1
  176. data/install/installer +4 -2
  177. data/modules/mommacat.ru +3 -1
  178. data/modules/mu/adoption.rb +1 -1
  179. data/modules/mu/cloud/dnszone.rb +2 -2
  180. data/modules/mu/cloud/machine_images.rb +26 -25
  181. data/modules/mu/cloud/resource_base.rb +213 -182
  182. data/modules/mu/cloud/server_pool.rb +1 -1
  183. data/modules/mu/cloud/ssh_sessions.rb +7 -5
  184. data/modules/mu/cloud/wrappers.rb +2 -2
  185. data/modules/mu/cloud.rb +1 -1
  186. data/modules/mu/config/bucket.rb +1 -1
  187. data/modules/mu/config/function.rb +6 -1
  188. data/modules/mu/config/loadbalancer.rb +24 -2
  189. data/modules/mu/config/ref.rb +12 -0
  190. data/modules/mu/config/role.rb +1 -1
  191. data/modules/mu/config/schema_helpers.rb +42 -9
  192. data/modules/mu/config/server.rb +43 -27
  193. data/modules/mu/config/tail.rb +19 -10
  194. data/modules/mu/config.rb +6 -5
  195. data/modules/mu/defaults/AWS.yaml +78 -114
  196. data/modules/mu/deploy.rb +9 -2
  197. data/modules/mu/groomer.rb +12 -4
  198. data/modules/mu/groomers/ansible.rb +104 -20
  199. data/modules/mu/groomers/chef.rb +15 -6
  200. data/modules/mu/master.rb +9 -4
  201. data/modules/mu/mommacat/daemon.rb +4 -2
  202. data/modules/mu/mommacat/naming.rb +1 -2
  203. data/modules/mu/mommacat/storage.rb +7 -2
  204. data/modules/mu/mommacat.rb +33 -6
  205. data/modules/mu/providers/aws/database.rb +161 -8
  206. data/modules/mu/providers/aws/dnszone.rb +11 -6
  207. data/modules/mu/providers/aws/endpoint.rb +81 -6
  208. data/modules/mu/providers/aws/firewall_rule.rb +254 -172
  209. data/modules/mu/providers/aws/function.rb +65 -3
  210. data/modules/mu/providers/aws/loadbalancer.rb +39 -28
  211. data/modules/mu/providers/aws/log.rb +2 -1
  212. data/modules/mu/providers/aws/role.rb +25 -7
  213. data/modules/mu/providers/aws/server.rb +36 -12
  214. data/modules/mu/providers/aws/server_pool.rb +237 -127
  215. data/modules/mu/providers/aws/storage_pool.rb +7 -1
  216. data/modules/mu/providers/aws/user.rb +1 -1
  217. data/modules/mu/providers/aws/userdata/linux.erb +6 -2
  218. data/modules/mu/providers/aws/userdata/windows.erb +7 -5
  219. data/modules/mu/providers/aws/vpc.rb +49 -25
  220. data/modules/mu/providers/aws.rb +13 -8
  221. data/modules/mu/providers/azure/container_cluster.rb +1 -1
  222. data/modules/mu/providers/azure/loadbalancer.rb +2 -2
  223. data/modules/mu/providers/azure/server.rb +5 -2
  224. data/modules/mu/providers/azure/userdata/linux.erb +1 -1
  225. data/modules/mu/providers/azure.rb +11 -8
  226. data/modules/mu/providers/cloudformation/dnszone.rb +1 -1
  227. data/modules/mu/providers/google/container_cluster.rb +15 -2
  228. data/modules/mu/providers/google/folder.rb +2 -1
  229. data/modules/mu/providers/google/function.rb +130 -4
  230. data/modules/mu/providers/google/habitat.rb +2 -1
  231. data/modules/mu/providers/google/loadbalancer.rb +407 -160
  232. data/modules/mu/providers/google/role.rb +16 -3
  233. data/modules/mu/providers/google/server.rb +5 -1
  234. data/modules/mu/providers/google/user.rb +25 -18
  235. data/modules/mu/providers/google/userdata/linux.erb +1 -1
  236. data/modules/mu/providers/google/vpc.rb +53 -7
  237. data/modules/mu/providers/google.rb +39 -39
  238. data/modules/mu.rb +8 -8
  239. data/modules/tests/elk.yaml +46 -0
  240. data/test/mu-master-test/controls/all_in_one.rb +1 -1
  241. metadata +207 -112
  242. data/cookbooks/firewall/CONTRIBUTING.md +0 -2
  243. data/cookbooks/firewall/MAINTAINERS.md +0 -19
  244. data/cookbooks/firewall/libraries/matchers.rb +0 -30
  245. data/extras/image-generators/AWS/rhel71.yaml +0 -17
@@ -19,7 +19,6 @@ module MU
19
19
  class LoadBalancer < MU::Cloud::LoadBalancer
20
20
 
21
21
  @lb = nil
22
- attr_reader :targetgroups
23
22
 
24
23
  # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like <tt>@vpc</tt>, for us.
25
24
  # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
@@ -39,13 +38,17 @@ module MU
39
38
  @config['targetgroups'].each { |tg|
40
39
  threads << Thread.new {
41
40
  MU.dupGlobals(parent_thread_id)
42
-
43
- if !@config['private']
44
- backends[tg['name']] = createBackendService(tg)
45
- targets[tg['name']] = createProxy(tg, backends[tg['name']])
46
- else
47
- backends[tg['name']] = createBackendService(tg)
48
- end
41
+ vpc_obj = myVpc(tg['vpc']).first if tg['vpc'] # XXX inherit top-level vpc config if it's set
42
+
43
+ # if !@config['private'] or ["INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED"].include?(@config['scheme'])
44
+ backends[tg['name']] = if ["EXTERNAL", "EXTERNAL_MANAGED", "INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED"].include?(@config['scheme'])
45
+ createBackendService(tg)
46
+ else
47
+ createBackendService(tg, region: @config['region'])
48
+ end
49
+
50
+ targets[tg['name']] = createProxy(tg, backends[tg['name']], region: (@config['global'] ? nil : @config['region']))
51
+ # end
49
52
  }
50
53
  }
51
54
  threads.each do |t|
@@ -53,30 +56,40 @@ module MU
53
56
  end
54
57
  end
55
58
 
59
+ @cloud_id = @mu_name
56
60
  @config["listeners"].each { |l|
57
- ruleobj = nil
58
- if !@config["private"]
59
- #TODO ip_address, port_range, target
60
- realproto = ["HTTP", "HTTPS"].include?(l['lb_protocol']) ? l['lb_protocol'] : "TCP"
61
- ruleobj = ::Google::Apis::ComputeV1::ForwardingRule.new(
62
- name: MU::Cloud::Google.nameStr(@mu_name+"-"+l['targetgroup']),
63
- description: @deploy.deploy_id,
64
- load_balancing_scheme: "EXTERNAL",
65
- target: targets[l['targetgroup']].self_link,
66
- ip_protocol: realproto,
67
- port_range: l['lb_port'].to_s
68
- )
61
+ ruleobj = ::Google::Apis::ComputeV1::ForwardingRule.new(
62
+ name: MU::Cloud::Google.nameStr(@mu_name+"-"+l['targetgroup']),
63
+ description: @deploy.deploy_id,
64
+ load_balancing_scheme: @config['scheme']
65
+ )
66
+
67
+ if ["INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED"].include?(@config['scheme'])
68
+ ruleobj.ip_protocol = "TCP"
69
+ ruleobj.all_ports = true
69
70
  else
70
- # TODO network, subnetwork, port_range, target
71
- ruleobj = ::Google::Apis::ComputeV1::ForwardingRule.new(
72
- name: MU::Cloud::Google.nameStr(@mu_name+"-"+l['targetgroup']),
73
- description: @deploy.deploy_id,
74
- load_balancing_scheme: "INTERNAL",
75
- backend_service: backends[l['targetgroup']].self_link,
76
- ip_protocol: l['lb_protocol'],
77
- ports: [l['lb_port'].to_s]
78
- )
71
+ if @config["private"]
72
+ ruleobj.ports = [l['lb_port'].to_s]
73
+ ruleobj.ip_protocol = l['lb_protocol']
74
+ else
75
+ ruleobj.ip_protocol = ["HTTP", "HTTPS"].include?(l['lb_protocol']) ? l['lb_protocol'] : "TCP"
76
+ ruleobj.port_range = l['lb_port'].to_s
77
+ end
79
78
  end
79
+
80
+ if @config['private'] and l['vpc'] # XXX inherit top-level vpc config if it's set
81
+ vpc_obj, _n = myVpc(l['vpc'])
82
+ ruleobj.network = vpc_obj.url.sub(/^.*?\/projects\//, 'projects/')
83
+ ruleobj.subnetwork = mySubnets(vpc_obj, l["vpc"]).first.url
84
+ end
85
+
86
+ if targets[l['targetgroup']]
87
+ ruleobj.target = targets[l['targetgroup']].self_link
88
+ else
89
+ ruleobj.backend_service = backends[l['targetgroup']].self_link
90
+ end
91
+
92
+ @cloud_desc_cache ||= {}
80
93
  if @config['global']
81
94
  MU.log "Creating Global Forwarding Rule #{@mu_name}", MU::NOTICE, details: ruleobj
82
95
  MU::Cloud::Google.compute(credentials: @config['credentials']).insert_global_forwarding_rule(
@@ -84,6 +97,7 @@ module MU
84
97
  ruleobj
85
98
  )
86
99
  else
100
+ ruleobj.network_tier = "STANDARD"
87
101
  MU.log "Creating regional Forwarding Rule #{@mu_name} in #{@config['region']}", MU::NOTICE, details: ruleobj
88
102
  MU::Cloud::Google.compute(credentials: @config['credentials']).insert_forwarding_rule(
89
103
  @project_id,
@@ -95,25 +109,83 @@ module MU
95
109
 
96
110
  end
97
111
 
112
+ # Called automatically by {MU::Deploy#createResources}
113
+ def groom
114
+ if @config['targetgroups']
115
+ @config['targetgroups'].each { |tg|
116
+ if tg['target']
117
+ backend_name = MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))
118
+ serverless = (tg['target']['type'] == "functions")
119
+ region_arg = (serverless or !@config['global']) ? @config['region'] : nil
120
+ neg_desc = createNetworkEndpointGroup(tg['name'], tg['target'], region: region_arg)
121
+ registerTarget(neg_desc.self_link, backends: [backend_name], serverless: serverless)
122
+ end
123
+ }
124
+ end
125
+
126
+ cloud_desc.each_pair { |rule, desc|
127
+ MU.log "LoadBalancer #{@config['name']} (#{rule}) is at #{desc.ip_address}", MU::SUMMARY
128
+ }
129
+ end
130
+
131
+ @cloud_desc_cache = nil
132
+ @backend_cache = nil
133
+ # Return the cloud descriptor for this LoadBalancer, or specifically
134
+ # its forwarding rule(s) since there's really no one artifact.
135
+ # @return [Google::Apis::Core::Hashable]
136
+ def cloud_desc(use_cache: true)
137
+ return @cloud_desc_cache if @cloud_desc_cache and use_cache
138
+ rules = {}
139
+
140
+ @config["listeners"].each { |l|
141
+ name = MU::Cloud::Google.nameStr(@cloud_id+"-"+l['targetgroup'])
142
+ rule = if @config['global']
143
+ MU::Cloud::Google.compute(credentials: @config['credentials']).get_global_forwarding_rule(
144
+ @project_id,
145
+ name
146
+ )
147
+ else
148
+ MU::Cloud::Google.compute(credentials: @config['credentials']).get_forwarding_rule(
149
+ @project_id,
150
+ @config['region'],
151
+ name
152
+ )
153
+ end
154
+ rule = rule.first if !rule.respond_to?(:name)
155
+ rules[rule.name] = rule
156
+ if rule.respond_to?(:backend_service) and !rule.backend_service.nil?
157
+ @backend_cache ||= []
158
+ @backend_cache << rule.backend_service.gsub(/.*?\//, '')
159
+ elsif rule.respond_to?(:target) and !rule.target.nil?
160
+ proxy = self.class.desc_from_url(rule.target, @project_id, credentials: @credentials)
161
+ if proxy.respond_to?(:url_map) and !proxy.url_map.nil?
162
+ urlmap = self.class.desc_from_url(proxy.url_map, @project_id, credentials: @credentials)
163
+ if urlmap.respond_to?(:default_service) and !urlmap.default_service.nil?
164
+ backend = self.class.desc_from_url(urlmap.default_service, @project_id, credentials: @credentials)
165
+ @backend_cache ||= []
166
+ @backend_cache << backend
167
+ end
168
+ end
169
+ end
170
+ }
171
+ rules = nil if rules.empty?
172
+ @backend_cache.uniq! if @backend_cache
173
+ @cloud_desc_cache = rules
174
+
175
+ rules
176
+ end
177
+
178
+
98
179
  # Return the metadata for this LoadBalancer
99
180
  # @return [Hash]
100
181
  def notify
182
+ descs = cloud_desc(use_cache: false).dup
101
183
  rules = {}
102
- resp = MU::Cloud::Google.compute(credentials: @config['credentials']).list_global_forwarding_rules(
103
- @project_id,
104
- filter: "description eq #{@deploy.deploy_id}"
105
- )
106
- if resp.nil? or resp.items.nil? or resp.items.size == 0
107
- resp = MU::Cloud::Google.compute(credentials: @config['credentials']).list_forwarding_rules(
108
- @project_id,
109
- @config['region'],
110
- filter: "description eq #{@deploy.deploy_id}"
111
- )
112
- end
113
- if !resp.nil? and !resp.items.nil?
114
- resp.items.each { |rule|
115
- rules[rule.name] = rule.to_h
116
- rules[rule.name].delete(:label_fingerprint)
184
+ if descs
185
+ descs.each_pair { |name, rule|
186
+ rules[name] = MU.structToHash(rule, stringify_keys: true)
187
+ rules[name].delete("label_fingerprint")
188
+ rules[name].delete("fingerprint")
117
189
  }
118
190
  end
119
191
  rules["project_id"] = @project_id
@@ -123,16 +195,42 @@ module MU
123
195
 
124
196
  # Register a Server node with an existing LoadBalancer.
125
197
  #
126
- # @param instance_id [String] A node to register.
127
- # @param targetgroups [Array<String>] The target group(s) of which this node should be made a member. Not applicable to classic LoadBalancers. If not supplied, the node will be registered to all available target groups on this LoadBalancer.
128
- def registerNode(instance_id, targetgroups: nil)
198
+ # @param target [String] A node or URL or something to register.
199
+ # @param backends [Array<String>] The target group(s) of which this node should be made a member.
200
+ def registerTarget(target, backends: nil, serverless: false)
201
+ cloud_desc
202
+
203
+ @backend_cache.each { |b|
204
+ next if backends and !backends.include?(b.name)
205
+
206
+ b.backends ||= []
207
+ if serverless
208
+ b.health_checks = []
209
+ b.timeout_sec = nil
210
+ b.port_name = nil
211
+ end
212
+ next if b.backends.map { |ext| ext.group }.include?(target)
213
+ b.backends << MU::Cloud::Google.compute(:Backend).new(
214
+ group: target
215
+ )
216
+ MU.log "Adding target #{target} to backend service #{b.name}", details: b
217
+ b.self_link =~ /\/projects\/[^\/]+\/([^\/]+)\/backendServices/
218
+ region = Regexp.last_match[1] == "global" ? nil : Regexp.last_match[1]
219
+ method = "update_#{region ? "region_" : ""}backend_service".to_sym
220
+ args = [@project_id]
221
+ args << region if region
222
+ args << b.name
223
+ args << b
224
+ MU::Cloud::Google.compute(credentials: @credentials).send(method, *args)
225
+ }
226
+
129
227
  end
130
228
 
131
229
  # Does this resource type exist as a global (cloud-wide) artifact, or
132
230
  # is it localized to a region/zone?
133
231
  # @return [Boolean]
134
232
  def self.isGlobal?
135
- true
233
+ false # XXX it's both, actually
136
234
  end
137
235
 
138
236
  # Denote whether this resource implementation is experiment, ready for
@@ -148,34 +246,59 @@ module MU
148
246
  # @return [void]
149
247
  def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: nil, credentials: nil, flags: {})
150
248
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
249
+
151
250
  return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
152
- filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
153
- if !ignoremaster and MU.mu_public_ip
154
- filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
155
- end
251
+ filter = "description eq #{deploy_id}" # most of these objects don't support labels
252
+ # filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
253
+ # if !ignoremaster and MU.mu_public_ip
254
+ # filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
255
+ # end
256
+
156
257
  MU.log "Placeholder: Google LoadBalancer artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
157
258
 
158
- if region
159
- ["forwarding_rule", "region_backend_service"].each { |type|
259
+ # if flags['global']
260
+ # XXX network_endpoint_group is actually a zonal artifact, ugh
261
+ # resp = MU::Cloud::Google.compute(credentials: credentials).list_network_endpoint_groups(flags["habitat"], filter: "description eq #{deploy_id}")
262
+ # if resp and resp.items
263
+ # resp.items.each { |neg|
264
+ # MU.log "Removing Network Endpoint Group #{neg.name}"
265
+ # MU::Cloud::Google.compute(credentials: credentials).delete_network_endpoint_group(flags["habitat"], neg.name) if !noop
266
+ # }
267
+ # end
268
+
269
+ ["global_forwarding_rule", "target_tcp_proxy", "target_grpc_proxy", "target_ssl_proxy", "target_http_proxy", "target_https_proxy", "url_map", "backend_service", "health_check", "http_health_check", "https_health_check"].each { |type|
160
270
  MU::Cloud::Google.compute(credentials: credentials).delete(
161
271
  type,
162
272
  flags["habitat"],
163
- region,
164
- noop
273
+ nil,
274
+ noop,
275
+ filter
165
276
  )
166
277
  }
167
- end
278
+ # end
279
+
280
+ if region
281
+ # Network Endpoint Groups don't have labels, so our deploy id gets
282
+ # shoved into the description.
283
+ resp = MU::Cloud::Google.compute(credentials: credentials).list_region_network_endpoint_groups(flags["habitat"], region, filter: "description eq #{deploy_id}")
284
+ if resp and resp.items
285
+ resp.items.each { |neg|
286
+ MU.log "Removing regional Network Endpoint Group #{neg.name}"
287
+ MU::Cloud::Google.compute(credentials: credentials).delete_region_network_endpoint_group(flags["habitat"], region, neg.name) if !noop
288
+ }
289
+ end
168
290
 
169
- if flags['global']
170
- ["global_forwarding_rule", "target_http_proxy", "target_https_proxy", "url_map", "backend_service", "health_check", "http_health_check", "https_health_check"].each { |type|
291
+ ["forwarding_rule", "region_url_map", "region_backend_service", "region_network_endpoint_group", "region_target_http_proxy", "region_target_https_proxy", "region_health_check"].each { |type|
171
292
  MU::Cloud::Google.compute(credentials: credentials).delete(
172
293
  type,
173
294
  flags["habitat"],
174
- nil,
175
- noop
295
+ region,
296
+ noop,
297
+ filter
176
298
  )
177
299
  }
178
300
  end
301
+
179
302
  end
180
303
 
181
304
  # Cloud-specific configuration properties.
@@ -184,6 +307,29 @@ module MU
184
307
  def self.schema(_config)
185
308
  toplevel_required = []
186
309
  schema = {
310
+ "targetgroups" => {
311
+ "items" => {
312
+ "properties" => {
313
+ "proto" => {
314
+ "enum" => ["HTTP", "HTTPS", "TCP", "SSL", "GRPC"]
315
+ },
316
+ "target" => MU::Config::Ref.schema(parent_obj: "loadbalancer", type: "functions"),
317
+ "vpc" => MU::Config::VPC.reference(MU::Config::VPC::ONE_SUBNET, MU::Config::VPC::NO_NAT_OPTS, "public")
318
+ }
319
+ }
320
+ },
321
+ "listeners" => {
322
+ "items" => {
323
+ "properties" => {
324
+ "vpc" => MU::Config::VPC.reference(MU::Config::VPC::ONE_SUBNET, MU::Config::VPC::NO_NAT_OPTS, "public")
325
+ }
326
+ }
327
+ },
328
+ "scheme" => {
329
+ "type" => "string",
330
+ "enum" => ["EXTERNAL", "INTERNAL", "INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED"],
331
+ "description" => "Choose +EXTERNAL+ for external HTTP(S), SSL Proxy, TCP Proxy and Network Load Balancing; +INTERNAL+ for Internal TCP/ UDP Load Balancing; +INTERNAL_MANAGED+ for Internal HTTP(S) Load Balancing; +INTERNAL_SELF_MANAGED+ for Traffic Director. If not specified, will default to +EXTERNAL+ or +INTERNAL+ depending on the value of the {private} flag."
332
+ },
187
333
  "named_ports" => {
188
334
  "type" => "array",
189
335
  "items" => {
@@ -211,6 +357,9 @@ module MU
211
357
  # @return [Boolean]: True if validation succeeded, False otherwise
212
358
  def self.validateConfig(lb, _configurator)
213
359
  ok = true
360
+
361
+ lb['region'] ||= MU::Cloud::Google.myRegion(lb['credentials'])
362
+
214
363
  if lb['classic']
215
364
  MU.log "LoadBalancer 'classic' flag has no meaning in Google Cloud", MU::WARN
216
365
  end
@@ -236,15 +385,19 @@ module MU
236
385
  end
237
386
 
238
387
  if lb['private'] and lb['global']
239
- MU.log "Private Google Cloud LoadBalancer requested, setting 'global' flag to false", MU::WARN
388
+ MU.log "Private Google Cloud LoadBalancer requested, setting 'global' flag to false", MU::DEBUG
240
389
  lb['global'] = false
241
390
  end
242
391
 
392
+ lb['scheme'] ||= lb['private'] ? "INTERNAL" : "EXTERNAL"
393
+
243
394
  lb["listeners"].each { |l|
244
- if lb["private"] and !["TCP", "UDP"].include?(l['lb_protocol'])
245
- MU.log "Only TCP and UDP listeners are valid for private LoadBalancers in Google Cloud", MU::ERR
246
- ok = false
395
+ if lb['scheme'] == "INTERNAL" and !["TCP", "UDP"].include?(l['lb_protocol'])
396
+ # MU.log "Only TCP and UDP listeners are valid for private LoadBalancers in Google Cloud", MU::ERR
397
+ # ok = false
247
398
  end
399
+ l['instance_protocol'] ||= l['lb_protocol']
400
+ l['instance_port'] ||= l['lb_port']
248
401
 
249
402
  if lb['global'] and l['lb_protocol'] == "UDP"
250
403
  MU.log "UDP LoadBalancers can only be per-region in Google Cloud. Setting 'global' to false.", MU::WARN
@@ -256,34 +409,36 @@ module MU
256
409
  end
257
410
  }
258
411
 
259
- lb["targetgroups"].each { |tg|
260
- if tg["healthcheck"]
261
- target = tg["healthcheck"]['target'].match(/^([^:]+):(\d+)(.*)/)
262
- if tg["proto"] != target[1]
263
- MU.log "LoadBalancer #{lb['name']} can't mix and match target group and health check protocols in Google Cloud", MU::ERR, details: tg
264
- ok = false
265
- end
266
- else
267
- # health checks are required; create a generic one
268
- tg["healthcheck"] = {
269
- "timeout" => 5,
270
- "interval" => 30,
271
- "unhealthy_threshold" => 2,
272
- "healthy_threshold" => 2,
273
- }
274
- if tg["proto"] == "HTTP" or tg["proto"] == "HTTPS"
275
- if lb['private']
276
- MU.log "Private GCP LoadBalancers can only target TCP or UDP protocols, changing #{tg["proto"]} to TCP", MU::NOTICE
277
- tg["proto"] = "TCP"
412
+ if lb['scheme'] != "INTERNAL_MANAGED"
413
+ lb["targetgroups"].each { |tg|
414
+ if tg["healthcheck"]
415
+ target = tg["healthcheck"]['target'].match(/^([^:]+):(\d+)(.*)/)
416
+ if tg["proto"] != target[1]
417
+ MU.log "LoadBalancer #{lb['name']} can't mix and match target group and health check protocols in Google Cloud", MU::ERR, details: tg
418
+ ok = false
278
419
  end
279
- tg["healthcheck"]["target"] = tg["proto"]+":"+tg["port"].to_s+"/"
280
- tg["healthcheck"]["httpcode"] = "200,301,302"
281
420
  else
282
- tg["healthcheck"]["target"] = tg["proto"]+":"+tg["port"].to_s
421
+ # health checks are required; create a generic one
422
+ tg["healthcheck"] = {
423
+ "timeout" => 5,
424
+ "interval" => 30,
425
+ "unhealthy_threshold" => 2,
426
+ "healthy_threshold" => 2,
427
+ }
428
+ if tg["proto"] == "HTTP" or tg["proto"] == "HTTPS"
429
+ if lb['scheme'] == "INTERNAL"
430
+ MU.log "INTERNAL GCP LoadBalancers can only target TCP or UDP protocols, changing #{tg["proto"]} to TCP", MU::NOTICE
431
+ tg["proto"] = "TCP"
432
+ end
433
+ tg["healthcheck"]["target"] = tg["proto"]+":"+tg["port"].to_s+"/"
434
+ tg["healthcheck"]["httpcode"] = "200,301,302"
435
+ else
436
+ tg["healthcheck"]["target"] = tg["proto"]+":"+tg["port"].to_s
437
+ end
438
+ MU.log "No healthcheck declared for target group #{tg['name']} in LoadBalancer #{lb['name']}, creating one.", details: tg
283
439
  end
284
- MU.log "No healthcheck declared for target group #{tg['name']} in LoadBalancer #{lb['name']}, creating one.", details: tg
285
- end
286
- }
440
+ }
441
+ end
287
442
 
288
443
  ok
289
444
  end
@@ -296,60 +451,153 @@ module MU
296
451
 
297
452
  private
298
453
 
299
- def createProxy(tg, backend)
300
- name = MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))
454
+ # Construct the method call to fetch descriptors for various backend
455
+ # components out of the chunks in a URL, as it might be referenced from
456
+ # another resource.
457
+ def self.desc_from_url(url, project_id, credentials: nil)
458
+ regions = MU::Cloud::Google.listRegions + ["global"]
459
+ loc_pattern = "("+regions.map { |r|
460
+ 'regions\/'+Regexp.quote(r)
461
+ }.join("|")+"|global)"
462
+ args = []
463
+ resource_name = nil
464
+ url =~ /\/projects\/#{Regexp.quote(project_id)}\/(#{loc_pattern})\//
465
+ location = Regexp.last_match[1]
466
+ global = (location == "global")
467
+ region = global ? nil : location.sub(/regions\//, '')
468
+
469
+ if url =~ /\/#{location}\/target(Https?|Http|Ssl|Grpc|Tcp)Proxies\/([^\/]+)$/i
470
+ proxytype = Regexp.last_match[1]
471
+ resource_name = Regexp.last_match[2]
472
+ args << "get_#{global ? "" : "region_"}target_#{proxytype.downcase}_proxy".to_sym
473
+ elsif url =~ /\/#{location}\/urlMaps\/([^\/]+)$/i
474
+ resource_name = Regexp.last_match[1]
475
+ args << "get_#{global ? "" : "region_"}url_map".to_sym
476
+ elsif url =~ /\/#{location}\/backendServices\/([^\/]+)$/i
477
+ resource_name = Regexp.last_match[1]
478
+ args << "get_#{global ? "" : "region_"}backend_service".to_sym
479
+ else
480
+ MU.log "I don't know how to extract a resource from #{url}", MU::ERR
481
+ end
482
+ args << project_id
483
+ args << region if !global and region
484
+ args << resource_name
301
485
 
302
- urlmap_obj = MU::Cloud::Google.compute(:UrlMap).new(
303
- name: name,
304
- description: @deploy.deploy_id,
305
- # TODO this is where path_matchers, host_rules, and tests go (the sophisticated
306
- # Layer 7 stuff)
307
- default_service: backend.self_link
308
- )
309
- MU.log "Creating url map #{tg['name']}", details: urlmap_obj
310
- urlmap = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_url_map(
311
- @project_id,
312
- urlmap_obj
313
- )
486
+ MU::Cloud::Google.compute(credentials: credentials).send(*args)
487
+ end
488
+
489
+ def createProxy(tg, backend, region: nil)
490
+ name = MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))
314
491
 
315
492
  desc = {
316
493
  :name => name,
317
494
  :description => @deploy.deploy_id,
318
- :url_map => urlmap.self_link
319
495
  }
320
496
 
321
- if tg['proto'] == "HTTP"
322
- target_obj = MU::Cloud::Google.compute(:TargetHttpProxy).new(desc)
323
- MU.log "Creating http target proxy #{tg['name']}", details: target_obj
324
- MU::Cloud::Google.compute(credentials: @config['credentials']).insert_target_http_proxy(
325
- @project_id,
326
- target_obj
327
- )
328
- else
497
+ realproto = @config['scheme'] == "INTERNAL_MANAGED" ? "TCP" : tg['proto']
498
+ proxytype = ("Target"+realproto.capitalize+"Proxy").to_sym
499
+
500
+ if ["HTTPS", "SSL"].include?(realproto)
329
501
  certdata = @deploy.nodeSSLCerts(self, false, 2048)
330
502
  cert_pem = certdata[0].to_s+File.read("/etc/pki/Mu_CA.pem")
331
503
  gcpcert = MU::Cloud::Google.createSSLCertificate(@mu_name.downcase+"-"+tg['name'], cert_pem, certdata[1], credentials: @config['credentials'])
332
504
 
333
505
  # TODO we need a method like MU::Cloud::AWS.findSSLCertificate, with option to hunt down an existing one
334
506
  desc[:ssl_certificates] = [gcpcert.self_link]
335
- target_obj = MU::Cloud::Google.compute(:TargetHttpsProxy).new(desc)
336
- MU.log "Creating https target proxy #{tg['name']}", details: target_obj
337
- MU::Cloud::Google.compute(credentials: @config['credentials']).insert_target_https_proxy(
338
- @project_id,
339
- target_obj
507
+ elsif realproto == "TCP"
508
+ desc[:service] = backend.self_link
509
+ end
510
+
511
+ if ["HTTP", "HTTPS"].include?(realproto)
512
+ urlmap_obj = MU::Cloud::Google.compute(:UrlMap).new(
513
+ name: name,
514
+ description: @deploy.deploy_id,
515
+ # TODO this is where path_matchers, host_rules, and tests go (the sophisticated
516
+ # Layer 7 stuff)
517
+ default_service: backend.self_link,
518
+ path_matchers: [MU::Cloud::Google.compute(:PathMatcher).new(
519
+ name: "star",
520
+ default_service: backend.self_link,
521
+ paths: ["*"]
522
+ )],
523
+ host_rules: [MU::Cloud::Google.compute(:HostRule).new(
524
+ hosts: ["*"],
525
+ path_matcher: "star"
526
+ )]
527
+ )
528
+ MU.log "Creating #{region ? region+" " : ""}url map #{tg['name']}", details: urlmap_obj
529
+
530
+ urlmap = if region
531
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_region_url_map(
532
+ @project_id,
533
+ region,
534
+ urlmap_obj
535
+ )
536
+ else
537
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_url_map(
538
+ @project_id,
539
+ urlmap_obj
540
+ )
541
+ end
542
+ desc[:url_map] = urlmap.self_link
543
+ end
544
+
545
+ target_obj = MU::Cloud::Google.compute(proxytype).new(desc)
546
+ MU.log "Creating #{region ? region+" " : ""}#{realproto} target proxy #{tg['name']}", details: target_obj
547
+
548
+ if region and ["HTTP", "HTTPS"].include?(realproto)
549
+ MU::Cloud::Google.compute(credentials: @config['credentials']).send(("insert_region_target_"+realproto.downcase+"_proxy").to_sym, @project_id, region, target_obj)
550
+ else
551
+ MU::Cloud::Google.compute(credentials: @config['credentials']).send(("insert_target_"+realproto.downcase+"_proxy").to_sym, @project_id, target_obj)
552
+ end
553
+
554
+ end
555
+
556
+ def createNetworkEndpointGroup(basename, target, region: nil, type: "SERVERLESS", vpc: nil)
557
+ function = MU::Config::Ref.get(target).kitten
558
+ if !function
559
+ MU::Config::Ref.get(target).kitten(debug: true)
560
+ raise MuError.new "Failed to locate Cloud Function from reference", details: target
561
+ end
562
+ neg_name = @deploy.getResourceName(basename, max_length: 19, never_gen_unique: true).downcase
563
+ begin
564
+ if region
565
+ MU::Cloud::Google.compute(credentials: @config['credentials']).get_region_network_endpoint_group(@project_id, region, neg_name)
566
+ else
567
+ MU::Cloud::Google.compute(credentials: @config['credentials']).get_global_network_endpoint_group(@project_id, neg_name)
568
+ end
569
+ rescue ::Google::Apis::ClientError => e
570
+ raise e if e.message !~ /notFound:/
571
+ neg_obj = MU::Cloud::Google.compute(:NetworkEndpointGroup).new(
572
+ name: neg_name,
573
+ description: @deploy.deploy_id,
574
+ cloud_function: MU::Cloud::Google.compute(:NetworkEndpointGroupCloudFunction).new(
575
+ function: function.cloud_id.gsub(/.*?\//, '')
576
+ ),
577
+ network_endpoint_type: type
340
578
  )
579
+ neg_obj.network = vpc.url if vpc and type != "SERVERLESS"
580
+ MU.log "Creating Network Endpoint Group #{neg_name}", details: neg_obj
581
+ if region
582
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_region_network_endpoint_group(@project_id, @config['region'], neg_obj)
583
+ else
584
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_global_network_endpoint_group(@project_id, neg_obj)
585
+ end
586
+ retry
341
587
  end
588
+
342
589
  end
343
590
 
344
- def createBackendService(tg)
591
+ def createBackendService(tg, region: nil)
345
592
  desc = {
346
593
  :name => MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"])),
347
594
  :description => @deploy.deploy_id,
348
- :load_balancing_scheme => @config['private'] ? "INTERNAL" : "EXTERNAL",
349
- :global => @config['global'],
595
+ :load_balancing_scheme => @config['scheme'],
350
596
  :protocol => tg['proto'],
351
597
  :timeout_sec => @config['idle_timeout']
352
598
  }
599
+ desc[:global] = region.nil?
600
+ desc[:backends] = []
353
601
  # TODO EXTERNAL only: port_name, enable_cdn
354
602
  if @config['connection_draining_timeout'] > 0
355
603
  desc[:connection_draining] = MU::Cloud::Google.compute(:ConnectionDraining).new(
@@ -376,21 +624,19 @@ module MU
376
624
  hc = createHealthCheck(tg["healthcheck"], tg["name"])
377
625
  desc[:health_checks] = [hc.self_link]
378
626
  end
627
+ if ["EXTERNAL", "INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED"].include?(@config['scheme'])
628
+ desc[:port_name] = "placeholder" # relevant when an actual instance group backend is added, required for some reason even if not relevant
629
+ end
379
630
 
380
631
  backend_obj = MU::Cloud::Google.compute(:BackendService).new(desc)
381
- MU.log "Creating backend service #{MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))}", details: backend_obj
382
- if @config['private'] and !@config['global']
383
- return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_region_backend_service(
384
- @project_id,
385
- @config['region'],
386
- backend_obj
387
- )
388
- else
389
- return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_backend_service(
390
- @project_id,
391
- backend_obj
392
- )
393
- end
632
+ MU.log "Creating #{region ? region : "global"} backend service #{MU::Cloud::Google.nameStr(@deploy.getResourceName(tg["name"]))}", MU::NOTICE, details: backend_obj
633
+
634
+ method = "insert_#{region ? "region_": ""}backend_service".to_sym
635
+ args = [@project_id]
636
+ args << region if region
637
+ args << backend_obj
638
+
639
+ MU::Cloud::Google.compute(credentials: @credentials).send(method, *args)
394
640
  end
395
641
 
396
642
  def createHealthCheck(hc, namebase)
@@ -401,8 +647,8 @@ module MU
401
647
  path = target[3]
402
648
  name = MU::Cloud::Google.nameStr(@deploy.getResourceName(namebase+"-hc-"+proto.downcase+"-"+port.to_s))
403
649
 
404
- if proto == "HTTP" or proto == "HTTPS"
405
- hc_obj = MU::Cloud::Google.compute(proto == "HTTP" ? :HttpHealthCheck : :HttpsHealthCheck).new(
650
+ httpcheck = if ["HTTP", "HTTPS", "HTTP2"].include?(proto)
651
+ MU::Cloud::Google.compute("#{proto.capitalize}HealthCheck".to_sym).new(
406
652
  check_interval_sec: hc["interval"],
407
653
  timeout_sec: hc["timeout"],
408
654
  unhealthy_threshold: hc["unhealthy_threshold"],
@@ -412,20 +658,12 @@ module MU
412
658
  port: port,
413
659
  request_path: path ? path : "/"
414
660
  )
415
- # other types:
416
- # type: SSL, HTTP2
417
- MU.log "Creating #{proto} health check #{name}", details: hc_obj
418
- if proto == "HTTP"
419
- return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_http_health_check(
420
- @project_id,
421
- hc_obj
422
- )
423
- else
424
- return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_https_health_check(
425
- @project_id,
426
- hc_obj
427
- )
428
- end
661
+ end
662
+
663
+ if proto == "HTTP" or proto == "HTTPS" and @config['global']
664
+ MU.log "Creating global #{proto} health check #{name}", details: httpcheck
665
+ method = "insert_#{proto.downcase}_health_check"
666
+ return MU::Cloud::Google.compute(credentials: @config['credentials']).send(method, @project_id, httpcheck)
429
667
  else
430
668
  desc = {
431
669
  :check_interval_sec => hc["interval"],
@@ -433,10 +671,10 @@ module MU
433
671
  :unhealthy_threshold => hc["unhealthy_threshold"],
434
672
  :healthy_threshold => hc["healthy_threshold"],
435
673
  :description => @deploy.deploy_id,
436
- :name => name
674
+ :name => name,
675
+ :type => proto
437
676
  }
438
677
  if proto == "TCP"
439
- desc[:type] = "TCP"
440
678
  desc[:tcp_health_check] = MU::Cloud::Google.compute(:TcpHealthCheck).new(
441
679
  port: port,
442
680
  proxy_header: "NONE",
@@ -444,27 +682,36 @@ module MU
444
682
  response: ""
445
683
  )
446
684
  elsif proto == "SSL"
447
- desc[:type] = "SSL"
448
685
  desc[:ssl_health_check] = MU::Cloud::Google.compute(:SslHealthCheck).new(
449
686
  port: port,
450
687
  proxy_header: "NONE",
451
688
  request: "", # XXX needs to be configurable
452
689
  response: "" # XXX needs to be configurable
453
690
  )
454
- elsif proto == "UDP"
455
- desc[:type] = "UDP"
691
+ elsif proto == "GRPC"
692
+ desc[:grpc_health_check] = MU::Cloud::Google.compute(:GrpcHealthCheck).new(
693
+ port: port,
694
+ port_specification: "USE_FIXED_PORT",
695
+ port_name: "", # XXX needs to be configurable
696
+ grpc_service_name: "" # XXX needs to be configurable
697
+ )
698
+ elsif proto == "UDP" # XXX deprecated I think?
456
699
  desc[:udp_health_check] = MU::Cloud::Google.compute(:UdpHealthCheck).new(
457
700
  port: port,
458
701
  request: "ORLY", # XXX needs to be configurable
459
702
  response: "YARLY" # XXX needs to be configurable
460
703
  )
704
+ elsif ["HTTP", "HTTPS", "HTTP2"].include?(proto)
705
+ desc["#{proto.downcase}_health_check".to_sym] = httpcheck
461
706
  end
462
707
  hc_obj = MU::Cloud::Google.compute(:HealthCheck).new(desc)
463
- MU.log "INSERTING HEALTH CHECK", MU::NOTICE, details: hc_obj
464
- return MU::Cloud::Google.compute(credentials: @config['credentials']).insert_health_check(
465
- @project_id,
466
- hc_obj
467
- )
708
+ method = "insert_#{@config['global'] ? "" : "region_" }health_check"
709
+ args = [@project_id]
710
+ args << @config['region'] if !@config['global']
711
+ args << hc_obj
712
+
713
+ MU.log "Creating #{@config['global'] ? "global" : @config['region'] } health check #{name}", details: hc_obj
714
+ return MU::Cloud::Google.compute(credentials: @config['credentials']).send(method, *args)
468
715
  end
469
716
 
470
717
  end