hetzner-k3s 0.3.9 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +10 -0
- data/lib/hetzner/infra/firewall.rb +79 -57
- data/lib/hetzner/infra/load_balancer.rb +14 -2
- data/lib/hetzner/k3s/cli.rb +78 -12
- data/lib/hetzner/k3s/cluster.rb +20 -43
- data/lib/hetzner/k3s/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ee4a4ac2c31ebff805ee20edc3658ffe64be32e50b524ee4af3646e3ffc3a3c
|
4
|
+
data.tar.gz: 8cbc33a2a696b19c8e614932d1daa7fa9beddaf9d69dd8377d909cb382e40f87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff2ca466abbd198b3bc76c8854113d90033fb606e9f11152ecf6d079564ee4dcbdab359a5b17229770a7dc531a9674b211d079a2204596efe3ec5b67157bf82e
|
7
|
+
data.tar.gz: a6a16c64b0ada5c4d1a740894df09a9f41ed0110b06cfd5629b1971c64836a5fd38bceebb7898432b275cb677779606ecd780b917d4095eb161987d26c0eecc0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -54,6 +54,8 @@ cluster_name: test
|
|
54
54
|
kubeconfig_path: "./kubeconfig"
|
55
55
|
k3s_version: v1.21.3+k3s1
|
56
56
|
ssh_key_path: "~/.ssh/id_rsa.pub"
|
57
|
+
ssh_allowed_networks:
|
58
|
+
- 0.0.0.0/0
|
57
59
|
verify_host_key: false
|
58
60
|
location: nbg1
|
59
61
|
masters:
|
@@ -72,6 +74,8 @@ It should hopefully be self explanatory; you can run `hetzner-k3s releases` to s
|
|
72
74
|
|
73
75
|
If you are using Docker, then set `kubeconfig_path` to `/cluster/kubeconfig` so that the kubeconfig is created in the same directory where your config file is.
|
74
76
|
|
77
|
+
If you don't want to specify the Hetzner token in the config file (for example if you want to use the tool with CI), then you can use the `HCLOUD_TOKEN` environment variable instead, which has predecence.
|
78
|
+
|
75
79
|
**Important**: The tool assignes the label `cluster` to each server it creates, with the clsuter name you specify in the config file, as the value. So please ensure you don't create unrelated servers in the same project having
|
76
80
|
the label `cluster=<cluster name>`, because otherwise they will be deleted if you delete the cluster. I recommend you create a separate Hetzner project for each cluster, see note at the end of this README for more details.
|
77
81
|
|
@@ -235,6 +239,12 @@ I recommend that you create a separate Hetzner project for each cluster, because
|
|
235
239
|
|
236
240
|
## changelog
|
237
241
|
|
242
|
+
- 0.4.0
|
243
|
+
- Ensure the masters are removed from the API load balancer before deleting the load balancer
|
244
|
+
- Ensure the servers are removed from the firewall before deleting it
|
245
|
+
- Allow using an environment variable to specify the Hetzner token
|
246
|
+
- Allow restricting SSH access to the nodes to specific networks
|
247
|
+
|
238
248
|
- 0.3.9
|
239
249
|
- Add command "version" to print the version of the tool in use
|
240
250
|
|
@@ -5,7 +5,9 @@ module Hetzner
|
|
5
5
|
@cluster_name = cluster_name
|
6
6
|
end
|
7
7
|
|
8
|
-
def create
|
8
|
+
def create(ha:, networks:)
|
9
|
+
@ha = ha
|
10
|
+
@networks = networks
|
9
11
|
puts
|
10
12
|
|
11
13
|
if firewall = find_firewall
|
@@ -16,16 +18,21 @@ module Hetzner
|
|
16
18
|
|
17
19
|
puts "Creating firewall..."
|
18
20
|
|
19
|
-
response = hetzner_client.post("/firewalls",
|
21
|
+
response = hetzner_client.post("/firewalls", create_firewall_config).body
|
20
22
|
puts "...firewall created."
|
21
23
|
puts
|
22
24
|
|
23
25
|
JSON.parse(response)["firewall"]["id"]
|
24
26
|
end
|
25
27
|
|
26
|
-
def delete
|
28
|
+
def delete(servers)
|
27
29
|
if firewall = find_firewall
|
28
30
|
puts "Deleting firewall..."
|
31
|
+
|
32
|
+
servers.each do |server|
|
33
|
+
hetzner_client.post("/firewalls/#{firewall["id"]}/actions/remove_from_resources", remove_targets_config(server["id"]))
|
34
|
+
end
|
35
|
+
|
29
36
|
hetzner_client.delete("/firewalls", firewall["id"])
|
30
37
|
puts "...firewall deleted."
|
31
38
|
else
|
@@ -37,64 +44,79 @@ module Hetzner
|
|
37
44
|
|
38
45
|
private
|
39
46
|
|
40
|
-
attr_reader :hetzner_client, :cluster_name, :firewall
|
47
|
+
attr_reader :hetzner_client, :cluster_name, :firewall, :ha, :networks
|
48
|
+
|
49
|
+
def create_firewall_config
|
50
|
+
rules = [
|
51
|
+
{
|
52
|
+
"description": "Allow port 22 (SSH)",
|
53
|
+
"direction": "in",
|
54
|
+
"protocol": "tcp",
|
55
|
+
"port": "22",
|
56
|
+
"source_ips": networks,
|
57
|
+
"destination_ips": []
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"description": "Allow ICMP (ping)",
|
61
|
+
"direction": "in",
|
62
|
+
"protocol": "icmp",
|
63
|
+
"port": nil,
|
64
|
+
"source_ips": [
|
65
|
+
"0.0.0.0/0",
|
66
|
+
"::/0"
|
67
|
+
],
|
68
|
+
"destination_ips": []
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"description": "Allow all TCP traffic between nodes on the private network",
|
72
|
+
"direction": "in",
|
73
|
+
"protocol": "tcp",
|
74
|
+
"port": "any",
|
75
|
+
"source_ips": [
|
76
|
+
"10.0.0.0/16"
|
77
|
+
],
|
78
|
+
"destination_ips": []
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"description": "Allow all UDP traffic between nodes on the private network",
|
82
|
+
"direction": "in",
|
83
|
+
"protocol": "udp",
|
84
|
+
"port": "any",
|
85
|
+
"source_ips": [
|
86
|
+
"10.0.0.0/16"
|
87
|
+
],
|
88
|
+
"destination_ips": []
|
89
|
+
}
|
90
|
+
]
|
91
|
+
|
92
|
+
unless ha
|
93
|
+
rules << {
|
94
|
+
"description": "Allow port 6443 (Kubernetes API server)",
|
95
|
+
"direction": "in",
|
96
|
+
"protocol": "tcp",
|
97
|
+
"port": "6443",
|
98
|
+
"source_ips": [
|
99
|
+
"0.0.0.0/0",
|
100
|
+
"::/0"
|
101
|
+
],
|
102
|
+
"destination_ips": []
|
103
|
+
}
|
104
|
+
end
|
41
105
|
|
42
|
-
def firewall_config
|
43
106
|
{
|
44
107
|
name: cluster_name,
|
45
|
-
rules:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
"0.0.0.0/0",
|
53
|
-
"::/0"
|
54
|
-
],
|
55
|
-
"destination_ips": []
|
56
|
-
},
|
57
|
-
{
|
58
|
-
"description": "Allow ICMP (ping)",
|
59
|
-
"direction": "in",
|
60
|
-
"protocol": "icmp",
|
61
|
-
"port": nil,
|
62
|
-
"source_ips": [
|
63
|
-
"0.0.0.0/0",
|
64
|
-
"::/0"
|
65
|
-
],
|
66
|
-
"destination_ips": []
|
67
|
-
},
|
68
|
-
{
|
69
|
-
"description": "Allow port 6443 (Kubernetes API server)",
|
70
|
-
"direction": "in",
|
71
|
-
"protocol": "tcp",
|
72
|
-
"port": "6443",
|
73
|
-
"source_ips": [
|
74
|
-
"0.0.0.0/0",
|
75
|
-
"::/0"
|
76
|
-
],
|
77
|
-
"destination_ips": []
|
78
|
-
},
|
79
|
-
{
|
80
|
-
"description": "Allow all TCP traffic between nodes on the private network",
|
81
|
-
"direction": "in",
|
82
|
-
"protocol": "tcp",
|
83
|
-
"port": "any",
|
84
|
-
"source_ips": [
|
85
|
-
"10.0.0.0/16"
|
86
|
-
],
|
87
|
-
"destination_ips": []
|
88
|
-
},
|
108
|
+
rules: rules
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def remove_targets_config(server_id)
|
113
|
+
{
|
114
|
+
"remove_from": [
|
89
115
|
{
|
90
|
-
"
|
91
|
-
|
92
|
-
|
93
|
-
"
|
94
|
-
"source_ips": [
|
95
|
-
"10.0.0.0/16"
|
96
|
-
],
|
97
|
-
"destination_ips": []
|
116
|
+
"server": {
|
117
|
+
"id": server_id
|
118
|
+
},
|
119
|
+
"type": "server"
|
98
120
|
}
|
99
121
|
]
|
100
122
|
}
|
@@ -19,7 +19,7 @@ module Hetzner
|
|
19
19
|
|
20
20
|
puts "Creating API load_balancer..."
|
21
21
|
|
22
|
-
response = hetzner_client.post("/load_balancers",
|
22
|
+
response = hetzner_client.post("/load_balancers", create_load_balancer_config).body
|
23
23
|
puts "...API load balancer created."
|
24
24
|
puts
|
25
25
|
|
@@ -29,6 +29,9 @@ module Hetzner
|
|
29
29
|
def delete(ha:)
|
30
30
|
if load_balancer = find_load_balancer
|
31
31
|
puts "Deleting API load balancer..." unless ha
|
32
|
+
|
33
|
+
hetzner_client.post("/load_balancers/#{load_balancer["id"]}/actions/remove_target", remove_targets_config)
|
34
|
+
|
32
35
|
hetzner_client.delete("/load_balancers", load_balancer["id"])
|
33
36
|
puts "...API load balancer deleted." unless ha
|
34
37
|
elsif ha
|
@@ -46,7 +49,7 @@ module Hetzner
|
|
46
49
|
"#{cluster_name}-api"
|
47
50
|
end
|
48
51
|
|
49
|
-
def
|
52
|
+
def create_load_balancer_config
|
50
53
|
{
|
51
54
|
"algorithm": {
|
52
55
|
"type": "round_robin"
|
@@ -76,6 +79,15 @@ module Hetzner
|
|
76
79
|
}
|
77
80
|
end
|
78
81
|
|
82
|
+
def remove_targets_config
|
83
|
+
{
|
84
|
+
"label_selector": {
|
85
|
+
"selector": "cluster=#{cluster_name},role=master"
|
86
|
+
},
|
87
|
+
"type": "label_selector"
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
79
91
|
def find_load_balancer
|
80
92
|
hetzner_client.get("/load_balancers")["load_balancers"].detect{ |load_balancer| load_balancer["name"] == load_balancer_name }
|
81
93
|
end
|
data/lib/hetzner/k3s/cli.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "http"
|
3
3
|
require "sshkey"
|
4
|
+
require 'ipaddr'
|
5
|
+
require 'open-uri'
|
4
6
|
|
5
7
|
require_relative "cluster"
|
6
8
|
require_relative "version"
|
@@ -23,7 +25,7 @@ module Hetzner
|
|
23
25
|
def create_cluster
|
24
26
|
validate_config_file :create
|
25
27
|
|
26
|
-
Cluster.new(hetzner_client: hetzner_client).create configuration: configuration
|
28
|
+
Cluster.new(hetzner_client: hetzner_client, hetzner_token: find_hetzner_token).create configuration: configuration
|
27
29
|
end
|
28
30
|
|
29
31
|
desc "delete-cluster", "Delete an existing k3s cluster in Hetzner Cloud"
|
@@ -31,7 +33,7 @@ module Hetzner
|
|
31
33
|
|
32
34
|
def delete_cluster
|
33
35
|
validate_config_file :delete
|
34
|
-
Cluster.new(hetzner_client: hetzner_client).delete configuration: configuration
|
36
|
+
Cluster.new(hetzner_client: hetzner_client, hetzner_token: find_hetzner_token).delete configuration: configuration
|
35
37
|
end
|
36
38
|
|
37
39
|
desc "upgrade-cluster", "Upgrade an existing k3s cluster in Hetzner Cloud to a new version"
|
@@ -41,7 +43,7 @@ module Hetzner
|
|
41
43
|
|
42
44
|
def upgrade_cluster
|
43
45
|
validate_config_file :upgrade
|
44
|
-
Cluster.new(hetzner_client: hetzner_client).upgrade configuration: configuration, new_k3s_version: options[:new_k3s_version], config_file: options[:config_file]
|
46
|
+
Cluster.new(hetzner_client: hetzner_client, hetzner_token: find_hetzner_token).upgrade configuration: configuration, new_k3s_version: options[:new_k3s_version], config_file: options[:config_file]
|
45
47
|
end
|
46
48
|
|
47
49
|
desc "releases", "List available k3s releases"
|
@@ -82,6 +84,7 @@ module Hetzner
|
|
82
84
|
case action
|
83
85
|
when :create
|
84
86
|
validate_ssh_key
|
87
|
+
validate_ssh_allowed_networks
|
85
88
|
validate_location
|
86
89
|
validate_k3s_version
|
87
90
|
validate_masters
|
@@ -107,12 +110,26 @@ module Hetzner
|
|
107
110
|
end
|
108
111
|
end
|
109
112
|
|
113
|
+
def valid_token?
|
114
|
+
return @valid unless @valid.nil?
|
115
|
+
|
116
|
+
begin
|
117
|
+
token = find_hetzner_token
|
118
|
+
@hetzner_client = Hetzner::Client.new(token: token)
|
119
|
+
response = hetzner_client.get("/locations")
|
120
|
+
error_code = response.dig("error", "code")
|
121
|
+
@valid = if error_code and error_code.size > 0
|
122
|
+
false
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
126
|
+
rescue
|
127
|
+
@valid = false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
110
131
|
def validate_token
|
111
|
-
|
112
|
-
@hetzner_client = Hetzner::Client.new(token: token)
|
113
|
-
hetzner_client.get("/locations")
|
114
|
-
rescue
|
115
|
-
errors << "Invalid Hetzner Cloid token"
|
132
|
+
errors << "Invalid Hetzner Cloud token" unless valid_token?
|
116
133
|
end
|
117
134
|
|
118
135
|
def validate_cluster_name
|
@@ -149,6 +166,7 @@ module Hetzner
|
|
149
166
|
end
|
150
167
|
|
151
168
|
def server_types
|
169
|
+
return [] unless valid_token?
|
152
170
|
@server_types ||= hetzner_client.get("/server_types")["server_types"].map{ |server_type| server_type["name"] }
|
153
171
|
rescue
|
154
172
|
@errors << "Cannot fetch server types with Hetzner API, please try again later"
|
@@ -156,13 +174,15 @@ module Hetzner
|
|
156
174
|
end
|
157
175
|
|
158
176
|
def locations
|
177
|
+
return [] unless valid_token?
|
159
178
|
@locations ||= hetzner_client.get("/locations")["locations"].map{ |location| location["name"] }
|
160
179
|
rescue
|
161
180
|
@errors << "Cannot fetch locations with Hetzner API, please try again later"
|
162
|
-
|
181
|
+
[]
|
163
182
|
end
|
164
183
|
|
165
184
|
def validate_location
|
185
|
+
return if locations.empty? && !valid_token?
|
166
186
|
errors << "Invalid location - available locations: nbg1 (Nuremberg, Germany), fsn1 (Falkenstein, Germany), hel1 (Helsinki, Finland)" unless locations.include? configuration.dig("location")
|
167
187
|
end
|
168
188
|
|
@@ -271,7 +291,7 @@ module Hetzner
|
|
271
291
|
instance_group_errors << "#{instance_group_type} is in an invalid format"
|
272
292
|
end
|
273
293
|
|
274
|
-
unless server_types.include?(instance_group["instance_type"])
|
294
|
+
unless !valid_token? or server_types.include?(instance_group["instance_type"])
|
275
295
|
instance_group_errors << "#{instance_group_type} has an invalid instance type"
|
276
296
|
end
|
277
297
|
|
@@ -296,16 +316,62 @@ module Hetzner
|
|
296
316
|
config_hash = YAML.load_file(File.expand_path(configuration["kubeconfig_path"]))
|
297
317
|
config_hash['current-context'] = configuration["cluster_name"]
|
298
318
|
@kubernetes_client = K8s::Client.config(K8s::Config.new(config_hash))
|
299
|
-
rescue
|
300
319
|
errors << "Cannot connect to the Kubernetes cluster"
|
301
320
|
false
|
302
321
|
end
|
303
322
|
|
304
|
-
|
305
323
|
def validate_verify_host_key
|
306
324
|
return unless [true, false].include?(configuration.fetch("ssh_key_path", false))
|
307
325
|
errors << "Please set the verify_host_key option to either true or false"
|
308
326
|
end
|
327
|
+
|
328
|
+
def find_hetzner_token
|
329
|
+
@token = ENV["HCLOUD_TOKEN"]
|
330
|
+
return @token if @token
|
331
|
+
@token = configuration.dig("hetzner_token")
|
332
|
+
end
|
333
|
+
|
334
|
+
def validate_ssh_allowed_networks
|
335
|
+
networks ||= configuration.dig("ssh_allowed_networks")
|
336
|
+
|
337
|
+
if networks.nil? or networks.empty?
|
338
|
+
errors << "At least one network/IP range must be specified for SSH access"
|
339
|
+
return
|
340
|
+
end
|
341
|
+
|
342
|
+
invalid_networks = networks.reject do |network|
|
343
|
+
IPAddr.new(network) rescue false
|
344
|
+
end
|
345
|
+
|
346
|
+
unless invalid_networks.empty?
|
347
|
+
invalid_networks.each do |network|
|
348
|
+
errors << "The network #{network} is an invalid range"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
invalid_ranges = networks.reject do |network|
|
353
|
+
network.include? "/"
|
354
|
+
end
|
355
|
+
|
356
|
+
unless invalid_ranges.empty?
|
357
|
+
invalid_ranges.each do |network|
|
358
|
+
errors << "Please use the CIDR notation for the networks to avoid ambiguity"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
return unless invalid_networks.empty?
|
363
|
+
|
364
|
+
current_ip = URI.open('http://whatismyip.akamai.com').read
|
365
|
+
|
366
|
+
current_ip_networks = networks.detect do |network|
|
367
|
+
IPAddr.new(network).include?(current_ip) rescue false
|
368
|
+
end
|
369
|
+
|
370
|
+
unless current_ip_networks
|
371
|
+
errors << "Your current IP #{current_ip} is not included into any of the networks you've specified, so we won't be able to SSH into the nodes"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
309
375
|
end
|
310
376
|
end
|
311
377
|
end
|
data/lib/hetzner/k3s/cluster.rb
CHANGED
@@ -16,12 +16,12 @@ require_relative "../k3s/client_patch"
|
|
16
16
|
|
17
17
|
|
18
18
|
class Cluster
|
19
|
-
def initialize(hetzner_client:)
|
19
|
+
def initialize(hetzner_client:, hetzner_token:)
|
20
20
|
@hetzner_client = hetzner_client
|
21
|
+
@hetzner_token = hetzner_token
|
21
22
|
end
|
22
23
|
|
23
24
|
def create(configuration:)
|
24
|
-
@hetzner_token = configuration.dig("hetzner_token")
|
25
25
|
@cluster_name = configuration.dig("cluster_name")
|
26
26
|
@kubeconfig_path = File.expand_path(configuration.dig("kubeconfig_path"))
|
27
27
|
@ssh_key_path = File.expand_path(configuration.dig("ssh_key_path"))
|
@@ -31,6 +31,7 @@ class Cluster
|
|
31
31
|
@location = configuration.dig("location")
|
32
32
|
@verify_host_key = configuration.fetch("verify_host_key", false)
|
33
33
|
@servers = []
|
34
|
+
@networks = configuration.dig("ssh_allowed_networks")
|
34
35
|
|
35
36
|
create_resources
|
36
37
|
|
@@ -69,7 +70,7 @@ class Cluster
|
|
69
70
|
:masters_config, :worker_node_pools,
|
70
71
|
:location, :ssh_key_path, :kubernetes_client,
|
71
72
|
:hetzner_token, :tls_sans, :new_k3s_version, :configuration,
|
72
|
-
:config_file, :verify_host_key
|
73
|
+
:config_file, :verify_host_key, :networks
|
73
74
|
|
74
75
|
|
75
76
|
def latest_k3s_version
|
@@ -78,10 +79,13 @@ class Cluster
|
|
78
79
|
end
|
79
80
|
|
80
81
|
def create_resources
|
82
|
+
master_instance_type = masters_config["instance_type"]
|
83
|
+
masters_count = masters_config["instance_count"]
|
84
|
+
|
81
85
|
firewall_id = Hetzner::Firewall.new(
|
82
86
|
hetzner_client: hetzner_client,
|
83
87
|
cluster_name: cluster_name
|
84
|
-
).create
|
88
|
+
).create(ha: (masters_count > 1), networks: networks)
|
85
89
|
|
86
90
|
network_id = Hetzner::Network.new(
|
87
91
|
hetzner_client: hetzner_client,
|
@@ -95,9 +99,6 @@ class Cluster
|
|
95
99
|
|
96
100
|
server_configs = []
|
97
101
|
|
98
|
-
master_instance_type = masters_config["instance_type"]
|
99
|
-
masters_count = masters_config["instance_count"]
|
100
|
-
|
101
102
|
masters_count.times do |i|
|
102
103
|
server_configs << {
|
103
104
|
location: location,
|
@@ -150,42 +151,15 @@ class Cluster
|
|
150
151
|
end
|
151
152
|
|
152
153
|
def delete_resources
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
threads = servers.map do |node|
|
159
|
-
Thread.new do
|
160
|
-
Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(server_name: node.metadata[:name])
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
threads.each(&:join) unless threads.empty?
|
165
|
-
end
|
166
|
-
rescue Timeout::Error, Excon::Error::Socket
|
167
|
-
puts "Unable to fetch nodes from Kubernetes API. Is the cluster online?"
|
168
|
-
end
|
169
|
-
|
170
|
-
# Deleting nodes defined in the config file just in case there are leftovers i.e. nodes that
|
171
|
-
# were not part of the cluster for some reason
|
172
|
-
|
173
|
-
threads = all_servers.map do |server|
|
174
|
-
Thread.new do
|
175
|
-
Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(server_name: server["name"])
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
threads.each(&:join) unless threads.empty?
|
180
|
-
|
181
|
-
puts
|
182
|
-
|
183
|
-
sleep 5 # give time for the servers to actually be deleted
|
154
|
+
Hetzner::LoadBalancer.new(
|
155
|
+
hetzner_client: hetzner_client,
|
156
|
+
cluster_name: cluster_name
|
157
|
+
).delete(ha: (masters.size > 1))
|
184
158
|
|
185
159
|
Hetzner::Firewall.new(
|
186
160
|
hetzner_client: hetzner_client,
|
187
161
|
cluster_name: cluster_name
|
188
|
-
).delete
|
162
|
+
).delete(all_servers)
|
189
163
|
|
190
164
|
Hetzner::Network.new(
|
191
165
|
hetzner_client: hetzner_client,
|
@@ -197,11 +171,13 @@ class Cluster
|
|
197
171
|
cluster_name: cluster_name
|
198
172
|
).delete(ssh_key_path: ssh_key_path)
|
199
173
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
174
|
+
threads = all_servers.map do |server|
|
175
|
+
Thread.new do
|
176
|
+
Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(server_name: server["name"])
|
177
|
+
end
|
178
|
+
end
|
204
179
|
|
180
|
+
threads.each(&:join) unless threads.empty?
|
205
181
|
end
|
206
182
|
|
207
183
|
def upgrade_cluster
|
@@ -249,6 +225,7 @@ class Cluster
|
|
249
225
|
--kube-scheduler-arg="bind-address=0.0.0.0" \
|
250
226
|
--node-taint CriticalAddonsOnly=true:NoExecute \
|
251
227
|
--kubelet-arg="cloud-provider=external" \
|
228
|
+
--advertise-address=$(hostname -I | awk '{print $2}') \
|
252
229
|
--node-ip=$(hostname -I | awk '{print $2}') \
|
253
230
|
--node-external-ip=$(hostname -I | awk '{print $1}') \
|
254
231
|
--flannel-iface=#{flannel_interface} \
|
data/lib/hetzner/k3s/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hetzner-k3s
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vito Botta
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|