hetzner-k3s 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hetzner
2
4
  class LoadBalancer
3
5
  def initialize(hetzner_client:, cluster_name:)
@@ -11,31 +13,31 @@ module Hetzner
11
13
 
12
14
  puts
13
15
 
14
- if load_balancer = find_load_balancer
15
- puts "API load balancer already exists, skipping."
16
+ if (load_balancer = find_load_balancer)
17
+ puts 'API load balancer already exists, skipping.'
16
18
  puts
17
- return load_balancer["id"]
19
+ return load_balancer['id']
18
20
  end
19
21
 
20
- puts "Creating API load_balancer..."
22
+ puts 'Creating API load_balancer...'
21
23
 
22
- response = hetzner_client.post("/load_balancers", create_load_balancer_config).body
23
- puts "...API load balancer created."
24
+ response = hetzner_client.post('/load_balancers', create_load_balancer_config).body
25
+ puts '...API load balancer created.'
24
26
  puts
25
27
 
26
- JSON.parse(response)["load_balancer"]["id"]
28
+ JSON.parse(response)['load_balancer']['id']
27
29
  end
28
30
 
29
- def delete(ha:)
30
- if load_balancer = find_load_balancer
31
- puts "Deleting API load balancer..." unless ha
31
+ def delete(high_availability:)
32
+ if (load_balancer = find_load_balancer)
33
+ puts 'Deleting API load balancer...' unless high_availability
32
34
 
33
- hetzner_client.post("/load_balancers/#{load_balancer["id"]}/actions/remove_target", remove_targets_config)
35
+ hetzner_client.post("/load_balancers/#{load_balancer['id']}/actions/remove_target", remove_targets_config)
34
36
 
35
- hetzner_client.delete("/load_balancers", load_balancer["id"])
36
- puts "...API load balancer deleted." unless ha
37
- elsif ha
38
- puts "API load balancer no longer exists, skipping."
37
+ hetzner_client.delete('/load_balancers', load_balancer['id'])
38
+ puts '...API load balancer deleted.' unless high_availability
39
+ elsif high_availability
40
+ puts 'API load balancer no longer exists, skipping.'
39
41
  end
40
42
 
41
43
  puts
@@ -43,54 +45,55 @@ module Hetzner
43
45
 
44
46
  private
45
47
 
46
- attr_reader :hetzner_client, :cluster_name, :load_balancer, :location, :network_id
48
+ attr_reader :hetzner_client, :cluster_name, :load_balancer, :location, :network_id
47
49
 
48
- def load_balancer_name
49
- "#{cluster_name}-api"
50
- end
50
+ def load_balancer_name
51
+ "#{cluster_name}-api"
52
+ end
51
53
 
52
- def create_load_balancer_config
53
- {
54
- "algorithm": {
55
- "type": "round_robin"
56
- },
57
- "load_balancer_type": "lb11",
58
- "location": location,
59
- "name": load_balancer_name,
60
- "network": network_id,
61
- "public_interface": true,
62
- "services": [
63
- {
64
- "destination_port": 6443,
65
- "listen_port": 6443,
66
- "protocol": "tcp",
67
- "proxyprotocol": false
68
- }
69
- ],
70
- "targets": [
71
- {
72
- "label_selector": {
73
- "selector": "cluster=#{cluster_name},role=master"
74
- },
75
- "type": "label_selector",
76
- "use_private_ip": true
77
- }
78
- ]
79
- }
80
- end
54
+ def create_load_balancer_config
55
+ {
56
+ algorithm: {
57
+ type: 'round_robin'
58
+ },
59
+ load_balancer_type: 'lb11',
60
+ location:,
61
+ name: load_balancer_name,
62
+ network: network_id,
63
+ public_interface: true,
64
+ services: [
65
+ {
66
+ destination_port: 6443,
67
+ listen_port: 6443,
68
+ protocol: 'tcp',
69
+ proxyprotocol: false
70
+ }
71
+ ],
72
+ targets: [
73
+ {
74
+ label_selector: {
75
+ selector: "cluster=#{cluster_name},role=master"
76
+ },
77
+ type: 'label_selector',
78
+ use_private_ip: true
79
+ }
80
+ ]
81
+ }
82
+ end
81
83
 
