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