hcloud 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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