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,105 @@
|
|
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
|
20
|
+
module HubClustersCreator
|
21
|
+
module Providers
|
22
|
+
# Azure is the AKS namespace
|
23
|
+
module Azure
|
24
|
+
# Helpers providers a collection of useful methods
|
25
|
+
module Helpers
|
26
|
+
private
|
27
|
+
|
28
|
+
def wait(interval: 20, timeout: 900, max_retries: 10)
|
29
|
+
max_attempts = timeout / interval
|
30
|
+
retries = attempts = 0
|
31
|
+
|
32
|
+
while attempts < max_attempts
|
33
|
+
begin
|
34
|
+
return if yield
|
35
|
+
rescue StandardError => e
|
36
|
+
raise Exception, "failed waiting for resource, retry: #{retries}, error: #{e}" if retries > max_retries
|
37
|
+
|
38
|
+
retries += 1
|
39
|
+
end
|
40
|
+
sleep(interval)
|
41
|
+
attempts += 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def hostname(fqdn)
|
46
|
+
fqdn.split('.').first
|
47
|
+
end
|
48
|
+
|
49
|
+
def dns(src, dest, zone, ttl: 120)
|
50
|
+
raise ArgumentError, "the domain: #{zone} does not exist" unless domain?(zone)
|
51
|
+
|
52
|
+
zone = domain(zone)
|
53
|
+
resource_group = zone.id.split('/')[4]
|
54
|
+
address = Azure::Dns::Mgmt::V2017_10_01::Models::ARecord.new
|
55
|
+
address.ipv4address = dest
|
56
|
+
record = Azure::Dns::Mgmt::V2017_10_01::Models::RecordSet.new
|
57
|
+
record.name = src
|
58
|
+
record.ttl = ttl
|
59
|
+
record.arecords = [address]
|
60
|
+
|
61
|
+
@dns.record_sets.create_or_update(resource_group, zone, src, 'A', record)
|
62
|
+
end
|
63
|
+
|
64
|
+
def domain?(name)
|
65
|
+
domains.map(&:name).include?(name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def domains
|
69
|
+
@dns.zones.list
|
70
|
+
end
|
71
|
+
|
72
|
+
def deployment(group, name)
|
73
|
+
deployments(group).select { |x| x.name == name }.first
|
74
|
+
end
|
75
|
+
|
76
|
+
def deployment?(name, group)
|
77
|
+
deployments(group).map(&:name).include?(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
def deployments(group)
|
81
|
+
@client.deployments.list_by_resource_group(group)
|
82
|
+
end
|
83
|
+
|
84
|
+
def managed_cluster?(name)
|
85
|
+
managed_clusters.map(&:name).include?(name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def managed_clusters
|
89
|
+
@containers.managed_clusters.list
|
90
|
+
end
|
91
|
+
|
92
|
+
# resource_group? check is the resource group exists
|
93
|
+
def resource_group?(name)
|
94
|
+
resource_groups.map(&:name).include?(name)
|
95
|
+
end
|
96
|
+
|
97
|
+
# resource_groups returns a list of resource groups
|
98
|
+
def resource_groups
|
99
|
+
@client.resource_groups.list
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
# rubocop:enable Metrics/LineLength,Metrics/MethodLength
|
@@ -0,0 +1,125 @@
|
|
1
|
+
---
|
2
|
+
type: object
|
3
|
+
title: Azure AKS Provider configuration
|
4
|
+
description: >
|
5
|
+
Defines the configuration required to initialize the provider.
|
6
|
+
required:
|
7
|
+
- client_id
|
8
|
+
- client_secret
|
9
|
+
- region
|
10
|
+
- subscription
|
11
|
+
- tenant
|
12
|
+
|
13
|
+
properties:
|
14
|
+
client_id:
|
15
|
+
$id: '#/config/client_id'
|
16
|
+
type: string
|
17
|
+
title: Service Principal Client ID
|
18
|
+
description: >
|
19
|
+
The associated client id from the service principal account you are
|
20
|
+
using to speak to the Azure API.
|
21
|
+
default: ''
|
22
|
+
pattern: ^.*$
|
23
|
+
|
24
|
+
client_secret:
|
25
|
+
$id: '#/config/client_secret'
|
26
|
+
type: string
|
27
|
+
title: Service Principal Client Secret
|
28
|
+
description: >
|
29
|
+
The client secret of the service principal being used to provision
|
30
|
+
the resources with.
|
31
|
+
default: ''
|
32
|
+
pattern: ^.*$
|
33
|
+
|
34
|
+
region:
|
35
|
+
$id: '#/config/region'
|
36
|
+
type: string
|
37
|
+
title: Azure Compute Region
|
38
|
+
description: >
|
39
|
+
The geographical region which you wish to build the cluster with.
|
40
|
+
default: ''
|
41
|
+
examples:
|
42
|
+
- uksouth
|
43
|
+
pattern: ^.*$
|
44
|
+
|
45
|
+
subscription:
|
46
|
+
$id: '#/config/subscription'
|
47
|
+
type: string
|
48
|
+
title: Subsription
|
49
|
+
description: >
|
50
|
+
The Azure client subscription you are using to provison the resources
|
51
|
+
under.
|
52
|
+
default: ''
|
53
|
+
pattern: ^.*$
|
54
|
+
|
55
|
+
tenant:
|
56
|
+
$id: '#/config/tenant'
|
57
|
+
type: string
|
58
|
+
title: Tenant ID
|
59
|
+
description: >
|
60
|
+
The application tenant id from the application registration / service
|
61
|
+
principal you are using. This can be found under the Application
|
62
|
+
Registration tab in the Azure portal
|
63
|
+
default: ''
|
64
|
+
pattern: ^.*$
|
65
|
+
|
66
|
+
---
|
67
|
+
type: object
|
68
|
+
title: Azure AKS Cluster configuration
|
69
|
+
description: >
|
70
|
+
Create an Azure AKS managed kubernetes cluster
|
71
|
+
required:
|
72
|
+
- machine_type
|
73
|
+
- services_ipv4_cidr
|
74
|
+
- ssh_key
|
75
|
+
- version
|
76
|
+
|
77
|
+
properties:
|
78
|
+
machine_type:
|
79
|
+
$id: '#/properties/machine_type'
|
80
|
+
tag: default
|
81
|
+
type: string
|
82
|
+
title: Machine Type
|
83
|
+
description: >
|
84
|
+
The machine type which the default nodes pool should use.
|
85
|
+
examples:
|
86
|
+
- Standard_DS2_v2
|
87
|
+
pattern: ^(.*)$
|
88
|
+
|
89
|
+
services_ipv4_cidr:
|
90
|
+
$id: '#/properties/services_ipv4_cidr'
|
91
|
+
tag: advanced
|
92
|
+
type: string
|
93
|
+
title: Cluster Services CIDR
|
94
|
+
default: ''
|
95
|
+
description: >
|
96
|
+
An optional network cidr configured for the cluster services,
|
97
|
+
otherwise GCP will decide.
|
98
|
+
examples:
|
99
|
+
- '10.0.0.0/16'
|
100
|
+
pattern: ^(([\d]{1,3}\.){3}[\d]{1,3}\/[\d]{1,2}|)$
|
101
|
+
|
102
|
+
ssh_key:
|
103
|
+
$id: '#/properties/ssh_key'
|
104
|
+
tag: default
|
105
|
+
type: string
|
106
|
+
title: SSH Public Key
|
107
|
+
default: ''
|
108
|
+
description: >
|
109
|
+
A public ssh key used provision the compute nodes with
|
110
|
+
examples:
|
111
|
+
- ssh-rsa
|
112
|
+
pattern: ^ssh-rsa.*$
|
113
|
+
|
114
|
+
version:
|
115
|
+
$id: '#/properties/version'
|
116
|
+
tag: default
|
117
|
+
type: string
|
118
|
+
title: Initial Kubernetes Version
|
119
|
+
default: '1.14.3'
|
120
|
+
description: >
|
121
|
+
The initial kubernetes version which the cluster should be
|
122
|
+
configured with.
|
123
|
+
examples:
|
124
|
+
- 1.14.3
|
125
|
+
pattern: ^(.*)$
|
@@ -0,0 +1,226 @@
|
|
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 'hub-clusters-creator/template'
|
19
|
+
require 'hub-clusters-creator/logging'
|
20
|
+
|
21
|
+
# rubocop:disable Metrics/MethodLength,Metrics/LineLength
|
22
|
+
module HubClustersCreator
|
23
|
+
module Providers
|
24
|
+
# Bootstrap the provider of the bootstrap job
|
25
|
+
# rubocop:disable Metrics/ClassLength
|
26
|
+
class Bootstrap
|
27
|
+
include Logging
|
28
|
+
include HubClustersCreator::Utils::Template
|
29
|
+
|
30
|
+
DEFAULT_CLUSTER_ADMIN_ROLE = <<~YAML
|
31
|
+
apiVersion: v1
|
32
|
+
kind: ServiceAccount
|
33
|
+
metadata:
|
34
|
+
name: sysadmin
|
35
|
+
namespace: kube-system
|
36
|
+
YAML
|
37
|
+
|
38
|
+
DEFAULT_CLUSTER_ADMIN_BINDING = <<~YAML
|
39
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
40
|
+
kind: ClusterRoleBinding
|
41
|
+
metadata:
|
42
|
+
name: cluster:admin
|
43
|
+
roleRef:
|
44
|
+
apiGroup: rbac.authorization.k8s.io
|
45
|
+
kind: ClusterRole
|
46
|
+
name: cluster-admin
|
47
|
+
subjects:
|
48
|
+
- kind: ServiceAccount
|
49
|
+
name: sysadmin
|
50
|
+
namespace: kube-system
|
51
|
+
YAML
|
52
|
+
|
53
|
+
# is the name of the container image
|
54
|
+
BOOTSTRAP_IMAGE = 'quay.io/appvia/hub-bootstrap:latest'
|
55
|
+
# is the name of the job
|
56
|
+
BOOTSTRAP_NAME = 'bootstrap'
|
57
|
+
# is the name of the namespace the job lives in
|
58
|
+
BOOTSTRAP_NAMESPACE = 'kube-system'
|
59
|
+
|
60
|
+
attr_accessor :client, :config, :name
|
61
|
+
|
62
|
+
def initialize(name, client, config)
|
63
|
+
@name = name
|
64
|
+
@client = client
|
65
|
+
@config = config
|
66
|
+
end
|
67
|
+
|
68
|
+
# provision_bootstrap is responsible for setting up the agents and strapper
|
69
|
+
# a) pushes in the configuration for the bootstrapper
|
70
|
+
# b) rolls out the kubernetes job to bootstrap the cluster
|
71
|
+
# c) grabs the services and provisions the dns
|
72
|
+
# rubocop:disable Metrics/AbcSize
|
73
|
+
def bootstrap(image = BOOTSTRAP_IMAGE)
|
74
|
+
client.wait_for_kubeapi
|
75
|
+
|
76
|
+
info 'applying the default cluster admin service account and role'
|
77
|
+
client.kubectl(DEFAULT_CLUSTER_ADMIN_ROLE)
|
78
|
+
client.kubectl(DEFAULT_CLUSTER_ADMIN_BINDING)
|
79
|
+
|
80
|
+
info 'attempting to bootstrap the cluster configuration'
|
81
|
+
client.kubectl(generate_bootstrap_config)
|
82
|
+
client.kubectl(generate_bootstrap_job(image))
|
83
|
+
|
84
|
+
info 'waiting for the bootstrap to complete successfully'
|
85
|
+
name = BOOTSTRAP_NAME
|
86
|
+
namespace = BOOTSTRAP_NAMESPACE
|
87
|
+
|
88
|
+
client.wait(name, namespace, 'jobs', version: 'batch/v1', interval: 10, timeout: 500) do |x|
|
89
|
+
x.status.nil? || x.status['succeeded'] <= 0 ? false : true
|
90
|
+
end
|
91
|
+
info 'bootstrap has successfully completed'
|
92
|
+
|
93
|
+
info 'waiting for grafana ingress load balancer to be provisioned'
|
94
|
+
# @step: wait for the ingress to appaar and provision and grab the address
|
95
|
+
@client.wait('loki-grafana', 'loki', 'ingresses', version: 'extensions/v1beta1') do |x|
|
96
|
+
x.status.loadBalancer.ingress.empty? ? false : true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
# rubocop:enable Metrics/AbcSize
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# generate_bootstrap_config returns the helm values for grafana
|
104
|
+
def generate_bootstrap_config
|
105
|
+
template = <<~YAML
|
106
|
+
apiVersion: v1
|
107
|
+
kind: ConfigMap
|
108
|
+
metadata:
|
109
|
+
name: #{BOOTSTRAP_NAME}
|
110
|
+
namespace: #{BOOTSTRAP_NAMESPACE}
|
111
|
+
data:
|
112
|
+
charts: |
|
113
|
+
loki/loki-stack,loki,--name loki --values /config/bundles/grafana.yaml
|
114
|
+
stable/prometheus,kube-system,--name prometheus
|
115
|
+
repositories: |
|
116
|
+
loki,https://grafana.github.io/loki/charts
|
117
|
+
grafana.yaml: |
|
118
|
+
loki:
|
119
|
+
enabled: true
|
120
|
+
networkPolicy:
|
121
|
+
enabled: true
|
122
|
+
promtail:
|
123
|
+
enabled: true
|
124
|
+
prometheus:
|
125
|
+
enabled: false
|
126
|
+
server:
|
127
|
+
fullnameOverride: prometheus-server
|
128
|
+
nodeExporter:
|
129
|
+
podSecurityPolicy:
|
130
|
+
enabled: true
|
131
|
+
networkPolicy:
|
132
|
+
enabled: true
|
133
|
+
grafana:
|
134
|
+
enabled: true
|
135
|
+
image:
|
136
|
+
repository: grafana/grafana
|
137
|
+
tag: <%= context[:grafana_version] || 'latest' %>
|
138
|
+
pullPolicy: IfNotPresent
|
139
|
+
sidecar:
|
140
|
+
datasources:
|
141
|
+
enabled: true
|
142
|
+
service:
|
143
|
+
type: NodePort
|
144
|
+
port: 80
|
145
|
+
targetPort: 3000
|
146
|
+
ingress:
|
147
|
+
enabled: true
|
148
|
+
hosts:
|
149
|
+
- <%= context[:grafana_hostname] %>
|
150
|
+
path: '/*'
|
151
|
+
networkPolicy:
|
152
|
+
enabled: true
|
153
|
+
persistence:
|
154
|
+
enabled: false
|
155
|
+
accessModes:
|
156
|
+
- ReadWriteOnce
|
157
|
+
size: <%= context[:grafana_disk_size] %><%= context[:grafana_disk_size].to_s.end_with?('Gi') ? '' : 'Gi' %>
|
158
|
+
grafana.ini:
|
159
|
+
server:
|
160
|
+
domain: <%= context[:grafana_hostname] %>
|
161
|
+
root_url: http://<%= context[:grafana_hostname] %>
|
162
|
+
paths:
|
163
|
+
data: /var/lib/grafana/data
|
164
|
+
logs: /var/log/grafana
|
165
|
+
plugins: /var/lib/grafana/plugins
|
166
|
+
provisioning: /etc/grafana/provisioning
|
167
|
+
analytics:
|
168
|
+
check_for_updates: true
|
169
|
+
log:
|
170
|
+
mode: console
|
171
|
+
grafana_net:
|
172
|
+
url: https://grafana.net
|
173
|
+
<%- unless (context[:github_client_id] || '').empty? -%>
|
174
|
+
auth.github:
|
175
|
+
allow_sign_up: true
|
176
|
+
<%- unless (context[:github_organization] || '').empty? %>
|
177
|
+
allowed_organizations: <%= context[:github_organization] %>
|
178
|
+
<%- end %>
|
179
|
+
api_url: https://api.github.com/user
|
180
|
+
auth_url: https://github.com/login/oauth/authorize
|
181
|
+
client_id: <%= context[:github_client_id] %>
|
182
|
+
client_secret: <%= context[:github_client_secret] %>
|
183
|
+
enabled: true
|
184
|
+
scopes: user,read:org
|
185
|
+
token_url: https://github.com/login/oauth/access_token
|
186
|
+
<%- end -%>
|
187
|
+
YAML
|
188
|
+
HubClustersCreator::Utils::Template::Render.new(config).render(template)
|
189
|
+
end
|
190
|
+
|
191
|
+
# generate_bootstrap_job is responsible for generating the bootstrap job
|
192
|
+
def generate_bootstrap_job(image)
|
193
|
+
template = <<-YAML
|
194
|
+
apiVersion: batch/v1
|
195
|
+
kind: Job
|
196
|
+
metadata:
|
197
|
+
name: #{BOOTSTRAP_NAME}
|
198
|
+
namespace: #{BOOTSTRAP_NAMESPACE}
|
199
|
+
spec:
|
200
|
+
backoffLimit: 20
|
201
|
+
template:
|
202
|
+
spec:
|
203
|
+
serviceAccountName: sysadmin
|
204
|
+
restartPolicy: OnFailure
|
205
|
+
containers:
|
206
|
+
- name: bootstrap
|
207
|
+
image: #{image}
|
208
|
+
imagePullPolicy: Always
|
209
|
+
env:
|
210
|
+
- name: CONFIG_DIR
|
211
|
+
value: /config
|
212
|
+
volumeMounts:
|
213
|
+
- name: bundle
|
214
|
+
mountPath: /config/bundles
|
215
|
+
volumes:
|
216
|
+
- name: bundle
|
217
|
+
configMap:
|
218
|
+
name: #{BOOTSTRAP_NAME}
|
219
|
+
YAML
|
220
|
+
template
|
221
|
+
end
|
222
|
+
end
|
223
|
+
# rubocop:enable Metrics/ClassLength
|
224
|
+
end
|
225
|
+
end
|
226
|
+
# rubocop:enable Metrics/MethodLength,Metrics/LineLength
|