82
- def remove_targets_config
83
- {
84
- "label_selector": {
85
- "selector": "cluster=#{cluster_name},role=master"
86
- },
87
- "type": "label_selector"
88
- }
89
- end
84
+ def remove_targets_config
85
+ {
86
+ label_selector: {
87
+ selector: "cluster=#{cluster_name},role=master"
88
+ },
89
+ type: 'label_selector'
90
+ }
91
+ end
90
92
 
91
- def find_load_balancer
92
- hetzner_client.get("/load_balancers")["load_balancers"].detect{ |load_balancer| load_balancer["name"] == load_balancer_name }
93
+ def find_load_balancer
94
+ hetzner_client.get('/load_balancers')['load_balancers'].detect do |load_balancer|
95
+ load_balancer['name'] == load_balancer_name
93
96
  end
94
-
97
+ end
95
98
  end
96
99
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hetzner
2
4
  class Network
3
5
  def initialize(hetzner_client:, cluster_name:)
@@ -9,29 +11,29 @@ module Hetzner
9
11
  @location = location
10
12
  puts
11
13
 
12
- if network = find_network
13
- puts "Private network already exists, skipping."
14
+ if (network = find_network)
15
+ puts 'Private network already exists, skipping.'
14
16
  puts
15
- return network["id"]
17
+ return network['id']
16
18
  end
17
19
 
18
- puts "Creating private network..."
20
+ puts 'Creating private network...'
19
21
 
20
- response = hetzner_client.post("/networks", network_config).body
22
+ response = hetzner_client.post('/networks', network_config).body
21
23
 
22
- puts "...private network created."
24
+ puts '...private network created.'
23
25
  puts
24
26
 
25
- JSON.parse(response)["network"]["id"]
27
+ JSON.parse(response)['network']['id']
26
28
  end
27
29
 
28
30
  def delete
29
- if network = find_network
30
- puts "Deleting network..."
31
- hetzner_client.delete("/networks", network["id"])
32
- puts "...network deleted."
31
+ if (network = find_network)
32
+ puts 'Deleting network...'
33
+ hetzner_client.delete('/networks', network['id'])
34
+ puts '...network deleted.'
33
35
  else
34
- puts "Network no longer exists, skipping."
36
+ puts 'Network no longer exists, skipping.'
35
37
  end
36
38
 
37
39
  puts
@@ -39,25 +41,24 @@ module Hetzner
39
41
 
40
42
  private
41
43
 
42
- attr_reader :hetzner_client, :cluster_name, :location
43
-
44
- def network_config
45
- {
46
- name: cluster_name,
47
- ip_range: "10.0.0.0/16",
48
- subnets: [
49
- {
50
- ip_range: "10.0.0.0/16",
51
- network_zone: (location == "ash" ? "us-east" : "eu-central"),
52
- type: "cloud"
53
- }
54
- ]
55
- }
56
- end
44
+ attr_reader :hetzner_client, :cluster_name, :location
57
45
 
58
- def find_network
59
- hetzner_client.get("/networks")["networks"].detect{ |network| network["name"] == cluster_name }
60
- end
46
+ def network_config
47
+ {
48
+ name: cluster_name,
49
+ ip_range: '10.0.0.0/16',
50
+ subnets: [
51
+ {
52
+ ip_range: '10.0.0.0/16',
53
+ network_zone: (location == 'ash' ? 'us-east' : 'eu-central'),
54
+ type: 'cloud'
55
+ }
56
+ ]
57
+ }
58
+ end
61
59
 
60
+ def find_network
61
+ hetzner_client.get('/networks')['networks'].detect { |network| network['name'] == cluster_name }
62
+ end
62
63
  end
