File Coverage

blib/lib/WWW/VastAI/API/Instances.pm
Criterion Covered Total %
statement 74 81 91.3
branch 28 50 56.0
condition 5 23 21.7
subroutine 18 19 94.7
pod 12 12 100.0
total 137 185 74.0


line stmt bran cond sub pod time code
1             package WWW::VastAI::API::Instances;
2             our $VERSION = '0.001';
3             # ABSTRACT: Instance lifecycle and helper methods for Vast.ai
4              
5 10     10   91 use Moo;
  10         21  
  10         65  
6 10     10   3796 use Carp qw(croak);
  10         72  
  10         772  
7 10     10   5529 use LWP::UserAgent;
  10         415577  
  10         438  
8 10     10   5830 use WWW::VastAI::Instance;
  10         38  
  10         349  
9 10     10   73 use namespace::clean;
  10         21  
  10         92  
10              
11             has client => (
12             is => 'ro',
13             required => 1,
14             weak_ref => 1,
15             );
16              
17             sub _wrap {
18 6     6   11 my ($self, $data) = @_;
19 6         112 return WWW::VastAI::Instance->new(
20             client => $self->client,
21             data => $data,
22             );
23             }
24              
25             sub _extract_instance {
26 8     8   15 my ($self, $result) = @_;
27              
28 8 50       20 return $result unless ref $result eq 'HASH';
29 8 50       17 return $result->{instance} if ref $result->{instance} eq 'HASH';
30 8 100       22 return $result->{instances} if ref $result->{instances} eq 'HASH';
31 4 50       11 return $result->{instances}[0] if ref $result->{instances} eq 'ARRAY';
32 4 100       11 return $result->{new_contract} if ref $result->{new_contract} eq 'HASH';
33              
34 3         5 return;
35             }
36              
37             sub list {
38 1     1 1 1014 my ($self) = @_;
39 1         14 my $result = $self->client->request_op('listInstances');
40 1 50 0     8 my $instances = ref $result eq 'HASH' ? ($result->{instances} || $result->{results} || []) : ($result || []);
      0        
41 1         2 return [ map { $self->_wrap($_) } @{$instances} ];
  1         5  
  1         2  
42             }
43              
44             sub get {
45 4     4 1 18 my ($self, $id) = @_;
46 4 50       8 croak "instance id required" unless defined $id;
47              
48 4         57 my $result = $self->client->request_op('getInstance', path => { id => $id });
49 4   33     13 my $instance = $self->_extract_instance($result) || $result;
50 4         8 return $self->_wrap($instance);
51             }
52              
53             sub create {
54 4     4 1 778 my ($self, $offer_id, %params) = @_;
55 4 100       238 croak "offer_id required" unless defined $offer_id;
56             croak "image or template_hash_id required"
57 3 50 66     145 unless $params{image} || $params{template_hash_id};
58              
59 2         14 my $result = $self->client->request_op(
60             'createInstance',
61             path => { id => $offer_id },
62             body => \%params,
63             );
64              
65 2         11 my $instance = $self->_extract_instance($result);
66 2 100       9 return $self->_wrap($instance) if $instance;
67              
68 1 50       5 my $new_id = ref $result eq 'HASH' ? $result->{new_contract} : $result;
69 1 50 33     7 return $self->get($new_id) if defined $new_id && !ref $new_id;
70              
71 0         0 croak 'create instance did not return an instance payload or contract id';
72             }
73              
74             sub update {
75 2     2 1 7 my ($self, $id, %params) = @_;
76 2 50       7 croak "instance id required" unless defined $id;
77              
78 2         12 my $result = $self->client->request_op(
79             'manageInstance',
80             path => { id => $id },
81             body => \%params,
82             );
83              
84 2         6 my $instance = $self->_extract_instance($result);
85 2 50       5 return $self->_wrap($instance) if $instance;
86              
87 2         4 return $self->get($id);
88             }
89              
90             sub start {
91 0     0 1 0 my ($self, $id) = @_;
92 0         0 return $self->update($id, state => 'running');
93             }
94              
95             sub stop {
96 1     1 1 10 my ($self, $id) = @_;
97 1         2 return $self->update($id, state => 'stopped');
98             }
99              
100             sub label {
101 1     1 1 10 my ($self, $id, $label) = @_;
102 1         5 return $self->update($id, label => $label);
103             }
104              
105             sub delete {
106 1     1 1 2 my ($self, $id) = @_;
107 1 50       4 croak "instance id required" unless defined $id;
108 1         6 return $self->client->request_op('deleteInstance', path => { id => $id });
109             }
110              
111             sub logs {
112 1     1 1 11 my ($self, $id, %params) = @_;
113 1 50       5 croak "instance id required" unless defined $id;
114              
115 1         5 my %body = (
116             tail => 100,
117             timestamps => 0,
118             %params,
119             );
120              
121 1         9 my $result = $self->client->request_op(
122             'requestInstanceLogs',
123             path => { id => $id },
124             body => \%body,
125             );
126              
127 1 50 33     8 if (ref $result eq 'HASH' && $result->{result_url}) {
128 0         0 my $ua = LWP::UserAgent->new(
129             agent => 'WWW-VastAI',
130             timeout => 30,
131             );
132 0         0 my $response = $ua->get($result->{result_url});
133 0 0       0 croak 'Failed to fetch instance logs: ' . $response->status_line
134             unless $response->is_success;
135 0         0 return $response->decoded_content;
136             }
137              
138 1 50 0     8 return ref $result eq 'HASH' ? ($result->{logs} || $result->{result} || $result) : $result;
139             }
140              
141             sub ssh_keys {
142 1     1 1 596 my ($self, $id) = @_;
143 1 50       4 croak "instance id required" unless defined $id;
144 1         8 my $result = $self->client->request_op('listInstanceSSHKeys', path => { id => $id });
145 1 50 0     9 return ref $result eq 'HASH' ? ($result->{ssh_keys} || $result->{results} || []) : ($result || []);
      0        
146             }
147              
148             sub attach_ssh_key {
149 1     1 1 732 my ($self, $id, $ssh_key) = @_;
150 1 50       4 croak "instance id required" unless defined $id;
151 1 50       3 croak "ssh key required" unless defined $ssh_key;
152              
153 1         9 return $self->client->request_op(
154             'attachInstanceSSHKey',
155             path => { id => $id },
156             body => { ssh_key => $ssh_key },
157             );
158             }
159              
160             sub detach_ssh_key {
161 1     1 1 10 my ($self, $id, $ssh_key_id) = @_;
162 1 50       4 croak "instance id required" unless defined $id;
163 1 50       3 croak "ssh key id required" unless defined $ssh_key_id;
164              
165 1         7 return $self->client->request_op(
166             'detachInstanceSSHKey',
167             path => {
168             id => $id,
169             ssh_key_id => $ssh_key_id,
170             },
171             );
172             }
173              
174             1;
175              
176             __END__