cloud-mu 3.5.0 → 3.6.3

Sign up to get free protection for your applications and to get access to all the features.
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