hcloud 1.1.0 → 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f32bc658bc4cb2d5151d8af866b7f09769b688bdda0fb3626932ba02268dd1c
4
- data.tar.gz: c9882c417f63c0b7100540cbfb3c86c299674904ac4676a5b85e934d888a72d8
3
+ metadata.gz: cdd378e8381d39a1fccf8cd2ce72ff3f024985fb5d5599978e928464e0018576
4
+ data.tar.gz: 885c2e766e37f274622be8a3519da323608576a765ba5dd7d104da1fd9c3237d
5
5
  SHA512:
6
- metadata.gz: d0f0a02ffe7bf1f53b2da59775df790d3340616a4c1a30c15cd24c6556d8412e713286b7d690e9c618ebfa9682b81f2ee1a6543e5c056b02c121f0655db3a818
7
- data.tar.gz: 3c5e42fdca1fa5e0e1ce8050052583b4055ae5a0b9206a8d020721d5f845ebdc26ffd99696d4fa9fac943cc9cf17f6b0de3306daa74bdc7f87d4fa719f963ac2
6
+ metadata.gz: 3e163d935512c077fbc7e3c94281d48aa1ba95eab1e5743190a66ab800e729ab1c8a905a974f86ca78c0e280bd77bc5763b9ec25e3b8b55db4725a8115cbabce
7
+ data.tar.gz: e26b48bb02882a3ec78b4412236466619a0e21759b9ba2f9f518fd17a591a0e1a0f9d3e344f63ef3502cbf3e293fc62577250247cc4f1b04908c2532bdbee7e2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.2.0](https://github.com/tonobo/hcloud-ruby/tree/v1.2.0) (2023-10-10)
4
+
5
+ [Full Changelog](https://github.com/tonobo/hcloud-ruby/compare/v1.1.0...v1.2.0)
6
+
7
+ **Closed issues:**
8
+
9
+ - \[Feature\] Add Primary IPs [\#57](https://github.com/tonobo/hcloud-ruby/issues/57)
10
+ - \[Feature\] Add Primary IPs [\#56](https://github.com/tonobo/hcloud-ruby/issues/56)
11
+ - \[Bug\] Firewalls do not expose actions [\#54](https://github.com/tonobo/hcloud-ruby/issues/54)
12
+ - \[Bug\] IPv6 global address is not parsed correctly [\#49](https://github.com/tonobo/hcloud-ruby/issues/49)
13
+ - \[Feature\] Add LoadBalancers and -Types [\#29](https://github.com/tonobo/hcloud-ruby/issues/29)
14
+ - \[Feature\] Add PlacementGroups [\#27](https://github.com/tonobo/hcloud-ruby/issues/27)
15
+ - \[Feature\] Add Certificates [\#26](https://github.com/tonobo/hcloud-ruby/issues/26)
16
+ - \[Feature\] Add Firewalls [\#25](https://github.com/tonobo/hcloud-ruby/issues/25)
17
+
18
+ **Merged pull requests:**
19
+
20
+ - lib: import active\_support before cherry-picking imports [\#77](https://github.com/tonobo/hcloud-ruby/pull/77) ([aufziehvogel](https://github.com/aufziehvogel))
21
+ - Dependencies: Drop rake, as it's unnecessary [\#74](https://github.com/tonobo/hcloud-ruby/pull/74) ([Kjarrigan](https://github.com/Kjarrigan))
22
+ - server: return `next_actions` data on create [\#72](https://github.com/tonobo/hcloud-ruby/pull/72) ([aufziehvogel](https://github.com/aufziehvogel))
23
+ - lib: implement primary IPs [\#65](https://github.com/tonobo/hcloud-ruby/pull/65) ([aufziehvogel](https://github.com/aufziehvogel))
24
+ - lib: implement certificates [\#64](https://github.com/tonobo/hcloud-ruby/pull/64) ([aufziehvogel](https://github.com/aufziehvogel))
25
+ - spec: include context doubles for doubles tests [\#63](https://github.com/tonobo/hcloud-ruby/pull/63) ([aufziehvogel](https://github.com/aufziehvogel))
26
+ - fix: return actions info on firewall create [\#59](https://github.com/tonobo/hcloud-ruby/pull/59) ([aufziehvogel](https://github.com/aufziehvogel))
27
+ - fix: do not interpret leading : in JSON as symbol [\#58](https://github.com/tonobo/hcloud-ruby/pull/58) ([aufziehvogel](https://github.com/aufziehvogel))
28
+ - lib: implement load balancer [\#55](https://github.com/tonobo/hcloud-ruby/pull/55) ([aufziehvogel](https://github.com/aufziehvogel))
29
+ - implement double tests for existing resources [\#53](https://github.com/tonobo/hcloud-ruby/pull/53) ([aufziehvogel](https://github.com/aufziehvogel))
30
+ - Add PlacementGroup [\#52](https://github.com/tonobo/hcloud-ruby/pull/52) ([aufziehvogel](https://github.com/aufziehvogel))
31
+ - firewall: please linter [\#51](https://github.com/tonobo/hcloud-ruby/pull/51) ([RaphaelPour](https://github.com/RaphaelPour))
32
+
3
33
  ## [v1.1.0](https://github.com/tonobo/hcloud-ruby/tree/v1.1.0) (2022-11-29)
4
34
 
5
35
  [Full Changelog](https://github.com/tonobo/hcloud-ruby/compare/v1.0.3...v1.1.0)
@@ -12,6 +42,7 @@
12
42
 
13
43
  **Merged pull requests:**
14
44
 
45
+ - version: bump to v1.1.0 [\#50](https://github.com/tonobo/hcloud-ruby/pull/50) ([aufziehvogel](https://github.com/aufziehvogel))
15
46
  - handle action array responses for firewall actions [\#48](https://github.com/tonobo/hcloud-ruby/pull/48) ([aufziehvogel](https://github.com/aufziehvogel))
16
47
  - fix auto pagination test to always use three pages [\#47](https://github.com/tonobo/hcloud-ruby/pull/47) ([aufziehvogel](https://github.com/aufziehvogel))
17
48
  - label support \(create, update, search\) [\#45](https://github.com/tonobo/hcloud-ruby/pull/45) ([aufziehvogel](https://github.com/aufziehvogel))
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hcloud (1.0.3)
4
+ hcloud (1.2.0)
5
5
  activemodel
6
6
  oj
7
7
  typhoeus
@@ -9,15 +9,15 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activemodel (7.0.3)
13
- activesupport (= 7.0.3)
14
- activesupport (7.0.3)
12
+ activemodel (7.0.4)
13
+ activesupport (= 7.0.4)
14
+ activesupport (7.0.4)
15
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
16
  i18n (>= 1.6, < 2)
17
17
  minitest (>= 5.1)
18
18
  tzinfo (~> 2.0)
19
- addressable (2.8.0)
20
- public_suffix (>= 2.0.2, < 5.0)
19
+ addressable (2.8.1)
20
+ public_suffix (>= 2.0.2, < 6.0)
21
21
  ast (2.4.2)
22
22
  builder (3.2.4)
23
23
  codecov (0.6.0)
@@ -28,29 +28,25 @@ GEM
28
28
  rexml
29
29
  diff-lcs (1.5.0)
30
30
  docile (1.4.0)
31
- dry-configurable (0.15.0)
31
+ dry-core (1.0.0)
32
32
  concurrent-ruby (~> 1.0)
33
- dry-core (~> 0.6)
34
- dry-container (0.9.0)
33
+ zeitwerk (~> 2.6)
34
+ dry-inflector (1.0.0)
35
+ dry-logic (1.5.0)
35
36
  concurrent-ruby (~> 1.0)
36
- dry-configurable (~> 0.13, >= 0.13.0)
37
- dry-core (0.7.1)
37
+ dry-core (~> 1.0, < 2)
38
+ zeitwerk (~> 2.6)
39
+ dry-types (1.7.0)
38
40
  concurrent-ruby (~> 1.0)
39
- dry-inflector (0.2.1)
40
- dry-logic (1.2.0)
41
- concurrent-ruby (~> 1.0)
42
- dry-core (~> 0.5, >= 0.5)
43
- dry-types (1.5.1)
44
- concurrent-ruby (~> 1.0)
45
- dry-container (~> 0.3)
46
- dry-core (~> 0.5, >= 0.5)
47
- dry-inflector (~> 0.1, >= 0.1.2)
48
- dry-logic (~> 1.0, >= 1.0.2)
49
- ethon (0.15.0)
41
+ dry-core (~> 1.0, < 2)
42
+ dry-inflector (~> 1.0, < 2)
43
+ dry-logic (>= 1.4, < 2)
44
+ zeitwerk (~> 2.6)
45
+ ethon (0.16.0)
50
46
  ffi (>= 1.15.0)
51
- faker (2.20.0)
47
+ faker (3.0.0)
52
48
  i18n (>= 1.8.11, < 2)
53
- ffi (1.15.5)
49
+ ffi (1.16.3)
54
50
  grape (1.6.2)
55
51
  activesupport
56
52
  builder
@@ -59,52 +55,53 @@ GEM
59
55
  rack (>= 1.3.0)
60
56
  rack-accept
61
57
  hashdiff (1.0.1)
62
- i18n (1.10.0)
58
+ i18n (1.12.0)
63
59
  concurrent-ruby (~> 1.0)
60
+ json (2.6.2)
64
61
  method_source (1.0.0)
65
- minitest (5.15.0)
66
- mustermann (1.1.1)
62
+ minitest (5.16.3)
63
+ mustermann (3.0.0)
67
64
  ruby2_keywords (~> 0.0.1)
68
65
  mustermann-grape (1.0.2)
69
66
  mustermann (>= 1.0.0)
70
- oj (3.13.11)
67
+ oj (3.16.1)
71
68
  parallel (1.22.1)
72
- parser (3.1.2.0)
69
+ parser (3.1.3.0)
73
70
  ast (~> 2.4.1)
74
71
  pry (0.14.1)
75
72
  coderay (~> 1.1)
76
73
  method_source (~> 1.0)
77
- public_suffix (4.0.7)
78
- rack (2.2.3.1)
74
+ public_suffix (5.0.0)
75
+ rack (3.0.1)
79
76
  rack-accept (0.4.5)
80
77
  rack (>= 0.4)
81
78
  rainbow (3.1.1)
82
- rake (13.0.6)
83
- regexp_parser (2.4.0)
79
+ regexp_parser (2.6.1)
84
80
  rexml (3.2.5)
85
- rspec (3.11.0)
86
- rspec-core (~> 3.11.0)
87
- rspec-expectations (~> 3.11.0)
88
- rspec-mocks (~> 3.11.0)
89
- rspec-core (3.11.0)
90
- rspec-support (~> 3.11.0)
91
- rspec-expectations (3.11.0)
81
+ rspec (3.12.0)
82
+ rspec-core (~> 3.12.0)
83
+ rspec-expectations (~> 3.12.0)
84
+ rspec-mocks (~> 3.12.0)
85
+ rspec-core (3.12.0)
86
+ rspec-support (~> 3.12.0)
87
+ rspec-expectations (3.12.0)
92
88
  diff-lcs (>= 1.2.0, < 2.0)
93
- rspec-support (~> 3.11.0)
94
- rspec-mocks (3.11.1)
89
+ rspec-support (~> 3.12.0)
90
+ rspec-mocks (3.12.0)
95
91
  diff-lcs (>= 1.2.0, < 2.0)
96
- rspec-support (~> 3.11.0)
97
- rspec-support (3.11.0)
98
- rubocop (1.29.0)
92
+ rspec-support (~> 3.12.0)
93
+ rspec-support (3.12.0)
94
+ rubocop (1.39.0)
95
+ json (~> 2.3)
99
96
  parallel (~> 1.10)
100
- parser (>= 3.1.0.0)
97
+ parser (>= 3.1.2.1)
101
98
  rainbow (>= 2.2.2, < 4.0)
102
99
  regexp_parser (>= 1.8, < 3.0)
103
100
  rexml (>= 3.2.5, < 4.0)
104
- rubocop-ast (>= 1.17.0, < 2.0)
101
+ rubocop-ast (>= 1.23.0, < 2.0)
105
102
  ruby-progressbar (~> 1.7)
106
103
  unicode-display_width (>= 1.4.0, < 3.0)
107
- rubocop-ast (1.17.0)
104
+ rubocop-ast (1.23.0)
108
105
  parser (>= 3.1.1.0)
109
106
  ruby-progressbar (1.11.0)
110
107
  ruby2_keywords (0.0.5)
@@ -116,13 +113,14 @@ GEM
116
113
  simplecov_json_formatter (0.1.4)
117
114
  typhoeus (1.4.0)
118
115
  ethon (>= 0.9.0)
119
- tzinfo (2.0.4)
116
+ tzinfo (2.0.5)
120
117
  concurrent-ruby (~> 1.0)
121
- unicode-display_width (2.1.0)
122
- webmock (3.14.0)
118
+ unicode-display_width (2.3.0)
119
+ webmock (3.18.1)
123
120
  addressable (>= 2.8.0)
124
121
  crack (>= 0.3.2)
125
122
  hashdiff (>= 0.4.0, < 2.0.0)
123
+ zeitwerk (2.6.6)
126
124
 
127
125
  PLATFORMS
128
126
  ruby
@@ -136,10 +134,9 @@ DEPENDENCIES
136
134
  grape
137
135
  hcloud!
138
136
  pry
139
- rake
140
137
  rspec
141
138
  rubocop
142
139
  webmock
143
140
 
144
141
  BUNDLED WITH
145
- 2.3.9
142
+ 2.3.25
data/hcloud.gemspec CHANGED
@@ -26,7 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'activemodel'
27
27
  spec.add_development_dependency 'bundler'
28
28
  spec.add_development_dependency 'grape'
29
- spec.add_development_dependency 'rake'
30
29
  spec.add_development_dependency 'rspec'
31
30
  spec.add_development_dependency 'webmock'
32
31
  spec.add_runtime_dependency 'activemodel'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class Certificate
5
+ require 'hcloud/certificate_resource'
6
+
7
+ include EntryLoader
8
+
9
+ schema(
10
+ created: :time
11
+ )
12
+
13
+ updatable :name
14
+ destructible
15
+
16
+ has_actions
17
+
18
+ def retry
19
+ prepare_request('actions/retry', j: COLLECT_ARGS.call(__method__, binding))
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class CertificateResource < AbstractResource
5
+ filter_attributes :name, :label_selector, :type
6
+
7
+ def [](arg)
8
+ case arg
9
+ when Integer then find_by(id: arg)
10
+ when String then find_by(name: arg)
11
+ end
12
+ end
13
+
14
+ def create(
15
+ name:,
16
+ type: :uploaded,
17
+ certificate: nil,
18
+ private_key: nil,
19
+ domain_names: nil,
20
+ labels: {}
21
+ )
22
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
23
+
24
+ case type
25
+ when :uploaded
26
+ raise Hcloud::Error::InvalidInput, 'no certificate given' if certificate.blank?
27
+ raise Hcloud::Error::InvalidInput, 'no private_key given' if private_key.blank?
28
+ when :managed
29
+ raise Hcloud::Error::InvalidInput, 'no domain_names given' if domain_names.to_a.empty?
30
+ end
31
+
32
+ prepare_request(
33
+ 'certificates', j: COLLECT_ARGS.call(__method__, binding),
34
+ expected_code: 201
35
+ ) do |response|
36
+ [
37
+ Action.new(client, response.parsed_json[:action]),
38
+ Certificate.new(client, response.parsed_json[:certificate])
39
+ ]
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/hcloud/client.rb CHANGED
@@ -86,10 +86,18 @@ module Hcloud
86
86
  SSHKeyResource.new(client: self)
87
87
  end
88
88
 
89
+ def certificates
90
+ CertificateResource.new(client: self)
91
+ end
92
+
89
93
  def floating_ips
90
94
  FloatingIPResource.new(client: self)
91
95
  end
92
96
 
97
+ def primary_ips
98
+ PrimaryIPResource.new(client: self)
99
+ end
100
+
93
101
  def networks
94
102
  NetworkResource.new(client: self)
95
103
  end
@@ -102,6 +110,18 @@ module Hcloud
102
110
  VolumeResource.new(client: self)
103
111
  end
104
112
 
113
+ def placement_groups
114
+ PlacementGroupResource.new(client: self)
115
+ end
116
+
117
+ def load_balancer_types
118
+ LoadBalancerTypeResource.new(client: self)
119
+ end
120
+
121
+ def load_balancers
122
+ LoadBalancerResource.new(client: self)
123
+ end
124
+
105
125
  class ResourceFuture < Delegator
106
126
  def initialize(request) # rubocop:disable Lint/MissingSuper
107
127
  @request = request
@@ -68,6 +68,27 @@ module Hcloud
68
68
  end
69
69
  end
70
70
 
71
+ def has_metrics # rubocop:disable Naming/PredicateName
72
+ define_method(:metrics) do |**kwargs|
73
+ raise Hcloud::Error::InvalidInput, 'no type given' if kwargs[:type].blank?
74
+ raise Hcloud::Error::InvalidInput, 'no start given' if kwargs[:start].blank?
75
+ raise Hcloud::Error::InvalidInput, 'no end given' if kwargs[:end].blank?
76
+ if kwargs[:start] > kwargs[:end]
77
+ raise Hcloud::Error::InvalidInput, 'start time must be before end time'
78
+ end
79
+
80
+ params = {
81
+ type: kwargs[:type],
82
+ start: kwargs[:start].iso8601,
83
+ end: kwargs[:end].iso8601,
84
+ step: kwargs[:step].to_i
85
+ }
86
+ prepare_request('metrics', method: :get, params: params) do |response|
87
+ response.parsed_json[:metrics].with_indifferent_access
88
+ end
89
+ end
90
+ end
91
+
71
92
  def resource_class
72
93
  ancestors.reverse.find { |const| const.include?(Hcloud::EntryLoader) }
73
94
  end
@@ -6,20 +6,31 @@ module Hcloud
6
6
 
7
7
  include EntryLoader
8
8
 
9
+ schema(
10
+ created: :time
11
+ )
12
+
9
13
  updatable :name
10
14
  destructible
11
15
 
12
16
  has_actions
13
17
 
14
- def set_rules(rules:) # rubocop:disable Naming/AccessorMethodName
18
+ def set_rules(rules:)
19
+ # Set rules to empty when nil is passed
20
+ rules = rules.to_a
21
+
15
22
  prepare_request('actions/set_rules', j: COLLECT_ARGS.call(__method__, binding))
16
23
  end
17
24
 
18
25
  def apply_to_resources(apply_to:)
26
+ raise Hcloud::Error::InvalidInput, 'no apply_to resources given' if apply_to.nil?
27
+
19
28
  prepare_request('actions/apply_to_resources', j: COLLECT_ARGS.call(__method__, binding))
20
29
  end
21
30
 
22
31
  def remove_from_resources(remove_from:)
32
+ raise Hcloud::Error::InvalidInput, 'no remove_from resources given' if remove_from.nil?
33
+
23
34
  prepare_request('actions/remove_from_resources', j: COLLECT_ARGS.call(__method__, binding))
24
35
  end
25
36
  end
@@ -12,11 +12,18 @@ module Hcloud
12
12
  end
13
13
 
14
14
  def create(name:, rules: [], apply_to: [], labels: {})
15
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
16
+
15
17
  prepare_request(
16
18
  'firewalls', j: COLLECT_ARGS.call(__method__, binding),
17
19
  expected_code: 201
18
20
  ) do |response|
19
- Firewall.new(client, response.parsed_json[:firewall])
21
+ [
22
+ response.parsed_json[:actions].map do |action|
23
+ Action.new(client, action)
24
+ end,
25
+ Firewall.new(client, response.parsed_json[:firewall])
26
+ ]
20
27
  end
21
28
  end
22
29
  end
@@ -18,6 +18,8 @@ module Hcloud
18
18
  has_actions
19
19
 
20
20
  def assign(server:)
21
+ raise Hcloud::Error::InvalidInput, 'no server given' if server.nil?
22
+
21
23
  prepare_request('actions/assign', j: COLLECT_ARGS.call(__method__, binding))
22
24
  end
23
25
 
@@ -26,6 +28,8 @@ module Hcloud
26
28
  end
27
29
 
28
30
  def change_dns_ptr(ip:, dns_ptr:)
31
+ raise Hcloud::Error::InvalidInput, 'no IP given' if ip.blank?
32
+
29
33
  prepare_request('actions/change_dns_ptr', j: COLLECT_ARGS.call(__method__, binding))
30
34
  end
31
35
  end
@@ -14,6 +14,11 @@ module Hcloud
14
14
  end
15
15
 
16
16
  def create(type:, server: nil, home_location: nil, description: nil, labels: {})
17
+ raise Hcloud::Error::InvalidInput, 'no type given' if type.blank?
18
+ if server.nil? && home_location.nil?
19
+ raise Hcloud::Error::InvalidInput, 'either server or home_location must be given'
20
+ end
21
+
17
22
  prepare_request(
18
23
  'floating_ips', j: COLLECT_ARGS.call(__method__, binding),
19
24
  expected_code: 201
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/hash/keys'
4
+
5
+ module Hcloud
6
+ class LoadBalancer
7
+ require 'hcloud/load_balancer_resource'
8
+
9
+ include EntryLoader
10
+
11
+ schema(
12
+ location: Location,
13
+ load_balancer_type: LoadBalancerType,
14
+ created: :time
15
+ )
16
+
17
+ protectable :delete
18
+ updatable :name
19
+ destructible
20
+
21
+ has_metrics
22
+ has_actions
23
+
24
+ %w[enable_public_interface disable_public_interface].each do |action|
25
+ define_method(action) do
26
+ prepare_request("actions/#{action}", method: :post)
27
+ end
28
+ end
29
+
30
+ def attach_to_network(network:, ip: nil)
31
+ raise Hcloud::Error::InvalidInput, 'no network given' if network.nil?
32
+
33
+ prepare_request('actions/attach_to_network', j: COLLECT_ARGS.call(__method__, binding))
34
+ end
35
+
36
+ def detach_from_network(network:)
37
+ raise Hcloud::Error::InvalidInput, 'no network given' if network.nil?
38
+
39
+ prepare_request('actions/detach_from_network', j: COLLECT_ARGS.call(__method__, binding))
40
+ end
41
+
42
+ def change_dns_ptr(ip:, dns_ptr:)
43
+ raise Hcloud::Error::InvalidInput, 'no IP given' if ip.blank?
44
+ raise Hcloud::Error::InvalidInput, 'no dns_ptr given' if dns_ptr.blank?
45
+
46
+ prepare_request('actions/change_dns_ptr', j: COLLECT_ARGS.call(__method__, binding))
47
+ end
48
+
49
+ def change_type(load_balancer_type:)
50
+ raise Hcloud::Error::InvalidInput, 'no type given' if load_balancer_type.blank?
51
+
52
+ prepare_request('actions/change_type', j: COLLECT_ARGS.call(__method__, binding))
53
+ end
54
+
55
+ def change_algorithm(type:)
56
+ raise Hcloud::Error::InvalidInput, 'no type given' if type.blank?
57
+
58
+ prepare_request('actions/change_algorithm', j: COLLECT_ARGS.call(__method__, binding))
59
+ end
60
+
61
+ def add_service(
62
+ protocol:, listen_port:, destination_port:, health_check:, proxyprotocol:, http: nil
63
+ )
64
+ validate_service_input(
65
+ protocol: protocol,
66
+ listen_port: listen_port,
67
+ destination_port: destination_port,
68
+ health_check: health_check,
69
+ proxyprotocol: proxyprotocol
70
+ )
71
+
72
+ prepare_request('actions/add_service', j: COLLECT_ARGS.call(__method__, binding))
73
+ end
74
+
75
+ def update_service(
76
+ protocol:, listen_port:, destination_port:, health_check:, proxyprotocol:, http: nil
77
+ )
78
+ validate_service_input(
79
+ protocol: protocol,
80
+ listen_port: listen_port,
81
+ destination_port: destination_port,
82
+ health_check: health_check,
83
+ proxyprotocol: proxyprotocol
84
+ )
85
+
86
+ prepare_request('actions/update_service', j: COLLECT_ARGS.call(__method__, binding))
87
+ end
88
+
89
+ def delete_service(listen_port:)
90
+ raise Hcloud::Error::InvalidInput, 'no listen_port given' if listen_port.nil?
91
+
92
+ prepare_request('actions/delete_service', j: COLLECT_ARGS.call(__method__, binding))
93
+ end
94
+
95
+ def add_target(type:, server: nil, label_selector: nil, ip: nil, use_private_ip: false)
96
+ validate_target_input(
97
+ type: type, server: server, label_selector: label_selector, ip: ip
98
+ )
99
+
100
+ prepare_request('actions/add_target', j: COLLECT_ARGS.call(__method__, binding))
101
+ end
102
+
103
+ def remove_target(type:, server: nil, label_selector: nil, ip: nil)
104
+ validate_target_input(
105
+ type: type, server: server, label_selector: label_selector, ip: ip
106
+ )
107
+
108
+ prepare_request('actions/remove_target', j: COLLECT_ARGS.call(__method__, binding))
109
+ end
110
+
111
+ private
112
+
113
+ def validate_service_input(
114
+ protocol:, listen_port:, destination_port:, health_check:, proxyprotocol:
115
+ )
116
+ raise Hcloud::Error::InvalidInput, 'no protocol given' if protocol.blank?
117
+ raise Hcloud::Error::InvalidInput, 'no listen_port given' if listen_port.nil?
118
+ raise Hcloud::Error::InvalidInput, 'no destination_port given' if destination_port.nil?
119
+ raise Hcloud::Error::InvalidInput, 'no health_check given' if health_check.nil?
120
+ raise Hcloud::Error::InvalidInput, 'no proxyprotocol given' if proxyprotocol.nil?
121
+ end
122
+
123
+ def validate_target_input(type:, server: nil, label_selector: nil, ip: nil)
124
+ raise Hcloud::Error::InvalidInput, 'no type given' if type.nil?
125
+
126
+ case type.to_sym
127
+ when :server
128
+ raise Hcloud::Error::InvalidInput, 'invalid server given' unless server.to_h.key?(:id)
129
+ when :ip
130
+ raise Hcloud::Error::InvalidInput, 'no IP given' if ip.blank?
131
+ when :label_selector
132
+ unless label_selector.to_h.key?(:selector)
133
+ raise Hcloud::Error::InvalidInput, 'invalid label_selector given'
134
+ end
135
+ else
136
+ raise Hcloud::Error::InvalidInput, 'invalid type given'
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class LoadBalancerResource < AbstractResource
5
+ filter_attributes :name, :label_selector
6
+
7
+ bind_to LoadBalancer
8
+
9
+ def [](arg)
10
+ case arg
11
+ when Integer then find_by(id: arg)
12
+ when String then find_by(name: arg)
13
+ end
14
+ end
15
+
16
+ def create(
17
+ name:, load_balancer_type:, algorithm:, location: nil, network_zone: nil,
18
+ network: nil, public_interface: nil, services: nil, targets: nil,
19
+ labels: {}
20
+ )
21
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
22
+ raise Hcloud::Error::InvalidInput, 'no type given' if load_balancer_type.blank?
23
+ if !algorithm.to_h.key?(:type) || algorithm[:type].blank?
24
+ raise Hcloud::Error::InvalidInput, 'invalid algorithm given'
25
+ end
26
+ if location.blank? && network_zone.blank?
27
+ raise Hcloud::Error::InvalidInput, 'either location or network_zone must be given'
28
+ end
29
+
30
+ prepare_request(
31
+ 'load_balancers', j: COLLECT_ARGS.call(__method__, binding),
32
+ expected_code: 201
33
+ ) do |response|
34
+ action = Action.new(client, response[:action]) if response[:action]
35
+ [action, LoadBalancer.new(client, response[:load_balancer])]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class LoadBalancerType
5
+ require 'hcloud/load_balancer_type_resource'
6
+
7
+ include EntryLoader
8
+
9
+ schema(
10
+ deprecated: :time
11
+ )
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class LoadBalancerTypeResource < AbstractResource
5
+ filter_attributes :name
6
+
7
+ bind_to LoadBalancerType
8
+
9
+ def [](arg)
10
+ case arg
11
+ when Integer then find_by(id: arg)
12
+ when String then find_by(name: arg)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -15,18 +15,29 @@ module Hcloud
15
15
  has_actions
16
16
 
17
17
  def add_subnet(type:, network_zone:, ip_range: nil)
18
+ raise Hcloud::Error::InvalidInput, 'no type given' if type.blank?
19
+ raise Hcloud::Error::InvalidInput, 'no network_zone given' if network_zone.blank?
20
+
18
21
  prepare_request('actions/add_subnet', j: COLLECT_ARGS.call(__method__, binding))
19
22
  end
20
23
 
21
24
  def del_subnet(ip_range:)
25
+ raise Hcloud::Error::InvalidInput, 'no ip_range given' if ip_range.blank?
26
+
22
27
  prepare_request('actions/delete_subnet', j: COLLECT_ARGS.call(__method__, binding))
23
28
  end
24
29
 
25
30
  def add_route(destination:, gateway:)
31
+ raise Hcloud::Error::InvalidInput, 'no destination given' if destination.blank?
32
+ raise Hcloud::Error::InvalidInput, 'no gateway given' if gateway.blank?
33
+
26
34
  prepare_request('actions/add_route', j: COLLECT_ARGS.call(__method__, binding))
27
35
  end
28
36
 
29
37
  def del_route(destination:, gateway:)
38
+ raise Hcloud::Error::InvalidInput, 'no destination given' if destination.blank?
39
+ raise Hcloud::Error::InvalidInput, 'no gateway given' if gateway.blank?
40
+
30
41
  prepare_request('actions/delete_route', j: COLLECT_ARGS.call(__method__, binding))
31
42
  end
32
43
  end
@@ -14,6 +14,9 @@ module Hcloud
14
14
  end
15
15
 
16
16
  def create(name:, ip_range:, subnets: nil, routes: nil, labels: {})
17
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
18
+ raise Hcloud::Error::InvalidInput, 'no IP range given' if ip_range.blank?
19
+
17
20
  prepare_request(
18
21
  'networks', j: COLLECT_ARGS.call(__method__, binding),
19
22
  expected_code: 201
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class PlacementGroup
5
+ require 'hcloud/placement_group_resource'
6
+
7
+ include EntryLoader
8
+
9
+ schema(
10
+ created: :time
11
+ )
12
+
13
+ updatable :name
14
+ destructible
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class PlacementGroupResource < AbstractResource
5
+ filter_attributes :type, :name
6
+
7
+ bind_to PlacementGroup
8
+
9
+ def [](arg)
10
+ return find_by(name: arg) if arg.is_a?(String)
11
+
12
+ super
13
+ end
14
+
15
+ # currently only spread is available
16
+ def create(name:, type: 'spread', labels: {})
17
+ if type.to_s != 'spread'
18
+ raise Hcloud::Error::InvalidInput, "invalid type #{type.inspect}, only 'spread' is allowed"
19
+ end
20
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
21
+
22
+ prepare_request(
23
+ 'placement_groups', j: COLLECT_ARGS.call(__method__, binding),
24
+ expected_code: 201
25
+ ) do |response|
26
+ PlacementGroup.new(client, response.parsed_json[:placement_group])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class PrimaryIP
5
+ require 'hcloud/primary_ip_resource'
6
+
7
+ include EntryLoader
8
+
9
+ schema(
10
+ datacenter: Datacenter,
11
+ created: :time
12
+ )
13
+
14
+ protectable :delete
15
+ updatable :name, :auto_delete
16
+ destructible
17
+
18
+ def assign(assignee_id:, assignee_type: 'server')
19
+ raise Hcloud::Error::InvalidInput, 'no assignee_id given' if assignee_id.nil?
20
+ raise Hcloud::Error::InvalidInput, 'no assignee_type given' if assignee_type.nil?
21
+
22
+ prepare_request('actions/assign', j: COLLECT_ARGS.call(__method__, binding))
23
+ end
24
+
25
+ def unassign
26
+ prepare_request('actions/unassign', method: :post)
27
+ end
28
+
29
+ def change_dns_ptr(ip:, dns_ptr:)
30
+ raise Hcloud::Error::InvalidInput, 'no IP given' if ip.blank?
31
+
32
+ prepare_request('actions/change_dns_ptr', j: { ip: ip, dns_ptr: dns_ptr })
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hcloud
4
+ class PrimaryIPResource < AbstractResource
5
+ filter_attributes :name, :label_selector, :ip
6
+
7
+ bind_to PrimaryIP
8
+
9
+ def [](arg)
10
+ case arg
11
+ when Integer then find_by(id: arg)
12
+ when String then find_by(name: arg)
13
+ end
14
+ end
15
+
16
+ def create(
17
+ name:,
18
+ type:,
19
+ assignee_id: nil,
20
+ assignee_type: 'server',
21
+ datacenter: nil,
22
+ auto_delete: nil,
23
+ labels: {}
24
+ )
25
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
26
+
27
+ unless %w[ipv4 ipv6].include?(type.to_s)
28
+ raise Hcloud::Error::InvalidInput, 'invalid type given'
29
+ end
30
+
31
+ raise Hcloud::Error::InvalidInput, 'no assignee_type given' if assignee_type.blank?
32
+
33
+ if assignee_id.nil? && datacenter.nil?
34
+ raise Hcloud::Error::InvalidInput, 'either assignee_id or datacenter must be given'
35
+ end
36
+
37
+ prepare_request(
38
+ 'primary_ips', j: COLLECT_ARGS.call(__method__, binding),
39
+ expected_code: 201
40
+ ) do |response|
41
+ action = Action.new(client, response[:action]) if response[:action]
42
+ [action, PrimaryIP.new(client, response[:primary_ip])]
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/hcloud/server.rb CHANGED
@@ -37,10 +37,15 @@ module Hcloud
37
37
  end
38
38
 
39
39
  def rebuild(image:)
40
+ raise Hcloud::Error::InvalidInput, 'no image given' if image.blank?
41
+
40
42
  prepare_request('actions/rebuild', j: { image: image }) { |j| j[:root_password] }
41
43
  end
42
44
 
43
- def change_type(server_type:, upgrade_disk: nil)
45
+ def change_type(server_type:, upgrade_disk:)
46
+ raise Hcloud::Error::InvalidInput, 'no server_type given' if server_type.blank?
47
+ raise Hcloud::Error::InvalidInput, 'no upgrade_disk given' if upgrade_disk.nil?
48
+
44
49
  prepare_request('actions/change_type', j: COLLECT_ARGS.call(__method__, binding))
45
50
  end
46
51
 
@@ -51,14 +56,20 @@ module Hcloud
51
56
  end
52
57
 
53
58
  def attach_iso(iso:)
59
+ raise Hcloud::Error::InvalidInput, 'no iso given' if iso.blank?
60
+
54
61
  prepare_request('actions/attach_iso', j: { iso: iso })
55
62
  end
56
63
 
57
64
  def attach_to_network(network:, ip: nil, alias_ips: nil)
65
+ raise Hcloud::Error::InvalidInput, 'no network given' if network.nil?
66
+
58
67
  prepare_request('actions/attach_to_network', j: COLLECT_ARGS.call(__method__, binding))
59
68
  end
60
69
 
61
70
  def detach_from_network(network:)
71
+ raise Hcloud::Error::InvalidInput, 'no network given' if network.nil?
72
+
62
73
  prepare_request('actions/detach_from_network', j: { network: network })
63
74
  end
64
75
 
@@ -20,7 +20,10 @@ module Hcloud
20
20
  [
21
21
  Action.new(client, response.parsed_json[:action]),
22
22
  Server.new(client, response.parsed_json[:server]),
23
- response.parsed_json[:root_password]
23
+ response.parsed_json[:root_password],
24
+ response.parsed_json[:next_actions].to_a.map do |action|
25
+ Action.new(client, action)
26
+ end
24
27
  ]
25
28
  end
26
29
  end
@@ -6,6 +6,10 @@ module Hcloud
6
6
 
7
7
  include EntryLoader
8
8
 
9
+ schema(
10
+ created: :time
11
+ )
12
+
9
13
  updatable :name
10
14
  destructible
11
15
  end
@@ -12,6 +12,12 @@ module Hcloud
12
12
  end
13
13
 
14
14
  def create(name:, public_key:, labels: {})
15
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
16
+
17
+ unless public_key.to_s.starts_with?('ssh')
18
+ raise Hcloud::Error::InvalidInput, 'no valid SSH key given'
19
+ end
20
+
15
21
  prepare_request(
16
22
  'ssh_keys', j: COLLECT_ARGS.call(__method__, binding),
17
23
  expected_code: 201
@@ -30,7 +30,7 @@ module Hcloud
30
30
  def parsed_json
31
31
  return {} if code == 204
32
32
 
33
- @parsed_json ||= Oj.load(body, symbol_keys: true).tap do |json|
33
+ @parsed_json ||= Oj.load(body, symbol_keys: true, mode: :compat).tap do |json|
34
34
  next unless request.hydra
35
35
 
36
36
  check_for_error(
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hcloud
4
- VERSION = '1.1.0'
4
+ VERSION = '1.2.0'
5
5
  end
data/lib/hcloud/volume.rb CHANGED
@@ -17,7 +17,9 @@ module Hcloud
17
17
 
18
18
  has_actions
19
19
 
20
- def attach(server:, automount:)
20
+ def attach(server:, automount: nil)
21
+ raise Hcloud::Error::InvalidInput, 'no server given' if server.nil?
22
+
21
23
  prepare_request('actions/attach', j: COLLECT_ARGS.call(__method__, binding))
22
24
  end
23
25
 
@@ -26,6 +28,8 @@ module Hcloud
26
28
  end
27
29
 
28
30
  def resize(size:)
31
+ raise Hcloud::Error::InvalidInput, 'invalid size given' unless size.to_i > self.size
32
+
29
33
  prepare_request('actions/resize', j: COLLECT_ARGS.call(__method__, binding))
30
34
  end
31
35
  end
@@ -12,6 +12,12 @@ module Hcloud
12
12
  end
13
13
 
14
14
  def create(size:, name:, automount: nil, format: nil, location: nil, server: nil, labels: {})
15
+ raise Hcloud::Error::InvalidInput, 'no name given' if name.blank?
16
+ raise Hcloud::Error::InvalidInput, 'invalid size given' unless size.to_i >= 10
17
+ if location.blank? && server.nil?
18
+ raise Hcloud::Error::InvalidInput, 'location or server must be given'
19
+ end
20
+
15
21
  prepare_request(
16
22
  'volumes', j: COLLECT_ARGS.call(__method__, binding),
17
23
  expected_code: 201
data/lib/hcloud.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'hcloud/version'
4
+ require 'active_support'
4
5
  require 'active_support/core_ext/object/to_query'
5
6
  require 'active_support/core_ext/hash/indifferent_access'
6
7
 
@@ -21,9 +22,15 @@ module Hcloud
21
22
  autoload :FloatingIP, 'hcloud/floating_ip'
22
23
  autoload :FloatingIPResource, 'hcloud/floating_ip_resource'
23
24
 
25
+ autoload :PrimaryIP, 'hcloud/primary_ip'
26
+ autoload :PrimaryIPResource, 'hcloud/primary_ip_resource'
27
+
24
28
  autoload :SSHKey, 'hcloud/ssh_key'
25
29
  autoload :SSHKeyResource, 'hcloud/ssh_key_resource'
26
30
 
31
+ autoload :Certificate, 'hcloud/certificate'
32
+ autoload :CertificateResource, 'hcloud/certificate_resource'
33
+
27
34
  autoload :Datacenter, 'hcloud/datacenter'
28
35
  autoload :DatacenterResource, 'hcloud/datacenter_resource'
29
36
 
@@ -50,6 +57,15 @@ module Hcloud
50
57
 
51
58
  autoload :Pagination, 'hcloud/pagination'
52
59
 
60
+ autoload :PlacementGroup, 'hcloud/placement_group'
61
+ autoload :PlacementGroupResource, 'hcloud/placement_group_resource'
62
+
63
+ autoload :LoadBalancerType, 'hcloud/load_balancer_type'
64
+ autoload :LoadBalancerTypeResource, 'hcloud/load_balancer_type_resource'
65
+
66
+ autoload :LoadBalancer, 'hcloud/load_balancer'
67
+ autoload :LoadBalancerResource, 'hcloud/load_balancer_resource'
68
+
53
69
  COLLECT_ARGS = proc do |method_name, bind|
54
70
  query = bind.receiver.method(method_name).parameters.inject({}) do |hash, (_type, name)|
55
71
  hash.merge(name => bind.local_variable_get(name))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hcloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Foerster
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-11-29 00:00:00.000000000 Z
12
+ date: 2023-10-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -53,20 +53,6 @@ dependencies:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
- - !ruby/object:Gem::Dependency
57
- name: rake
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: rspec
72
58
  requirement: !ruby/object:Gem::Requirement
@@ -155,7 +141,6 @@ files:
155
141
  - Gemfile.lock
156
142
  - LICENSE
157
143
  - README.md
158
- - Rakefile
159
144
  - bin/console
160
145
  - bin/setup
161
146
  - hcloud.gemspec
@@ -163,6 +148,8 @@ files:
163
148
  - lib/hcloud/abstract_resource.rb
164
149
  - lib/hcloud/action.rb
165
150
  - lib/hcloud/action_resource.rb
151
+ - lib/hcloud/certificate.rb
152
+ - lib/hcloud/certificate_resource.rb
166
153
  - lib/hcloud/client.rb
167
154
  - lib/hcloud/datacenter.rb
168
155
  - lib/hcloud/datacenter_resource.rb
@@ -177,11 +164,19 @@ files:
177
164
  - lib/hcloud/image_resource.rb
178
165
  - lib/hcloud/iso.rb
179
166
  - lib/hcloud/iso_resource.rb
167
+ - lib/hcloud/load_balancer.rb
168
+ - lib/hcloud/load_balancer_resource.rb
169
+ - lib/hcloud/load_balancer_type.rb
170
+ - lib/hcloud/load_balancer_type_resource.rb
180
171
  - lib/hcloud/location.rb
181
172
  - lib/hcloud/location_resource.rb
182
173
  - lib/hcloud/network.rb
183
174
  - lib/hcloud/network_resource.rb
184
175
  - lib/hcloud/pagination.rb
176
+ - lib/hcloud/placement_group.rb
177
+ - lib/hcloud/placement_group_resource.rb
178
+ - lib/hcloud/primary_ip.rb
179
+ - lib/hcloud/primary_ip_resource.rb
185
180
  - lib/hcloud/server.rb
186
181
  - lib/hcloud/server_resource.rb
187
182
  - lib/hcloud/server_type.rb
@@ -211,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
206
  - !ruby/object:Gem::Version
212
207
  version: '0'
213
208
  requirements: []
214
- rubygems_version: 3.1.6
209
+ rubygems_version: 3.3.7
215
210
  signing_key:
216
211
  specification_version: 4
217
212
  summary: HetznerCloud native Ruby client
data/Rakefile DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- task default: :spec