63
64
  end
@@ -1,36 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hetzner
2
4
  class PlacementGroup
3
- def initialize(hetzner_client:, cluster_name:)
5
+ def initialize(hetzner_client:, cluster_name:, pool_name: nil)
4
6
  @hetzner_client = hetzner_client
5
7
  @cluster_name = cluster_name
8
+ @placement_group_name = pool_name ? "#{cluster_name}-#{pool_name}" : cluster_name
6
9
  end
7
10
 
8
11
  def create
9
12
  puts
10
13
 
11
14
  if (placement_group = find_placement_group)
12
- puts "Placement group already exists, skipping."
15
+ puts "Placement group #{placement_group_name} already exists, skipping."
13
16
  puts
14
- return placement_group["id"]
17
+ return placement_group['id']
15
18
  end
16
19
 
17
- puts "Creating placement group..."
20
+ puts "Creating placement group #{placement_group_name}..."
18
21
 
19
- response = hetzner_client.post("/placement_groups", placement_group_config).body
22
+ response = hetzner_client.post('/placement_groups', placement_group_config).body
20
23
 
21
- puts "...placement group created."
24
+ puts "...placement group #{placement_group_name} created."
22
25
  puts
23
26
 
24
- JSON.parse(response)["placement_group"]["id"]
27
+ JSON.parse(response)['placement_group']['id']
25
28
  end
26
29
 
27
30
  def delete
28
31
  if (placement_group = find_placement_group)
29
- puts "Deleting placement group..."
30
- hetzner_client.delete("/placement_groups", placement_group["id"])
31
- puts "...placement group deleted."
32
+ puts "Deleting placement group #{placement_group_name}..."
33
+ hetzner_client.delete('/placement_groups', placement_group['id'])
34
+ puts "...placement group #{placement_group_name} deleted."
32
35
  else
33
- puts "Placement group no longer exists, skipping."
36
+ puts "Placement group #{placement_group_name} no longer exists, skipping."
34
37
  end
35
38
 
36
39
  puts
@@ -38,18 +41,19 @@ module Hetzner
38
41
 
39
42
  private
40
43
 
41
- attr_reader :hetzner_client, :cluster_name
44
+ attr_reader :hetzner_client, :cluster_name, :placement_group_name
42
45
 
43
- def placement_group_config
44
- {
45
- name: cluster_name,
46
- type: "spread"
47
- }
48
- end
46
+ def placement_group_config
47
+ {
48
+ name: placement_group_name,
49
+ type: 'spread'
50
+ }
51
+ end
49
52
 
50
- def find_placement_group
51
- hetzner_client.get("/placement_groups")["placement_groups"].detect{ |placement_group| placement_group["name"] == cluster_name }
53
+ def find_placement_group
54
+ hetzner_client.get('/placement_groups')['placement_groups'].detect do |placement_group|
55
+ placement_group['name'] == placement_group_name
52
56
  end
53
-
57
+ end
54
58
  end
55
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hetzner
2
4
  class Server
3
5
  def initialize(hetzner_client:, cluster_name:)
@@ -12,7 +14,7 @@ module Hetzner
12
14
 
13
15
  server_name = "#{cluster_name}-#{instance_type}-#{instance_id}"
14
16
 
15
- if server = find_server(server_name)
17
+ if (server = find_server(server_name))
16
18
  puts "Server #{server_name} already exists, skipping."
17
19
  puts
18
20
  return server
@@ -22,8 +24,8 @@ module Hetzner
22
24
 
23
25
  server_config = {
24
26
  name: server_name,
25
- location: location,
26
- image: image,
27
+ location:,
28
+ image:,
27
29
  firewalls: [
28
30
  { firewall: firewall_id }
29
31
  ],
@@ -34,18 +36,18 @@ module Hetzner
34
36
  ssh_keys: [
35
37
  ssh_key_id
36
38
  ],
37
- user_data: user_data,
39
+ user_data:,
38
40
  labels: {
39
41
  cluster: cluster_name,
40
- role: (server_name =~ /master/ ? "master" : "worker")
42
+ role: (server_name =~ /master/ ? 'master' : 'worker')
41
43
  },
42
44
  placement_group: placement_group_id
43
45
  }
