hetzner-k3s 0.5.8 → 0.6.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +31 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -1
- data/Gemfile +13 -2
- data/Gemfile.lock +22 -53
- data/README.md +8 -3
- data/bin/build.sh +12 -6
- data/config/warble.rb +182 -0
- data/exe/hetzner-k3s +3 -0
- data/hetzner-k3s.gemspec +4 -4
- data/lib/hetzner/infra/client.rb +5 -5
- data/lib/hetzner/infra/firewall.rb +7 -9
- data/lib/hetzner/infra/load_balancer.rb +1 -1
- data/lib/hetzner/infra/network.rb +19 -9
- data/lib/hetzner/infra/server.rb +3 -4
- data/lib/hetzner/k3s/cli.rb +6 -5
- data/lib/hetzner/k3s/cluster.rb +55 -36
- data/lib/hetzner/k3s/configuration.rb +55 -23
- data/lib/hetzner/k3s/version.rb +1 -1
- data/lib/hetzner/utils.rb +19 -10
- metadata +25 -23
data/lib/hetzner/k3s/cli.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
-
require '
|
4
|
+
require 'openssl'
|
5
|
+
require 'httparty'
|
5
6
|
require 'sshkey'
|
6
7
|
require 'ipaddr'
|
7
8
|
require 'open-uri'
|
@@ -27,14 +28,14 @@ module Hetzner
|
|
27
28
|
option :config_file, required: true
|
28
29
|
def create_cluster
|
29
30
|
configuration.validate action: :create
|
30
|
-
Cluster.new(configuration:).create
|
31
|
+
Cluster.new(configuration: configuration).create
|
31
32
|
end
|
32
33
|
|
33
34
|
desc 'delete-cluster', 'Delete an existing k3s cluster in Hetzner Cloud'
|
34
35
|
option :config_file, required: true
|
35
36
|
def delete_cluster
|
36
37
|
configuration.validate action: :delete
|
37
|
-
Cluster.new(configuration:).delete
|
38
|
+
Cluster.new(configuration: configuration).delete
|
38
39
|
end
|
39
40
|
|
40
41
|
desc 'upgrade-cluster', 'Upgrade an existing k3s cluster in Hetzner Cloud to a new version'
|
@@ -43,7 +44,7 @@ module Hetzner
|
|
43
44
|
option :force, default: 'false'
|
44
45
|
def upgrade_cluster
|
45
46
|
configuration.validate action: :upgrade
|
46
|
-
Cluster.new(configuration:).upgrade(new_k3s_version: options[:new_k3s_version], config_file: options[:config_file])
|
47
|
+
Cluster.new(configuration: configuration).upgrade(new_k3s_version: options[:new_k3s_version], config_file: options[:config_file])
|
47
48
|
end
|
48
49
|
|
49
50
|
desc 'releases', 'List available k3s releases'
|
@@ -59,7 +60,7 @@ module Hetzner
|
|
59
60
|
|
60
61
|
def configuration
|
61
62
|
@configuration ||= begin
|
62
|
-
config = ::Hetzner::Configuration.new(options:)
|
63
|
+
config = ::Hetzner::Configuration.new(options: options)
|
63
64
|
@hetzner_token = config.hetzner_token
|
64
65
|
config
|
65
66
|
end
|
data/lib/hetzner/k3s/cluster.rb
CHANGED
@@ -4,7 +4,7 @@ require 'net/ssh'
|
|
4
4
|
require 'securerandom'
|
5
5
|
require 'base64'
|
6
6
|
require 'timeout'
|
7
|
-
require '
|
7
|
+
require 'fileutils'
|
8
8
|
|
9
9
|
require_relative '../infra/client'
|
10
10
|
require_relative '../infra/firewall'
|
@@ -35,7 +35,8 @@ class Cluster
|
|
35
35
|
@masters_location = configuration['location']
|
36
36
|
@verify_host_key = configuration.fetch('verify_host_key', false)
|
37
37
|
@servers = []
|
38
|
-
@
|
38
|
+
@ssh_networks = configuration['ssh_allowed_networks']
|
39
|
+
@api_networks = configuration['api_allowed_networks']
|
39
40
|
@enable_encryption = configuration.fetch('enable_encryption', false)
|
40
41
|
@kube_api_server_args = configuration.fetch('kube_api_server_args', [])
|
41
42
|
@kube_scheduler_args = configuration.fetch('kube_scheduler_args', [])
|
@@ -82,17 +83,17 @@ class Cluster
|
|
82
83
|
:masters_config, :worker_node_pools,
|
83
84
|
:masters_location, :public_ssh_key_path,
|
84
85
|
:hetzner_token, :new_k3s_version,
|
85
|
-
:config_file, :verify_host_key, :
|
86
|
+
:config_file, :verify_host_key, :ssh_networks, :private_ssh_key_path,
|
86
87
|
:enable_encryption, :kube_api_server_args, :kube_scheduler_args,
|
87
88
|
:kube_controller_manager_args, :kube_cloud_controller_manager_args,
|
88
|
-
:kubelet_args, :kube_proxy_args
|
89
|
+
:kubelet_args, :kube_proxy_args, :api_networks
|
89
90
|
|
90
91
|
def find_worker_node_pools(configuration)
|
91
92
|
configuration.fetch('worker_node_pools', [])
|
92
93
|
end
|
93
94
|
|
94
95
|
def latest_k3s_version
|
95
|
-
response =
|
96
|
+
response = HTTParty.get('https://api.github.com/repos/k3s-io/k3s/tags').body
|
96
97
|
JSON.parse(response).first['name']
|
97
98
|
end
|
98
99
|
|
@@ -102,22 +103,22 @@ class Cluster
|
|
102
103
|
end
|
103
104
|
|
104
105
|
def delete_placement_groups
|
105
|
-
Hetzner::PlacementGroup.new(hetzner_client
|
106
|
+
Hetzner::PlacementGroup.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete
|
106
107
|
|
107
108
|
worker_node_pools.each do |pool|
|
108
109
|
pool_name = pool['name']
|
109
|
-
Hetzner::PlacementGroup.new(hetzner_client
|
110
|
+
Hetzner::PlacementGroup.new(hetzner_client: hetzner_client, cluster_name: cluster_name, pool_name: pool_name).delete
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
113
114
|
def delete_resources
|
114
|
-
Hetzner::LoadBalancer.new(hetzner_client
|
115
|
+
Hetzner::LoadBalancer.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(high_availability: (masters.size > 1))
|
115
116
|
|
116
|
-
Hetzner::Firewall.new(hetzner_client
|
117
|
+
Hetzner::Firewall.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(all_servers)
|
117
118
|
|
118
|
-
Hetzner::Network.new(hetzner_client
|
119
|
+
Hetzner::Network.new(hetzner_client: hetzner_client, cluster_name: cluster_name, existing_network: existing_network).delete
|
119
120
|
|
120
|
-
Hetzner::SSHKey.new(hetzner_client
|
121
|
+
Hetzner::SSHKey.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(public_ssh_key_path: public_ssh_key_path)
|
121
122
|
|
122
123
|
delete_placement_groups
|
123
124
|
delete_servers
|
@@ -195,7 +196,21 @@ class Cluster
|
|
195
196
|
def master_script(master)
|
196
197
|
server = master == first_master ? ' --cluster-init ' : " --server https://#{api_server_ip}:6443 "
|
197
198
|
flannel_interface = find_flannel_interface(master)
|
198
|
-
|
199
|
+
|
200
|
+
available_k3s_releases = Hetzner::Configuration.available_releases
|
201
|
+
wireguard_native_min_version_index = available_k3s_releases.find_index('v1.23.6+k3s1')
|
202
|
+
selected_version_index = available_k3s_releases.find_index(k3s_version)
|
203
|
+
|
204
|
+
flannel_wireguard = if enable_encryption
|
205
|
+
if selected_version_index >= wireguard_native_min_version_index
|
206
|
+
' --flannel-backend=wireguard-native '
|
207
|
+
else
|
208
|
+
' --flannel-backend=wireguard '
|
209
|
+
end
|
210
|
+
else
|
211
|
+
' '
|
212
|
+
end
|
213
|
+
|
199
214
|
extra_args = "#{kube_api_server_args_list} #{kube_scheduler_args_list} #{kube_controller_manager_args_list} #{kube_cloud_controller_manager_args_list} #{kubelet_args_list} #{kube_proxy_args_list}"
|
200
215
|
taint = schedule_workloads_on_masters? ? ' ' : ' --node-taint CriticalAddonsOnly=true:NoExecute '
|
201
216
|
|
@@ -293,7 +308,7 @@ class Cluster
|
|
293
308
|
namespace: 'kube-system'
|
294
309
|
name: 'hcloud'
|
295
310
|
stringData:
|
296
|
-
network: "#{cluster_name}"
|
311
|
+
network: "#{existing_network || cluster_name}"
|
297
312
|
token: "#{configuration.hetzner_token}"
|
298
313
|
EOF
|
299
314
|
BASH
|
@@ -313,7 +328,7 @@ class Cluster
|
|
313
328
|
puts
|
314
329
|
puts 'Deploying k3s System Upgrade Controller...'
|
315
330
|
|
316
|
-
cmd = 'kubectl apply -f https://github.com/rancher/system-upgrade-controller/releases/download/v0.
|
331
|
+
cmd = 'kubectl apply -f https://github.com/rancher/system-upgrade-controller/releases/download/v0.9.1/system-upgrade-controller.yaml'
|
317
332
|
|
318
333
|
run cmd, kubeconfig_path: kubeconfig_path
|
319
334
|
|
@@ -340,7 +355,7 @@ class Cluster
|
|
340
355
|
|
341
356
|
run cmd, kubeconfig_path: kubeconfig_path
|
342
357
|
|
343
|
-
cmd = 'kubectl apply -f https://raw.githubusercontent.com/hetznercloud/csi-driver/
|
358
|
+
cmd = 'kubectl apply -f https://raw.githubusercontent.com/hetznercloud/csi-driver/master/deploy/kubernetes/hcloud-csi.yml'
|
344
359
|
|
345
360
|
run cmd, kubeconfig_path: kubeconfig_path
|
346
361
|
|
@@ -408,7 +423,7 @@ class Cluster
|
|
408
423
|
|
409
424
|
masters.each do |master|
|
410
425
|
master_private_ip = master['private_net'][0]['ip']
|
411
|
-
sans
|
426
|
+
sans += " --tls-san=#{master_private_ip} "
|
412
427
|
end
|
413
428
|
|
414
429
|
sans
|
@@ -458,7 +473,7 @@ class Cluster
|
|
458
473
|
|
459
474
|
def placement_group_id(pool_name = nil)
|
460
475
|
@placement_groups ||= {}
|
461
|
-
@placement_groups[pool_name || '__masters__'] ||= Hetzner::PlacementGroup.new(hetzner_client
|
476
|
+
@placement_groups[pool_name || '__masters__'] ||= Hetzner::PlacementGroup.new(hetzner_client: hetzner_client, cluster_name: cluster_name, pool_name: pool_name).create
|
462
477
|
end
|
463
478
|
|
464
479
|
def master_instance_type
|
@@ -470,15 +485,15 @@ class Cluster
|
|
470
485
|
end
|
471
486
|
|
472
487
|
def firewall_id
|
473
|
-
@firewall_id ||= Hetzner::Firewall.new(hetzner_client
|
488
|
+
@firewall_id ||= Hetzner::Firewall.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(high_availability: (masters_count > 1), ssh_networks: ssh_networks, api_networks: api_networks)
|
474
489
|
end
|
475
490
|
|
476
491
|
def network_id
|
477
|
-
@network_id ||= Hetzner::Network.new(hetzner_client
|
492
|
+
@network_id ||= Hetzner::Network.new(hetzner_client: hetzner_client, cluster_name: cluster_name, existing_network: existing_network).create(location: masters_location)
|
478
493
|
end
|
479
494
|
|
480
495
|
def ssh_key_id
|
481
|
-
@ssh_key_id ||= Hetzner::SSHKey.new(hetzner_client
|
496
|
+
@ssh_key_id ||= Hetzner::SSHKey.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(public_ssh_key_path: public_ssh_key_path)
|
482
497
|
end
|
483
498
|
|
484
499
|
def master_definitions_for_create
|
@@ -489,13 +504,13 @@ class Cluster
|
|
489
504
|
instance_type: master_instance_type,
|
490
505
|
instance_id: "master#{i + 1}",
|
491
506
|
location: masters_location,
|
492
|
-
placement_group_id
|
493
|
-
firewall_id
|
494
|
-
network_id
|
495
|
-
ssh_key_id
|
496
|
-
image
|
497
|
-
additional_packages
|
498
|
-
additional_post_create_commands:
|
507
|
+
placement_group_id: placement_group_id,
|
508
|
+
firewall_id: firewall_id,
|
509
|
+
network_id: network_id,
|
510
|
+
ssh_key_id: ssh_key_id,
|
511
|
+
image: image,
|
512
|
+
additional_packages: additional_packages,
|
513
|
+
additional_post_create_commands: additional_post_create_commands
|
499
514
|
}
|
500
515
|
end
|
501
516
|
|
@@ -529,12 +544,12 @@ class Cluster
|
|
529
544
|
instance_id: "pool-#{worker_node_pool_name}-worker#{i + 1}",
|
530
545
|
placement_group_id: placement_group_id(worker_node_pool_name),
|
531
546
|
location: worker_location,
|
532
|
-
firewall_id
|
533
|
-
network_id
|
534
|
-
ssh_key_id
|
535
|
-
image
|
536
|
-
additional_packages
|
537
|
-
additional_post_create_commands:
|
547
|
+
firewall_id: firewall_id,
|
548
|
+
network_id: network_id,
|
549
|
+
ssh_key_id: ssh_key_id,
|
550
|
+
image: image,
|
551
|
+
additional_packages: additional_packages,
|
552
|
+
additional_post_create_commands: additional_post_create_commands
|
538
553
|
}
|
539
554
|
end
|
540
555
|
|
@@ -542,7 +557,7 @@ class Cluster
|
|
542
557
|
end
|
543
558
|
|
544
559
|
def create_load_balancer
|
545
|
-
Hetzner::LoadBalancer.new(hetzner_client
|
560
|
+
Hetzner::LoadBalancer.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(location: masters_location, network_id: network_id)
|
546
561
|
end
|
547
562
|
|
548
563
|
def server_configs
|
@@ -562,7 +577,7 @@ class Cluster
|
|
562
577
|
|
563
578
|
threads = server_configs.map do |server_config|
|
564
579
|
Thread.new do
|
565
|
-
servers << Hetzner::Server.new(hetzner_client
|
580
|
+
servers << Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(**server_config)
|
566
581
|
end
|
567
582
|
end
|
568
583
|
|
@@ -584,7 +599,7 @@ class Cluster
|
|
584
599
|
def delete_servers
|
585
600
|
threads = all_servers.map do |server|
|
586
601
|
Thread.new do
|
587
|
-
Hetzner::Server.new(hetzner_client
|
602
|
+
Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).delete(server_name: server['name'])
|
588
603
|
end
|
589
604
|
end
|
590
605
|
|
@@ -642,4 +657,8 @@ class Cluster
|
|
642
657
|
def hetzner_client
|
643
658
|
configuration.hetzner_client
|
644
659
|
end
|
660
|
+
|
661
|
+
def existing_network
|
662
|
+
configuration['existing_network']
|
663
|
+
end
|
645
664
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Hetzner
|
4
4
|
class Configuration
|
5
|
-
GITHUB_DELIM_LINKS = ','
|
6
|
-
GITHUB_LINK_REGEX = /<([^>]+)>; rel
|
5
|
+
GITHUB_DELIM_LINKS = ','
|
6
|
+
GITHUB_LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/
|
7
7
|
|
8
8
|
attr_reader :hetzner_client
|
9
9
|
|
@@ -52,7 +52,7 @@ module Hetzner
|
|
52
52
|
releases = page_releases
|
53
53
|
link_header = response.headers['link']
|
54
54
|
|
55
|
-
|
55
|
+
until link_header.nil?
|
56
56
|
next_page_url = extract_next_github_page_url(link_header)
|
57
57
|
|
58
58
|
break if next_page_url.nil?
|
@@ -67,10 +67,10 @@ module Hetzner
|
|
67
67
|
releases.sort
|
68
68
|
end
|
69
69
|
rescue StandardError
|
70
|
-
if defined?errors
|
71
|
-
errors << 'Cannot fetch the releases with
|
70
|
+
if defined? errors
|
71
|
+
errors << 'Cannot fetch the releases with Github API, please try again later. This may be due to API rate limits.'
|
72
72
|
else
|
73
|
-
puts 'Cannot fetch the releases with
|
73
|
+
puts 'Cannot fetch the releases with Github API, please try again later. This may be due to API rate limits.'
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -92,21 +92,20 @@ module Hetzner
|
|
92
92
|
configuration
|
93
93
|
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
attr_reader :configuration, :errors, :options
|
95
|
+
private_class_method
|
98
96
|
|
99
97
|
def self.fetch_releases(url)
|
100
|
-
response =
|
98
|
+
response = HTTParty.get(url)
|
101
99
|
[response, JSON.parse(response.body).map { |hash| hash['name'] }]
|
102
100
|
end
|
103
101
|
|
104
102
|
def self.extract_next_github_page_url(link_header)
|
105
103
|
link_header.split(GITHUB_DELIM_LINKS).each do |link|
|
106
104
|
GITHUB_LINK_REGEX.match(link.strip) do |match|
|
107
|
-
url_part
|
105
|
+
url_part = match[1]
|
106
|
+
meta_part = match[2]
|
108
107
|
next if !url_part || !meta_part
|
109
|
-
return url_part if meta_part ==
|
108
|
+
return url_part if meta_part == 'next'
|
110
109
|
end
|
111
110
|
end
|
112
111
|
|
@@ -115,17 +114,22 @@ module Hetzner
|
|
115
114
|
|
116
115
|
def self.assign_url_part(meta_part, url_part)
|
117
116
|
case meta_part
|
118
|
-
when
|
117
|
+
when 'next'
|
119
118
|
url_part
|
120
119
|
end
|
121
120
|
end
|
122
121
|
|
122
|
+
private
|
123
|
+
|
124
|
+
attr_reader :configuration, :errors, :options
|
125
|
+
|
123
126
|
def validate_create
|
124
127
|
validate_public_ssh_key
|
125
128
|
validate_private_ssh_key
|
126
129
|
validate_ssh_allowed_networks
|
130
|
+
validate_api_allowed_networks
|
127
131
|
validate_masters_location
|
128
|
-
validate_k3s_version
|
132
|
+
# validate_k3s_version
|
129
133
|
validate_masters
|
130
134
|
validate_worker_node_pools
|
131
135
|
validate_verify_host_key
|
@@ -137,11 +141,12 @@ module Hetzner
|
|
137
141
|
validate_kube_cloud_controller_manager_args
|
138
142
|
validate_kubelet_args
|
139
143
|
validate_kube_proxy_args
|
144
|
+
validate_existing_network
|
140
145
|
end
|
141
146
|
|
142
147
|
def validate_upgrade
|
143
148
|
validate_kubeconfig_path_must_exist
|
144
|
-
validate_new_k3s_version
|
149
|
+
# validate_new_k3s_version
|
145
150
|
end
|
146
151
|
|
147
152
|
def validate_public_ssh_key
|
@@ -165,11 +170,11 @@ module Hetzner
|
|
165
170
|
errors << 'Invalid Private SSH key path'
|
166
171
|
end
|
167
172
|
|
168
|
-
def
|
169
|
-
networks ||= configuration[
|
173
|
+
def validate_networks(configuration_option, access_type)
|
174
|
+
networks ||= configuration[configuration_option]
|
170
175
|
|
171
176
|
if networks.nil? || networks.empty?
|
172
|
-
errors <<
|
177
|
+
errors << "At least one network/IP range must be specified for #{access_type} access"
|
173
178
|
return
|
174
179
|
end
|
175
180
|
|
@@ -181,7 +186,7 @@ module Hetzner
|
|
181
186
|
|
182
187
|
unless invalid_networks.empty?
|
183
188
|
invalid_networks.each do |network|
|
184
|
-
errors << "The network #{network} is an invalid range"
|
189
|
+
errors << "The #{access_type} network #{network} is an invalid range"
|
185
190
|
end
|
186
191
|
end
|
187
192
|
|
@@ -191,7 +196,7 @@ module Hetzner
|
|
191
196
|
|
192
197
|
unless invalid_ranges.empty?
|
193
198
|
invalid_ranges.each do |_network|
|
194
|
-
errors << 'Please use the CIDR notation for the networks to avoid ambiguity'
|
199
|
+
errors << 'Please use the CIDR notation for the #{access_type} networks to avoid ambiguity'
|
195
200
|
end
|
196
201
|
end
|
197
202
|
|
@@ -199,13 +204,30 @@ module Hetzner
|
|
199
204
|
|
200
205
|
current_ip = URI.open('http://whatismyip.akamai.com').read
|
201
206
|
|
202
|
-
|
207
|
+
current_ip_network = networks.detect do |network|
|
203
208
|
IPAddr.new(network).include?(current_ip)
|
204
209
|
rescue StandardError
|
205
210
|
false
|
206
211
|
end
|
207
212
|
|
208
|
-
|
213
|
+
unless current_ip_network
|
214
|
+
case access_type
|
215
|
+
when "SSH"
|
216
|
+
errors << "Your current IP #{current_ip} is not included into any of the #{access_type} networks you've specified, so we won't be able to SSH into the nodes "
|
217
|
+
when "API"
|
218
|
+
errors << "Your current IP #{current_ip} is not included into any of the #{access_type} networks you've specified, so we won't be able to connect to the Kubernetes API"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
def validate_ssh_allowed_networks
|
225
|
+
return
|
226
|
+
validate_networks('ssh_allowed_networks', 'SSH')
|
227
|
+
end
|
228
|
+
|
229
|
+
def validate_api_allowed_networks
|
230
|
+
validate_networks('api_allowed_networks', 'API')
|
209
231
|
end
|
210
232
|
|
211
233
|
def validate_masters_location
|
@@ -379,7 +401,7 @@ module Hetzner
|
|
379
401
|
|
380
402
|
begin
|
381
403
|
token = hetzner_token
|
382
|
-
@hetzner_client = Hetzner::Client.new(token:)
|
404
|
+
@hetzner_client = Hetzner::Client.new(token: token)
|
383
405
|
response = hetzner_client.get('/locations')
|
384
406
|
error_code = response.dig('error', 'code')
|
385
407
|
@valid = error_code != 'unauthorized'
|
@@ -450,5 +472,15 @@ module Hetzner
|
|
450
472
|
@errors << 'Cannot fetch server types with Hetzner API, please try again later'
|
451
473
|
false
|
452
474
|
end
|
475
|
+
|
476
|
+
def validate_existing_network
|
477
|
+
return unless configuration['existing_network']
|
478
|
+
|
479
|
+
existing_network = Hetzner::Network.new(hetzner_client: hetzner_client, cluster_name: configuration['cluster_name'], existing_network: configuration['existing_network']).get
|
480
|
+
|
481
|
+
return if existing_network
|
482
|
+
|
483
|
+
@errors << "You have specified that you want to use the existing network named '#{configuration['existing_network']} but this network doesn't exist"
|
484
|
+
end
|
453
485
|
end
|
454
486
|
end
|
data/lib/hetzner/k3s/version.rb
CHANGED
data/lib/hetzner/utils.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
Net::SSH::Transport::Algorithms::ALGORITHMS.values.each { |algs| algs.reject! { |a| a =~ /^ecd(sa|h)-sha2/ } }
|
4
|
+
Net::SSH::KnownHosts::SUPPORTED_TYPE.reject! { |t| t =~ /^ecd(sa|h)-sha2/ }
|
5
|
+
|
6
|
+
require 'childprocess'
|
7
|
+
|
3
8
|
module Utils
|
4
9
|
CMD_FILE_PATH = '/tmp/cli.cmd'
|
5
10
|
|
@@ -19,8 +24,6 @@ module Utils
|
|
19
24
|
end
|
20
25
|
|
21
26
|
def run(command, kubeconfig_path:)
|
22
|
-
env = ENV.to_hash.merge({ 'KUBECONFIG' => kubeconfig_path })
|
23
|
-
|
24
27
|
write_file CMD_FILE_PATH, <<-CONTENT
|
25
28
|
set -euo pipefail
|
26
29
|
#{command}
|
@@ -29,20 +32,19 @@ module Utils
|
|
29
32
|
FileUtils.chmod('+x', CMD_FILE_PATH)
|
30
33
|
|
31
34
|
begin
|
32
|
-
process =
|
35
|
+
process = ChildProcess.build('bash', '-c', CMD_FILE_PATH)
|
36
|
+
process.io.inherit!
|
37
|
+
process.environment['KUBECONFIG'] = kubeconfig_path
|
38
|
+
process.environment['HCLOUD_TOKEN'] = ENV.fetch('HCLOUD_TOKEN', '')
|
33
39
|
|
34
40
|
at_exit do
|
35
|
-
process
|
41
|
+
process.stop
|
36
42
|
rescue Errno::ESRCH, Interrupt
|
37
43
|
# ignore
|
38
44
|
end
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
rescue Subprocess::NonZeroExit
|
44
|
-
puts 'Command failed: non-zero exit code'
|
45
|
-
exit 1
|
46
|
+
process.start
|
47
|
+
process.wait
|
46
48
|
rescue Interrupt
|
47
49
|
puts 'Command interrupted'
|
48
50
|
exit 1
|
@@ -86,6 +88,13 @@ module Utils
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
output.chop
|
91
|
+
# rescue StandardError => e
|
92
|
+
# p [e.class, e.message]
|
93
|
+
# retries += 1
|
94
|
+
# retry unless retries > 15 || e.message =~ /Bad file descriptor/
|
95
|
+
rescue Timeout::Error, IOError, Errno::EBADF
|
96
|
+
retries += 1
|
97
|
+
retry unless retries > 15
|
89
98
|
rescue Net::SSH::Disconnect => e
|
90
99
|
retries += 1
|
91
100
|
retry unless retries > 15 || e.message =~ /Too many authentication failures/
|