File Coverage

blib/lib/WWW/Hetzner/Cloud/API/Servers.pm
Criterion Covered Total %
statement 82 121 67.7
branch 33 86 38.3
condition 6 18 33.3
subroutine 19 28 67.8
pod 22 22 100.0
total 162 275 58.9


line stmt bran cond sub pod time code
1             package WWW::Hetzner::Cloud::API::Servers;
2             # ABSTRACT: Hetzner Cloud Servers API
3              
4             our $VERSION = '0.100';
5              
6 25     25   179 use Moo;
  25         67  
  25         165  
7 25     25   10063 use Carp qw(croak);
  25         59  
  25         1829  
8 25     25   14683 use WWW::Hetzner::Cloud::Server;
  25         187  
  25         1312  
9 25     25   244 use namespace::clean;
  25         66  
  25         131  
10              
11              
12             has client => (
13             is => 'ro',
14             required => 1,
15             weak_ref => 1,
16             );
17              
18             sub _wrap {
19 9     9   30 my ($self, $data) = @_;
20 9         304 return WWW::Hetzner::Cloud::Server->new(
21             client => $self->client,
22             %$data,
23             );
24             }
25              
26             sub _wrap_list {
27 4     4   15 my ($self, $list) = @_;
28 4         17 return [ map { $self->_wrap($_) } @$list ];
  2         9  
29             }
30              
31              
32             sub list {
33 6     6 1 4202 my ($self, %params) = @_;
34              
35 6         63 my $result = $self->client->get('/servers', params => \%params);
36 4   50     73 return $self->_wrap_list($result->{servers} // []);
37             }
38              
39              
40             sub list_by_label {
41 1     1 1 38 my ($self, $label_selector) = @_;
42 1         6 return $self->list(label_selector => $label_selector);
43             }
44              
45              
46             sub get {
47 4     4 1 47 my ($self, $id) = @_;
48 4 50       17 croak "Server ID required" unless $id;
49              
50 4         51 my $result = $self->client->get("/servers/$id");
51 4         23 return $self->_wrap($result->{server});
52             }
53              
54              
55             sub create {
56 5     5 1 2181 my ($self, %params) = @_;
57              
58 5 100       246 croak "name required" unless $params{name};
59 4 100       215 croak "server_type required" unless $params{server_type};
60 3 100       177 croak "image required" unless $params{image};
61              
62             my $body = {
63             name => $params{name},
64             server_type => $params{server_type},
65             image => $params{image},
66 2         11 };
67              
68             # Location/Datacenter (mutually exclusive)
69 2 100       10 $body->{location} = $params{location} if $params{location};
70 2 50       8 $body->{datacenter} = $params{datacenter} if $params{datacenter};
71              
72             # SSH Keys (array of names or IDs)
73 2 50       7 $body->{ssh_keys} = $params{ssh_keys} if $params{ssh_keys};
74              
75             # Labels (hash)
76 2 50       9 $body->{labels} = $params{labels} if $params{labels};
77              
78             # Cloud-init user data
79 2 50       10 $body->{user_data} = $params{user_data} if $params{user_data};
80              
81             # Start server after create (default: true)
82 2   50     18 $body->{start_after_create} = $params{start_after_create} // 1;
83              
84             # Placement group (ID or name)
85 2 50       10 $body->{placement_group} = $params{placement_group} if $params{placement_group};
86              
87             # Networks (array of network IDs)
88 2 50       27 $body->{networks} = $params{networks} if $params{networks};
89              
90             # Volumes (array of volume IDs)
91 2 50       9 $body->{volumes} = $params{volumes} if $params{volumes};
92              
93             # Automount volumes
94 2 50       9 $body->{automount} = $params{automount} if exists $params{automount};
95              
96             # Firewalls (array of firewall IDs)
97 2 50       7 if ($params{firewalls}) {
98             $body->{firewalls} = [
99 0         0 map { { firewall => $_ } } @{$params{firewalls}}
  0         0  
  0         0  
100             ];
101             }
102              
103             # Public network configuration
104 2 50 33     22 if ($params{public_net} || exists $params{enable_ipv4} || exists $params{enable_ipv6}) {
      33        
105 0   0     0 $body->{public_net} = $params{public_net} // {};
106 0 0       0 $body->{public_net}{enable_ipv4} = $params{enable_ipv4} if exists $params{enable_ipv4};
107 0 0       0 $body->{public_net}{enable_ipv6} = $params{enable_ipv6} if exists $params{enable_ipv6};
108 0 0       0 $body->{public_net}{ipv4} = $params{ipv4} if $params{ipv4};
109 0 0       0 $body->{public_net}{ipv6} = $params{ipv6} if $params{ipv6};
110             }
111              
112 2         22 my $result = $self->client->post('/servers', $body);
113 2         13 return $self->_wrap($result->{server});
114             }
115              
116              
117             sub delete {
118 1     1 1 35 my ($self, $id) = @_;
119 1 50       6 croak "Server ID required" unless $id;
120              
121 1         10 return $self->client->delete("/servers/$id");
122             }
123              
124              
125             sub power_on {
126 1     1 1 36 my ($self, $id) = @_;
127 1 50       6 croak "Server ID required" unless $id;
128              
129 1         12 return $self->client->post("/servers/$id/actions/poweron", {});
130             }
131              
132              
133             sub power_off {
134 1     1 1 131 my ($self, $id) = @_;
135 1 50       4 croak "Server ID required" unless $id;
136              
137 1         9 return $self->client->post("/servers/$id/actions/poweroff", {});
138             }
139              
140              
141             sub reboot {
142 1     1 1 25 my ($self, $id) = @_;
143 1 50       4 croak "Server ID required" unless $id;
144              
145 1         9 return $self->client->post("/servers/$id/actions/reboot", {});
146             }
147              
148              
149             sub shutdown {
150 1     1 1 22 my ($self, $id) = @_;
151 1 50       3 croak "Server ID required" unless $id;
152              
153 1         7 return $self->client->post("/servers/$id/actions/shutdown", {});
154             }
155              
156              
157             sub rebuild {
158 1     1 1 20 my ($self, $id, $image) = @_;
159 1 50       4 croak "Server ID required" unless $id;
160 1 50       3 croak "Image required" unless $image;
161              
162 1         8 return $self->client->post("/servers/$id/actions/rebuild", { image => $image });
163             }
164              
165              
166             sub change_type {
167 1     1 1 54 my ($self, $id, $server_type, %opts) = @_;
168 1 50       6 croak "Server ID required" unless $id;
169 1 50       5 croak "Server type required" unless $server_type;
170              
171             return $self->client->post("/servers/$id/actions/change_type", {
172             server_type => $server_type,
173 1   50     18 upgrade_disk => $opts{upgrade_disk} // 1,
174             });
175             }
176              
177              
178             sub reset {
179 0     0 1 0 my ($self, $id) = @_;
180 0 0       0 croak "Server ID required" unless $id;
181              
182 0         0 return $self->client->post("/servers/$id/actions/reset", {});
183             }
184              
185              
186             sub enable_rescue {
187 0     0 1 0 my ($self, $id, %opts) = @_;
188 0 0       0 croak "Server ID required" unless $id;
189              
190 0   0     0 my $body = { type => $opts{type} // 'linux64' };
191 0 0       0 $body->{ssh_keys} = $opts{ssh_keys} if $opts{ssh_keys};
192              
193 0         0 return $self->client->post("/servers/$id/actions/enable_rescue", $body);
194             }
195              
196              
197             sub disable_rescue {
198 0     0 1 0 my ($self, $id) = @_;
199 0 0       0 croak "Server ID required" unless $id;
200              
201 0         0 return $self->client->post("/servers/$id/actions/disable_rescue", {});
202             }
203              
204              
205             sub request_console {
206 0     0 1 0 my ($self, $id) = @_;
207 0 0       0 croak "Server ID required" unless $id;
208              
209 0         0 return $self->client->post("/servers/$id/actions/request_console", {});
210             }
211              
212              
213             sub reset_password {
214 0     0 1 0 my ($self, $id) = @_;
215 0 0       0 croak "Server ID required" unless $id;
216              
217 0         0 return $self->client->post("/servers/$id/actions/reset_password", {});
218             }
219              
220              
221             sub attach_iso {
222 0     0 1 0 my ($self, $id, $iso) = @_;
223 0 0       0 croak "Server ID required" unless $id;
224 0 0       0 croak "ISO required" unless $iso;
225              
226 0         0 return $self->client->post("/servers/$id/actions/attach_iso", { iso => $iso });
227             }
228              
229              
230             sub detach_iso {
231 0     0 1 0 my ($self, $id) = @_;
232 0 0       0 croak "Server ID required" unless $id;
233              
234 0         0 return $self->client->post("/servers/$id/actions/detach_iso", {});
235             }
236              
237              
238             sub enable_backup {
239 0     0 1 0 my ($self, $id) = @_;
240 0 0       0 croak "Server ID required" unless $id;
241              
242 0         0 return $self->client->post("/servers/$id/actions/enable_backup", {});
243             }
244              
245              
246             sub disable_backup {
247 0     0 1 0 my ($self, $id) = @_;
248 0 0       0 croak "Server ID required" unless $id;
249              
250 0         0 return $self->client->post("/servers/$id/actions/disable_backup", {});
251             }
252              
253              
254             sub update {
255 1     1 1 59 my ($self, $id, %params) = @_;
256 1 50       5 croak "Server ID required" unless $id;
257              
258 1         3 my $body = {};
259 1 50       7 $body->{name} = $params{name} if exists $params{name};
260 1 50       14 $body->{labels} = $params{labels} if exists $params{labels};
261              
262 1         12 my $result = $self->client->put("/servers/$id", $body);
263 1         9 return $self->_wrap($result->{server});
264             }
265              
266              
267             sub wait_for_status {
268 1     1 1 37 my ($self, $id, $status, $timeout) = @_;
269 1   50     5 $timeout //= 120;
270              
271 1         3 my $start = time;
272 1         6 while (time - $start < $timeout) {
273 3         30 my $server = $self->get($id);
274 3 100       116 return $server if $server->status eq $status;
275 2         4001335 sleep 2;
276             }
277              
278 0           croak "Timeout waiting for server $id to reach status '$status'";
279             }
280              
281              
282             1;
283              
284             __END__