44
46
 
45
- response = hetzner_client.post("/servers", server_config)
47
+ response = hetzner_client.post('/servers', server_config)
46
48
  response_body = response.body
47
49
 
48
- server = JSON.parse(response_body)["server"]
50
+ server = JSON.parse(response_body)['server']
49
51
 
50
52
  unless server
51
53
  puts "Error creating server #{server_name}. Response details below:"
@@ -61,9 +63,9 @@ module Hetzner
61
63
  end
62
64
 
63
65
  def delete(server_name:)
64
- if server = find_server(server_name)
66
+ if (server = find_server(server_name))
65
67
  puts "Deleting server #{server_name}..."
66
- hetzner_client.delete "/servers", server["id"]
68
+ hetzner_client.delete '/servers', server['id']
67
69
  puts "...server #{server_name} deleted."
68
70
  else
69
71
  puts "Server #{server_name} no longer exists, skipping."
@@ -72,31 +74,30 @@ module Hetzner
72
74
 
73
75
  private
74
76
 
75
- attr_reader :hetzner_client, :cluster_name, :additional_packages
76
-
77
- def find_server(server_name)
78
- hetzner_client.get("/servers?sort=created:desc")["servers"].detect{ |network| network["name"] == server_name }
79
- end
77
+ attr_reader :hetzner_client, :cluster_name, :additional_packages
80
78
 
