hub-clusters-creator 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Makefile +28 -0
- data/bin/aks.rb +42 -0
- data/bin/gke.rb +48 -0
- data/docker/Dockerfile +20 -0
- data/docker/entrypoint.sh +89 -0
- data/hub-clusters-creator.gemspec +34 -0
- data/lib/hub-clusters-creator.rb +49 -0
- data/lib/hub-clusters-creator/agent.rb +142 -0
- data/lib/hub-clusters-creator/errors.rb +48 -0
- data/lib/hub-clusters-creator/kube/kube.rb +147 -0
- data/lib/hub-clusters-creator/logging.rb +46 -0
- data/lib/hub-clusters-creator/providers/aks/azure.rb +272 -0
- data/lib/hub-clusters-creator/providers/aks/helpers.rb +105 -0
- data/lib/hub-clusters-creator/providers/aks/schema.yaml +125 -0
- data/lib/hub-clusters-creator/providers/bootstrap.rb +226 -0
- data/lib/hub-clusters-creator/providers/gke/gke.rb +264 -0
- data/lib/hub-clusters-creator/providers/gke/helpers.rb +364 -0
- data/lib/hub-clusters-creator/providers/gke/schema.yaml +411 -0
- data/lib/hub-clusters-creator/providers/schema.yaml +113 -0
- data/lib/hub-clusters-creator/template.rb +45 -0
- data/lib/hub-clusters-creator/version.rb +20 -0
- metadata +192 -0
@@ -0,0 +1,264 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2019 Rohith Jayawardene <gambol99@gmail.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU General Public License
|
7
|
+
# as published by the Free Software Foundation; either version 2
|
8
|
+
# of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
require 'google/apis/compute_v1'
|
19
|
+
require 'google/apis/container_v1beta1'
|
20
|
+
require 'google/apis/dns_v1'
|
21
|
+
require 'googleauth'
|
22
|
+
|
23
|
+
require 'hub-clusters-creator/errors'
|
24
|
+
require 'hub-clusters-creator/kube/kube'
|
25
|
+
require 'hub-clusters-creator/logging'
|
26
|
+
require 'hub-clusters-creator/providers/bootstrap'
|
27
|
+
require 'hub-clusters-creator/providers/gke/helpers'
|
28
|
+
|
29
|
+
# rubocop:disable Metrics/ClassLength,Metrics/LineLength,Metrics/MethodLength
|
30
|
+
module HubClustersCreator
|
31
|
+
module Providers
|
32
|
+
# GKE provides the GKE implmentation
|
33
|
+
class GKE
|
34
|
+
DEFAULT_PSP_CLUSTER_ROLE = <<~YAML
|
35
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
36
|
+
kind: ClusterRole
|
37
|
+
metadata:
|
38
|
+
name: default:psp
|
39
|
+
rules:
|
40
|
+
- apiGroups:
|
41
|
+
- policy
|
42
|
+
resourceNames:
|
43
|
+
- gce.unprivileged-addon
|
44
|
+
resources:
|
45
|
+
- podsecuritypolicies
|
46
|
+
verbs:
|
47
|
+
- use
|
48
|
+
YAML
|
49
|
+
|
50
|
+
DEFAULT_PSP_CLUSTERROLE_BINDING = <<~YAML
|
51
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
52
|
+
kind: ClusterRoleBinding
|
53
|
+
metadata:
|
54
|
+
name: default:psp
|
55
|
+
roleRef:
|
56
|
+
apiGroup: rbac.authorization.k8s.io
|
57
|
+
kind: ClusterRole
|
58
|
+
name: default:psp
|
59
|
+
subjects:
|
60
|
+
- apiGroup: rbac.authorization.k8s.io
|
61
|
+
kind: Group
|
62
|
+
name: system:authenticated
|
63
|
+
- apiGroup: rbac.authorization.k8s.io
|
64
|
+
kind: Group
|
65
|
+
name: system:serviceaccounts
|
66
|
+
YAML
|
67
|
+
|
68
|
+
# Compute are a collection of methods used to interact with GCP
|
69
|
+
include Errors
|
70
|
+
include GCP::Compute
|
71
|
+
include GCP::Containers
|
72
|
+
include Logging
|
73
|
+
|
74
|
+
Container = Google::Apis::ContainerV1beta1
|
75
|
+
Compute = Google::Apis::ComputeV1
|
76
|
+
Dns = Google::Apis::DnsV1
|
77
|
+
|
78
|
+
def initialize(provider)
|
79
|
+
@account = provider[:account]
|
80
|
+
@project = provider[:project]
|
81
|
+
@region = provider[:region]
|
82
|
+
@compute = Compute::ComputeService.new
|
83
|
+
@gke = Container::ContainerService.new
|
84
|
+
@dns = Dns::DnsService.new
|
85
|
+
@client = nil
|
86
|
+
|
87
|
+
@compute.authorization = authorize
|
88
|
+
@gke.authorization = authorize
|
89
|
+
@dns.authorization = authorize
|
90
|
+
end
|
91
|
+
|
92
|
+
# create is responsible for building the infrastructure
|
93
|
+
def create(name, config)
|
94
|
+
# @step: validate the configuration
|
95
|
+
begin
|
96
|
+
validate(config)
|
97
|
+
rescue StandardError => e
|
98
|
+
raise ConfigurationError, "invalid configuration, error: #{e}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# @step: provision the infrastructure
|
102
|
+
begin
|
103
|
+
provision_gke(name, config)
|
104
|
+
rescue StandardError => e
|
105
|
+
raise InfrastructureError, "failed to provision cluster: '#{name}', error: #{e}"
|
106
|
+
end
|
107
|
+
|
108
|
+
# @step: initialize the cluster
|
109
|
+
begin
|
110
|
+
c = provision_cluster(name, config)
|
111
|
+
rescue StandardError => e
|
112
|
+
raise InitializerError, "failed to initialize the cluster: '#{name}', error: #{e}"
|
113
|
+
end
|
114
|
+
|
115
|
+
{
|
116
|
+
cluster: {
|
117
|
+
ca: c.master_auth.cluster_ca_certificate,
|
118
|
+
endpoint: "https://#{c.endpoint}",
|
119
|
+
token: @client.account('sysadmin')
|
120
|
+
},
|
121
|
+
config: config,
|
122
|
+
services: {
|
123
|
+
grafana: {
|
124
|
+
hostname: config[:grafana_hostname]
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
# destroy is used to kill off a cluster
|
131
|
+
def destroy(name)
|
132
|
+
@gke.delete_project_location_cluster("projects/#{@project}/locations/#{@region}/clusters/#{name}")
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# provision_gke is responsible for provisioning the infrastucture
|
138
|
+
# rubocop:disable Metrics/AbcSize
|
139
|
+
def provision_gke(name, config)
|
140
|
+
info "checking if the gke cluster: '#{name}' exists"
|
141
|
+
if cluster?(name)
|
142
|
+
info "skipping the creation of cluster: '#{name}' as it already exists"
|
143
|
+
else
|
144
|
+
info "cluster: '#{name}' does not exist, creating now"
|
145
|
+
path = "projects/#{@project}/locations/#{@region}"
|
146
|
+
operation = @gke.create_project_location_cluster(path, cluster_spec(config))
|
147
|
+
|
148
|
+
info "waiting for the cluster: '#{name}' to be created, operation: '#{operation.name}'"
|
149
|
+
status = hold_for_operation(operation.name)
|
150
|
+
unless status.status_message.nil?
|
151
|
+
raise InfrastructureError, "operation: '#{x.operation_type}' failed, error: #{x.status_message}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
gke = cluster(name)
|
155
|
+
|
156
|
+
# @step: create a cloud-nat device if private networking enabled
|
157
|
+
# and nothing exists already
|
158
|
+
if config[:enable_private_network]
|
159
|
+
info 'checking if cloud-nat device has been created'
|
160
|
+
router('router') do |x|
|
161
|
+
unless x.nats
|
162
|
+
x.nats = default_cloud_nat('cloud-nat')
|
163
|
+
patch_router('router', x)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
info "provisioning a dns entry for the master api = > #{gke.endpoint}"
|
169
|
+
# dns(kubeapi_name(config).to_s, gke.endpoint, config[:domain])
|
170
|
+
end
|
171
|
+
# rubocop:enable Metrics/AbcSize
|
172
|
+
|
173
|
+
# provision_cluster is responsible for kickstarting the cluster
|
174
|
+
# rubocop:disable Metrics/AbcSize
|
175
|
+
def provision_cluster(name, config)
|
176
|
+
info "waiting for the master api endpoint to be available on cluster: #{name}"
|
177
|
+
thing = cluster(name)
|
178
|
+
@client = HubClustersCreator::Kube.new(thing.endpoint, token: authorize.access_token)
|
179
|
+
@client.wait_for_kubeapi
|
180
|
+
|
181
|
+
# @step: if psp is enabled we need to add the roles and bindings
|
182
|
+
info 'creating the default psp binding to unpriviledged policy'
|
183
|
+
@client.kubectl(DEFAULT_PSP_CLUSTER_ROLE)
|
184
|
+
@client.kubectl(DEFAULT_PSP_CLUSTERROLE_BINDING)
|
185
|
+
|
186
|
+
# @step: bootstrap the cluster and wait
|
187
|
+
HubClustersCreator::Providers::Bootstrap.new(name, @client, config).bootstrap
|
188
|
+
|
189
|
+
ingress = @client.get('loki-grafana', 'loki', 'ingresses', version: 'extensions/v1beta1')
|
190
|
+
address = ingress.status.loadBalancer.ingress.first.ip
|
191
|
+
|
192
|
+
# @step: update the dns record for the ingress
|
193
|
+
unless (config[:grafana_hostname] || '').empty?
|
194
|
+
info "adding a dns record for #{config[:grafana_hostname]} => #{address}"
|
195
|
+
dns(config[:grafana_hostname].split('.').first, address, config[:domain])
|
196
|
+
end
|
197
|
+
|
198
|
+
cluster(name)
|
199
|
+
end
|
200
|
+
# rubocop:enable Metrics/AbcSize
|
201
|
+
|
202
|
+
# validate is responsible for validating the options for cluster creation
|
203
|
+
# rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
204
|
+
def validate(config)
|
205
|
+
raise ConfigurationError, "domain: #{config[:domain]} does not exist within project" unless domain?(config[:domain])
|
206
|
+
raise ConfigurationError, 'disk size must be positive' unless config[:disk_size_gb].positive?
|
207
|
+
raise ConfigurationError, 'size must be positive' unless config[:size].positive?
|
208
|
+
|
209
|
+
# @check the networking options
|
210
|
+
raise ConfigurationError, 'the network does not exist' unless network?(config[:network])
|
211
|
+
raise ConfigurationError, 'the subnetwork does not exist' unless subnet?(config[:subnetwork], config[:network]) && !config[:create_subnetwork]
|
212
|
+
|
213
|
+
# @check if subnets exist - need to do something more clever
|
214
|
+
# and check for overlapping subnety really but i can't find a gem
|
215
|
+
network_checks = []
|
216
|
+
network_checks.push(config['cluster_ipv4_cidr']) if config['cluster_ipv4_cidr']
|
217
|
+
network_checks.push(config['master_ipv4_cidr_block']) if config['master_ipv4_cidr_block']
|
218
|
+
network_checks.push(config['services_ipv4_cidr']) if config['services_ipv4_cidr']
|
219
|
+
|
220
|
+
nets = networks
|
221
|
+
network_checks.each do |n|
|
222
|
+
nets.each { |x| raise ConfigurationError, "network: #{n} already exists" if n == x.cidr }
|
223
|
+
end
|
224
|
+
|
225
|
+
if config[:enable_private_network] && !config[:master_ipv4_cidr_block]
|
226
|
+
raise ConfigurationError, 'you must specify a master_ipv4_cidr_block'
|
227
|
+
end
|
228
|
+
|
229
|
+
config
|
230
|
+
end
|
231
|
+
# rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
232
|
+
|
233
|
+
# patch_router is a wrapper for the patch router
|
234
|
+
def patch_router(name, router)
|
235
|
+
@compute.patch_router(@project, @region, name, router)
|
236
|
+
end
|
237
|
+
|
238
|
+
# default_cloud_nat returns a default cloud nat configuration
|
239
|
+
def default_cloud_nat(name = 'cloud-nat')
|
240
|
+
[
|
241
|
+
Google::Apis::ComputeV1::RouterNat.new(
|
242
|
+
log_config: Google::Apis::ComputeV1::RouterNatLogConfig.new(enable: false, filter: 'ALL'),
|
243
|
+
name: name,
|
244
|
+
nat_ip_allocate_option: 'AUTO_ONLY',
|
245
|
+
source_subnetwork_ip_ranges_to_nat: 'ALL_SUBNETWORKS_ALL_IP_RANGES'
|
246
|
+
)
|
247
|
+
]
|
248
|
+
end
|
249
|
+
|
250
|
+
# authorize is responsible for providing an access token to operate
|
251
|
+
def authorize(scopes = ['https://www.googleapis.com/auth/cloud-platform'])
|
252
|
+
if @authorizer.nil?
|
253
|
+
@authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
|
254
|
+
json_key_io: StringIO.new(@account),
|
255
|
+
scope: scopes
|
256
|
+
)
|
257
|
+
@authorizer.fetch_access_token!
|
258
|
+
end
|
259
|
+
@authorizer
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
# rubocop:enable Metrics/ClassLength,Metrics/LineLength,Metrics/MethodLength
|
@@ -0,0 +1,364 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2019 Rohith Jayawardene <gambol99@gmail.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU General Public License
|
7
|
+
# as published by the Free Software Foundation; either version 2
|
8
|
+
# of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
# rubocop:disable Metrics/LineLength,Metrics/MethodLength,Metrics/ModuleLength
|
20
|
+
module HubClustersCreator
|
21
|
+
module Providers
|
22
|
+
# GCP is the namespace
|
23
|
+
module GCP
|
24
|
+
# Containers is a GKE container methods
|
25
|
+
module Containers
|
26
|
+
private
|
27
|
+
|
28
|
+
# gke_locations returns a list of compute locations
|
29
|
+
def gke_locations
|
30
|
+
@gke.list_project_locations("projects/#{@project}").locations.select do |x|
|
31
|
+
x.name.start_with?("#{@region}-")
|
32
|
+
end.map(&:name)
|
33
|
+
end
|
34
|
+
|
35
|
+
# operation returns the current status of an operation
|
36
|
+
def operation(id)
|
37
|
+
@gke.get_project_location_operation("projects/#{@project}/locations/#{@region}/operations/*", operation_id: id)
|
38
|
+
end
|
39
|
+
|
40
|
+
# operations returns a list of all operations
|
41
|
+
def operations
|
42
|
+
list = @gke.list_project_location_operations("projects/#{@project}/locations/#{@region}").operations
|
43
|
+
list.each { |x| yield x } if block_given?
|
44
|
+
list
|
45
|
+
end
|
46
|
+
|
47
|
+
# operations_by_resource returns any operations filtered by the resource
|
48
|
+
def operations_by_resource(name, resource, operation_type = '')
|
49
|
+
operations.select do |x|
|
50
|
+
next unless x.target_link.end_with?("#{resource}/#{name}")
|
51
|
+
next if !operation_type.empty? && (!x.operation_type == operation_type)
|
52
|
+
|
53
|
+
true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# hold_for_operation is responisble for waiting for an operation to complete or error
|
58
|
+
# rubocop:disable Lint/RescueException
|
59
|
+
def hold_for_operation(id, interval = 10, timeout = 900)
|
60
|
+
max_attempts = timeout / interval
|
61
|
+
retries = attempts = 0
|
62
|
+
|
63
|
+
while attempts < max_attempts
|
64
|
+
begin
|
65
|
+
resp = operation(id)
|
66
|
+
return resp if !resp.nil? && resp.status == 'DONE'
|
67
|
+
rescue Exception => e
|
68
|
+
raise Exception, "failed waiting on operation: #{id}, error: #{e}" if retries > 10
|
69
|
+
|
70
|
+
retries += 1
|
71
|
+
end
|
72
|
+
sleep(interval)
|
73
|
+
attempts += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
raise Exception, "operation: #{id} has timed out waiting to finish"
|
77
|
+
end
|
78
|
+
# rubocop:enable Lint/RescueException
|
79
|
+
|
80
|
+
# cluster returns a specific cluster
|
81
|
+
def cluster(name)
|
82
|
+
return nil unless cluster?(name)
|
83
|
+
|
84
|
+
clusters.select { |x| x.name = name }.first
|
85
|
+
end
|
86
|
+
|
87
|
+
# cluster? check if a gke cluster exists
|
88
|
+
def cluster?(name)
|
89
|
+
clusters.map(&:name).include?(name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# clusters returns a list of clusters
|
93
|
+
def clusters
|
94
|
+
path = "projects/#{@project}/locations/#{@region}"
|
95
|
+
list = @gke.list_zone_clusters(nil, nil, parent: path).clusters || []
|
96
|
+
list.each { |x| yield x } if block_given?
|
97
|
+
list
|
98
|
+
end
|
99
|
+
|
100
|
+
# cluster_spec is responsible for generating a cluster specification from options
|
101
|
+
# rubocop:disable Metrics/AbcSize
|
102
|
+
def cluster_spec(options)
|
103
|
+
locations = gke_locations
|
104
|
+
|
105
|
+
request = Google::Apis::ContainerV1beta1::CreateClusterRequest.new(
|
106
|
+
parent: "projects/#{@project}/locations/#{@region}",
|
107
|
+
project_id: @project
|
108
|
+
)
|
109
|
+
request.cluster = Google::Apis::ContainerV1beta1::Cluster.new(
|
110
|
+
name: options[:name],
|
111
|
+
description: options[:description],
|
112
|
+
initial_cluster_version: options[:version],
|
113
|
+
|
114
|
+
#
|
115
|
+
## Addons
|
116
|
+
#
|
117
|
+
addons_config: Google::Apis::ContainerV1beta1::AddonsConfig.new(
|
118
|
+
cloud_run_config: Google::Apis::ContainerV1beta1::CloudRunConfig.new(
|
119
|
+
disabled: !options[:enable_cloud_run]
|
120
|
+
),
|
121
|
+
horizontal_pod_autoscaling: Google::Apis::ContainerV1beta1::HorizontalPodAutoscaling.new(
|
122
|
+
disabled: !options[:enable_horizontal_pod_autoscaler]
|
123
|
+
),
|
124
|
+
http_load_balancing: Google::Apis::ContainerV1beta1::HttpLoadBalancing.new(
|
125
|
+
disabled: !options[:enable_http_loadbalancer]
|
126
|
+
),
|
127
|
+
istio_config: Google::Apis::ContainerV1beta1::IstioConfig.new(
|
128
|
+
auth: 'AUTH_MUTUAL_TLS',
|
129
|
+
disabled: !options[:enable_istio]
|
130
|
+
),
|
131
|
+
kubernetes_dashboard: Google::Apis::ContainerV1beta1::KubernetesDashboard.new(
|
132
|
+
disabled: true
|
133
|
+
),
|
134
|
+
network_policy_config: Google::Apis::ContainerV1beta1::NetworkPolicyConfig.new(
|
135
|
+
disabled: false
|
136
|
+
)
|
137
|
+
),
|
138
|
+
|
139
|
+
maintenance_policy: Google::Apis::ContainerV1beta1::MaintenancePolicy.new(
|
140
|
+
window: Google::Apis::ContainerV1beta1::MaintenanceWindow.new(
|
141
|
+
daily_maintenance_window: Google::Apis::ContainerV1beta1::DailyMaintenanceWindow.new(
|
142
|
+
start_time: options[:maintenance_window]
|
143
|
+
)
|
144
|
+
)
|
145
|
+
),
|
146
|
+
|
147
|
+
#
|
148
|
+
## Authentication
|
149
|
+
#
|
150
|
+
master_auth: Google::Apis::ContainerV1beta1::MasterAuth.new(
|
151
|
+
client_certificate_config: Google::Apis::ContainerV1beta1::ClientCertificateConfig.new(
|
152
|
+
issue_client_certificate: false
|
153
|
+
)
|
154
|
+
),
|
155
|
+
|
156
|
+
#
|
157
|
+
## Network
|
158
|
+
#
|
159
|
+
ip_allocation_policy: Google::Apis::ContainerV1beta1::IpAllocationPolicy.new(
|
160
|
+
cluster_ipv4_cidr_block: options[:cluster_ipv4_cidr],
|
161
|
+
create_subnetwork: options[:create_subnetwork],
|
162
|
+
services_ipv4_cidr_block: options[:services_ipv4_cidr],
|
163
|
+
subnetwork_name: options[:subnetwork],
|
164
|
+
use_ip_aliases: true
|
165
|
+
),
|
166
|
+
locations: locations,
|
167
|
+
|
168
|
+
#
|
169
|
+
## Features
|
170
|
+
#
|
171
|
+
monitoring_service: ('monitoring.googleapis.com/kubernetes' if options[:enable_monitoring]),
|
172
|
+
logging_service: ('logging.googleapis.com/kubernetes' if options[:enable_logging]),
|
173
|
+
|
174
|
+
binary_authorization: Google::Apis::ContainerV1beta1::BinaryAuthorization.new(
|
175
|
+
enabled: options[:enable_binary_authorization]
|
176
|
+
),
|
177
|
+
legacy_abac: Google::Apis::ContainerV1beta1::LegacyAbac.new(
|
178
|
+
enabled: false
|
179
|
+
),
|
180
|
+
network_policy: Google::Apis::ContainerV1beta1::NetworkPolicy.new(
|
181
|
+
enabled: options[:enable_network_policies]
|
182
|
+
),
|
183
|
+
pod_security_policy_config: Google::Apis::ContainerV1beta1::PodSecurityPolicyConfig.new(
|
184
|
+
enabled: options[:enable_pod_security_policies]
|
185
|
+
),
|
186
|
+
|
187
|
+
#
|
188
|
+
## Node Pools
|
189
|
+
#
|
190
|
+
node_pools: [
|
191
|
+
Google::Apis::ContainerV1beta1::NodePool.new(
|
192
|
+
autoscaling: Google::Apis::ContainerV1beta1::NodePoolAutoscaling.new(
|
193
|
+
autoprovisioned: false,
|
194
|
+
enabled: options[:enable_autoscaler],
|
195
|
+
max_node_count: options[:max_size],
|
196
|
+
min_node_count: options[:size]
|
197
|
+
),
|
198
|
+
config: Google::Apis::ContainerV1beta1::NodeConfig.new(
|
199
|
+
disk_size_gb: options[:disk_size_gb],
|
200
|
+
image_type: options[:image_type],
|
201
|
+
machine_type: options[:machine_type],
|
202
|
+
oauth_scopes: [
|
203
|
+
'https://www.googleapis.com/auth/compute',
|
204
|
+
'https://www.googleapis.com/auth/devstorage.read_only',
|
205
|
+
'https://www.googleapis.com/auth/logging.write',
|
206
|
+
'https://www.googleapis.com/auth/monitoring'
|
207
|
+
],
|
208
|
+
preemptible: options[:preemptible]
|
209
|
+
),
|
210
|
+
initial_node_count: options[:size],
|
211
|
+
locations: locations,
|
212
|
+
management: Google::Apis::ContainerV1beta1::NodeManagement.new(
|
213
|
+
auto_repair: options[:enable_autorepair],
|
214
|
+
auto_upgrade: options[:enable_autoupgrade]
|
215
|
+
),
|
216
|
+
max_pods_constraint: Google::Apis::ContainerV1beta1::MaxPodsConstraint.new(
|
217
|
+
max_pods_per_node: 110
|
218
|
+
),
|
219
|
+
name: 'compute',
|
220
|
+
version: options[:version]
|
221
|
+
)
|
222
|
+
]
|
223
|
+
)
|
224
|
+
|
225
|
+
if options[:enable_private_network]
|
226
|
+
request.cluster.private_cluster = true
|
227
|
+
request.cluster.private_cluster_config = Google::Apis::ContainerV1beta1::PrivateClusterConfig.new(
|
228
|
+
enable_private_endpoint: options[:enable_private_endpoint],
|
229
|
+
enable_private_nodes: true,
|
230
|
+
master_ipv4_cidr_block: options[:master_ipv4_cidr_block]
|
231
|
+
)
|
232
|
+
|
233
|
+
# @step: do we have any authorized cidr's
|
234
|
+
if options[:authorized_master_cidrs].size.positive?
|
235
|
+
request.cluster.master_authorized_networks_config = Google::Apis::ContainerV1beta1::MasterAuthorizedNetworksConfig.new(
|
236
|
+
cidr_blocks: [],
|
237
|
+
enabled: true
|
238
|
+
)
|
239
|
+
options[:authorized_master_cidrs].each do |x|
|
240
|
+
block = Google::Apis::ContainerV1beta1::CidrBlock.new(
|
241
|
+
cidr_block: x[:cidr],
|
242
|
+
display_name: x[:name]
|
243
|
+
)
|
244
|
+
|
245
|
+
request.cluster.master_authorized_networks_config.cidr_blocks.push(block)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
request
|
250
|
+
end
|
251
|
+
# rubocop:enable Metrics/AbcSize
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
# rubocop:enable Metrics/LineLength,Metrics/MethodLength
|
256
|
+
end
|
257
|
+
|
258
|
+
# rubocop:disable Metrics/LineLength,Metrics/MethodLength
|
259
|
+
module HubClustersCreator
|
260
|
+
module Providers
|
261
|
+
# GCP namespaces the GCP methods
|
262
|
+
module GCP
|
263
|
+
# Compute provides some helper methods / functions to the GCP agent
|
264
|
+
module Compute
|
265
|
+
# router returns a specfic router
|
266
|
+
def router(name)
|
267
|
+
r = routers.select { |x| x.name == name }.first
|
268
|
+
yield r if block_given?
|
269
|
+
r
|
270
|
+
end
|
271
|
+
|
272
|
+
# router? check if the router exists
|
273
|
+
def router?(name)
|
274
|
+
routers.map(&:name).include?(name)
|
275
|
+
end
|
276
|
+
|
277
|
+
# routers returns the list of routers
|
278
|
+
def routers
|
279
|
+
list = @compute.list_routers(@project, @region).items
|
280
|
+
list.each { |x| yield x } if block_given?
|
281
|
+
list
|
282
|
+
end
|
283
|
+
|
284
|
+
# network? checks if the network exists in the region and project
|
285
|
+
def network?(name)
|
286
|
+
networks.items.map(&:name).include?(name)
|
287
|
+
end
|
288
|
+
|
289
|
+
# networks returns a list of networks in the region and project
|
290
|
+
def networks
|
291
|
+
list = @compute.list_networks(@project)
|
292
|
+
list.each { |x| yield x } if block_given?
|
293
|
+
list
|
294
|
+
end
|
295
|
+
|
296
|
+
# subnet? checks if the subnet exists in the project, network and region
|
297
|
+
def subnet?(name, network)
|
298
|
+
subnets(network).include?(name)
|
299
|
+
end
|
300
|
+
|
301
|
+
# dns is responsible for adding / updating a dns record in a zone
|
302
|
+
def dns(src, dest, zone, record = 'A')
|
303
|
+
raise ArgumentError, "the managed zone: #{zone} does not exist" unless domain?(zone)
|
304
|
+
|
305
|
+
hostname = "#{src}.#{zone}."
|
306
|
+
change = Google::Apis::DnsV1::Change.new(
|
307
|
+
additions: [
|
308
|
+
Google::Apis::DnsV1::ResourceRecordSet.new(
|
309
|
+
kind: 'dns#resourceRecordSet',
|
310
|
+
name: hostname,
|
311
|
+
rrdatas: [dest],
|
312
|
+
ttl: 120,
|
313
|
+
type: record
|
314
|
+
)
|
315
|
+
]
|
316
|
+
)
|
317
|
+
|
318
|
+
# @step: check a record already exists and if so add for deletion
|
319
|
+
dns_records(zone).rrsets.each do |x|
|
320
|
+
next unless x.name == hostname
|
321
|
+
|
322
|
+
change.deletions = [x]
|
323
|
+
end
|
324
|
+
|
325
|
+
managed_zone = domain(zone)
|
326
|
+
@dns.create_change(@project, managed_zone.name, change)
|
327
|
+
end
|
328
|
+
|
329
|
+
# dns_records returns a list of dns recordsets
|
330
|
+
def dns_records(zone)
|
331
|
+
raise ArgumentError, "the managed zone: #{zone} does not exist" unless domain?(zone)
|
332
|
+
|
333
|
+
managed_zone = domain(zone)
|
334
|
+
@dns.list_resource_record_sets(@project, managed_zone.name)
|
335
|
+
end
|
336
|
+
|
337
|
+
# domain? checks if the domain exists
|
338
|
+
def domain?(name)
|
339
|
+
domains.map { |x| x.dns_name.chomp('.') }.include?(name)
|
340
|
+
end
|
341
|
+
|
342
|
+
# domain returns a specific domain
|
343
|
+
def domain(name)
|
344
|
+
domains.select { |x| x.dns_name.chomp('.') == name }.first
|
345
|
+
end
|
346
|
+
|
347
|
+
# domains provides a list of domains
|
348
|
+
def domains
|
349
|
+
@dns.list_managed_zones(@project).managed_zones
|
350
|
+
end
|
351
|
+
|
352
|
+
# subnets returns a list of subnets in the network
|
353
|
+
def subnets(network)
|
354
|
+
list = @compute.list_subnetworks(@project, @region).items.select do |x|
|
355
|
+
x.network.end_with?(network)
|
356
|
+
end.map(&:name)
|
357
|
+
list.each { |x| yield x } if block_given?
|
358
|
+
list
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
# rubocop:enable Metrics/LineLength,Metrics/MethodLength,Metrics/ModuleLength
|
364
|
+
end
|