81
- def user_data
82
- packages = ["fail2ban"]
83
- packages += additional_packages if additional_packages
84
- packages = "'" + packages.join("', '") + "'"
85
-
86
- <<~EOS
87
- #cloud-config
88
- packages: [#{packages}]
89
- runcmd:
90
- - sed -i 's/[#]*PermitRootLogin yes/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config
91
- - sed -i 's/[#]*PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
92
- - systemctl restart sshd
93
- - systemctl stop systemd-resolved
94
- - systemctl disable systemd-resolved
95
- - rm /etc/resolv.conf
96
- - echo "nameserver 1.1.1.1" > /etc/resolv.conf
97
- - echo "nameserver 1.0.0.1" >> /etc/resolv.conf
98
- EOS
99
- end
79
+ def find_server(server_name)
80
+ hetzner_client.get('/servers?sort=created:desc')['servers'].detect { |network| network['name'] == server_name }
81
+ end
100
82
 
83
+ def user_data
84
+ packages = ['fail2ban']
85
+ packages += additional_packages if additional_packages
86
+ packages = "'#{packages.join("', '")}'"
87
+
88
+ <<~YAML
89
+ #cloud-config
90
+ packages: [#{packages}]
91
+ runcmd:
92
+ - sed -i 's/[#]*PermitRootLogin yes/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config
93
+ - sed -i 's/[#]*PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
94
+ - systemctl restart sshd
95
+ - systemctl stop systemd-resolved
96
+ - systemctl disable systemd-resolved
97
+ - rm /etc/resolv.conf
98
+ - echo "nameserver 1.1.1.1" > /etc/resolv.conf
99
+ - echo "nameserver 1.0.0.1" >> /etc/resolv.conf
100
+ YAML
101
+ end
101
102
  end
102
103
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hetzner
2
4
  class SSHKey
3
5
  def initialize(hetzner_client:, cluster_name:)
@@ -11,34 +13,34 @@ module Hetzner
11
13
  puts
12
14
 
13
15
  if (public_ssh_key = find_public_ssh_key)
14
- puts "SSH key already exists, skipping."
16
+ puts 'SSH key already exists, skipping.'
15
17
  puts
16
- return public_ssh_key["id"]
18
+ return public_ssh_key['id']
17
19
  end
18
20
 
19
- puts "Creating SSH key..."
21
+ puts 'Creating SSH key...'
20
22
 
21
- response = hetzner_client.post("/ssh_keys", ssh_key_config).body
23
+ response = hetzner_client.post('/ssh_keys', ssh_key_config).body
22
24
 
23
- puts "...SSH key created."
25
+ puts '...SSH key created.'
24
26
  puts
25
27
 
26
- JSON.parse(response)["ssh_key"]["id"]
28
+ JSON.parse(response)['ssh_key']['id']
27
29
  end
28
30
 
29
31
  def delete(public_ssh_key_path:)
30
32
  @public_ssh_key_path = public_ssh_key_path
31
33
 
32
34
  if (public_ssh_key = find_public_ssh_key)
33
- if public_ssh_key["name"] == cluster_name
34
- puts "Deleting ssh_key..."
35
- hetzner_client.delete("/ssh_keys", public_ssh_key["id"])
36
- puts "...ssh_key deleted."
35
+ if public_ssh_key['name'] == cluster_name
36
+ puts 'Deleting ssh_key...'
37
+ hetzner_client.delete('/ssh_keys', public_ssh_key['id'])
38
+ puts '...ssh_key deleted.'
37
39
  else
38
40
  puts "The SSH key existed before creating the cluster, so I won't delete it."
39
41
  end
40
42
  else
41
- puts "SSH key no longer exists, skipping."
43
+ puts 'SSH key no longer exists, skipping.'
42
44
  end
43
45
 
44
46
  puts
@@ -46,36 +48,33 @@ module Hetzner
46
48
 
47
49
  private
48
50
 
49
- attr_reader :hetzner_client, :cluster_name, :public_ssh_key_path
50
-
51
- def public_ssh_key
52
- @public_ssh_key ||= File.read(public_ssh_key_path).chop
53
- end
51
+ attr_reader :hetzner_client, :cluster_name, :public_ssh_key_path
54
52
 
55
- def ssh_key_config
56
- {
57
- name: cluster_name,
58
- public_key: public_ssh_key
59
- }
60
- end
53
+ def public_ssh_key
54
+ @public_ssh_key ||= File.read(public_ssh_key_path).chop
55
+ end
61
56
 
62
- def fingerprint
63
- @fingerprint ||= ::SSHKey.fingerprint(public_ssh_key)
64
- end
57
+ def ssh_key_config
58
+ {
59
+ name: cluster_name,
60
+ public_key: public_ssh_key
61
+ }
62
+ end
65
63
 
66
- def find_public_ssh_key
67
- key = hetzner_client.get("/ssh_keys")["ssh_keys"].detect do |ssh_key|
68
- ssh_key["fingerprint"] == fingerprint
69
- end
64
+ def fingerprint
65
+ @fingerprint ||= ::SSHKey.fingerprint(public_ssh_key)
66
+ end
70
67
 
71
- unless key
72
- key = hetzner_client.get("/ssh_keys")["ssh_keys"].detect do |ssh_key|
73
- ssh_key["name"] == cluster_name
74
- end
75
- end
68
+ def find_public_ssh_key
69
+ key = hetzner_client.get('/ssh_keys')['ssh_keys'].detect do |ssh_key|
70
+ ssh_key['fingerprint'] == fingerprint
71
+ end
76
72
 
77
- key
73
+ key ||= hetzner_client.get('/ssh_keys')['ssh_keys'].detect do |ssh_key|
74
+ ssh_key['name'] == cluster_name
78
75
  end
79
76
 
77
+ key
78
+ end
80
79
  end
81
80
  end
data/lib/hetzner/infra.rb CHANGED
@@ -1,2 +1,6 @@
1
- module Hetzner::Infra
1
+ # frozen_string_literal: true
2
+
3
+ module Hetzner
4
+ module Infra
5
+ end
2
6
  end