1 |
95b003ff
|
Origo
|
#!/usr/bin/perl
|
2 |
|
|
|
3 |
|
|
# All rights reserved and Copyright (c) 2020 Origo Systems ApS.
|
4 |
|
|
# This file is provided with no warranty, and is subject to the terms and conditions defined in the license file LICENSE.md.
|
5 |
|
|
# The license file is part of this source code package and its content is also available at:
|
6 |
|
|
# https://www.origo.io/info/stabiledocs/licensing/stabile-open-source-license
|
7 |
|
|
|
8 |
|
|
package Stabile::Servers;
|
9 |
|
|
|
10 |
|
|
use Error qw(:try);
|
11 |
|
|
use Data::UUID;
|
12 |
|
|
use Proc::Daemon;
|
13 |
|
|
use File::Basename;
|
14 |
|
|
use lib dirname (__FILE__);
|
15 |
|
|
use File::Basename;
|
16 |
|
|
use lib dirname (__FILE__);
|
17 |
|
|
use Stabile;
|
18 |
|
|
#use Encode::Escape;
|
19 |
|
|
|
20 |
|
|
$\ = ''; # Some of the above seems to set this to \n, resulting in every print appending a line feed
|
21 |
|
|
|
22 |
|
|
$cpuovercommision = $Stabile::config->get('CPU_OVERCOMMISION') || 1;
|
23 |
|
|
$dpolicy = $Stabile::config->get('DISTRIBUTION_POLICY') || 'disperse'; #"disperse" or "pack"
|
24 |
|
|
$amtpasswd = $Stabile::config->get('AMT_PASSWD') || "";
|
25 |
|
|
$brutalsleep = $Stabile::config->get('BRUTAL_SLEEP') || "";
|
26 |
|
|
$sshcmd = $sshcmd || $Stabile::sshcmd;
|
27 |
|
|
|
28 |
|
|
my %ahash; # A hash of accounts and associated privileges current user has access to
|
29 |
|
|
|
30 |
|
|
#my %options=();
|
31 |
|
|
#Getopt::Std::getopts("a:hfu:m:k:", \%options); # -a action -h help -f full-list (all users) -u uuid -m match pattern -k keywords
|
32 |
|
|
|
33 |
|
|
try {
|
34 |
|
|
Init(); # Perform various initalization tasks
|
35 |
|
|
process() if ($package);
|
36 |
|
|
|
37 |
|
|
if ($action || %params) {
|
38 |
|
|
untie %register;
|
39 |
|
|
untie %networkreg;
|
40 |
|
|
untie %nodereg;
|
41 |
|
|
untie %xmlreg;
|
42 |
|
|
}
|
43 |
|
|
|
44 |
|
|
} catch Error with {
|
45 |
|
|
my $ex = shift;
|
46 |
|
|
print $Stabile::q->header('text/html', '500 Internal Server Error') unless ($console);
|
47 |
|
|
if ($ex->{-text}) {
|
48 |
|
|
print "Got error: ", $ex->{-text}, " on line ", $ex->{-line}, "\n";
|
49 |
|
|
} else {
|
50 |
|
|
print "Status=ERROR\n";
|
51 |
|
|
}
|
52 |
|
|
} finally {
|
53 |
|
|
};
|
54 |
|
|
|
55 |
|
|
1;
|
56 |
|
|
|
57 |
|
|
sub getObj {
|
58 |
|
|
my %h = %{@_[0]};
|
59 |
|
|
$console = 1 if $h{"console"};
|
60 |
|
|
$api = 1 if $h{"api"};
|
61 |
|
|
my $uuid = $h{"uuid"};
|
62 |
|
|
$uuid = $curuuid if ($uuid eq 'this');
|
63 |
|
|
my $obj;
|
64 |
c899e439
|
Origo
|
$action = $action || $h{'action'};
|
65 |
|
|
|
66 |
|
|
if ($h{'action'} eq 'destroy' || $action eq 'destroy' || $action eq 'attach' || $action eq 'detach' || $action =~ /changepassword|sshaccess/) {
|
67 |
95b003ff
|
Origo
|
$obj = \%h;
|
68 |
|
|
return $obj;
|
69 |
|
|
}
|
70 |
|
|
|
71 |
|
|
# Allow specifying nicmac1 instead of uuid if known
|
72 |
|
|
if (!$uuid) {
|
73 |
|
|
$uuid = nicmac1ToUuid($h{"nicmac1"});
|
74 |
|
|
}
|
75 |
|
|
my $status = 'new';
|
76 |
|
|
$status = $register{$uuid}->{'status'} if ($register{$uuid});
|
77 |
|
|
|
78 |
|
|
my $objaction = lc $h{"action"};
|
79 |
|
|
$objaction = "" if ($status eq "new");
|
80 |
|
|
|
81 |
|
|
if ((!$uuid) && $status eq 'new') {
|
82 |
|
|
my $ug = new Data::UUID;
|
83 |
|
|
$uuid = $ug->create_str();
|
84 |
|
|
if ($uripath =~ /servers(\.cgi)?\/(.+)/) {
|
85 |
|
|
my $huuid = $2;
|
86 |
|
|
if ($ug->to_string($ug->from_string($huuid)) eq $huuid) { # Check for valid uuid
|
87 |
|
|
$uuid = $huuid;
|
88 |
|
|
}
|
89 |
|
|
}
|
90 |
|
|
};
|
91 |
|
|
unless ($uuid && length $uuid == 36) {
|
92 |
|
|
$posterror .= "Status=Error Invalid uuid.\n";
|
93 |
|
|
return;
|
94 |
|
|
}
|
95 |
|
|
|
96 |
|
|
my $dbobj = $register{$uuid} || {};
|
97 |
|
|
|
98 |
|
|
my $name = $h{"name"} || $dbobj->{'name'};
|
99 |
|
|
utf8::decode($name);
|
100 |
|
|
my $memory = $h{"memory"} || $dbobj->{'memory'};
|
101 |
|
|
my $vcpu = $h{"vcpu"} || $dbobj->{'vcpu'};
|
102 |
|
|
my $boot = $h{"boot"} || $dbobj->{'boot'};
|
103 |
04c16f26
|
hq
|
my $loader = $h{"loader"} || $dbobj->{'loader'};
|
104 |
95b003ff
|
Origo
|
my $image = $h{"image"} || $dbobj->{'image'};
|
105 |
|
|
my $imagename = $h{"imagename"} || $dbobj->{'imagename'};
|
106 |
|
|
if ($image && $image ne '--' && !($image =~ /^\//)) { # Image is registered by uuid - we find the path
|
107 |
|
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {$posterror = "Unable to access image uuid register"; return;};
|
108 |
|
|
$image = $imagereg2{$image}->{'path'};
|
109 |
|
|
$imagename = $imagereg2{$image}->{'name'};
|
110 |
|
|
untie %imagereg2;
|
111 |
|
|
return unless ($image);
|
112 |
|
|
}
|
113 |
|
|
my $image2 = $h{"image2"} || $dbobj->{'image2'};
|
114 |
|
|
my $image3 = $h{"image3"} || $dbobj->{'image3'};
|
115 |
|
|
my $image4 = $h{"image4"} || $dbobj->{'image4'};
|
116 |
|
|
my $image2name = $h{"image2name"} || $dbobj->{'image2name'};
|
117 |
|
|
my $image3name = $h{"image3name"} || $dbobj->{'image3name'};
|
118 |
|
|
my $image4name = $h{"image4name"} || $dbobj->{'image4name'};
|
119 |
|
|
if ($image2 && $image2 ne '--' && !($image2 =~ /^\//)) { # Image2 is registered by uuid - we find the path
|
120 |
|
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {$postreply = "Unable to access image uuid register"; return $postreply;};
|
121 |
|
|
$image2 = $imagereg2{$image2}->{'path'};
|
122 |
|
|
$image2name = $imagereg2{$image2}->{'name'};
|
123 |
|
|
untie %imagereg2;
|
124 |
|
|
}
|
125 |
|
|
my $diskbus = $h{"diskbus"} || $dbobj->{'diskbus'};
|
126 |
|
|
my $diskdev = "vda";
|
127 |
|
|
my $diskdev2 = "vdb";
|
128 |
|
|
my $diskdev3 = "vdc";
|
129 |
|
|
my $diskdev4 = "vdd";
|
130 |
|
|
if ($diskbus eq "ide") {$diskdev = "hda"; $diskdev2 = "hdb"; $diskdev3 = "hdc"; $diskdev4 = "hdd"};
|
131 |
|
|
my $cdrom = $h{"cdrom"} || $dbobj->{'cdrom'};
|
132 |
04c16f26
|
hq
|
if ($cdrom && $cdrom ne '--' && !($cdrom =~ /^\//) && $cdrom ne 'virtio') {
|
133 |
95b003ff
|
Origo
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {$postreply = "Unable to access image uuid register"; return $postreply;};
|
134 |
|
|
$cdrom = $imagereg2{$cdrom}->{'path'};
|
135 |
|
|
untie %imagereg2;
|
136 |
|
|
}
|
137 |
|
|
|
138 |
|
|
my $networkuuid1 = $h{"networkuuid1"} || $dbobj->{'networkuuid1'};
|
139 |
|
|
if ($h{"networkuuid1"} eq "0") {$networkuuid1 = "0"}; #Stupid perl... :-)
|
140 |
|
|
my $networkid1 = $h{"networkid1"} || $dbobj->{'networkid1'};
|
141 |
|
|
my $networkname1 = $h{"networkname1"} || $dbobj->{'networkname1'};
|
142 |
|
|
my $nicmodel1 = $h{"nicmodel1"} || $dbobj->{'nicmodel1'};
|
143 |
|
|
my $nicmac1 = $h{"nicmac1"} || $dbobj->{'nicmac1'};
|
144 |
|
|
if (!$nicmac1 || $nicmac1 eq "--") {$nicmac1 = randomMac();}
|
145 |
|
|
|
146 |
|
|
my $networkuuid2 = $h{"networkuuid2"} || $dbobj->{'networkuuid2'};
|
147 |
|
|
if ($h{"networkuuid2"} eq "0") {$networkuuid2 = "0"};
|
148 |
|
|
my $networkid2 = $h{"networkid2"} || $dbobj->{'networkid2'};
|
149 |
|
|
my $networkname2 = $h{"networkname2"} || $dbobj->{'networkname2'};
|
150 |
|
|
my $nicmac2 = $h{"nicmac2"} || $dbobj->{'nicmac2'};
|
151 |
|
|
if (!$nicmac2 || $nicmac2 eq "--") {$nicmac2 = randomMac();}
|
152 |
|
|
|
153 |
|
|
my $networkuuid3 = $h{"networkuuid3"} || $dbobj->{'networkuuid3'};
|
154 |
|
|
if ($h{"networkuuid3"} eq "0") {$networkuuid3 = "0"};
|
155 |
|
|
my $networkid3 = $h{"networkid3"} || $dbobj->{'networkid3'};
|
156 |
|
|
my $networkname3 = $h{"networkname3"} || $dbobj->{'networkname3'};
|
157 |
|
|
my $nicmac3 = $h{"nicmac3"} || $dbobj->{'nicmac3'};
|
158 |
|
|
if (!$nicmac3 || $nicmac3 eq "--") {$nicmac3 = randomMac();}
|
159 |
|
|
|
160 |
|
|
my $action = $h{"action"};
|
161 |
|
|
my $notes = $h{"notes"};
|
162 |
|
|
$notes = $dbobj->{'notes'} if (!$notes || $notes eq '--');
|
163 |
|
|
my $reguser = $dbobj->{'user'};
|
164 |
|
|
my $autostart = ($h{"autostart"} ."") || $dbobj->{'autostart'};
|
165 |
|
|
if ($autostart && $autostart ne "false") {$autostart = "true";}
|
166 |
|
|
my $locktonode = ($h{"locktonode"} ."") || $dbobj->{'locktonode'};
|
167 |
|
|
if ($locktonode && $locktonode ne "false") {$locktonode = "true";}
|
168 |
|
|
my $mac;
|
169 |
|
|
$mac = $dbobj->{'mac'} unless ($objaction eq 'start');
|
170 |
|
|
# $mac = $h{"mac"} if ($isadmin && $locktonode eq 'true' && $h{"mac"});
|
171 |
|
|
$mac = $h{"mac"} if ($isadmin && $h{"mac"});
|
172 |
|
|
my $domuser = $h{"user"} || $user; # Set if user is trying to move server to another account
|
173 |
|
|
|
174 |
|
|
# Sanity checks
|
175 |
|
|
if (
|
176 |
|
|
($name && length $name > 255)
|
177 |
|
|
|| ($networkuuid1<0)
|
178 |
|
|
|| ($networkuuid2<0)
|
179 |
|
|
|| ($networkuuid3<0)
|
180 |
|
|
|| ($networkuuid1>1 && length $networkuuid1 != 36)
|
181 |
|
|
|| ($networkuuid2>1 && length $networkuuid2 != 36)
|
182 |
|
|
|| ($networkuuid3>1 && length $networkuuid3 != 36)
|
183 |
|
|
|| ($image && length $image > 255)
|
184 |
|
|
|| ($imagename && length $imagename > 255)
|
185 |
|
|
|| ($image2 && length $image2 > 255)
|
186 |
|
|
|| ($image3 && length $image3 > 255)
|
187 |
|
|
|| ($image4 && length $image4 > 255)
|
188 |
|
|
|| ($image2name && length $image2name > 255)
|
189 |
|
|
|| ($image3name && length $image3name > 255)
|
190 |
|
|
|| ($image4name && length $image4name > 255)
|
191 |
|
|
|| ($cdrom && length $cdrom > 255)
|
192 |
a439a9c4
|
hq
|
|| ($memory && ($memory<64 || $memory >1024*64))
|
193 |
95b003ff
|
Origo
|
) {
|
194 |
a439a9c4
|
hq
|
$postreply .= "Status=ERROR Invalid server data: $name\n";
|
195 |
95b003ff
|
Origo
|
return 0;
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
# Security check
|
199 |
2a63870a
|
Christian Orellana
|
if ($status eq 'new' && (($action && $action ne '--' && $action ne 'save') || !$image || $image eq '--')) {
|
200 |
|
|
$postreply .= "Status=ERROR Bad server data: $name\n";
|
201 |
|
|
$postmsg = "Bad server data";
|
202 |
95b003ff
|
Origo
|
return 0;
|
203 |
|
|
}
|
204 |
|
|
if (!$reguser && $status ne 'new'
|
205 |
|
|
&& !($name && $memory && $vcpu && $boot && $image && $diskbus && $networkuuid1 && $nicmodel1)) {
|
206 |
|
|
$posterror .= "Status=ERROR Insufficient data: $name\n";
|
207 |
|
|
return 0;
|
208 |
|
|
}
|
209 |
|
|
if (!$isadmin) {
|
210 |
|
|
if (($networkuuid1>1 && $networkreg{$networkuuid1}->{'user'} ne $user)
|
211 |
|
|
|| ($networkuuid2>1 && $networkreg{$networkuuid2}->{'user'} ne $user)
|
212 |
|
|
|| ($networkuuid3>1 && $networkreg{$networkuuid3}->{'user'} ne $user)
|
213 |
|
|
)
|
214 |
|
|
{
|
215 |
|
|
$postreply .= "Status=ERROR No privileges: $networkname1 $networkname2\n";
|
216 |
|
|
return 0;
|
217 |
|
|
}
|
218 |
91a21c75
|
hq
|
if ( ($reguser && ($user ne $reguser) && $action ) || ($reguser && $status eq "new"))
|
219 |
95b003ff
|
Origo
|
{
|
220 |
|
|
$postreply .= "Status=ERROR No privileges: $name\n";
|
221 |
|
|
return 0;
|
222 |
|
|
}
|
223 |
|
|
if (!($image =~ /\/$user\//)
|
224 |
|
|
|| ($image2 && $image2 ne "--" && !($image2 =~ /\/$user\//))
|
225 |
|
|
|| ($image3 && $image3 ne "--" && !($image3 =~ /\/$user\//))
|
226 |
|
|
|| ($image4 && $image4 ne "--" && !($image4 =~ /\/$user\//))
|
227 |
|
|
)
|
228 |
|
|
{
|
229 |
|
|
$postreply .= "Status=ERROR No image privileges: $name\n";
|
230 |
|
|
return 0;
|
231 |
|
|
}
|
232 |
|
|
}
|
233 |
|
|
|
234 |
|
|
# No action - regular save of domain properties
|
235 |
04c16f26
|
hq
|
$cdrom = '--' if ($cdrom eq 'virtio' && $action ne 'mountcd');
|
236 |
95b003ff
|
Origo
|
|
237 |
|
|
$obj = {
|
238 |
|
|
uuid => $uuid,
|
239 |
|
|
status => $status,
|
240 |
|
|
name => $name,
|
241 |
|
|
memory => $memory,
|
242 |
|
|
vcpu => $vcpu,
|
243 |
|
|
image => $image,
|
244 |
|
|
imagename => $imagename,
|
245 |
|
|
image2 => $image2,
|
246 |
|
|
image2name => $image2name,
|
247 |
|
|
image3 => $image3,
|
248 |
|
|
image3name => $image3name,
|
249 |
|
|
image4 => $image4,
|
250 |
|
|
image4name => $image4name,
|
251 |
|
|
diskbus => $diskbus,
|
252 |
|
|
cdrom => $cdrom,
|
253 |
|
|
boot => $boot,
|
254 |
04c16f26
|
hq
|
loader=> $loader,
|
255 |
95b003ff
|
Origo
|
networkuuid1 => $networkuuid1,
|
256 |
|
|
networkid1 => $networkid1,
|
257 |
|
|
networkname1 => $networkname1,
|
258 |
|
|
nicmodel1 => $nicmodel1,
|
259 |
|
|
nicmac1 => $nicmac1,
|
260 |
|
|
networkuuid2 => $networkuuid2,
|
261 |
|
|
networkid2 => $networkid2,
|
262 |
|
|
networkname2 => $networkname2,
|
263 |
|
|
nicmac2 => $nicmac2,
|
264 |
|
|
networkuuid3 => $networkuuid3,
|
265 |
|
|
networkid3 => $networkid3,
|
266 |
|
|
networkname3 => $networkname3,
|
267 |
|
|
nicmac3 => $nicmac3,
|
268 |
|
|
notes => $notes,
|
269 |
|
|
autostart => $autostart,
|
270 |
|
|
locktonode => $locktonode,
|
271 |
|
|
mac => $mac,
|
272 |
|
|
user => $domuser
|
273 |
|
|
};
|
274 |
|
|
return $obj;
|
275 |
|
|
}
|
276 |
|
|
|
277 |
|
|
sub Init {
|
278 |
|
|
# Tie database tables to hashes
|
279 |
|
|
unless ( tie(%register,'Tie::DBI', Hash::Merge::merge({table=>'domains'}, $Stabile::dbopts)) ) {return "Unable to access image register"};
|
280 |
|
|
unless ( tie(%networkreg,'Tie::DBI', Hash::Merge::merge({table=>'networks'}, $Stabile::dbopts)) ) {return "Unable to access network register"};
|
281 |
|
|
unless ( tie(%nodereg,'Tie::DBI', Hash::Merge::merge({table=>'nodes', key=>'mac'}, $Stabile::dbopts)) ) {return "Unable to access nodes register"};
|
282 |
|
|
unless ( tie(%xmlreg,'Tie::DBI', Hash::Merge::merge({table=>'domainxml'}, $Stabile::dbopts)) ) {return "Unable to access domainxml register"};
|
283 |
|
|
|
284 |
|
|
# simplify globals initialized in Stabile.pm
|
285 |
|
|
$tktuser = $tktuser || $Stabile::tktuser;
|
286 |
|
|
$user = $user || $Stabile::user;
|
287 |
|
|
$isadmin = $isadmin || $Stabile::isadmin;
|
288 |
|
|
$privileges = $privileges || $Stabile::privileges;
|
289 |
|
|
|
290 |
|
|
# Create aliases of functions
|
291 |
|
|
*header = \&CGI::header;
|
292 |
|
|
*to_json = \&JSON::to_json;
|
293 |
|
|
|
294 |
|
|
*Showautostart = \&Autostartall;
|
295 |
|
|
|
296 |
|
|
*do_save = \&Save;
|
297 |
|
|
*do_tablelist = \&do_list;
|
298 |
|
|
*do_jsonlist = \&do_list;
|
299 |
|
|
*do_showautostart = \&action;
|
300 |
|
|
*do_autostartall = \&privileged_action;
|
301 |
|
|
*do_help = \&action;
|
302 |
|
|
|
303 |
|
|
*do_start = \&privileged_action;
|
304 |
|
|
*do_destroy = \&action;
|
305 |
|
|
*do_shutdown = \&action;
|
306 |
|
|
*do_suspend = \&action;
|
307 |
|
|
*do_resume = \&action;
|
308 |
|
|
*do_remove = \&privileged_action;
|
309 |
|
|
*do_move = \&action;
|
310 |
|
|
*do_mountcd = \&action;
|
311 |
c899e439
|
Origo
|
*do_changepassword = \&privileged_action;
|
312 |
|
|
*do_sshaccess = \&privileged_action;
|
313 |
95b003ff
|
Origo
|
|
314 |
|
|
*do_gear_start = \&do_gear_action;
|
315 |
|
|
*do_gear_autostart = \&do_gear_action;
|
316 |
|
|
*do_gear_showautostart = \&do_gear_action;
|
317 |
|
|
*do_gear_autostartall = \&do_gear_action;
|
318 |
|
|
*do_gear_remove = \&do_gear_action;
|
319 |
c899e439
|
Origo
|
*do_gear_changepassword = \&do_gear_action;
|
320 |
|
|
*do_gear_sshaccess = \&do_gear_action;
|
321 |
95b003ff
|
Origo
|
|
322 |
|
|
}
|
323 |
|
|
|
324 |
|
|
sub do_list {
|
325 |
|
|
my ($uuid, $action) = @_;
|
326 |
|
|
if ($help) {
|
327 |
|
|
return <<END
|
328 |
|
|
GET:uuid:
|
329 |
|
|
List servers current user has access to.
|
330 |
|
|
END
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
my $res;
|
334 |
|
|
my $filter;
|
335 |
|
|
my $statusfilter;
|
336 |
|
|
my $uuidfilter;
|
337 |
|
|
my $curserv = $register{$curuuid};
|
338 |
|
|
if ($curuuid && ($isadmin || $curserv->{'user'} eq $user) && $uripath =~ /servers(\.cgi)?\/(\?|)(this)/) {
|
339 |
|
|
$uuidfilter = $curuuid;
|
340 |
|
|
} elsif ($uripath =~ /servers(\.cgi)?\/(\?|)(name|status)/) {
|
341 |
|
|
$filter = $3 if ($uripath =~ /servers(\.cgi)?\/\??name(:|=)(.+)/);
|
342 |
|
|
$filter = $1 if ($filter =~ /(.*)\*$/);
|
343 |
|
|
$statusfilter = $4 if ($uripath =~ /servers(\.cgi)?\/\??(.+ AND )?status(:|=)(\w+)/);
|
344 |
|
|
} elsif ($uripath =~ /servers(\.cgi)?\/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/) {
|
345 |
|
|
$uuidfilter = $2;
|
346 |
|
|
}
|
347 |
|
|
$filter = $1 if ($filter =~ /(.*)\*/);
|
348 |
|
|
|
349 |
|
|
my $sysuuid;
|
350 |
|
|
if ($params{'system'}) {
|
351 |
|
|
$sysuuid = $params{'system'};
|
352 |
|
|
$sysuuid = $cursysuuid || $curuuid if ($params{'system'} eq 'this');
|
353 |
|
|
}
|
354 |
|
|
my @curregvalues;
|
355 |
|
|
my @regkeys;
|
356 |
|
|
if ($fulllist && $isadmin) {
|
357 |
|
|
@regkeys = keys %register;
|
358 |
|
|
} elsif ($uuidfilter && $isadmin) {
|
359 |
|
|
@regkeys = (tied %register)->select_where("uuid = '$uuidfilter'");
|
360 |
|
|
} elsif ($sysuuid) {
|
361 |
|
|
@regkeys = (tied %register)->select_where("system = '$sysuuid' OR uuid = '$sysuuid'");
|
362 |
|
|
} else {
|
363 |
|
|
@regkeys = (tied %register)->select_where("user = '$user'");
|
364 |
|
|
}
|
365 |
|
|
|
366 |
|
|
unless (tie(%sysreg,'Tie::DBI', Hash::Merge::merge({table=>'systems'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access systems register"}|; return $res;};
|
367 |
|
|
unless (tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access images register"}|; return $res;};
|
368 |
|
|
|
369 |
|
|
foreach my $k (@regkeys) {
|
370 |
|
|
$valref = $register{$k};
|
371 |
|
|
# Only include VM's belonging to current user (or all users if specified and user is admin)
|
372 |
|
|
if ($user eq $valref->{'user'} || $fulllist || ($uuidfilter && $isadmin)) {
|
373 |
|
|
next unless (!$sysuuid || $valref->{'system'} eq $sysuuid || $valref->{'uuid'} eq $sysuuid);
|
374 |
|
|
|
375 |
|
|
my $validatedref = validateItem($valref);
|
376 |
|
|
my %val = %{$validatedref}; # Deference and assign to new ass array, effectively cloning object
|
377 |
|
|
$val{'memory'} += 0;
|
378 |
|
|
$val{'vcpu'} += 0;
|
379 |
|
|
$val{'nodetype'} = 'parent';
|
380 |
|
|
$val{'internalip'} = $networkreg{$val{'networkuuid1'}}->{'internalip'};
|
381 |
|
|
$val{'self'} = 1 if ($curuuid && $curuuid eq $val{'uuid'});
|
382 |
|
|
if ($action eq 'treelist') {
|
383 |
|
|
if ($val{'system'} && $val{'system'} ne '') {
|
384 |
|
|
my $sysuuid = $val{'system'};
|
385 |
|
|
my $sysname = $sysreg{$sysuuid}->{'name'};
|
386 |
|
|
if (!$sysname) {
|
387 |
|
|
$sysname = $1 if ($sysname =~ /(.+)\..*/);
|
388 |
|
|
$sysname = $val{'name'};
|
389 |
|
|
$sysname =~ s/server/System/i;
|
390 |
|
|
}
|
391 |
|
|
$sysreg{$sysuuid} = {
|
392 |
|
|
uuid => $sysuuid,
|
393 |
|
|
name => $sysname,
|
394 |
|
|
user => 'irigo'
|
395 |
|
|
};
|
396 |
|
|
|
397 |
|
|
my %pval = %{$sysreg{$sysuuid}};
|
398 |
|
|
$pval{'nodetype'} = 'parent';
|
399 |
|
|
$pval{'status'} = '--';
|
400 |
|
|
$val{'nodetype'} = 'child';
|
401 |
|
|
|
402 |
|
|
my @children;
|
403 |
|
|
push @children,\%val;
|
404 |
|
|
$pval{'children'} = \@children;
|
405 |
|
|
push @curregvalues,\%pval;
|
406 |
|
|
} else {
|
407 |
|
|
push @curregvalues,\%val;
|
408 |
|
|
}
|
409 |
|
|
} elsif ($filter || $statusfilter || $uuidfilter) { # List filtered servers
|
410 |
|
|
my $fmatch;
|
411 |
|
|
my $smatch;
|
412 |
|
|
my $umatch;
|
413 |
|
|
$fmatch = 1 if (!$filter || $val{'name'}=~/$filter/i);
|
414 |
|
|
$smatch = 1 if (!$statusfilter || $statusfilter eq 'all'
|
415 |
|
|
|| $statusfilter eq $val{'status'}
|
416 |
|
|
);
|
417 |
|
|
$umatch = 1 if ($val{'uuid'} eq $uuidfilter);
|
418 |
|
|
if ($fmatch && $smatch && !$uuidfilter) {
|
419 |
|
|
push @curregvalues,\%val;
|
420 |
|
|
} elsif ($umatch) {
|
421 |
|
|
push @curregvalues,\%val;
|
422 |
|
|
last;
|
423 |
|
|
}
|
424 |
|
|
} else {
|
425 |
|
|
push @curregvalues,\%val;
|
426 |
|
|
}
|
427 |
|
|
}
|
428 |
|
|
}
|
429 |
|
|
tied(%sysreg)->commit;
|
430 |
|
|
untie(%sysreg);
|
431 |
|
|
untie %imagereg;
|
432 |
|
|
@curregvalues = (sort {$a->{'status'} cmp $b->{'status'}} @curregvalues); # Sort by status
|
433 |
|
|
|
434 |
|
|
# Sort @curregvalues
|
435 |
2a63870a
|
Christian Orellana
|
@curregvalues = (sort {$b->{'name'} <=> $a->{'name'}} @curregvalues); # Always sort by name first
|
436 |
95b003ff
|
Origo
|
my $sort = 'status';
|
437 |
|
|
$sort = $2 if ($uripath =~ /sort\((\+|\-)(\S+)\)/);
|
438 |
|
|
my $reverse;
|
439 |
|
|
$reverse = 1 if ($1 eq '-');
|
440 |
|
|
if ($reverse) { # sort reverse
|
441 |
|
|
if ($sort =~ /memory|vcpu/) {
|
442 |
|
|
@curregvalues = (sort {$b->{$sort} <=> $a->{$sort}} @curregvalues); # Sort as number
|
443 |
|
|
} else {
|
444 |
|
|
@curregvalues = (sort {$b->{$sort} cmp $a->{$sort}} @curregvalues); # Sort as string
|
445 |
|
|
}
|
446 |
|
|
} else {
|
447 |
|
|
if ($sort =~ /memory|vcpu/) {
|
448 |
|
|
@curregvalues = (sort {$a->{$sort} <=> $b->{$sort}} @curregvalues); # Sort as number
|
449 |
|
|
} else {
|
450 |
|
|
@curregvalues = (sort {$a->{$sort} cmp $b->{$sort}} @curregvalues); # Sort as string
|
451 |
|
|
}
|
452 |
|
|
}
|
453 |
|
|
|
454 |
|
|
if ($action eq 'tablelist') {
|
455 |
|
|
my $t2;
|
456 |
|
|
|
457 |
|
|
if ($isadmin) {
|
458 |
|
|
$t2 = Text::SimpleTable->new(36,20,20,10,10,12,7);
|
459 |
|
|
$t2->row('uuid', 'name', 'imagename', 'memory', 'user', 'mac', 'status');
|
460 |
|
|
} else {
|
461 |
|
|
$t2 = Text::SimpleTable->new(36,20,20,10,10,7);
|
462 |
|
|
$t2->row('uuid', 'name', 'imagename', 'memory', 'user', 'status');
|
463 |
|
|
}
|
464 |
|
|
$t2->hr;
|
465 |
|
|
my $pattern = $options{m};
|
466 |
|
|
foreach $rowref (@curregvalues){
|
467 |
|
|
if ($pattern) {
|
468 |
|
|
my $rowtext = $rowref->{'uuid'} . " " . $rowref->{'name'} . " " . $rowref->{'imagename'} . " " . $rowref->{'memory'}
|
469 |
|
|
. " " . $rowref->{'user'} . " " . $rowref->{'status'};
|
470 |
|
|
$rowtext .= " " . $rowref->{'mac'} if ($isadmin);
|
471 |
|
|
next unless ($rowtext =~ /$pattern/i);
|
472 |
|
|
}
|
473 |
|
|
if ($isadmin) {
|
474 |
|
|
$t2->row($rowref->{'uuid'}, $rowref->{'name'}, $rowref->{'imagename'}, $rowref->{'memory'},
|
475 |
|
|
$rowref->{'user'}, $rowref->{'mac'}, $rowref->{'status'});
|
476 |
|
|
} else {
|
477 |
|
|
$t2->row($rowref->{'uuid'}, $rowref->{'name'}, $rowref->{'imagename'}, $rowref->{'memory'},
|
478 |
|
|
$rowref->{'user'}, $rowref->{'status'});
|
479 |
|
|
}
|
480 |
|
|
}
|
481 |
|
|
$res .= $t2->draw;
|
482 |
|
|
} elsif ($console) {
|
483 |
|
|
$res .= Dumper(\@curregvalues);
|
484 |
|
|
} else {
|
485 |
|
|
my $json_text;
|
486 |
|
|
if ($uuidfilter && @curregvalues) {
|
487 |
|
|
$json_text = to_json($curregvalues[0], {pretty => 1});
|
488 |
|
|
} else {
|
489 |
|
|
$json_text = to_json(\@curregvalues, {pretty => 1});
|
490 |
|
|
}
|
491 |
|
|
|
492 |
|
|
$json_text =~ s/\x/ /g;
|
493 |
|
|
$json_text =~ s/\"\"/"--"/g;
|
494 |
c899e439
|
Origo
|
$json_text =~ s/null/"--"/g;
|
495 |
04c16f26
|
hq
|
$json_text =~ s/"autostart"\s?:\s?"true"/"autostart": true/g;
|
496 |
|
|
$json_text =~ s/"autostart"\s?:\s?"--"/"autostart": false/g;
|
497 |
|
|
$json_text =~ s/"locktonode"\s?:\s?"true"/"locktonode": true/g;
|
498 |
|
|
$json_text =~ s/"locktonode"\s?:\s?"--"/"locktonode": false/g;
|
499 |
|
|
$json_text =~ s/"loader"\s?:\s?"--"/"loader": "bios"/g;
|
500 |
95b003ff
|
Origo
|
if ($action eq 'jsonlist' || $action eq 'list' || !$action) {
|
501 |
|
|
$res .= $json_text;
|
502 |
|
|
} else {
|
503 |
|
|
$res .= qq|{"action": "$action", "identifier": "uuid", "label": "uuid", "items" : $json_text}|;
|
504 |
|
|
}
|
505 |
|
|
}
|
506 |
|
|
return $res;
|
507 |
|
|
}
|
508 |
|
|
|
509 |
|
|
sub do_uuidshow {
|
510 |
|
|
my ($uuid, $action) = @_;
|
511 |
|
|
if ($help) {
|
512 |
|
|
return <<END
|
513 |
|
|
GET:uuid:
|
514 |
|
|
Simple action for showing a single server.
|
515 |
|
|
END
|
516 |
|
|
}
|
517 |
|
|
my $res;
|
518 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
519 |
|
|
my $u = $uuid || $options{u};
|
520 |
|
|
if ($u || $u eq '0') {
|
521 |
|
|
foreach my $uuid (keys %register) {
|
522 |
|
|
if (($register{$uuid}->{'user'} eq $user || $register{$uuid}->{'user'} eq 'common' || $isadmin)
|
523 |
|
|
&& $uuid =~ /^$u/) {
|
524 |
|
|
my %hash = %{$register{$uuid}};
|
525 |
|
|
delete $hash{'action'};
|
526 |
|
|
my $dump = Dumper(\%hash);
|
527 |
|
|
$dump =~ s/undef/"--"/g;
|
528 |
|
|
$res .= $dump;
|
529 |
|
|
last;
|
530 |
|
|
}
|
531 |
|
|
}
|
532 |
|
|
}
|
533 |
|
|
return $res;
|
534 |
|
|
}
|
535 |
|
|
|
536 |
|
|
sub do_uuidlookup {
|
537 |
|
|
if ($help) {
|
538 |
|
|
return <<END
|
539 |
|
|
GET:uuid:
|
540 |
|
|
Simple action for looking up a uuid or part of a uuid and returning the complete uuid.
|
541 |
|
|
END
|
542 |
|
|
}
|
543 |
|
|
my $res;
|
544 |
|
|
$res .= header('text/plain') unless $console;
|
545 |
|
|
my $u = $options{u};
|
546 |
|
|
$u = $curuuid unless ($u || $u eq '0');
|
547 |
|
|
my $ruuid;
|
548 |
|
|
if ($u || $u eq '0') {
|
549 |
|
|
my $match;
|
550 |
|
|
foreach my $uuid (keys %register) {
|
551 |
|
|
if ($uuid =~ /^$u/) {
|
552 |
|
|
$ruuid = $uuid if ($register{$uuid}->{'user'} eq $user || index($privileges,"a")!=-1);
|
553 |
|
|
$match = 1;
|
554 |
|
|
last;
|
555 |
|
|
}
|
556 |
|
|
}
|
557 |
|
|
if (!$match && $isadmin) { # If no match and user is admin, do comprehensive lookup
|
558 |
|
|
foreach my $uuid (keys %register) {
|
559 |
|
|
if ($uuid =~ /^$u/ || $register{$uuid}->{'name'} =~ /^$u/) {
|
560 |
|
|
$ruuid = $uuid;
|
561 |
|
|
last;
|
562 |
|
|
}
|
563 |
|
|
}
|
564 |
|
|
}
|
565 |
|
|
}
|
566 |
|
|
$res .= "$ruuid\n" if ($ruuid);
|
567 |
|
|
return $res;
|
568 |
|
|
}
|
569 |
|
|
|
570 |
|
|
sub do_destroyuserservers {
|
571 |
|
|
if ($help) {
|
572 |
|
|
return <<END
|
573 |
|
|
GET::
|
574 |
|
|
Simple action for destroying all servers belonging to a user
|
575 |
|
|
END
|
576 |
|
|
}
|
577 |
|
|
my $res;
|
578 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
579 |
|
|
destroyUserServers($user);
|
580 |
|
|
$res .= $postreply;
|
581 |
|
|
return $res;
|
582 |
|
|
}
|
583 |
|
|
|
584 |
|
|
sub do_removeuserservers {
|
585 |
|
|
if ($help) {
|
586 |
|
|
return <<END
|
587 |
|
|
GET::
|
588 |
|
|
Simple action for removing all servers belonging to a user
|
589 |
|
|
END
|
590 |
|
|
}
|
591 |
|
|
my $res;
|
592 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
593 |
|
|
removeUserServers($user);
|
594 |
|
|
$res .= $postreply;
|
595 |
|
|
return $res;
|
596 |
|
|
}
|
597 |
|
|
|
598 |
|
|
sub do_getappid {
|
599 |
|
|
my ($uuid, $action) = @_;
|
600 |
|
|
if ($help) {
|
601 |
|
|
return <<END
|
602 |
|
|
GET:uuid:
|
603 |
|
|
Simple action for getting the app id
|
604 |
|
|
END
|
605 |
|
|
}
|
606 |
|
|
my $res;
|
607 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
608 |
|
|
$uuid = $uuid || $options{u};
|
609 |
|
|
$uuid = $curuuid unless ($uuid);
|
610 |
|
|
if ($uuid && $register{$uuid}) {
|
611 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access image register"};
|
612 |
|
|
$res .= "appid: ". $imagereg{$register{$uuid}->{image}}->{appid}, "\n";
|
613 |
|
|
untie %imagereg;
|
614 |
|
|
}
|
615 |
|
|
return $res;
|
616 |
|
|
}
|
617 |
|
|
|
618 |
|
|
sub do_setrunning {
|
619 |
|
|
my ($uuid, $action) = @_;
|
620 |
|
|
if ($help) {
|
621 |
|
|
return <<END
|
622 |
|
|
GET:uuid:
|
623 |
|
|
Simple action for setting status back to running after e.g. an upgrade
|
624 |
|
|
END
|
625 |
|
|
}
|
626 |
|
|
my $res;
|
627 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
628 |
|
|
$uuid = $uuid || $options{u};
|
629 |
|
|
$uuid = $curuuid unless ($uuid);
|
630 |
|
|
if ($uuid && $register{$uuid}) {
|
631 |
|
|
$register{$uuid}->{'status'} = 'running';
|
632 |
|
|
$main::updateUI->({ tab => 'servers',
|
633 |
|
|
user => $user,
|
634 |
|
|
uuid => $uuid,
|
635 |
|
|
status => 'running' })
|
636 |
|
|
|
637 |
|
|
};
|
638 |
|
|
$res .= "Status=OK Set status of $register{$uuid}->{'name'} to running\n";
|
639 |
|
|
return $res;
|
640 |
|
|
}
|
641 |
|
|
|
642 |
|
|
sub do_getappinfo {
|
643 |
|
|
my ($uuid, $action) = @_;
|
644 |
|
|
if ($help) {
|
645 |
|
|
return <<END
|
646 |
|
|
GET:uuid:
|
647 |
|
|
Simple action for getting the apps basic info
|
648 |
|
|
END
|
649 |
|
|
}
|
650 |
|
|
my $res;
|
651 |
|
|
$res .= $Stabile::q->header('application/json') unless $console;
|
652 |
|
|
$uuid = $uuid || $options{u};
|
653 |
|
|
$uuid = $curuuid unless ($uuid);
|
654 |
|
|
my %appinfo;
|
655 |
|
|
if ($uuid && $register{$uuid}) {
|
656 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access image register"};
|
657 |
|
|
$appinfo{'appid'} = $imagereg{$register{$uuid}->{image}}->{appid} || '';
|
658 |
|
|
$appinfo{'managementlink'} = $imagereg{$register{$uuid}->{image}}->{managementlink} || '';
|
659 |
|
|
$appinfo{'managementlink'} =~ s/{uuid}/$register{$uuid}->{networkuuid1}/;
|
660 |
|
|
|
661 |
|
|
my $termlink = $imagereg{$register{$uuid}->{image}}->{terminallink} || '';
|
662 |
|
|
$termlink =~ s/{uuid}/$register{$uuid}->{networkuuid1}/;
|
663 |
|
|
my $burl = $baseurl;
|
664 |
|
|
$burl = $1 if ($termlink =~ /\/stabile/ && $baseurl =~ /(.+)\/stabile/); # Unpretty, but works for now
|
665 |
6fdc8676
|
hq
|
# $termlink = $1 if ($termlink =~ /\/(.+)/);
|
666 |
|
|
# $termlink = "$burl/$termlink" unless ($termlink =~ /^http/ || !$termlink); # || $termlink =~ /^\//
|
667 |
95b003ff
|
Origo
|
$appinfo{'terminallink'} = $termlink;
|
668 |
|
|
|
669 |
|
|
$appinfo{'upgradelink'} = $imagereg{$register{$uuid}->{image}}->{upgradelink} || '';
|
670 |
|
|
$appinfo{'upgradelink'} =~ s/{uuid}/$register{$uuid}->{networkuuid1}/;
|
671 |
|
|
$appinfo{'version'} = $imagereg{$register{$uuid}->{image}}->{version} || '';
|
672 |
|
|
$appinfo{'status'} = $register{$uuid}->{status} || '';
|
673 |
|
|
$appinfo{'name'} = $register{$uuid}->{name} || '';
|
674 |
d3d1a2d4
|
Origo
|
$appinfo{'system'} = $register{$uuid}->{system} || '';
|
675 |
|
|
|
676 |
|
|
if ($appinfo{'system'}) {
|
677 |
|
|
unless (tie(%sysreg,'Tie::DBI', Hash::Merge::merge({table=>'systems'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access systems register"}|; return $res;};
|
678 |
|
|
$appinfo{'systemname'} = $sysreg{$appinfo{'system'}}->{name} || '';
|
679 |
|
|
untie(%sysreg);
|
680 |
|
|
} else {
|
681 |
|
|
$appinfo{'systemname'} = $appinfo{'name'};
|
682 |
|
|
}
|
683 |
|
|
|
684 |
95b003ff
|
Origo
|
|
685 |
|
|
if ($appinfo{'appid'}) {
|
686 |
|
|
my @regkeys = (tied %imagereg)->select_where("appid = '$appinfo{appid}'");
|
687 |
|
|
foreach my $k (@regkeys) {
|
688 |
|
|
my $imgref = $imagereg{$k};
|
689 |
|
|
if ($imgref->{'path'} =~ /\.master\.qcow2$/ && $imgref->{'appid'} eq $appinfo{'appid'}
|
690 |
|
|
&& $imgref->{'installable'} && $imgref->{'installable'} ne 'false'
|
691 |
|
|
) {
|
692 |
|
|
if ($imgref->{'version'} > $appinfo{'currentversion'}) {
|
693 |
|
|
$appinfo{'currentversion'} = $imgref->{'version'};
|
694 |
|
|
$appinfo{'appname'} = $imgref->{'name'};
|
695 |
|
|
}
|
696 |
|
|
}
|
697 |
|
|
}
|
698 |
|
|
}
|
699 |
|
|
|
700 |
|
|
untie %imagereg;
|
701 |
|
|
}
|
702 |
|
|
$appinfo{'appstoreurl'} = $appstoreurl;
|
703 |
|
|
$appinfo{'dnsdomain'} = ($enginelinked)?$dnsdomain:'';
|
704 |
6fdc8676
|
hq
|
$appinfo{'dnssubdomain'} = ($enginelinked)?substr($engineid, 0, 8):'';
|
705 |
95b003ff
|
Origo
|
$appinfo{'uuid'} = $uuid;
|
706 |
|
|
$appinfo{'user'} = $user;
|
707 |
|
|
$appinfo{'remoteip'} = $remoteip;
|
708 |
|
|
$res .= to_json(\%appinfo, { pretty => 1 });
|
709 |
|
|
return $res;
|
710 |
|
|
}
|
711 |
|
|
|
712 |
|
|
sub do_removeserver {
|
713 |
|
|
if ($help) {
|
714 |
|
|
return <<END
|
715 |
|
|
GET:uuid:
|
716 |
|
|
Simple action for destroying and removing a single server
|
717 |
|
|
END
|
718 |
|
|
}
|
719 |
|
|
my $res;
|
720 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
721 |
|
|
if ($curuuid) {
|
722 |
|
|
removeUserServers($user, $curuuid, 1);
|
723 |
|
|
}
|
724 |
|
|
else {
|
725 |
|
|
$postreply .= "Status=Error Unable to uninstall\n";
|
726 |
|
|
}
|
727 |
|
|
$res .= $postreply;
|
728 |
|
|
return $res;
|
729 |
|
|
}
|
730 |
|
|
|
731 |
|
|
sub do_updateregister {
|
732 |
|
|
if ($help) {
|
733 |
|
|
return <<END
|
734 |
|
|
GET::
|
735 |
|
|
Update server register
|
736 |
|
|
END
|
737 |
|
|
}
|
738 |
|
|
my $res;
|
739 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
740 |
|
|
return unless $isadmin;
|
741 |
|
|
updateRegister();
|
742 |
|
|
$res .= "Status=OK Updated server registry for all users\n";
|
743 |
|
|
return $res;
|
744 |
|
|
}
|
745 |
|
|
|
746 |
|
|
sub Autostartall {
|
747 |
|
|
my ($uuid, $action) = @_;
|
748 |
|
|
if ($help) {
|
749 |
|
|
return <<END
|
750 |
|
|
GET::
|
751 |
|
|
Start all servers marked for autostart. When called as showautostart only shows which would be started.
|
752 |
|
|
END
|
753 |
|
|
}
|
754 |
|
|
my $res;
|
755 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
756 |
|
|
my $mes;
|
757 |
|
|
return $res if ($isreadonly);
|
758 |
|
|
|
759 |
|
|
# Wait for all pistons to be online
|
760 |
|
|
my $nodedown;
|
761 |
|
|
my $nodecount;
|
762 |
|
|
for (my $i = 0; $i < 10; $i++) {
|
763 |
|
|
$nodedown = 0;
|
764 |
|
|
foreach my $node (values %nodereg) {
|
765 |
|
|
if ($node->{'status'} ne 'running' && $node->{'status'} ne 'maintenance') {
|
766 |
|
|
$nodedown = 1;
|
767 |
|
|
}
|
768 |
|
|
else {
|
769 |
|
|
$nodecount++ unless ($node->{'status'} eq 'maintenance');
|
770 |
|
|
}
|
771 |
|
|
}
|
772 |
|
|
if ($nodedown) {
|
773 |
|
|
# Wait and see if nodes come online
|
774 |
|
|
$mes = "Waiting for nodes...(" . (10 - $i) . ")\n";
|
775 |
|
|
print $mes if ($console);
|
776 |
|
|
$res .= $mes;
|
777 |
|
|
sleep 5;
|
778 |
|
|
}
|
779 |
|
|
else {
|
780 |
|
|
last;
|
781 |
|
|
}
|
782 |
|
|
}
|
783 |
|
|
|
784 |
|
|
if (!%nodereg || $nodedown || !$nodecount) {
|
785 |
|
|
$mes = "Not autostarting servers - not all nodes ready!\n";
|
786 |
|
|
print $mes if ($console);
|
787 |
|
|
$res .= $mes;
|
788 |
|
|
}
|
789 |
|
|
else {
|
790 |
|
|
$mes = "$nodecount nodes ready - autostarting servers...\n";
|
791 |
|
|
print $mes if ($console);
|
792 |
|
|
$res .= $mes;
|
793 |
|
|
if ($action eq "showautostart") {
|
794 |
|
|
$mes = "Only showing which servers would be starting!\n";
|
795 |
|
|
print $mes if ($console);
|
796 |
|
|
$res .= $mes;
|
797 |
|
|
}
|
798 |
|
|
|
799 |
|
|
$Stabile::Networks::user = $user;
|
800 |
|
|
require "$Stabile::basedir/cgi/networks.cgi";
|
801 |
|
|
$Stabile::Networks::console = 1;
|
802 |
|
|
|
803 |
|
|
foreach my $dom (values %register) {
|
804 |
2a63870a
|
Christian Orellana
|
if ($dom->{'autostart'} eq '1' || $dom->{'autostart'} eq 'true') {
|
805 |
|
|
$res .= "Checking if $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'}) should be started\n";
|
806 |
95b003ff
|
Origo
|
my $networkstatus1 = $networkreg{$dom->{'networkuuid1'}}->{status};
|
807 |
|
|
my $networkstatus2 = ($networkreg{$dom->{'networkuuid2'}})?$networkreg{$dom->{'networkuuid2'}}->{status}:'';
|
808 |
|
|
my $networkstatus3 = ($networkreg{$dom->{'networkuuid3'}})?$networkreg{$dom->{'networkuuid3'}}->{status}:'';
|
809 |
|
|
my @dnets;
|
810 |
|
|
push @dnets, $dom->{'networkuuid1'} if ($dom->{'networkuuid1'} && $dom->{'networkuuid1'} ne '--' && $networkstatus1 ne 'up');
|
811 |
|
|
push @dnets, $dom->{'networkuuid2'} if ($dom->{'networkuuid2'} && $dom->{'networkuuid2'} ne '--' && $networkstatus2 ne 'up');
|
812 |
|
|
push @dnets, $dom->{'networkuuid3'} if ($dom->{'networkuuid3'} && $dom->{'networkuuid3'} ne '--' && $networkstatus3 ne 'up');
|
813 |
|
|
my $i;
|
814 |
|
|
for ($i=0; $i<5; $i++) { # wait for status newer than 10 secs
|
815 |
|
|
validateItem($dom);
|
816 |
|
|
last if (time() - $dom->{timestamp} < 10);
|
817 |
2a63870a
|
Christian Orellana
|
$mes = "Waiting for newer timestamp, current is " . (time() - $dom->{timestamp}) . " old\n";
|
818 |
95b003ff
|
Origo
|
print $mes if ($console);
|
819 |
|
|
$res .= $mes;
|
820 |
|
|
sleep 2;
|
821 |
|
|
}
|
822 |
|
|
if (
|
823 |
|
|
$dom->{'status'} eq 'shutoff' || $dom->{'status'} eq 'inactive'
|
824 |
|
|
) {
|
825 |
|
|
if ($action eq "showautostart") { # Dry run
|
826 |
|
|
$mes = "Starting $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'})\n";
|
827 |
|
|
print $mes if ($console);
|
828 |
|
|
$res .= $mes;
|
829 |
|
|
}
|
830 |
|
|
else {
|
831 |
|
|
$mes = "Starting $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'})\n";
|
832 |
|
|
print $mes if ($console);
|
833 |
|
|
$res .= $mes;
|
834 |
|
|
$postreply = Start($dom->{'uuid'});
|
835 |
|
|
print $postreply if ($console);
|
836 |
|
|
$res .= $postreply;
|
837 |
48fcda6b
|
Origo
|
# $mes = `REMOTE_USER=$dom->{'user'} $base/cgi/servers.cgi -a start -u $dom->{'uuid'}`;
|
838 |
|
|
print $mes if ($console);
|
839 |
|
|
$res .= $mes;
|
840 |
95b003ff
|
Origo
|
sleep 1;
|
841 |
|
|
}
|
842 |
|
|
}
|
843 |
|
|
elsif (@dnets) {
|
844 |
|
|
if ($action eq "showautostart") { # Dry run
|
845 |
|
|
foreach my $networkuuid (@dnets) {
|
846 |
|
|
$mes = "Would bring network $networkreg{$networkuuid}->{name} up for $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'})\n";
|
847 |
|
|
print $mes if ($console);
|
848 |
|
|
$res .= $mes;
|
849 |
|
|
}
|
850 |
|
|
}
|
851 |
|
|
else {
|
852 |
|
|
foreach my $networkuuid (@dnets) {
|
853 |
|
|
$mes = "Bringing network $networkreg{$networkuuid}->{name} up for $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'})\n";
|
854 |
|
|
print $mes if ($console);
|
855 |
|
|
$res .= $mes;
|
856 |
|
|
$mes = Stabile::Networks::Activate($networkuuid, 'activate');
|
857 |
|
|
print $mes if ($console);
|
858 |
|
|
$res .= $mes;
|
859 |
|
|
sleep 1;
|
860 |
|
|
}
|
861 |
|
|
}
|
862 |
|
|
}
|
863 |
2a63870a
|
Christian Orellana
|
} else {
|
864 |
|
|
$res .= "Not marked for autostart $dom->{'name'} ($dom->{'user'}, $dom->{'uuid'})\n";
|
865 |
95b003ff
|
Origo
|
}
|
866 |
|
|
}
|
867 |
|
|
}
|
868 |
|
|
return $res;
|
869 |
|
|
}
|
870 |
|
|
|
871 |
|
|
sub do_listnodeavailability {
|
872 |
|
|
if ($help) {
|
873 |
|
|
return <<END
|
874 |
|
|
GET::
|
875 |
|
|
Utility call - only informational. Shows availability of nodes for starting servers.
|
876 |
|
|
END
|
877 |
|
|
}
|
878 |
|
|
my $res;
|
879 |
|
|
$res .= $Stabile::q->header('application/json') unless ($console);
|
880 |
|
|
my ($temp1, $temp2, $temp3, $temp4, $ahashref) = locateTargetNode();
|
881 |
|
|
my @avalues = values %$ahashref;
|
882 |
|
|
my @sorted_values = (sort {$b->{'index'} <=> $a->{'index'}} @avalues);
|
883 |
|
|
$res .= to_json(\@sorted_values, { pretty => 1 });
|
884 |
|
|
return $res;
|
885 |
|
|
}
|
886 |
|
|
|
887 |
|
|
sub do_listbillingdata {
|
888 |
|
|
if ($help) {
|
889 |
|
|
return <<END
|
890 |
|
|
GET::
|
891 |
|
|
List current billing data.
|
892 |
|
|
END
|
893 |
|
|
}
|
894 |
|
|
my $res;
|
895 |
|
|
$res .= $Stabile::q->header('application/json') unless ($console);
|
896 |
|
|
my $buser = URI::Escape::uri_unescape($params{'user'}) || $user;
|
897 |
|
|
my %b;
|
898 |
|
|
my @bmonths;
|
899 |
|
|
if ($isadmin || $buser eq $user) {
|
900 |
|
|
my $bmonth = URI::Escape::uri_unescape($params{'month'}) || $month;
|
901 |
|
|
my $byear = URI::Escape::uri_unescape($params{'year'}) || $year;
|
902 |
|
|
if ($bmonth eq "all") {
|
903 |
|
|
@bmonths = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12");
|
904 |
|
|
}
|
905 |
|
|
else {
|
906 |
|
|
@bmonths = ($bmonth);
|
907 |
|
|
}
|
908 |
|
|
|
909 |
|
|
unless ( tie(%billingreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_domains', key=>'usernodetime'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
910 |
|
|
|
911 |
|
|
my @nkeys = keys %nodereg;
|
912 |
|
|
foreach my $bm (@bmonths) {
|
913 |
|
|
my $vcpuavg = 0;
|
914 |
|
|
my $memoryavg = 0;
|
915 |
|
|
foreach my $nmac (@nkeys) {
|
916 |
|
|
$vcpuavg += $billingreg{"$buser-$nmac-$byear-$bm"}->{'vcpuavg'};
|
917 |
|
|
$memoryavg += $billingreg{"$buser-$nmac-$byear-$bm"}->{'memoryavg'};
|
918 |
|
|
}
|
919 |
|
|
$b{"$buser-$byear-$bm"} = {
|
920 |
|
|
id => "$buser-$byear-$bm",
|
921 |
|
|
vcpuavg => $vcpuavg,
|
922 |
|
|
memoryavg => $memoryavg,
|
923 |
|
|
month => $bm + 0,
|
924 |
|
|
year => $byear + 0
|
925 |
|
|
}
|
926 |
|
|
}
|
927 |
|
|
untie %billingreg;
|
928 |
|
|
}
|
929 |
|
|
my @bvalues = values %b;
|
930 |
|
|
$res .= "{\"identifier\": \"id\", \"label\": \"id\", \"items\":" . to_json(\@bvalues) . "}";
|
931 |
|
|
return $res;
|
932 |
|
|
}
|
933 |
|
|
|
934 |
|
|
# Print list of available actions on objects
|
935 |
|
|
sub do_plainhelp {
|
936 |
|
|
my $res;
|
937 |
|
|
$res .= $Stabile::q->header('text/plain') unless $console;
|
938 |
|
|
$res .= <<END
|
939 |
|
|
new [name="name"]
|
940 |
|
|
* start: Starts a server
|
941 |
|
|
* destroy: Destroys a server, i.e. terminates the VM, equivalent of turning the power off a physical computer
|
942 |
|
|
* shutdown: Asks the operating system of a server to shut down via ACPI
|
943 |
|
|
* suspend: Suspends the VM, effectively putting the server to sleep
|
944 |
|
|
* resume: Resumes a suspended VM, effectively waking the server from sleep
|
945 |
|
|
* move [mac="mac"]: Moves a server to specified node. If no node is specified, moves to other node with highest availability
|
946 |
|
|
index
|
947 |
|
|
* delete: Deletes a server. Image and network are not deleted, only information about the server. Server cannot be
|
948 |
|
|
runing
|
949 |
|
|
* mountcd [cdrom="path"]: Mounts a cd rom
|
950 |
|
|
END
|
951 |
|
|
;
|
952 |
|
|
return $res;
|
953 |
|
|
}
|
954 |
|
|
|
955 |
|
|
# Helper function
|
956 |
|
|
sub recurse($) {
|
957 |
|
|
my($path) = @_;
|
958 |
|
|
my @files;
|
959 |
|
|
## append a trailing / if it's not there
|
960 |
|
|
$path .= '/' if($path !~ /\/$/);
|
961 |
|
|
## loop through the files contained in the directory
|
962 |
|
|
for my $eachFile (glob($path.'*')) {
|
963 |
|
|
## if the file is a directory
|
964 |
|
|
if( -d $eachFile) {
|
965 |
|
|
## pass the directory to the routine ( recursion )
|
966 |
|
|
push(@files,recurse($eachFile));
|
967 |
|
|
} else {
|
968 |
|
|
push(@files,$eachFile);
|
969 |
|
|
}
|
970 |
|
|
}
|
971 |
|
|
return @files;
|
972 |
|
|
}
|
973 |
|
|
|
974 |
|
|
sub Start {
|
975 |
|
|
my ($uuid, $action, $obj) = @_;
|
976 |
|
|
$dmac = $obj->{mac};
|
977 |
|
|
$buildsystem = $obj->{buildsystem};
|
978 |
|
|
$uistatus = $obj->{uistatus};
|
979 |
|
|
if ($help) {
|
980 |
|
|
return <<END
|
981 |
|
|
GET:uuid,mac:
|
982 |
|
|
Start a server. Supply mac for starting on specific node.
|
983 |
|
|
END
|
984 |
|
|
}
|
985 |
|
|
$dmac = $dmac || $params{'mac'};
|
986 |
|
|
return "Status=ERROR No uuid\n" unless ($register{$uuid});
|
987 |
|
|
my $serv = $register{$uuid};
|
988 |
|
|
$postreply = '' if ($buildsystem);
|
989 |
|
|
|
990 |
|
|
my $name = $serv->{'name'};
|
991 |
|
|
utf8::decode($name);
|
992 |
|
|
my $image = $serv->{'image'};
|
993 |
|
|
my $image2 = $serv->{'image2'};
|
994 |
|
|
my $image3 = $serv->{'image3'};
|
995 |
|
|
my $image4 = $serv->{'image4'};
|
996 |
|
|
my $memory = $serv->{'memory'};
|
997 |
|
|
my $vcpu = $serv->{'vcpu'};
|
998 |
|
|
my $vgpu = $serv->{'vgpu'};
|
999 |
|
|
my $dbstatus = $serv->{'status'};
|
1000 |
|
|
my $mac = $serv->{'mac'};
|
1001 |
|
|
my $macname = $serv->{'macname'};
|
1002 |
|
|
my $networkuuid1 = $serv->{'networkuuid1'};
|
1003 |
|
|
my $networkuuid2 = $serv->{'networkuuid2'};
|
1004 |
|
|
my $networkuuid3 = $serv->{'networkuuid3'};
|
1005 |
|
|
my $nicmodel1 = $serv->{'nicmodel1'};
|
1006 |
|
|
my $nicmac1 = $serv->{'nicmac1'};
|
1007 |
|
|
my $nicmac2 = $serv->{'nicmac2'};
|
1008 |
|
|
my $nicmac3 = $serv->{'nicmac3'};
|
1009 |
|
|
my $boot = $serv->{'boot'};
|
1010 |
04c16f26
|
hq
|
my $loader = $serv->{'loader'};
|
1011 |
95b003ff
|
Origo
|
my $diskbus = $serv->{'diskbus'};
|
1012 |
|
|
my $cdrom = $serv->{'cdrom'};
|
1013 |
|
|
my $diskdev = "vda";
|
1014 |
|
|
my $diskdev2 = "vdb";
|
1015 |
|
|
my $diskdev3 = "vdc";
|
1016 |
|
|
my $diskdev4 = "vdd";
|
1017 |
|
|
if ($diskbus eq "ide") {$diskdev = "hda"; $diskdev2 = "hdb"; $diskdev3 = "hdc"; $diskdev4 = "hdd"};
|
1018 |
|
|
|
1019 |
|
|
my $mem = $memory * 1024;
|
1020 |
|
|
|
1021 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access image register"};
|
1022 |
|
|
|
1023 |
|
|
my $img = $imagereg{$image};
|
1024 |
|
|
my $imagename = $img->{'name'};
|
1025 |
|
|
my $imagestatus = $img->{'status'};
|
1026 |
|
|
my $img2 = $imagereg{$image2};
|
1027 |
|
|
my $image2status = $img2->{'status'};
|
1028 |
|
|
my $img3 = $imagereg{$image3};
|
1029 |
|
|
my $image3status = $img3->{'status'};
|
1030 |
|
|
my $img4 = $imagereg{$image4};
|
1031 |
|
|
my $image4status = $img4->{'status'};
|
1032 |
|
|
|
1033 |
|
|
if (!$imagereg{$image}) {
|
1034 |
|
|
$postreply .= "Status=Error Image $image not found - please select a new image for your server, not starting $name\n";
|
1035 |
|
|
untie %imagereg;
|
1036 |
|
|
return $postreply;
|
1037 |
|
|
}
|
1038 |
|
|
untie %imagereg;
|
1039 |
|
|
|
1040 |
|
|
if ($imagestatus ne "used" && $imagestatus ne "cloning") {
|
1041 |
|
|
$postreply .= "Status=ERROR Image $imagename $image is $imagestatus, not starting $name\n";
|
1042 |
|
|
} elsif ($image2 && $image2 ne '--' && $image2status ne "used" && $image2status ne "cloning") {
|
1043 |
|
|
$postreply .= "Status=ERROR Image2 is $image2status, not starting $name\n";
|
1044 |
|
|
} elsif ($image3 && $image3 ne '--' && $image3status ne "used" && $image3status ne "cloning") {
|
1045 |
|
|
$postreply .= "Status=ERROR Image3 is $image3status, not starting $name\n";
|
1046 |
|
|
} elsif ($image4 && $image4 ne '--' && $image4status ne "used" && $image4status ne "cloning") {
|
1047 |
|
|
$postreply .= "Status=ERROR Image4 is $image4status, not starting $name\n";
|
1048 |
|
|
} elsif (overQuotas($memory,$vcpu)) {
|
1049 |
|
|
$main::syslogit->($user, "info", "Over quota starting a $dbstatus domain: $uuid");
|
1050 |
|
|
$postreply .= "Status=ERROR Over quota - not starting $name\n";
|
1051 |
|
|
# Status inactive is typically caused by a movepiston having problems. We should not start inactive servers since
|
1052 |
|
|
# they could possibly be running even if movepiston is down. Movepiston on the node should be brought up to update
|
1053 |
|
|
# the status, or the node should be removed from the stabile.
|
1054 |
|
|
# We now allow to force start of inactive server when dmac is specified
|
1055 |
|
|
} elsif ((!$dmac || $dmac eq $mac) && $dbstatus eq 'inactive' && $nodereg{$mac} && ($nodereg{$mac}->{'status'} eq 'inactive' || $nodereg{$mac}->{'status'} eq 'shutdown')) {
|
1056 |
|
|
$main::syslogit->($user, "info", "Not starting inactive domain: $uuid (last seen on $mac)");
|
1057 |
|
|
$postreply .= "Status=ERROR Not starting $name - Please bring up node $macname\n";
|
1058 |
|
|
} elsif ($dbstatus eq 'inactive' || $dbstatus eq 'shutdown' || $dbstatus eq 'shutoff' || $dbstatus eq 'new') {
|
1059 |
|
|
unless ($dmac && $isadmin) {
|
1060 |
|
|
$dmac = $mac if ($dbstatus eq 'inactive'); # If movepiston crashed while shutting down, allow server to start on same node
|
1061 |
|
|
}
|
1062 |
|
|
$uistatus = "starting" unless ($uistatus);
|
1063 |
|
|
my $hypervisor = getHypervisor($image);
|
1064 |
|
|
my ($targetmac, $targetname, $targetip, $port) = locateTargetNode($uuid, $dmac, $mem, $vcpu, $image, $image2 ,$image3, $image4, $hypervisor);
|
1065 |
|
|
|
1066 |
|
|
# Build XML for starting domain
|
1067 |
|
|
my $graphics = "vnc";
|
1068 |
|
|
$graphics = "rdp" if ($hypervisor eq "vbox");
|
1069 |
|
|
my $net1 = $networkreg{$networkuuid1};
|
1070 |
|
|
my $networkid1 = $net1->{'id'}; # Get the current vlan id of the network
|
1071 |
|
|
my $net2 = $networkreg{$networkuuid2};
|
1072 |
|
|
my $networkid2 = $net2->{'id'}; # Get the current vlan id of the network
|
1073 |
|
|
my $net3 = $networkreg{$networkuuid2};
|
1074 |
|
|
my $networkid3 = $net3->{'id'}; # Get the current vlan id of the network
|
1075 |
|
|
my $networkid1ip = $net1->{'internalip'};
|
1076 |
|
|
$networkid1ip = $net1->{'externalip'} if ($net1->{'type'} eq 'externalip');
|
1077 |
|
|
|
1078 |
|
|
my $uname = $name . substr($uuid,0,8); # We don't enforce unique names, so we make them
|
1079 |
|
|
$uname =~ s/[^[:ascii:]]/_/g; # Get rid of funny chars - they mess up Guacamole
|
1080 |
|
|
$uname =~ s/\W/_/g;
|
1081 |
|
|
|
1082 |
|
|
my $driver1;
|
1083 |
|
|
my $driver2;
|
1084 |
|
|
if ($hypervisor eq 'kvm') {
|
1085 |
|
|
my $fmt1 = ($image =~ /\.qcow2$/)?'qcow2':'raw';
|
1086 |
|
|
my $fmt2 = ($image2 =~ /\.qcow2$/)?'qcow2':'raw';
|
1087 |
|
|
my $fmt3 = ($image3 =~ /\.qcow2$/)?'qcow2':'raw';
|
1088 |
|
|
my $fmt4 = ($image4 =~ /\.qcow2$/)?'qcow2':'raw';
|
1089 |
2a63870a
|
Christian Orellana
|
my $cache1 = ($image =~ /\/node\//)?'default':'writeback';
|
1090 |
|
|
my $cache2 = ($image2 =~ /\/node\//)?'default':'writeback';
|
1091 |
|
|
my $cache3 = ($image3 =~ /\/node\//)?'default':'writeback';
|
1092 |
|
|
my $cache4 = ($image4 =~ /\/node\//)?'default':'writeback';
|
1093 |
|
|
$driver1 = "\n <driver name='qemu' type='$fmt1' cache='$cache1'/>";
|
1094 |
|
|
$driver2 = "\n <driver name='qemu' type='$fmt2' cache='$cache2'/>";
|
1095 |
|
|
$driver3 = "\n <driver name='qemu' type='$fmt3' cache='$cache3'/>";
|
1096 |
|
|
$driver4 = "\n <driver name='qemu' type='$fmt4' cache='$cache4'/>";
|
1097 |
95b003ff
|
Origo
|
}
|
1098 |
|
|
|
1099 |
|
|
my $networktype1 = "user";
|
1100 |
|
|
my $networksource1 = "default";
|
1101 |
|
|
my $networkforward1 = "bridge";
|
1102 |
|
|
my $networkisolated1 = "no";
|
1103 |
|
|
$networksource1 = "vboxnet0" if ($hypervisor eq "vbox");
|
1104 |
|
|
if ($networkid1 eq '0') {
|
1105 |
|
|
$networktype1 = "user";
|
1106 |
|
|
$networkforward1 = "nat";
|
1107 |
|
|
$networkisolated1 = "yes"
|
1108 |
|
|
} elsif ($networkid1 == 1) {
|
1109 |
|
|
$networktype1 = "network" ;
|
1110 |
|
|
$networkforward1 = "nat";
|
1111 |
|
|
$networkisolated1 = "yes"
|
1112 |
|
|
} elsif ($networkid1 > 1) {
|
1113 |
|
|
$networktype1 = "bridge";
|
1114 |
|
|
$networksource1 = "br$networkid1";
|
1115 |
|
|
}
|
1116 |
|
|
my $networktype2 = "user";
|
1117 |
|
|
my $networksource2 = "default";
|
1118 |
|
|
my $networkforward2 = "bridge";
|
1119 |
|
|
my $networkisolated2 = "no";
|
1120 |
|
|
$networksource2 = "vboxnet0" if ($hypervisor eq "vbox");
|
1121 |
|
|
if ($networkid2 eq '0') {
|
1122 |
|
|
$networktype2 = "user";
|
1123 |
|
|
$networkforward2 = "nat";
|
1124 |
|
|
$networkisolated2 = "yes"
|
1125 |
|
|
} elsif ($networkid2 == 1) {
|
1126 |
|
|
$networktype2 = "network" ;
|
1127 |
|
|
$networkforward2 = "nat";
|
1128 |
|
|
$networkisolated2 = "yes"
|
1129 |
|
|
} elsif ($networkid2 > 1) {
|
1130 |
|
|
$networktype2 = "bridge";
|
1131 |
|
|
$networksource2 = "br$networkid2";
|
1132 |
|
|
}
|
1133 |
|
|
my $networktype3 = "user";
|
1134 |
|
|
my $networksource3 = "default";
|
1135 |
|
|
my $networkforward3 = "bridge";
|
1136 |
|
|
my $networkisolated3 = "no";
|
1137 |
|
|
$networksource3 = "vboxnet0" if ($hypervisor eq "vbox");
|
1138 |
|
|
if ($networkid3 eq '0') {
|
1139 |
|
|
$networktype3 = "user";
|
1140 |
|
|
$networkforward3 = "nat";
|
1141 |
|
|
$networkisolated3 = "yes"
|
1142 |
|
|
} elsif ($networkid3 == 1) {
|
1143 |
|
|
$networktype3 = "network" ;
|
1144 |
|
|
$networkforward3 = "nat";
|
1145 |
|
|
$networkisolated3 = "yes"
|
1146 |
|
|
} elsif ($networkid3 > 1) {
|
1147 |
|
|
$networktype3 = "bridge";
|
1148 |
|
|
$networksource3 = "br$networkid3";
|
1149 |
|
|
}
|
1150 |
|
|
|
1151 |
|
|
my $xml = "<domain type='$hypervisor' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>\n";
|
1152 |
|
|
# if ($vgpu && $vgpu ne "--") {
|
1153 |
|
|
# $xml .= <<ENDXML2
|
1154 |
|
|
# <qemu:commandline>
|
1155 |
|
|
# <qemu:arg value='-device'/>
|
1156 |
|
|
# <qemu:arg value='vfio-pci,host=01:00.0,x-vga=on'/>
|
1157 |
|
|
# <qemu:arg value='-device'/>
|
1158 |
|
|
# <qemu:arg value='vfio-pci,host=02:00.0,x-vga=on'/>
|
1159 |
|
|
# </qemu:commandline>
|
1160 |
|
|
#ENDXML2
|
1161 |
|
|
# ;
|
1162 |
|
|
# }
|
1163 |
|
|
|
1164 |
|
|
# <qemu:arg value='-set'/>
|
1165 |
|
|
# <qemu:arg value='device.hostdev1.x-vga=on'/>
|
1166 |
|
|
# <qemu:arg value='-cpu'/>
|
1167 |
|
|
# <qemu:arg value='host,kvm=off'/>
|
1168 |
|
|
# <qemu:arg value='-device'/>
|
1169 |
|
|
# <qemu:arg value='pci-assign,host=01:00.0,id=hostdev0,configfd=20,bus=pci.0,addr=0x6,x-pci-vendor-id=0x10DE,x-pci-device-id=0x11BA,x-pci-sub-vendor-id=0x10DE,x-pci-sub-device-id=0x0965'/>
|
1170 |
|
|
|
1171 |
|
|
# <cpu mode='host-model'>
|
1172 |
|
|
# <vendor>Intel</vendor>
|
1173 |
|
|
# <model>core2duo</model>
|
1174 |
|
|
# </cpu>
|
1175 |
|
|
|
1176 |
|
|
# <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
|
1177 |
|
|
# <nvram template='/usr/share/OVMF/OVMF_VARS.fd'/>
|
1178 |
04c16f26
|
hq
|
my $loader_xml = <<ENDXML
|
1179 |
|
|
<bootmenu enable='yes' timeout='200'/>
|
1180 |
|
|
<smbios mode='sysinfo'/>
|
1181 |
|
|
ENDXML
|
1182 |
|
|
;
|
1183 |
|
|
if ($loader eq 'uefi') {
|
1184 |
|
|
$loader_xml = <<ENDXML
|
1185 |
|
|
<loader readonly='yes' secure='no' type='pflash'>/usr/share/ovmf/OVMF.fd</loader>
|
1186 |
|
|
<nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/tmp/guest_VARS.fd</nvram>
|
1187 |
|
|
ENDXML
|
1188 |
|
|
;
|
1189 |
|
|
}
|
1190 |
95b003ff
|
Origo
|
|
1191 |
705b5366
|
hq
|
if ($vgpu && $vgpu ne "--") {
|
1192 |
|
|
$xml .= <<ENDXML
|
1193 |
95b003ff
|
Origo
|
<cpu mode='host-passthrough'>
|
1194 |
|
|
<feature policy='disable' name='hypervisor'/>
|
1195 |
|
|
</cpu>
|
1196 |
|
|
ENDXML
|
1197 |
|
|
;
|
1198 |
705b5366
|
hq
|
} else {
|
1199 |
|
|
$xml .= <<ENDXML
|
1200 |
|
|
<cpu mode='host-model'>
|
1201 |
|
|
</cpu>
|
1202 |
|
|
ENDXML
|
1203 |
|
|
;
|
1204 |
95b003ff
|
Origo
|
}
|
1205 |
|
|
$xml .= <<ENDXML
|
1206 |
|
|
<name>$uname</name>
|
1207 |
|
|
<uuid>$uuid</uuid>
|
1208 |
|
|
<memory>$mem</memory>
|
1209 |
|
|
<vcpu>$vcpu</vcpu>
|
1210 |
|
|
<os>
|
1211 |
|
|
<type arch='x86_64' machine='pc'>hvm</type>
|
1212 |
|
|
<boot dev='$boot'/>
|
1213 |
04c16f26
|
hq
|
$loader_xml
|
1214 |
95b003ff
|
Origo
|
</os>
|
1215 |
|
|
<sysinfo type='smbios'>
|
1216 |
|
|
<bios>
|
1217 |
|
|
<entry name='vendor'>Origo</entry>
|
1218 |
|
|
</bios>
|
1219 |
|
|
<system>
|
1220 |
|
|
<entry name='manufacturer'>Origo</entry>
|
1221 |
|
|
<entry name='sku'>$networkid1ip</entry>
|
1222 |
|
|
</system>
|
1223 |
|
|
</sysinfo>
|
1224 |
|
|
<features>
|
1225 |
|
|
ENDXML
|
1226 |
|
|
;
|
1227 |
|
|
if ($vgpu && $vgpu ne "--") { $xml .= <<ENDXML
|
1228 |
|
|
<kvm>
|
1229 |
|
|
<hidden state='on'/>
|
1230 |
|
|
</kvm>
|
1231 |
|
|
ENDXML
|
1232 |
|
|
;
|
1233 |
|
|
}
|
1234 |
|
|
$xml .= <<ENDXML
|
1235 |
|
|
<pae/>
|
1236 |
|
|
<acpi/>
|
1237 |
|
|
<apic/>
|
1238 |
|
|
</features>
|
1239 |
|
|
<clock offset='localtime'>
|
1240 |
|
|
<timer name='rtc' tickpolicy='catchup' track='guest'/>
|
1241 |
|
|
<timer name='pit' tickpolicy='delay'/>
|
1242 |
|
|
<timer name='hpet' present='no'/>
|
1243 |
|
|
</clock>
|
1244 |
|
|
<on_poweroff>destroy</on_poweroff>
|
1245 |
04c16f26
|
hq
|
<on_reboot>restart</on_reboot>½
|
1246 |
95b003ff
|
Origo
|
<on_crash>restart</on_crash>
|
1247 |
|
|
<devices>
|
1248 |
e837d785
|
hq
|
<sound model='ich6'/>
|
1249 |
95b003ff
|
Origo
|
ENDXML
|
1250 |
|
|
;
|
1251 |
|
|
# if ($vgpu && $vgpu ne "--") {
|
1252 |
|
|
# $xml .= <<ENDXML2
|
1253 |
|
|
# <hostdev mode='subsystem' type='pci' managed='yes'>
|
1254 |
|
|
# <source>
|
1255 |
|
|
# <address domain='0x0000' bus='0x01' slot='0x00' function='0x0' multifunction='on'/>
|
1256 |
|
|
# </source>
|
1257 |
|
|
# </hostdev>
|
1258 |
|
|
# <hostdev mode='subsystem' type='pci' managed='yes'>
|
1259 |
|
|
# <source>
|
1260 |
|
|
# <address domain='0x0000' bus='0x02' slot='0x00' function='0x0' multifunction='on'/>
|
1261 |
|
|
# </source>
|
1262 |
|
|
# </hostdev>
|
1263 |
|
|
#ENDXML2
|
1264 |
|
|
#;
|
1265 |
|
|
# }
|
1266 |
|
|
if ($image && $image ne "" && $image ne "--") {
|
1267 |
|
|
$xml .= <<ENDXML2
|
1268 |
|
|
<disk type='file' device='disk'>
|
1269 |
|
|
<source file='$image'/>$driver1
|
1270 |
|
|
<target dev='$diskdev' bus='$diskbus'/>
|
1271 |
|
|
</disk>
|
1272 |
|
|
ENDXML2
|
1273 |
|
|
;
|
1274 |
|
|
};
|
1275 |
|
|
|
1276 |
|
|
if ($image2 && $image2 ne "" && $image2 ne "--") {
|
1277 |
|
|
$xml .= <<ENDXML2
|
1278 |
|
|
<disk type='file' device='disk'>$driver2
|
1279 |
|
|
<source file='$image2'/>
|
1280 |
|
|
<target dev='$diskdev2' bus='$diskbus'/>
|
1281 |
|
|
</disk>
|
1282 |
|
|
ENDXML2
|
1283 |
|
|
;
|
1284 |
|
|
};
|
1285 |
|
|
if ($image3 && $image3 ne "" && $image3 ne "--") {
|
1286 |
|
|
$xml .= <<ENDXML2
|
1287 |
|
|
<disk type='file' device='disk'>$driver3
|
1288 |
|
|
<source file='$image3'/>
|
1289 |
|
|
<target dev='$diskdev3' bus='$diskbus'/>
|
1290 |
|
|
</disk>
|
1291 |
|
|
ENDXML2
|
1292 |
|
|
;
|
1293 |
|
|
};
|
1294 |
|
|
if ($image4 && $image4 ne "" && $image4 ne "--") {
|
1295 |
|
|
$xml .= <<ENDXML2
|
1296 |
|
|
<disk type='file' device='disk'>$driver4
|
1297 |
|
|
<source file='$image4'/>
|
1298 |
|
|
<target dev='$diskdev4' bus='$diskbus'/>
|
1299 |
|
|
</disk>
|
1300 |
|
|
ENDXML2
|
1301 |
|
|
;
|
1302 |
|
|
};
|
1303 |
|
|
|
1304 |
|
|
unless ($image4 && $image4 ne '--' && $diskbus eq 'ide') {
|
1305 |
|
|
if ($cdrom && $cdrom ne "" && $cdrom ne "--") {
|
1306 |
|
|
$xml .= <<ENDXML3
|
1307 |
|
|
<disk type='file' device='cdrom'>
|
1308 |
|
|
<source file='$cdrom'/>
|
1309 |
|
|
<target dev='hdd' bus='ide'/>
|
1310 |
|
|
<readonly/>
|
1311 |
|
|
</disk>
|
1312 |
|
|
ENDXML3
|
1313 |
|
|
;
|
1314 |
|
|
} elsif ($hypervisor ne "vbox") {
|
1315 |
|
|
$xml .= <<ENDXML3
|
1316 |
|
|
<disk type='file' device='cdrom'>
|
1317 |
|
|
<target dev='hdd' bus='ide'/>
|
1318 |
|
|
<readonly/>
|
1319 |
|
|
</disk>
|
1320 |
|
|
ENDXML3
|
1321 |
|
|
;
|
1322 |
|
|
}
|
1323 |
|
|
}
|
1324 |
|
|
|
1325 |
|
|
$xml .= <<ENDXML4
|
1326 |
|
|
<interface type='$networktype1'>
|
1327 |
|
|
<source $networktype1='$networksource1'/>
|
1328 |
|
|
<forward mode='$networkforward1'/>
|
1329 |
|
|
<port isolated='$networkisolated1'/>
|
1330 |
|
|
<model type='$nicmodel1'/>
|
1331 |
|
|
<mac address='$nicmac1'/>
|
1332 |
|
|
</interface>
|
1333 |
|
|
ENDXML4
|
1334 |
|
|
;
|
1335 |
|
|
|
1336 |
|
|
if (($networkuuid2 && $networkuuid2 ne '--') || $networkuuid2 eq '0') {
|
1337 |
|
|
$xml .= <<ENDXML5
|
1338 |
|
|
<interface type='$networktype2'>
|
1339 |
|
|
<source $networktype2='$networksource2'/>
|
1340 |
|
|
<forward mode='$networkforward2'/>
|
1341 |
|
|
<port isolated='$networkisolated2'/>
|
1342 |
|
|
<model type='$nicmodel1'/>
|
1343 |
|
|
<mac address='$nicmac2'/>
|
1344 |
|
|
</interface>
|
1345 |
|
|
ENDXML5
|
1346 |
|
|
;
|
1347 |
|
|
}
|
1348 |
|
|
if (($networkuuid3 && $networkuuid3 ne '--') || $networkuuid3 eq '0') {
|
1349 |
|
|
$xml .= <<ENDXML5
|
1350 |
|
|
<interface type='$networktype3'>
|
1351 |
|
|
<source $networktype3='$networksource3'/>
|
1352 |
|
|
<forward mode='$networkforward3'/>
|
1353 |
|
|
<port isolated='$networkisolated3'/>
|
1354 |
|
|
<model type='$nicmodel1'/>
|
1355 |
|
|
<mac address='$nicmac3'/>
|
1356 |
|
|
</interface>
|
1357 |
|
|
ENDXML5
|
1358 |
|
|
;
|
1359 |
|
|
}
|
1360 |
|
|
$xml .= <<ENDXML6
|
1361 |
|
|
<serial type='pty'>
|
1362 |
|
|
<source path='/dev/pts/0'/>
|
1363 |
|
|
<target port='0'/>
|
1364 |
|
|
</serial>
|
1365 |
|
|
<input type='tablet' bus='usb'/>
|
1366 |
|
|
<graphics type='$graphics' port='$port'/>
|
1367 |
|
|
</devices>
|
1368 |
|
|
</domain>
|
1369 |
|
|
ENDXML6
|
1370 |
|
|
;
|
1371 |
|
|
|
1372 |
|
|
|
1373 |
|
|
# <graphics type='$graphics' port='$port' keymap='en-us'/>
|
1374 |
|
|
# <console type='pty' tty='/dev/pts/0'>
|
1375 |
|
|
# <source path='/dev/pts/0'/>
|
1376 |
|
|
# <target port='0'/>
|
1377 |
|
|
# </console>
|
1378 |
|
|
# <graphics type='$graphics' port='-1' autoport='yes'/>
|
1379 |
|
|
|
1380 |
|
|
$xmlreg{$uuid} = {
|
1381 |
|
|
xml=>URI::Escape::uri_escape($xml)
|
1382 |
|
|
};
|
1383 |
|
|
|
1384 |
|
|
# Actually ask node to start domain
|
1385 |
|
|
if ($targetmac) {
|
1386 |
|
|
$register{$uuid}->{'mac'} = $targetmac;
|
1387 |
|
|
$register{$uuid}->{'macname'} = $targetname;
|
1388 |
|
|
$register{$uuid}->{'macip'} = $targetip;
|
1389 |
|
|
|
1390 |
|
|
my $tasks = $nodereg{$targetmac}->{'tasks'};
|
1391 |
|
|
$tasks .= "START $uuid $user\n";
|
1392 |
|
|
# Also update allowed port forwards - obsolete
|
1393 |
|
|
# $tasks .= "PERMITOPEN $user\n";
|
1394 |
|
|
$nodereg{$targetmac}->{'tasks'} = $tasks;
|
1395 |
|
|
tied(%nodereg)->commit;
|
1396 |
|
|
$uiuuid = $uuid;
|
1397 |
|
|
$uidisplayip = $targetip;
|
1398 |
|
|
$uidisplayport = $port;
|
1399 |
|
|
$register{$uuid}->{'status'} = $uistatus;
|
1400 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
1401 |
|
|
tied(%register)->commit;
|
1402 |
|
|
|
1403 |
|
|
# Activate networks
|
1404 |
|
|
require "$Stabile::basedir/cgi/networks.cgi";
|
1405 |
|
|
Stabile::Networks::Activate($networkuuid1, 'activate');
|
1406 |
|
|
Stabile::Networks::Activate($networkuuid2, 'activate') if ($networkuuid2 && $networkuuid2 ne '--');
|
1407 |
|
|
Stabile::Networks::Activate($networkuuid3, 'activate') if ($networkuuid3 && $networkuuid3 ne '--');
|
1408 |
|
|
|
1409 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for ". $serv->{'status'} . " on $targetname ($targetmac)");
|
1410 |
|
|
$postreply .= "Status=starting OK $uistatus ". $serv->{'name'} . "\n";
|
1411 |
|
|
} else {
|
1412 |
|
|
$main::syslogit->($user, "info", "Could not find $hypervisor target for creating $uuid ($image)");
|
1413 |
|
|
$postreply .= "Status=ERROR problem $uistatus ". $serv->{'name'} . " (unable to locate target node)\n";
|
1414 |
|
|
};
|
1415 |
|
|
} else {
|
1416 |
|
|
$main::syslogit->($user, "info", "Problem $uistatus a $dbstatus domain: $uuid");
|
1417 |
|
|
$postreply .= "Status=ERROR problem $uistatus ". $serv->{'name'} . "\n";
|
1418 |
|
|
}
|
1419 |
|
|
#return ($uiuuid, $uidisplayip, $uidisplayport, $postreply, $targetmac);
|
1420 |
|
|
return $postreply;
|
1421 |
|
|
}
|
1422 |
|
|
|
1423 |
|
|
sub do_attach {
|
1424 |
|
|
my ($uuid, $action, $obj) = @_;
|
1425 |
|
|
if ($help) {
|
1426 |
|
|
return <<END
|
1427 |
|
|
GET:uuid,image:
|
1428 |
|
|
Attaches an image to a server as a disk device. Image must not be in use.
|
1429 |
|
|
END
|
1430 |
|
|
}
|
1431 |
|
|
my $dev = '';
|
1432 |
|
|
my $imagenum = 0;
|
1433 |
|
|
my $serv = $register{$uuid};
|
1434 |
|
|
|
1435 |
|
|
if (!$serv->{'uuid'} || ($serv->{'status'} ne 'running' && $serv->{'status'} ne 'paused')) {
|
1436 |
|
|
return "Status=Error Server must exist and be running\n";
|
1437 |
|
|
}
|
1438 |
|
|
my $macip = $serv->{macip};
|
1439 |
|
|
my $image = $obj->{image} || $obj->{path};
|
1440 |
|
|
if ($image && !($image =~ /^\//)) { # We have a uuid
|
1441 |
|
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {return "Status=Error Unable to access images register\n"};
|
1442 |
|
|
$image = $imagereg2{$image}->{'path'} if ($imagereg2{$image});
|
1443 |
|
|
untie %imagereg2;
|
1444 |
|
|
}
|
1445 |
|
|
unless (tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$postreply .= "Status=Error Unable to access images register\n"; return $postreply;};
|
1446 |
|
|
unless ($macip && $imagereg{$image} && $imagereg{$image}->{'user'} eq $user && $serv->{'user'} eq $user) {$postreply .= "Status=Error Invalid image or server\n"; return $postreply;};
|
1447 |
|
|
if ($imagereg{$image}->{'status'} ne 'unused') {return "Status=Error Image $image is already in use ($imagereg{$image}->{'status'})\n"};
|
1448 |
|
|
|
1449 |
|
|
my $cmd = qq|$sshcmd $macip "LIBVIRT_DEFAULT_URI=qemu:///system virsh domblklist $uuid"|;
|
1450 |
|
|
my $res = `$cmd`;
|
1451 |
|
|
unless ($res =~ /vdb\s+.+/) {$dev = 'vdb'; $imagenum = 2};
|
1452 |
|
|
unless ($dev || $res =~ /vdc\s+.+/) {$dev = 'vdc'; $imagenum = 3};
|
1453 |
|
|
unless ($dev || $res =~ /vdd\s+.+/) {$dev = 'vdd'; $imagenum = 4};
|
1454 |
|
|
if (!$dev) {
|
1455 |
|
|
$postreply = "Status=Error No more images can be attached\n";
|
1456 |
|
|
} else {
|
1457 |
|
|
my $xml = <<END
|
1458 |
|
|
<disk type='file' device='disk'>
|
1459 |
|
|
<driver type='qcow2' name='qemu' cache='default'/>
|
1460 |
|
|
<source file='$image'/>
|
1461 |
|
|
<target dev='$dev' bus='virtio'/>
|
1462 |
|
|
</disk>
|
1463 |
|
|
END
|
1464 |
|
|
;
|
1465 |
|
|
$cmd = qq|$sshcmd $macip "echo \\"$xml\\" > /tmp/attach-device-$uuid.xml"|;
|
1466 |
|
|
$res = `$cmd`;
|
1467 |
|
|
$res .= `$sshcmd $macip LIBVIRT_DEFAULT_URI=qemu:///system virsh attach-device $uuid /tmp/attach-device-$uuid.xml`;
|
1468 |
|
|
chomp $res;
|
1469 |
|
|
if ($res =~ /successfully/) {
|
1470 |
|
|
$postreply .= "Status=OK Attaching $image to $dev\n";
|
1471 |
|
|
$imagereg{$image}->{'status'} = 'active';
|
1472 |
|
|
$imagereg{$image}->{'domains'} = $uuid;
|
1473 |
|
|
$imagereg{$image}->{'domainnames'} = $serv->{'name'};
|
1474 |
|
|
$serv->{"image$imagenum"} = $image;
|
1475 |
|
|
$serv->{"image$imagenum"."name"} = $imagereg{$image}->{'name'};
|
1476 |
|
|
$serv->{"image$imagenum"."type"} = 'qcow2';
|
1477 |
|
|
} else {
|
1478 |
|
|
$postreply .= "Status=Error Unable to attach image $image to $dev ($res)\n";
|
1479 |
|
|
}
|
1480 |
|
|
}
|
1481 |
|
|
untie %imagereg;
|
1482 |
|
|
return $postreply;
|
1483 |
|
|
}
|
1484 |
|
|
|
1485 |
|
|
sub do_detach {
|
1486 |
|
|
my ($uuid, $action, $obj) = @_;
|
1487 |
|
|
if ($help) {
|
1488 |
|
|
return <<END
|
1489 |
|
|
GET:uuid,image:
|
1490 |
|
|
Detaches a disk device and the associated image from a running server. All associated file-systems within the server should be unmounted before detaching, otherwise data loss i very probable. Use with care.
|
1491 |
|
|
END
|
1492 |
|
|
}
|
1493 |
|
|
my $dev = '';
|
1494 |
|
|
my $serv = $register{$uuid};
|
1495 |
|
|
|
1496 |
|
|
if (!$serv->{'uuid'} || ($serv->{'status'} ne 'running' && $serv->{'status'} ne 'paused')) {
|
1497 |
|
|
return "Status=Error Server must exist and be running\n";
|
1498 |
|
|
}
|
1499 |
|
|
my $macip = $serv->{macip};
|
1500 |
|
|
|
1501 |
|
|
my $image = $obj->{image} || $obj->{path} || $serv->{'image2'};
|
1502 |
|
|
if ($image && !($image =~ /^\//)) { # We have a uuid
|
1503 |
|
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
1504 |
|
|
$image = $imagereg2{$image}->{'path'} if ($imagereg2{$image});
|
1505 |
|
|
untie %imagereg2;
|
1506 |
|
|
}
|
1507 |
|
|
unless (tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$postreply .= "Status=Error Unable to access images register\n"; return $postreply;};
|
1508 |
|
|
unless ($macip && $imagereg{$image} && $imagereg{$image}->{'user'} eq $user && $serv->{'user'} eq $user) {$postreply .= "Status=Error Invalid image or server. Server must have a secondary image attached.\n"; return $postreply;};
|
1509 |
|
|
|
1510 |
|
|
my $cmd = qq|$sshcmd $macip "LIBVIRT_DEFAULT_URI=qemu:///system virsh domblklist $uuid"|;
|
1511 |
|
|
my $res = `$cmd`;
|
1512 |
|
|
$dev = $1 if ($res =~ /(vd.)\s+.+$image/);
|
1513 |
|
|
if (!$dev) {
|
1514 |
|
|
$postreply = qq|Status=Error Image $image, $cmd, is not currently attached\n|;
|
1515 |
|
|
} elsif ($dev eq 'vda') {
|
1516 |
|
|
$postreply = "Status=Error You cannot detach the primary image\n";
|
1517 |
|
|
} else {
|
1518 |
|
|
$res = `$sshcmd $macip LIBVIRT_DEFAULT_URI=qemu:///system virsh detach-disk $uuid $dev`;
|
1519 |
|
|
chomp $res;
|
1520 |
|
|
if ($res =~ /successfully/) {
|
1521 |
|
|
$postreply .= "Status=OK Detaching image $image, $imagereg{$image}->{'uuid'} from $dev\n";
|
1522 |
|
|
my $imagenum;
|
1523 |
|
|
$imagenum = 2 if ($serv->{'image2'} eq $image);
|
1524 |
|
|
$imagenum = 3 if ($serv->{'image3'} eq $image);
|
1525 |
|
|
$imagenum = 4 if ($serv->{'image4'} eq $image);
|
1526 |
|
|
$imagereg{$image}->{'status'} = 'unused';
|
1527 |
|
|
$imagereg{$image}->{'domains'} = '';
|
1528 |
|
|
$imagereg{$image}->{'domainnames'} = '';
|
1529 |
|
|
if ($imagenum) {
|
1530 |
|
|
$serv->{"image$imagenum"} = '';
|
1531 |
|
|
$serv->{"image$imagenum"."name"} = '';
|
1532 |
|
|
$serv->{"image$imagenum"."type"} = '';
|
1533 |
|
|
}
|
1534 |
|
|
} else {
|
1535 |
|
|
$postreply .= "Status=Error Unable to attach image $image to $dev ($res)\n";
|
1536 |
|
|
}
|
1537 |
|
|
}
|
1538 |
|
|
untie %imagereg;
|
1539 |
|
|
return $postreply;
|
1540 |
|
|
}
|
1541 |
|
|
|
1542 |
|
|
sub Destroy {
|
1543 |
|
|
my ($uuid, $action, $obj) = @_;
|
1544 |
|
|
if ($help) {
|
1545 |
|
|
return <<END
|
1546 |
|
|
GET:uuid,wait:
|
1547 |
|
|
Marks a server for halt, i.e. pull the plug if regular shutdown does not work or is not desired. Server and storage is preserved.
|
1548 |
|
|
END
|
1549 |
|
|
}
|
1550 |
|
|
my $uistatus = 'destroying';
|
1551 |
|
|
my $name = $register{$uuid}->{'name'};
|
1552 |
|
|
my $mac = $register{$uuid}->{'mac'};
|
1553 |
|
|
my $macname = $register{$uuid}->{'macname'};
|
1554 |
|
|
my $dbstatus = $register{$uuid}->{'status'};
|
1555 |
|
|
my $wait = $obj->{'wait'};
|
1556 |
|
|
if ($dbstatus eq 'running' or $dbstatus eq 'paused'
|
1557 |
|
|
or $dbstatus eq 'shuttingdown' or $dbstatus eq 'starting'
|
1558 |
|
|
or $dbstatus eq 'destroying' or $dbstatus eq 'upgrading'
|
1559 |
|
|
or $dbstatus eq 'suspending' or $dbstatus eq 'resuming') {
|
1560 |
|
|
if ($wait) {
|
1561 |
|
|
$postreply = destroyUserServers($user, 1, $uuid);
|
1562 |
|
|
} else {
|
1563 |
|
|
my $tasks = $nodereg{$mac}->{'tasks'};
|
1564 |
|
|
$nodereg{$mac}->{'tasks'} = $tasks . "DESTROY $uuid $user\n";
|
1565 |
|
|
tied(%nodereg)->commit;
|
1566 |
|
|
$register{$uuid}->{'status'} = $uistatus;
|
1567 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
1568 |
|
|
$uiuuid = $uuid;
|
1569 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for $uistatus on $macname ($mac)");
|
1570 |
|
|
$postreply .= "Status=destroying $uistatus ". $register{$uuid}->{'name'} . "\n";
|
1571 |
|
|
}
|
1572 |
|
|
} else {
|
1573 |
|
|
$main::syslogit->($user, "info", "Problem $uistatus a $dbstatus domain: $name ($uuid)");
|
1574 |
|
|
$postreply .= "Status=ERROR problem $uistatus $name\n";
|
1575 |
|
|
}
|
1576 |
|
|
return $postreply;
|
1577 |
|
|
}
|
1578 |
|
|
|
1579 |
|
|
sub getHypervisor {
|
1580 |
|
|
my $image = shift;
|
1581 |
|
|
# Produce a mapping of image file suffixes to hypervisors
|
1582 |
|
|
my %idreg;
|
1583 |
|
|
unless ( tie(%idreg,'Tie::DBI', Hash::Merge::merge({table=>'nodeidentities', key=>'identity'}, $Stabile::dbopts)) ) {return "Unable to access nodeidentities register"};
|
1584 |
|
|
my @idvalues = values %idreg;
|
1585 |
|
|
my %formats;
|
1586 |
|
|
foreach my $val (@idvalues) {
|
1587 |
|
|
my %h = %$val;
|
1588 |
|
|
foreach (split(/,/,$h{'formats'})) {
|
1589 |
|
|
$formats{lc $_} = $h{'hypervisor'}
|
1590 |
|
|
}
|
1591 |
|
|
}
|
1592 |
|
|
untie %idreg;
|
1593 |
|
|
|
1594 |
|
|
# and then determine the hypervisor in question
|
1595 |
|
|
my $hypervisor = "vbox";
|
1596 |
|
|
my ($pathname, $path, $suffix) = fileparse($image, '\.[^\.]*');
|
1597 |
|
|
$suffix = substr $suffix, 1;
|
1598 |
|
|
my $hypervisor = $formats{lc $suffix};
|
1599 |
|
|
return $hypervisor;
|
1600 |
|
|
}
|
1601 |
|
|
|
1602 |
|
|
sub nicmac1ToUuid {
|
1603 |
|
|
my $nicmac1 = shift;
|
1604 |
|
|
my $uuid;
|
1605 |
|
|
return $uuid unless $nicmac1;
|
1606 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user' AND nicmac1 = '$nicmac1");
|
1607 |
|
|
foreach my $k (@regkeys) {
|
1608 |
|
|
my $val = $register{$k};
|
1609 |
|
|
my %h = %$val;
|
1610 |
|
|
if (lc $h{'nicmac1'} eq lc $nicmac1 && $user eq $h{'user'}) {
|
1611 |
|
|
$uuid = $h{'uuid'};
|
1612 |
|
|
last;
|
1613 |
|
|
}
|
1614 |
|
|
}
|
1615 |
|
|
return $uuid;
|
1616 |
|
|
}
|
1617 |
|
|
|
1618 |
|
|
sub randomMac {
|
1619 |
|
|
my ( %vendor, $lladdr, $i );
|
1620 |
|
|
# $lladdr = '00';
|
1621 |
|
|
$lladdr = '52:54:00';# KVM vendor string
|
1622 |
|
|
while ( ++$i )
|
1623 |
|
|
# { last if $i > 10;
|
1624 |
|
|
{ last if $i > 6;
|
1625 |
|
|
$lladdr .= ':' if $i % 2;
|
1626 |
|
|
$lladdr .= sprintf "%" . ( qw (X x) [int ( rand ( 2 ) ) ] ), int ( rand ( 16 ) );
|
1627 |
|
|
}
|
1628 |
|
|
return $lladdr;
|
1629 |
|
|
}
|
1630 |
|
|
|
1631 |
|
|
sub overQuotas {
|
1632 |
|
|
my $meminc = shift;
|
1633 |
|
|
my $vcpuinc = shift;
|
1634 |
|
|
my $usedmemory = 0;
|
1635 |
|
|
my $usedvcpus = 0;
|
1636 |
|
|
my $overquota = 0;
|
1637 |
|
|
return $overquota if ($isadmin || $Stabile::userprivileges =~ /a/); # Don't enforce quotas for admins
|
1638 |
|
|
|
1639 |
|
|
my $memoryquota = $usermemoryquota;
|
1640 |
|
|
my $vcpuquota = $uservcpuquota;
|
1641 |
|
|
|
1642 |
|
|
if (!$memoryquota || !$vcpuquota) { # 0 or empty quota means use defaults
|
1643 |
|
|
$memoryquota = $memoryquota || $Stabile::config->get('MEMORY_QUOTA');
|
1644 |
|
|
$vcpuquota = $vcpuquota || $Stabile::config->get('VCPU_QUOTA');
|
1645 |
|
|
}
|
1646 |
|
|
|
1647 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user'");
|
1648 |
|
|
foreach my $k (@regkeys) {
|
1649 |
|
|
my $val = $register{$k};
|
1650 |
|
|
if ($val->{'user'} eq $user && $val->{'status'} ne "shutoff" &&
|
1651 |
|
|
$val->{'status'} ne "inactive" && $val->{'status'} ne "shutdown" ) {
|
1652 |
|
|
|
1653 |
|
|
$usedmemory += $val->{'memory'};
|
1654 |
|
|
$usedvcpus += $val->{'vcpu'};
|
1655 |
|
|
}
|
1656 |
|
|
}
|
1657 |
|
|
$overquota = $usedmemory+$meminc if ($memoryquota!=-1 && $usedmemory+$meminc > $memoryquota); # -1 means no quota
|
1658 |
|
|
$overquota = $usedvcpus+$vcpuinc if ($vcpuquota!=-1 && $usedvcpus+$vcpuinc > $vcpuquota);
|
1659 |
|
|
return $overquota;
|
1660 |
|
|
}
|
1661 |
|
|
|
1662 |
|
|
sub validateItem {
|
1663 |
|
|
my $valref = shift;
|
1664 |
|
|
my $img = $imagereg{$valref->{'image'}};
|
1665 |
|
|
my $imagename = $img->{'name'};
|
1666 |
|
|
$valref->{'imagename'} = $imagename if ($imagename);
|
1667 |
|
|
my $imagetype = $img->{'type'};
|
1668 |
|
|
$valref->{'imagetype'} = $imagetype if ($imagetype);
|
1669 |
|
|
|
1670 |
|
|
# imagex may be registered by uuid instead of path - find the path
|
1671 |
|
|
# We now support up to 4 images
|
1672 |
|
|
for (my $i=2; $i<=4; $i++) {
|
1673 |
|
|
if ($valref->{"image$i"} && $valref->{"image$i"} ne '--' && !($valref->{"image$i"} =~ /^\//)) {
|
1674 |
|
|
unless ( tie(%imagereg2,'Tie::DBI', Hash::Merge::merge({table=>'images', CLOBBER=>1}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
1675 |
|
|
$valref->{"image$i"} = $imagereg2{$valref->{"image$i"}}->{'path'};
|
1676 |
|
|
untie %imagereg2;
|
1677 |
|
|
}
|
1678 |
|
|
|
1679 |
|
|
my $imgi = $imagereg{$valref->{"image$i"}};
|
1680 |
|
|
$valref->{"image$i" . 'name'} = $imgi->{'name'} || $valref->{"image$i" . 'name'};
|
1681 |
|
|
$valref->{"image$i" . 'type'} = $imgi->{'type'} || $valref->{"image$i" . 'type'};
|
1682 |
|
|
}
|
1683 |
|
|
|
1684 |
|
|
my $net1 = $networkreg{$valref->{'networkuuid1'}};
|
1685 |
|
|
my $networkname1 = $net1->{'name'};
|
1686 |
|
|
$valref->{'networkname1'} = $networkname1 if ($networkname1);
|
1687 |
|
|
my $net2 = $networkreg{$valref->{'networkuuid2'}};
|
1688 |
|
|
my $networkname2 = $net2->{'name'};
|
1689 |
|
|
$valref->{'networkname2'} = $networkname2 if ($networkname2);
|
1690 |
|
|
my $name = $valref->{'name'};
|
1691 |
|
|
$valref->{'name'} = $imagename unless $name;
|
1692 |
|
|
|
1693 |
|
|
if ($valref->{'status'} eq "shutoff" || $valref->{'status'} eq "inactive") {
|
1694 |
|
|
my $node = $nodereg{$valref->{'mac'}};
|
1695 |
|
|
if ($valref->{'image'} =~ /\/mnt\/stabile\/node\//) {
|
1696 |
|
|
$valref->{'mac'} = $img->{'mac'};
|
1697 |
|
|
$valref->{'macname'} = $node->{'name'};
|
1698 |
|
|
$valref->{'macip'} = $node->{'ip'};
|
1699 |
|
|
} elsif ($valref->{'image2'} =~ /\/mnt\/stabile\/node\//) {
|
1700 |
|
|
$valref->{'mac'} = $imagereg{$valref->{'image2'}}->{'mac'};
|
1701 |
|
|
$valref->{'macname'} = $node->{'name'};
|
1702 |
|
|
$valref->{'macip'} = $node->{'ip'};
|
1703 |
|
|
} elsif ($valref->{'image3'} =~ /\/mnt\/stabile\/node\//) {
|
1704 |
|
|
$valref->{'mac'} = $imagereg{$valref->{'image3'}}->{'mac'};
|
1705 |
|
|
$valref->{'macname'} = $node->{'name'};
|
1706 |
|
|
$valref->{'macip'} = $node->{'ip'};
|
1707 |
|
|
} elsif ($valref->{'image4'} =~ /\/mnt\/stabile\/node\//) {
|
1708 |
|
|
$valref->{'mac'} = $imagereg{$valref->{'image4'}}->{'mac'};
|
1709 |
|
|
$valref->{'macname'} = $node->{'name'};
|
1710 |
|
|
$valref->{'macip'} = $node->{'ip'};
|
1711 |
|
|
}
|
1712 |
|
|
}
|
1713 |
|
|
# Mark domains we have heard from in the last 20 secs as inactive
|
1714 |
|
|
my $dbtimestamp = 0;
|
1715 |
|
|
$dbtimestamp = $register{$valref->{'uuid'}}->{'timestamp'} if ($register{$valref->{'uuid'}});
|
1716 |
|
|
my $timediff = $current_time - $dbtimestamp;
|
1717 |
|
|
if ($timediff >= 20) {
|
1718 |
|
|
if (! ($valref->{'status'} eq "shutoff"
|
1719 |
|
|
|| $valref->{'status'} eq "starting"
|
1720 |
|
|
# || $valref->{'status'} eq "shuttingdown"
|
1721 |
|
|
# || $valref->{'status'} eq "destroying"
|
1722 |
|
|
|| ($valref->{'status'} eq "moving" && $timediff<40)
|
1723 |
|
|
)) { # Move has probably failed
|
1724 |
|
|
$valref->{'status'} = "inactive";
|
1725 |
|
|
$imagereg{$valref->{'image'}}->{'status'} = "used" if ($valref->{'image'} && $imagereg{$valref->{'image'}});
|
1726 |
|
|
$imagereg{$valref->{'image2'}}->{'status'} = "used" if ($valref->{'image2'} && $imagereg{$valref->{'imag2'}});
|
1727 |
|
|
$imagereg{$valref->{'image3'}}->{'status'} = "used" if ($valref->{'image3'} && $imagereg{$valref->{'image3'}});
|
1728 |
|
|
$imagereg{$valref->{'image4'}}->{'status'} = "used" if ($valref->{'image4'} && $imagereg{$valref->{'image4'}});
|
1729 |
|
|
}
|
1730 |
|
|
};
|
1731 |
|
|
return $valref;
|
1732 |
|
|
}
|
1733 |
|
|
|
1734 |
|
|
# Run through all domains and mark domains we have heard from in the last 20 secs as inactive
|
1735 |
|
|
sub updateRegister {
|
1736 |
|
|
unless ( tie(%userreg,'Tie::DBI', Hash::Merge::merge({table=>'users', key=>'username', CLOBBER=>1}, $Stabile::dbopts)) ) {return "Unable to access user register"};
|
1737 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
1738 |
|
|
|
1739 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user'");
|
1740 |
|
|
|
1741 |
|
|
foreach my $k (@regkeys) {
|
1742 |
|
|
my $valref = $register{$k};
|
1743 |
|
|
next unless ($userreg{$valref->{'user'}});
|
1744 |
|
|
my $dbtimestamp = $valref->{'timestamp'};
|
1745 |
|
|
my $dbstatus = $valref->{'status'};
|
1746 |
|
|
my $timediff = $current_time - $dbtimestamp;
|
1747 |
|
|
my $imgstatus;
|
1748 |
|
|
my $domstatus;
|
1749 |
|
|
if ($timediff >= 20) {
|
1750 |
|
|
if ( $valref->{'status'} eq "shutoff" ) {
|
1751 |
|
|
$imgstatus = 'used';
|
1752 |
|
|
} elsif (( $valref->{'status'} eq "starting"
|
1753 |
|
|
|| $valref->{'status'} eq "shuttingdown"
|
1754 |
|
|
) && $timediff>50) {
|
1755 |
|
|
$imgstatus = 'used';
|
1756 |
|
|
$domstatus = 'inactive';
|
1757 |
|
|
} elsif ($valref->{'status'} eq "destroying" || $valref->{'status'} eq "moving") {
|
1758 |
|
|
;
|
1759 |
|
|
} else {
|
1760 |
|
|
$domstatus = 'inactive';
|
1761 |
|
|
$imgstatus = 'used';
|
1762 |
|
|
}
|
1763 |
|
|
$valref->{'status'} = $domstatus if ($domstatus);
|
1764 |
|
|
my $image = $valref->{'image'};
|
1765 |
|
|
my $image2 = $valref->{'image2'};
|
1766 |
|
|
my $image3 = $valref->{'image3'};
|
1767 |
|
|
my $image4 = $valref->{'image4'};
|
1768 |
|
|
$imagereg{$image}->{'status'} = $imgstatus if ($imgstatus);
|
1769 |
|
|
$imagereg{$image2}->{'status'} = $imgstatus if ($image2 && $imgstatus);
|
1770 |
|
|
$imagereg{$image3}->{'status'} = $imgstatus if ($image3 && $imgstatus);
|
1771 |
|
|
$imagereg{$image4}->{'status'} = $imgstatus if ($image4 && $imgstatus);
|
1772 |
|
|
if ($domstatus eq 'inactive ' && $dbstatus ne 'inactive') {
|
1773 |
|
|
$main::updateUI->({ tab=>'servers',
|
1774 |
|
|
user=>$valref->{'user'},
|
1775 |
|
|
uuid=>$valref->{'uuid'},
|
1776 |
|
|
sender=>'updateRegister',
|
1777 |
|
|
status=>'inactive'})
|
1778 |
|
|
}
|
1779 |
|
|
};
|
1780 |
|
|
|
1781 |
|
|
}
|
1782 |
|
|
untie %userreg;
|
1783 |
|
|
untie %imagereg;
|
1784 |
|
|
}
|
1785 |
|
|
|
1786 |
|
|
|
1787 |
|
|
sub locateTargetNode {
|
1788 |
|
|
my ($uuid, $dmac, $mem, $vcpu, $image, $image2, $image3, $image4, $hypervisor, $smac)= @_;
|
1789 |
|
|
my $targetname;
|
1790 |
|
|
my $targetip;
|
1791 |
|
|
my $port;
|
1792 |
|
|
my $targetnode;
|
1793 |
|
|
my $targetindex; # Availability index of located target node
|
1794 |
|
|
my %avhash;
|
1795 |
|
|
|
1796 |
|
|
my $mnode = $register{$uuid};
|
1797 |
|
|
$dmac = $mnode->{'mac'}
|
1798 |
|
|
if (!$dmac
|
1799 |
|
|
&& $mnode->{'locktonode'} eq 'true'
|
1800 |
|
|
&& $mnode->{'mac'}
|
1801 |
|
|
&& $mnode->{'mac'} ne '--'
|
1802 |
|
|
);
|
1803 |
|
|
|
1804 |
|
|
$dmac = '' unless ($isadmin); # Only allow admins to select specific node
|
1805 |
|
|
if ($dmac && !$nodereg{$dmac}) {
|
1806 |
|
|
$main::syslogit->($user, "info", "The target node $dmac no longer exists, starting $uuid on another node if possible");
|
1807 |
|
|
$dmac = '';
|
1808 |
|
|
}
|
1809 |
|
|
|
1810 |
|
|
my $imageonnode = ($image =~ /\/mnt\/stabile\/node\//
|
1811 |
|
|
|| $image2 =~ /\/mnt\/stabile\/node\//
|
1812 |
|
|
|| $image3 =~ /\/mnt\/stabile\/node\//
|
1813 |
|
|
|| $image4 =~ /\/mnt\/stabile\/node\//
|
1814 |
|
|
);
|
1815 |
|
|
|
1816 |
|
|
foreach $node (values %nodereg) {
|
1817 |
|
|
my $nstatus = $node->{'status'};
|
1818 |
|
|
my $maintenance = $node->{'maintenance'};
|
1819 |
|
|
my $nmac = $node->{'mac'};
|
1820 |
|
|
|
1821 |
|
|
if (($nstatus eq 'running' || $nstatus eq 'asleep' || $nstatus eq 'maintenance' || $nstatus eq 'waking')
|
1822 |
|
|
&& $smac ne $nmac
|
1823 |
|
|
&& (( ($node->{'memfree'} > $mem+512*1024)
|
1824 |
|
|
&& (($node->{'vmvcpus'} + $vcpu) <= ($cpuovercommision * $node->{'cpucores'} * $node->{'cpucount'})) ) || $action eq 'listnodeavailability')
|
1825 |
|
|
) {
|
1826 |
|
|
# Determine how available this node is
|
1827 |
|
|
# Available memory
|
1828 |
|
|
my $memweight = 0.2; # memory weighing factor
|
1829 |
|
|
my $memindex = $avhash{$nmac}->{'memindex'} = int(100* $memweight* $node->{'memfree'} / (1024*1024) )/100;
|
1830 |
|
|
# Free cores
|
1831 |
|
|
my $cpuindex = $avhash{$nmac}->{'cpuindex'} = int(100*($cpuovercommision * $node->{'cpucores'} * $node->{'cpucount'} - $node->{'vmvcpus'} - $node->{'reservedvcpus'}))/100;
|
1832 |
|
|
# Asleep - not asleep gives a +3
|
1833 |
|
|
my $sleepindex = $avhash{$nmac}->{'sleepindex'} = ($node->{'status'} eq 'asleep' || $node->{'status'} eq 'waking')?'0':'3';
|
1834 |
|
|
$avhash{$nmac}->{'vmvcpus'} = $node->{'vmvcpus'};
|
1835 |
|
|
# $avhash{$nmac}->{'cpucommision'} = $cpuovercommision * $node->{'cpucores'} * $node->{'cpucount'};
|
1836 |
|
|
# $avhash{$nmac}->{'cpureservation'} = $node->{'vmvcpus'} + $node->{'reservedvcpus'};
|
1837 |
|
|
|
1838 |
|
|
$avhash{$nmac}->{'name'} = $node->{'name'};
|
1839 |
|
|
$avhash{$nmac}->{'mac'} = $node->{'mac'};
|
1840 |
|
|
|
1841 |
|
|
my $aindex = $memindex + $cpuindex + $sleepindex;
|
1842 |
|
|
# Don't use nodes that are out of memory of cores
|
1843 |
|
|
$aindex = 0 if ($memindex <= 0 || $cpuindex <= 0);
|
1844 |
|
|
$avhash{$nmac}->{'index'} = $aindex;
|
1845 |
|
|
|
1846 |
|
|
$avhash{$nmac}->{'storfree'} = $node->{'storfree'};
|
1847 |
c899e439
|
Origo
|
$avhash{$nmac}->{'memfree'} = $node->{'memfree'};
|
1848 |
95b003ff
|
Origo
|
$avhash{$nmac}->{'ip'} = $node->{'ip'};
|
1849 |
|
|
$avhash{$nmac}->{'identity'} = $node->{'identity'};
|
1850 |
|
|
$avhash{$nmac}->{'status'} = $node->{'status'};
|
1851 |
|
|
$avhash{$nmac}->{'maintenance'} = $maintenance;
|
1852 |
|
|
$avhash{$nmac}->{'reservedvcpus'} = $node->{'reservedvcpus'};
|
1853 |
|
|
my $nodeidentity = $node->{'identity'};
|
1854 |
|
|
$nodeidentity = 'kvm' if ($nodeidentity eq 'local_kvm');
|
1855 |
|
|
|
1856 |
|
|
if ($hypervisor eq $nodeidentity) {
|
1857 |
|
|
# If image is on node, we must start on same node - registered when moving image
|
1858 |
|
|
if ($imageonnode) {
|
1859 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
1860 |
|
|
$dmac = $imagereg{$image}->{'mac'};
|
1861 |
|
|
$dmac = $imagereg{$image2}->{'mac'} unless ($dmac);
|
1862 |
|
|
$dmac = $imagereg{$image3}->{'mac'} unless ($dmac);
|
1863 |
|
|
$dmac = $imagereg{$image4}->{'mac'} unless ($dmac);
|
1864 |
|
|
|
1865 |
|
|
untie %imagereg;
|
1866 |
|
|
if (!$dmac) {
|
1867 |
|
|
$postreply .= "Status=ERROR Image node not found\n";
|
1868 |
|
|
last;
|
1869 |
|
|
}
|
1870 |
|
|
}
|
1871 |
|
|
$dmac = "" if ($dmac eq "--");
|
1872 |
a439a9c4
|
hq
|
# If a specific node is asked for, match mac addresses
|
1873 |
95b003ff
|
Origo
|
if ($dmac eq $nmac) {
|
1874 |
|
|
$targetnode = $node;
|
1875 |
|
|
last;
|
1876 |
|
|
} elsif (!$dmac && $nstatus ne "maintenance" && !$maintenance) {
|
1877 |
|
|
# pack or disperse
|
1878 |
|
|
if (!$targetindex) {
|
1879 |
|
|
$targetindex = $aindex;
|
1880 |
|
|
$targetnode = $node;
|
1881 |
|
|
} elsif ($dpolicy eq 'pack') {
|
1882 |
|
|
if ($aindex < $targetindex) {
|
1883 |
|
|
$targetnode = $node;
|
1884 |
|
|
$targetindex = $aindex;
|
1885 |
|
|
}
|
1886 |
|
|
} else {
|
1887 |
|
|
if ($aindex > $targetindex) {
|
1888 |
|
|
$targetnode = $node;
|
1889 |
|
|
$targetindex = $aindex;
|
1890 |
|
|
}
|
1891 |
|
|
}
|
1892 |
|
|
}
|
1893 |
|
|
}
|
1894 |
|
|
}
|
1895 |
|
|
}
|
1896 |
|
|
|
1897 |
|
|
if ($targetnode && $uuid) {
|
1898 |
|
|
if ($targetnode->{'status'} eq 'asleep') {
|
1899 |
|
|
my $nmac = $targetnode->{'mac'};
|
1900 |
|
|
my $realmac = substr($nmac,0,2).":".substr($nmac,2,2).":".substr($nmac,4,2).":".substr($nmac,6,2).":".substr($nmac,8,2).":".substr($nmac,10,2);
|
1901 |
|
|
my $nlogmsg = "Node $nmac marked for wake ";
|
1902 |
|
|
if ($brutalsleep && (
|
1903 |
|
|
($targetnode->{'amtip'} && $targetnode->{'amtip'} ne '--')
|
1904 |
|
|
|| ($targetnode->{'ipmiip'} && $targetnode->{'ipmiip'} ne '--')
|
1905 |
|
|
)) {
|
1906 |
|
|
my $wakecmd;
|
1907 |
|
|
if ($targetnode->{'amtip'} && $targetnode->{'amtip'} ne '--') {
|
1908 |
|
|
$wakecmd = "echo 'y' | AMT_PASSWORD='$amtpasswd' /usr/bin/amttool $targetnode->{'amtip'} powerup pxe";
|
1909 |
|
|
} else {
|
1910 |
|
|
$wakecmd = "ipmitool -I lanplus -H $targetnode->{'ipmiip'} -U ADMIN -P ADMIN power on";
|
1911 |
|
|
}
|
1912 |
|
|
$nlogmsg .= `$wakecmd`;
|
1913 |
|
|
} else {
|
1914 |
|
|
my $broadcastip = $targetnode->{'ip'};
|
1915 |
|
|
$broadcastip =~ s/\.\d{1,3}$/.255/;
|
1916 |
|
|
$nlogmsg .= 'on lan ' . `/usr/bin/wakeonlan -i $broadcastip $realmac`;
|
1917 |
|
|
}
|
1918 |
|
|
$targetnode->{'status'} = "waking";
|
1919 |
|
|
$nlogmsg =~ s/\n/ /g;
|
1920 |
|
|
$main::syslogit->($user, "info", $nlogmsg);
|
1921 |
|
|
$postreply .= "Status=OK waking $targetnode->{'name'}\n";
|
1922 |
|
|
}
|
1923 |
|
|
$targetname = $targetnode->{'name'};
|
1924 |
|
|
$targetmac = $targetnode->{'mac'};
|
1925 |
|
|
$targetip = $targetnode->{'ip'};
|
1926 |
|
|
$targetip = $targetnode->{'ip'};
|
1927 |
|
|
my $porttaken = 1;
|
1928 |
|
|
while ($porttaken) {
|
1929 |
|
|
$porttaken = 0;
|
1930 |
|
|
$port = $targetnode->{'vms'} + (($hypervisor eq "vbox")?3389:5900);
|
1931 |
|
|
$port += int(rand(200));
|
1932 |
|
|
my @regkeys = (tied %register)->select_where("port = '$port' AND macip = '$targetip'");
|
1933 |
|
|
foreach my $k (@regkeys) {
|
1934 |
|
|
$r = $register{$k};
|
1935 |
|
|
if ($r->{'port'} eq $port && $r->{'macip'} eq $targetip) {
|
1936 |
|
|
$porttaken = 1;
|
1937 |
|
|
}
|
1938 |
|
|
}
|
1939 |
|
|
}
|
1940 |
|
|
$targetnode->{'vms'}++;
|
1941 |
|
|
$targetnode->{'vmvcpus'} += $vcpu;
|
1942 |
|
|
$register{$uuid}->{'port'} = $port;
|
1943 |
|
|
# $register{$uuid}->{'mac'} = $targetmac;
|
1944 |
|
|
# $register{$uuid}->{'macname'} = $targetname;
|
1945 |
|
|
# $register{$uuid}->{'macip'} = $targetip;
|
1946 |
|
|
$register{$uuid}->{'display'} = (($hypervisor eq "vbox")?'rdp':'vnc');
|
1947 |
|
|
} else {
|
1948 |
|
|
my $macstatus;
|
1949 |
|
|
$macstatus = $nodereg{$dmac}->{status} if ($nodereg{$dmac});
|
1950 |
|
|
$main::syslogit->($user, "info", "Could not find target for $uuid, $dmac, $mem, $vcpu, $image, $image2,$image3,$image4, $hypervisor, $smac, dmac-status: $macstatus") if ($uuid);
|
1951 |
|
|
}
|
1952 |
|
|
return ($targetmac, $targetname, $targetip, $port, \%avhash);
|
1953 |
|
|
}
|
1954 |
|
|
|
1955 |
|
|
sub destroyUserServers {
|
1956 |
|
|
my $username = shift;
|
1957 |
|
|
my $wait = shift; # Should we wait for servers do die
|
1958 |
|
|
my $duuid = shift;
|
1959 |
|
|
return unless ($isadmin || $user eq $username);
|
1960 |
|
|
my @updateList;
|
1961 |
|
|
|
1962 |
|
|
my @regkeys = (tied %register)->select_where("user = '$username'");
|
1963 |
|
|
foreach my $uuid (@regkeys) {
|
1964 |
|
|
if ($register{$uuid}->{'user'} eq $username
|
1965 |
|
|
&& $register{$uuid}->{'status'} ne 'shutoff'
|
1966 |
|
|
&& (!$duuid || $duuid eq $uuid)
|
1967 |
|
|
) {
|
1968 |
|
|
$postreply .= "Destroying $username server $register{$uuid}->{'name'}, $uuid\n";
|
1969 |
|
|
Destroy($uuid);
|
1970 |
|
|
push (@updateList,{ tab=>'servers',
|
1971 |
|
|
user=>$user,
|
1972 |
|
|
uuid=>$duuid,
|
1973 |
|
|
status=>'destroying'});
|
1974 |
|
|
}
|
1975 |
|
|
}
|
1976 |
|
|
$main::updateUI->(@updateList) if (@updateList);
|
1977 |
|
|
if ($wait) {
|
1978 |
|
|
my @regkeys = (tied %register)->select_where("user = '$username'");
|
1979 |
|
|
my $activeservers = 1;
|
1980 |
|
|
my $i = 0;
|
1981 |
|
|
while ($activeservers && $i<10) {
|
1982 |
|
|
$activeservers = 0;
|
1983 |
|
|
foreach my $k (@regkeys) {
|
1984 |
|
|
my $valref = $register{$k};
|
1985 |
|
|
if ($username eq $valref->{'user'}
|
1986 |
|
|
&& ($valref->{'status'} ne 'shutoff'
|
1987 |
|
|
&& $valref->{'status'} ne 'inactive')
|
1988 |
|
|
&& (!$duuid || $duuid eq $valref->{'uuid'})
|
1989 |
|
|
) {
|
1990 |
|
|
$activeservers = $valref->{'uuid'};
|
1991 |
|
|
}
|
1992 |
|
|
}
|
1993 |
|
|
$i++;
|
1994 |
|
|
if ($activeservers) {
|
1995 |
|
|
my $res .= "Status=OK Waiting $i for server $register{$activeservers}->{'name'}, $register{$activeservers}->{'status'} to die...\n";
|
1996 |
9de5a3f1
|
hq
|
# print $res if ($console);
|
1997 |
95b003ff
|
Origo
|
$postreply .= $res;
|
1998 |
|
|
sleep 2;
|
1999 |
|
|
}
|
2000 |
|
|
}
|
2001 |
|
|
$postreply .= "Status=OK Servers halted for $username\n" unless ($activeservers);
|
2002 |
|
|
}
|
2003 |
|
|
return $postreply;
|
2004 |
|
|
}
|
2005 |
|
|
|
2006 |
|
|
sub removeUserServers {
|
2007 |
|
|
my $username = shift;
|
2008 |
|
|
my $uuid = shift;
|
2009 |
|
|
my $destroy = shift; # Should running servers be destroyed before removing
|
2010 |
|
|
return unless (($isadmin || $user eq $username) && !$isreadonly);
|
2011 |
|
|
$user = $username;
|
2012 |
|
|
my @regkeys = (tied %register)->select_where("user = '$username'");
|
2013 |
|
|
foreach my $ruuid (@regkeys) {
|
2014 |
|
|
next if ($uuid && $ruuid ne $uuid);
|
2015 |
|
|
if ($destroy && $register{$ruuid}->{'user'} eq $username && ($register{$ruuid}->{'status'} ne 'shutoff' && $register{$ruuid}->{'status'} ne 'inactive')) {
|
2016 |
|
|
destroyUserServers($username, 1, $ruuid);
|
2017 |
|
|
}
|
2018 |
|
|
|
2019 |
|
|
if ($register{$ruuid}->{'user'} eq $username && ($register{$ruuid}->{'status'} eq 'shutoff' || $register{$ruuid}->{'status'} eq 'inactive')) {
|
2020 |
|
|
$postreply .= "Removing $username server $register{$ruuid}->{'name'}, $ruuid" . ($console?'':'<br>') . "\n";
|
2021 |
|
|
Remove($ruuid);
|
2022 |
|
|
}
|
2023 |
|
|
}
|
2024 |
|
|
}
|
2025 |
|
|
|
2026 |
|
|
sub Remove {
|
2027 |
|
|
my ($uuid, $action) = @_;
|
2028 |
|
|
if ($help) {
|
2029 |
|
|
return <<END
|
2030 |
|
|
DELETE:uuid:
|
2031 |
|
|
Removes a server. Server must be shutoff. Does not remove associated images or networks.
|
2032 |
|
|
END
|
2033 |
|
|
}
|
2034 |
|
|
my $reguser = $register{$uuid}->{'user'};
|
2035 |
|
|
my $dbstatus = $register{$uuid}->{'status'};
|
2036 |
|
|
my $image = $register{$uuid}->{'image'};
|
2037 |
|
|
my $image2 = $register{$uuid}->{'image2'};
|
2038 |
|
|
my $image3 = $register{$uuid}->{'image3'};
|
2039 |
|
|
my $image4 = $register{$uuid}->{'image4'};
|
2040 |
|
|
my $name = $register{$uuid}->{'name'};
|
2041 |
|
|
$image2 = '' if ($image2 eq '--');
|
2042 |
|
|
$image3 = '' if ($image3 eq '--');
|
2043 |
|
|
$image4 = '' if ($image4 eq '--');
|
2044 |
|
|
|
2045 |
|
|
if ($reguser ne $user) {
|
2046 |
|
|
$postreply .= "Status=ERROR You cannot delete a vm you don't own\n";
|
2047 |
|
|
} elsif ($dbstatus eq 'inactive' || $dbstatus eq 'shutdown' || $dbstatus eq 'shutoff') {
|
2048 |
|
|
|
2049 |
|
|
# Delete software packages and monitors from register
|
2050 |
|
|
$postmsg .= deletePackages($uuid);
|
2051 |
|
|
my $sname = $register{$uuid}->{'name'};
|
2052 |
|
|
utf8::decode($sname);
|
2053 |
48fcda6b
|
Origo
|
$postmsg .= deleteMonitors($uuid)?" deleted monitors for $sname ":'';
|
2054 |
95b003ff
|
Origo
|
|
2055 |
|
|
delete $register{$uuid};
|
2056 |
|
|
delete $xmlreg{$uuid};
|
2057 |
|
|
|
2058 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
2059 |
|
|
$imagereg{$image}->{'status'} = "unused" if ($imagereg{$image});
|
2060 |
|
|
$imagereg{$image2}->{'status'} = "unused" if ($image2 && $imagereg{$image2});
|
2061 |
|
|
$imagereg{$image3}->{'status'} = "unused" if ($image3 && $imagereg{$image3});
|
2062 |
|
|
$imagereg{$image4}->{'status'} = "unused" if ($image4 && $imagereg{$image4});
|
2063 |
|
|
untie %imagereg;
|
2064 |
|
|
|
2065 |
|
|
# Delete metrics
|
2066 |
|
|
my $metricsdir = "/var/lib/graphite/whisper/domains/$uuid";
|
2067 |
|
|
`rm -r $metricsdir` if (-e $metricsdir);
|
2068 |
|
|
my $rrdfile = "/var/cache/rrdtool/".$uuid."_highres.rrd";
|
2069 |
|
|
`rm $rrdfile` if (-e $rrdfile);
|
2070 |
|
|
|
2071 |
|
|
$main::syslogit->($user, "info", "Deleted domain $uuid from db");
|
2072 |
|
|
utf8::decode($name);
|
2073 |
48fcda6b
|
Origo
|
$postmsg .= " deleted server $name";
|
2074 |
95b003ff
|
Origo
|
$postreply = "[]";
|
2075 |
|
|
sleep 1;
|
2076 |
|
|
} else {
|
2077 |
|
|
$postreply .= "Status=ERROR Cannot delete a $dbstatus server\n";
|
2078 |
|
|
}
|
2079 |
|
|
return $postreply;
|
2080 |
|
|
}
|
2081 |
|
|
|
2082 |
|
|
# Delete all monitors belonging to a server
|
2083 |
|
|
sub deleteMonitors {
|
2084 |
|
|
my ($serveruuid) = @_;
|
2085 |
|
|
my $match;
|
2086 |
|
|
if ($serveruuid) {
|
2087 |
|
|
if ($register{$serveruuid}->{'user'} eq $user || $isadmin) {
|
2088 |
|
|
local($^I, @ARGV) = ('.bak', "/etc/mon/mon.cf");
|
2089 |
|
|
# undef $/; # This makes <> read in the entire file in one go
|
2090 |
|
|
my $uuidmatch;
|
2091 |
|
|
while (<>) {
|
2092 |
|
|
if (/^watch (\S+)/) {
|
2093 |
|
|
if ($1 eq $serveruuid) {$uuidmatch = $serveruuid}
|
2094 |
|
|
else {$uuidmatch = ''};
|
2095 |
|
|
};
|
2096 |
|
|
if ($uuidmatch) {
|
2097 |
|
|
$match = 1;
|
2098 |
|
|
} else {
|
2099 |
|
|
#chomp;
|
2100 |
|
|
print unless (/^hostgroup $serveruuid/);
|
2101 |
|
|
}
|
2102 |
|
|
close ARGV if eof;
|
2103 |
|
|
}
|
2104 |
|
|
#$/ = "\n";
|
2105 |
|
|
}
|
2106 |
|
|
unlink glob "/var/log/stabile/*:$serveruuid:*";
|
2107 |
|
|
}
|
2108 |
|
|
`/usr/bin/moncmd reset keepstate` if ($match);
|
2109 |
|
|
return $match;
|
2110 |
|
|
}
|
2111 |
|
|
|
2112 |
|
|
sub deletePackages {
|
2113 |
|
|
my ($uuid, $issystem, %packreg) = @_;
|
2114 |
|
|
unless ( tie(%packreg,'Tie::DBI', Hash::Merge::merge({table=>'packages', key=>'id'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
2115 |
|
|
|
2116 |
|
|
my @domains;
|
2117 |
|
|
if ($issystem) {
|
2118 |
|
|
foreach my $valref (values %register) {
|
2119 |
|
|
if (($valref->{'system'} eq $uuid || $uuid eq '*')
|
2120 |
|
|
&& ($valref->{'user'} eq $user || $fulllist)) {
|
2121 |
|
|
push(@domains, $valref->{'uuid'});
|
2122 |
|
|
}
|
2123 |
|
|
}
|
2124 |
|
|
} else { # Allow if domain no longer exists or belongs to user
|
2125 |
|
|
push(@domains, $uuid) if (!$register{$uuid} || $register{$uuid}->{'user'} eq $user || $fulllist);
|
2126 |
|
|
}
|
2127 |
|
|
|
2128 |
|
|
foreach my $domuuid (@domains) {
|
2129 |
|
|
foreach my $packref (values %packreg) {
|
2130 |
|
|
my $id = $packref->{'id'};
|
2131 |
|
|
if (substr($id, 0,36) eq $domuuid || ($uuid eq '*' && $packref->{'user'} eq $user)) {
|
2132 |
|
|
delete $packreg{$id};
|
2133 |
|
|
}
|
2134 |
|
|
}
|
2135 |
|
|
}
|
2136 |
|
|
tied(%packreg)->commit;# if (%packreg);
|
2137 |
|
|
if ($issystem) {
|
2138 |
|
|
my $sname = $register{$uuid}->{'name'};
|
2139 |
|
|
utf8::decode($sname);
|
2140 |
|
|
return "Status=OK Cleared packages for $sname\n";
|
2141 |
|
|
} elsif ($register{$uuid}) {
|
2142 |
|
|
my $sname = $register{$uuid}->{'name'};
|
2143 |
|
|
utf8::decode($sname);
|
2144 |
|
|
return "Status=OK Cleared packages for $sname\n";
|
2145 |
|
|
} else {
|
2146 |
|
|
return "Status=OK Cleared packages. System not registered\n";
|
2147 |
|
|
}
|
2148 |
|
|
}
|
2149 |
|
|
|
2150 |
|
|
sub Save {
|
2151 |
|
|
my ($uuid, $action, $obj) = @_;
|
2152 |
|
|
if ($help) {
|
2153 |
|
|
return <<END
|
2154 |
04c16f26
|
hq
|
POST:uuid, name, user, system, autostart, locktonode, mac, memory, vcpu, boot, loader, diskbus, nicmodel1, vgpu, cdrom, image, image2, image3, image4, networkuuid2, networkuuid3, networkuuid1, nicmac1, nicmac2, nicmac3:
|
2155 |
95b003ff
|
Origo
|
To save a servers of networks you either PUT or POST a JSON array to the main endpoint with objects representing the servers with the changes you want.
|
2156 |
|
|
Depending on your privileges not all changes are permitted. If you save without specifying a uuid, a new server is created.
|
2157 |
|
|
If you pass [user] parameter it is assumed you want to move server to this user's account.
|
2158 |
|
|
Supported parameters:
|
2159 |
|
|
|
2160 |
|
|
uuid: UUID
|
2161 |
|
|
name: string
|
2162 |
|
|
user: string
|
2163 |
48fcda6b
|
Origo
|
system: UUID of stack this server belongs to
|
2164 |
95b003ff
|
Origo
|
autostart: true|false
|
2165 |
|
|
locktonode: true|false
|
2166 |
|
|
mac: MAC address of target node
|
2167 |
|
|
|
2168 |
|
|
memory: int bytes
|
2169 |
|
|
vcpu: int
|
2170 |
|
|
boot: hd|cdrom|network
|
2171 |
04c16f26
|
hq
|
loader: bios|uefi
|
2172 |
95b003ff
|
Origo
|
diskbus: virtio|ide|scsi
|
2173 |
|
|
nicmodel1: virtio|rtl8139|ne2k_pci|e1000|i82551|i82557b|i82559er|pcnet
|
2174 |
|
|
vgpu: int
|
2175 |
|
|
|
2176 |
|
|
cdrom: string path
|
2177 |
|
|
image: string path
|
2178 |
|
|
image2: string path
|
2179 |
|
|
image3: string path
|
2180 |
|
|
image4: string path
|
2181 |
|
|
|
2182 |
|
|
networkuuid1: UUID of network connection
|
2183 |
|
|
networkuuid2: UUID of network connection
|
2184 |
|
|
networkuuid3: UUID of network connection
|
2185 |
|
|
|
2186 |
|
|
END
|
2187 |
|
|
}
|
2188 |
|
|
|
2189 |
|
|
# notes, opemail, opfullname, opphone, email, fullname, phone, services, recovery, alertemail
|
2190 |
|
|
# notes: string
|
2191 |
|
|
# opemail: string
|
2192 |
|
|
# opfullname: string
|
2193 |
|
|
# opphone: string
|
2194 |
|
|
# email: string
|
2195 |
|
|
# fullname: string
|
2196 |
|
|
# phone: string
|
2197 |
|
|
# services: string
|
2198 |
|
|
# recovery: string
|
2199 |
|
|
# alertemail: string
|
2200 |
|
|
|
2201 |
|
|
my $system = $obj->{system};
|
2202 |
|
|
my $newsystem = $obj->{newsystem};
|
2203 |
|
|
my $buildsystem = $obj->{buildsystem};
|
2204 |
|
|
my $nicmac1 = $obj->{nicmac1};
|
2205 |
|
|
$console = $console || $obj->{console};
|
2206 |
|
|
|
2207 |
|
|
$postmsg = '' if ($buildsystem);
|
2208 |
|
|
if (!$uuid && $nicmac1) {
|
2209 |
|
|
$uuid = nicmac1ToUuid($nicmac1); # If no uuid try to locate based on mac
|
2210 |
|
|
}
|
2211 |
|
|
if (!$uuid && $uripath =~ /servers(\.cgi)?\/(.+)/) { # Try to parse uuid out of URI
|
2212 |
|
|
my $huuid = $2;
|
2213 |
|
|
if ($ug->to_string($ug->from_string($huuid)) eq $huuid) { # Check for valid uuid
|
2214 |
|
|
$uuid = $huuid;
|
2215 |
|
|
}
|
2216 |
|
|
}
|
2217 |
|
|
my $regserv = $register{$uuid};
|
2218 |
|
|
my $status = $regserv->{'status'} || 'new';
|
2219 |
|
|
if ((!$uuid) && $status eq 'new') {
|
2220 |
|
|
my $ug = new Data::UUID;
|
2221 |
|
|
$uuid = $ug->create_str();
|
2222 |
|
|
};
|
2223 |
|
|
unless ($uuid && length $uuid == 36){
|
2224 |
48fcda6b
|
Origo
|
$postmsg = "Status=Error No valid uuid ($uuid), $obj->{image}";
|
2225 |
95b003ff
|
Origo
|
return $postmsg;
|
2226 |
|
|
}
|
2227 |
|
|
$nicmac1 = $nicmac1 || $regserv->{'nicmac1'};
|
2228 |
|
|
my $name = $obj->{name} || $regserv->{'name'};
|
2229 |
|
|
my $memory = $obj->{memory} || $regserv->{'memory'};
|
2230 |
|
|
my $vcpu = $obj->{vcpu} || $regserv->{'vcpu'};
|
2231 |
|
|
my $image = $obj->{image} || $regserv->{'image'};
|
2232 |
|
|
my $imagename = $obj->{imagename} || $regserv->{'imagename'};
|
2233 |
|
|
my $image2 = $obj->{image2} || $regserv->{'image2'};
|
2234 |
|
|
my $image2name = $obj->{image2name} || $regserv->{'image2name'};
|
2235 |
|
|
my $image3 = $obj->{image3} || $regserv->{'image3'};
|
2236 |
|
|
my $image3name = $obj->{image3name} || $regserv->{'image3name'};
|
2237 |
|
|
my $image4 = $obj->{image4} || $regserv->{'image4'};
|
2238 |
|
|
my $image4name = $obj->{image4name} || $regserv->{'image4name'};
|
2239 |
|
|
my $diskbus = $obj->{diskbus} || $regserv->{'diskbus'};
|
2240 |
|
|
my $cdrom = $obj->{cdrom} || $regserv->{'cdrom'};
|
2241 |
|
|
my $boot = $obj->{boot} || $regserv->{'boot'};
|
2242 |
04c16f26
|
hq
|
my $loader = $obj->{loader} || $regserv->{'loader'};
|
2243 |
95b003ff
|
Origo
|
my $networkuuid1 = ($obj->{networkuuid1} || $obj->{networkuuid1} eq '0')?$obj->{networkuuid1}:$regserv->{'networkuuid1'};
|
2244 |
|
|
my $networkid1 = $obj->{networkid1} || $regserv->{'networkid1'};
|
2245 |
|
|
my $networkname1 = $obj->{networkname1} || $regserv->{'networkname1'};
|
2246 |
|
|
my $nicmodel1 = $obj->{nicmodel1} || $regserv->{'nicmodel1'};
|
2247 |
|
|
my $networkuuid2 = ($obj->{networkuuid2} || $obj->{networkuuid2} eq '0')?$obj->{networkuuid2}:$regserv->{'networkuuid2'};
|
2248 |
|
|
my $networkid2 = $obj->{networkid2} || $regserv->{'networkid2'};
|
2249 |
|
|
my $networkname2 = $obj->{networkname2} || $regserv->{'networkname2'};
|
2250 |
|
|
my $nicmac2 = $obj->{nicmac2} || $regserv->{'nicmac2'};
|
2251 |
|
|
my $networkuuid3 = ($obj->{networkuuid3} || $obj->{networkuuid3} eq '0')?$obj->{networkuuid3}:$regserv->{'networkuuid3'};
|
2252 |
|
|
my $networkid3 = $obj->{networkid3} || $regserv->{'networkid3'};
|
2253 |
|
|
my $networkname3 = $obj->{networkname3} || $regserv->{'networkname3'};
|
2254 |
|
|
my $nicmac3 = $obj->{nicmac3} || $regserv->{'nicmac3'};
|
2255 |
|
|
my $notes = $obj->{notes} || $regserv->{'notes'};
|
2256 |
|
|
my $autostart = $obj->{autostart} || $regserv->{'autostart'};
|
2257 |
|
|
my $locktonode = $obj->{locktonode} || $regserv->{'locktonode'};
|
2258 |
|
|
my $mac = $obj->{mac} || $regserv->{'mac'};
|
2259 |
|
|
my $created = $regserv->{'created'} || time;
|
2260 |
|
|
# Sanity checks
|
2261 |
|
|
my $tenderpaths = $Stabile::config->get('STORAGE_POOLS_LOCAL_PATHS') || "/mnt/stabile/images";
|
2262 |
|
|
my @tenderpathslist = split(/,\s*/, $tenderpaths);
|
2263 |
|
|
|
2264 |
|
|
$networkid1 = $networkreg{$networkuuid1}->{'id'};
|
2265 |
|
|
my $networktype1 = $networkreg{$networkuuid1}->{'type'};
|
2266 |
|
|
my $networktype2;
|
2267 |
|
|
if (!$nicmac1 || $nicmac1 eq "--") {$nicmac1 = randomMac();}
|
2268 |
|
|
if ($networkuuid2 && $networkuuid2 ne "--") {
|
2269 |
|
|
$networkid2 = $networkreg{$networkuuid2}->{'id'};
|
2270 |
|
|
$nicmac2 = randomMac() if (!$nicmac2 || $nicmac2 eq "--");
|
2271 |
|
|
$networktype2 = $networkreg{$networkuuid2}->{'type'};
|
2272 |
|
|
}
|
2273 |
|
|
if ($networkuuid3 && $networkuuid3 ne "--") {
|
2274 |
|
|
$networkid3 = $networkreg{$networkuuid3}->{'id'};
|
2275 |
|
|
$networkname3 = $networkreg{$networkuuid3}->{'name'};
|
2276 |
|
|
$nicmac3 = randomMac() if (!$nicmac3 || $nicmac3 eq "--");
|
2277 |
|
|
$networktype3 = $networkreg{$networkuuid3}->{'type'};
|
2278 |
|
|
}
|
2279 |
|
|
|
2280 |
|
|
my $imgdup;
|
2281 |
|
|
my $netdup;
|
2282 |
|
|
my $json_text; # returned if all goes well
|
2283 |
|
|
|
2284 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
2285 |
|
|
|
2286 |
|
|
if ($networkid1 > 1 && $networkid2 > 1 && $networktype1 ne 'gateway' && $networktype2 ne 'gateway'
|
2287 |
|
|
&& $networkuuid1 eq $networkuuid2) {
|
2288 |
|
|
$netdup = 1;
|
2289 |
|
|
}
|
2290 |
|
|
if ($networkid1 > 1 && $networkid3 > 1 && $networktype1 ne 'gateway' && $networktype3 ne 'gateway'
|
2291 |
|
|
&& $networkuuid1 eq $networkuuid3) {
|
2292 |
|
|
$netdup = 11;
|
2293 |
|
|
}
|
2294 |
|
|
|
2295 |
|
|
if ($image eq $image2
|
2296 |
|
|
|| $image eq $image3
|
2297 |
|
|
|| $image eq $image4
|
2298 |
|
|
|| $image2 && $image2 ne '--' && $image2 eq $image3
|
2299 |
|
|
|| $image2 && $image2 ne '--' && $image2 eq $image4
|
2300 |
|
|
|| $image3 && $image3 ne '--' && $image3 eq $image4
|
2301 |
|
|
) {
|
2302 |
|
|
$imgdup = 1;
|
2303 |
|
|
} elsif ($image =~ m/\.master\.qcow2/
|
2304 |
|
|
|| $image2 =~ m/\.master\.qcow2/
|
2305 |
|
|
|| $image3 =~ m/\.master\.qcow2/
|
2306 |
|
|
|| $image4 =~ m/\.master\.qcow2/
|
2307 |
|
|
) {
|
2308 |
|
|
$imgdup = 2;
|
2309 |
|
|
} else {
|
2310 |
|
|
# Check if another server is using image
|
2311 |
|
|
my @regkeys = (tied %register)->select_where("user = '$user' OR user = 'common'");
|
2312 |
|
|
foreach my $k (@regkeys) {
|
2313 |
|
|
my $val = $register{$k};
|
2314 |
|
|
my %h = %$val;
|
2315 |
|
|
if ($h{'uuid'} ne $uuid) {
|
2316 |
|
|
if (
|
2317 |
|
|
$image eq $h{'image'} || $image eq $h{'image2'}|| $image eq $h{'image3'}|| $image eq $h{'image4'}
|
2318 |
|
|
) {
|
2319 |
|
|
$imgdup = 51;
|
2320 |
|
|
} elsif ($image2 && $image2 ne "--" &&
|
2321 |
|
|
($image2 eq $h{'image'} || $image2 eq $h{'image2'} || $image2 eq $h{'image3'} || $image2 eq $h{'image4'})
|
2322 |
|
|
) {
|
2323 |
|
|
$imgdup = 52;
|
2324 |
|
|
} elsif ($image3 && $image3 ne "--" &&
|
2325 |
|
|
($image3 eq $h{'image'} || $image3 eq $h{'image2'} || $image3 eq $h{'image3'} || $image3 eq $h{'image4'})
|
2326 |
|
|
) {
|
2327 |
|
|
$imgdup = 53;
|
2328 |
|
|
} elsif ($image4 && $image4 ne "--" &&
|
2329 |
|
|
($image4 eq $h{'image'} || $image4 eq $h{'image2'} || $image4 eq $h{'image3'} || $image4 eq $h{'image4'})
|
2330 |
|
|
) {
|
2331 |
|
|
$imgdup = 54;
|
2332 |
|
|
}
|
2333 |
|
|
|
2334 |
|
|
if ($networkid1>1) {
|
2335 |
|
|
if ($networktype1 ne 'gateway' &&
|
2336 |
|
|
($networkuuid1 eq $h{'networkuuid1'} || $networkuuid1 eq $h{'networkuuid2'})
|
2337 |
|
|
) {
|
2338 |
|
|
$netdup = 51;
|
2339 |
|
|
}
|
2340 |
|
|
}
|
2341 |
|
|
if ($networkid2>1) {
|
2342 |
|
|
if ($networktype2 ne 'gateway' && $networkuuid2 && $networkuuid2 ne "--" &&
|
2343 |
|
|
($networkuuid2 eq $h{'networkuuid1'} || $networkuuid2 eq $h{'networkuuid2'})
|
2344 |
|
|
) {
|
2345 |
|
|
$netdup = 52;
|
2346 |
|
|
}
|
2347 |
|
|
}
|
2348 |
|
|
}
|
2349 |
|
|
}
|
2350 |
|
|
my $legalpath;
|
2351 |
|
|
if ($image =~ m/\/mnt\/stabile\/node\/$user/) {
|
2352 |
|
|
$legalpath = 1;
|
2353 |
|
|
} else {
|
2354 |
|
|
foreach my $path (@tenderpathslist) {
|
2355 |
|
|
if ($image =~ m/$path\/$user/) {
|
2356 |
|
|
$legalpath = 1;
|
2357 |
|
|
last;
|
2358 |
|
|
}
|
2359 |
|
|
}
|
2360 |
|
|
}
|
2361 |
|
|
$imgdup = 6 unless $legalpath;
|
2362 |
|
|
if ($image2 && $image2 ne "--") { # TODO: We should probably check for conflicting nodes for image3 and image 4 too
|
2363 |
|
|
if ($image2 =~ m/\/mnt\/stabile\/node\/$user/) {
|
2364 |
|
|
if ($image =~ m/\/mnt\/stabile\/node\/$user/) {
|
2365 |
|
|
if ($imagereg{$image}->{'mac'} eq $imagereg{$image2}->{'mac'}) {
|
2366 |
|
|
$legalpath = 1;
|
2367 |
|
|
} else {
|
2368 |
|
|
$legalpath = 0; # Images are on two different nodes
|
2369 |
|
|
}
|
2370 |
|
|
} else {
|
2371 |
|
|
$legalpath = 1;
|
2372 |
|
|
}
|
2373 |
|
|
} else {
|
2374 |
|
|
$legalpath = 0;
|
2375 |
|
|
foreach my $path (@tenderpathslist) {
|
2376 |
|
|
if ($image2 =~ m/$path\/$user/) {
|
2377 |
|
|
$legalpath = 1;
|
2378 |
|
|
last;
|
2379 |
|
|
}
|
2380 |
|
|
}
|
2381 |
|
|
}
|
2382 |
|
|
$imgdup = 7 unless $legalpath;
|
2383 |
|
|
}
|
2384 |
|
|
}
|
2385 |
|
|
|
2386 |
|
|
if (!$imgdup && !$netdup) {
|
2387 |
|
|
if ($status eq "new") {
|
2388 |
|
|
$status = "shutoff";
|
2389 |
|
|
$name = $name || 'New Server';
|
2390 |
|
|
$memory = $memory || 1024;
|
2391 |
|
|
$vcpu = $vcpu || 1;
|
2392 |
|
|
$imagename = $imagename || '--';
|
2393 |
|
|
$image2 = $image2 || '--';
|
2394 |
|
|
$image2name = $image2name || '--';
|
2395 |
|
|
$image3 = $image3 || '--';
|
2396 |
|
|
$image3name = $image3name || '--';
|
2397 |
|
|
$image4 = $image4 || '--';
|
2398 |
|
|
$image4name = $image4name || '--';
|
2399 |
|
|
$diskbus = $diskbus || 'ide';
|
2400 |
|
|
$cdrom = $cdrom || '--';
|
2401 |
|
|
$boot = $boot || 'hd';
|
2402 |
04c16f26
|
hq
|
$loader = $loader || 'bios';
|
2403 |
95b003ff
|
Origo
|
$networkuuid1 = $networkuuid1 || 1;
|
2404 |
|
|
$networkid1 = $networkid1 || 1;
|
2405 |
|
|
$networkname1 = $networkname1 || '--';
|
2406 |
|
|
$nicmodel1 = $nicmodel1 || 'rtl8139';
|
2407 |
|
|
$nicmac1 = $nicmac1 || randomMac();
|
2408 |
|
|
$networkuuid2 = $networkuuid2 || '--';
|
2409 |
|
|
$networkid2 = $networkid2 || '--';
|
2410 |
|
|
$networkname2 = $networkname2 || '--';
|
2411 |
|
|
$nicmac2 = $nicmac2 || randomMac();
|
2412 |
|
|
$networkuuid3 = $networkuuid3 || '--';
|
2413 |
|
|
$networkid3 = $networkid3 || '--';
|
2414 |
|
|
$networkname3 = $networkname3 || '--';
|
2415 |
|
|
$nicmac3 = $nicmac3 || randomMac();
|
2416 |
|
|
# $uiuuid = $uuid; # No need to update ui for new server with jsonreststore
|
2417 |
8d7785ff
|
Origo
|
$postmsg .= "OK Created new server: $name";
|
2418 |
3657de20
|
Origo
|
$postmsg .= ", uuid: $uuid " if ($console);
|
2419 |
95b003ff
|
Origo
|
}
|
2420 |
|
|
# Update status of images
|
2421 |
|
|
my @imgs = ($image, $image2, $image3, $image4);
|
2422 |
|
|
my @imgkeys = ('image', 'image2', 'image3', 'image4');
|
2423 |
|
|
for (my $i=0; $i<4; $i++) {
|
2424 |
|
|
my $img = $imgs[$i];
|
2425 |
|
|
my $k = $imgkeys[$i];
|
2426 |
|
|
my $regimg = $imagereg{$img};
|
2427 |
|
|
# if ($img && $img ne '--' && ($status eq 'new' || $img ne $regserv->{$k})) { # Servers image changed - update image status
|
2428 |
|
|
if ($img && $img ne '--') { # Always update image status
|
2429 |
|
|
$regimg->{'status'} = 'used' if (
|
2430 |
|
|
$regimg->{'status'} eq 'unused'
|
2431 |
|
|
# Image cannot be active if server is shutoff
|
2432 |
|
|
|| ($regimg->{'status'} eq 'active' && $status eq 'shutoff')
|
2433 |
|
|
);
|
2434 |
|
|
$regimg->{'domains'} = $uuid;
|
2435 |
|
|
$regimg->{'domainnames'} = $name;
|
2436 |
|
|
}
|
2437 |
|
|
# If image has changed, release the old image
|
2438 |
|
|
if ($status ne 'new' && $img ne $regserv->{$k} && $imagereg{$regserv->{$k}}) {
|
2439 |
|
|
$imagereg{$regserv->{$k}}->{'status'} = 'unused';
|
2440 |
|
|
delete $imagereg{$regserv->{$k}}->{'domains'};
|
2441 |
|
|
delete $imagereg{$regserv->{$k}}->{'domainnames'};
|
2442 |
|
|
}
|
2443 |
|
|
}
|
2444 |
|
|
|
2445 |
|
|
my $valref = {
|
2446 |
|
|
uuid=>$uuid,
|
2447 |
|
|
user=>$user,
|
2448 |
|
|
name=>$name,
|
2449 |
|
|
memory=>$memory,
|
2450 |
|
|
vcpu=>$vcpu,
|
2451 |
|
|
image=>$image,
|
2452 |
|
|
imagename=>$imagename,
|
2453 |
|
|
image2=>$image2,
|
2454 |
|
|
image2name=>$image2name,
|
2455 |
|
|
image3=>$image3,
|
2456 |
|
|
image3name=>$image3name,
|
2457 |
|
|
image4=>$image4,
|
2458 |
|
|
image4name=>$image4name,
|
2459 |
|
|
diskbus=>$diskbus,
|
2460 |
|
|
cdrom=>$cdrom,
|
2461 |
|
|
boot=>$boot,
|
2462 |
04c16f26
|
hq
|
loader=>$loader,
|
2463 |
95b003ff
|
Origo
|
networkuuid1=>$networkuuid1,
|
2464 |
|
|
networkid1=>$networkid1,
|
2465 |
|
|
networkname1=>$networkname1,
|
2466 |
|
|
nicmodel1=>$nicmodel1,
|
2467 |
|
|
nicmac1=>$nicmac1,
|
2468 |
|
|
networkuuid2=>$networkuuid2,
|
2469 |
|
|
networkid2=>$networkid2,
|
2470 |
|
|
networkname2=>$networkname2,
|
2471 |
|
|
nicmac2=>$nicmac2,
|
2472 |
|
|
networkuuid3=>$networkuuid3,
|
2473 |
|
|
networkid3=>$networkid3,
|
2474 |
|
|
networkname3=>$networkname3,
|
2475 |
|
|
nicmac3=>$nicmac3,
|
2476 |
|
|
status=>$status,
|
2477 |
|
|
notes=>$notes,
|
2478 |
|
|
autostart=>$autostart,
|
2479 |
|
|
locktonode=>$locktonode,
|
2480 |
|
|
action=>"",
|
2481 |
|
|
created=>$created
|
2482 |
|
|
};
|
2483 |
|
|
$valref->{'system'} = $system if ($system);
|
2484 |
|
|
if ($mac && $locktonode eq 'true') {
|
2485 |
|
|
$valref->{'mac'} = $mac;
|
2486 |
|
|
$valref->{'macip'} = $nodereg{$mac}->{'ip'};
|
2487 |
|
|
$valref->{'macname'} = $nodereg{$mac}->{'name'};
|
2488 |
|
|
}
|
2489 |
|
|
if ($newsystem) {
|
2490 |
|
|
my $ug = new Data::UUID;
|
2491 |
|
|
$sysuuid = $ug->create_str();
|
2492 |
|
|
$valref->{'system'} = $sysuuid;
|
2493 |
3657de20
|
Origo
|
$postmsg .= "OK sysuuid: $sysuuid " if ($console);
|
2494 |
95b003ff
|
Origo
|
}
|
2495 |
|
|
|
2496 |
|
|
# Remove domain uuid from old networks. Leave gateways alone - they get updated on next listing
|
2497 |
|
|
my $oldnetworkuuid1 = $regserv->{'networkuuid1'};
|
2498 |
|
|
if ($oldnetworkuuid1 ne $networkuuid1 && $networkreg{$oldnetworkuuid1}) {
|
2499 |
|
|
$networkreg{$oldnetworkuuid1}->{'domains'} =~ s/($uuid)(,?)( ?)//;
|
2500 |
|
|
}
|
2501 |
|
|
|
2502 |
|
|
$register{$uuid} = validateItem($valref);
|
2503 |
|
|
|
2504 |
|
|
if ($networkreg{$networkuuid1}->{'type'} eq 'gateway') {
|
2505 |
04c16f26
|
hq
|
# We now remove before adding to support API calls that dont necessarily list afterwards
|
2506 |
|
|
$networkreg{$networkuuid1}->{'domains'} =~ s/($uuid)(,?)( ?)//;
|
2507 |
95b003ff
|
Origo
|
my $domains = $networkreg{$networkuuid1}->{'domains'};
|
2508 |
|
|
$networkreg{$networkuuid1}->{'domains'} = ($domains?"$domains, ":"") . $uuid;
|
2509 |
04c16f26
|
hq
|
|
2510 |
|
|
$networkreg{$networkuuid1}->{'domainnames'} =~ s/($name)(,?)( ?)//;
|
2511 |
95b003ff
|
Origo
|
my $domainnames = $networkreg{$networkuuid1}->{'domainnames'};
|
2512 |
|
|
$networkreg{$networkuuid1}->{'domainnames'} = ($domainnames?"$domainnames, ":"") . $name;
|
2513 |
|
|
} else {
|
2514 |
|
|
$networkreg{$networkuuid1}->{'domains'} = $uuid;
|
2515 |
|
|
$networkreg{$networkuuid1}->{'domainnames'} = $name;
|
2516 |
|
|
}
|
2517 |
|
|
|
2518 |
|
|
if ($networkuuid2 && $networkuuid2 ne '--') {
|
2519 |
|
|
if ($networkreg{$networkuuid2}->{'type'} eq 'gateway') {
|
2520 |
04c16f26
|
hq
|
$networkreg{$networkuuid2}->{'domains'} =~ s/($uuid)(,?)( ?)//;
|
2521 |
95b003ff
|
Origo
|
my $domains = $networkreg{$networkuuid2}->{'domains'};
|
2522 |
|
|
$networkreg{$networkuuid2}->{'domains'} = ($domains?"$domains, ":"") . $uuid;
|
2523 |
04c16f26
|
hq
|
|
2524 |
|
|
$networkreg{$networkuuid2}->{'domainnames'} =~ s/($name)(,?)( ?)//;
|
2525 |
95b003ff
|
Origo
|
my $domainnames = $networkreg{$networkuuid2}->{'domainnames'};
|
2526 |
|
|
$networkreg{$networkuuid2}->{'domainnames'} = ($domainnames?"$domainnames, ":"") . $name;
|
2527 |
|
|
} else {
|
2528 |
|
|
$networkreg{$networkuuid2}->{'domains'} = $uuid;
|
2529 |
|
|
$networkreg{$networkuuid2}->{'domainnames'} = $name;
|
2530 |
|
|
}
|
2531 |
|
|
}
|
2532 |
|
|
|
2533 |
|
|
if ($networkuuid3 && $networkuuid3 ne '--') {
|
2534 |
|
|
if ($networkreg{$networkuuid3}->{'type'} eq 'gateway') {
|
2535 |
|
|
my $domains = $networkreg{$networkuuid3}->{'domains'};
|
2536 |
|
|
$networkreg{$networkuuid3}->{'domains'} = ($domains?"$domains, ":"") . $uuid;
|
2537 |
|
|
my $domainnames = $networkreg{$networkuuid3}->{'domainnames'};
|
2538 |
|
|
$networkreg{$networkuuid3}->{'domainnames'} = ($domainnames?"$domainnames, ":"") . $name;
|
2539 |
|
|
} else {
|
2540 |
|
|
$networkreg{$networkuuid3}->{'domains'} = $uuid;
|
2541 |
|
|
$networkreg{$networkuuid3}->{'domainnames'} = $name;
|
2542 |
|
|
}
|
2543 |
|
|
}
|
2544 |
|
|
my %jitem = %{$register{$uuid}};
|
2545 |
|
|
$json_text = to_json(\%jitem, {pretty=>1});
|
2546 |
|
|
$json_text =~ s/null/"--"/g;
|
2547 |
|
|
$uiuuid = $uuid;
|
2548 |
|
|
$uiname = $name;
|
2549 |
|
|
|
2550 |
|
|
tied(%register)->commit;
|
2551 |
|
|
tied(%imagereg)->commit;
|
2552 |
|
|
tied(%networkreg)->commit;
|
2553 |
|
|
|
2554 |
|
|
} else {
|
2555 |
48fcda6b
|
Origo
|
$postmsg .= "ERROR This image ($image) cannot be used ($imgdup) " if ($imgdup);
|
2556 |
|
|
$postmsg .= "ERROR This network ($networkname1) cannot be used ($netdup)" if ($netdup);
|
2557 |
95b003ff
|
Origo
|
}
|
2558 |
|
|
|
2559 |
|
|
my $domuser = $obj->{'user'};
|
2560 |
|
|
# We were asked to move server to another account
|
2561 |
|
|
if ($domuser && $domuser ne '--' && $domuser ne $user) {
|
2562 |
|
|
unless ( tie(%userreg,'Tie::DBI', Hash::Merge::merge({table=>'users', key=>'username', CLOBBER=>0}, $Stabile::dbopts)) ) {throw Error::Simple("Stroke=Error User register could not be accessed")};
|
2563 |
|
|
if ($status eq 'shutoff' || $status eq 'inactive') {
|
2564 |
|
|
unless ( tie(%userreg,'Tie::DBI', Hash::Merge::merge({table=>'users', key=>'username', CLOBBER=>1}, $Stabile::dbopts)) ) {$posterror = "Unable to access user register"; return 0;};
|
2565 |
|
|
my @accounts = split(/,\s*/, $userreg{$tktuser}->{'accounts'});
|
2566 |
|
|
my @accountsprivs = split(/,\s*/, $userreg{$tktuser}->{'accountsprivileges'});
|
2567 |
|
|
%ahash = ($tktuser, $userreg{$tktuser}->{'privileges'}); # Include tktuser in accounts hash
|
2568 |
|
|
for my $i (0 .. scalar @accounts)
|
2569 |
|
|
{
|
2570 |
|
|
next unless $accounts[$i];
|
2571 |
|
|
$ahash{$accounts[$i]} = $accountsprivs[$i] || 'r';
|
2572 |
|
|
}
|
2573 |
|
|
untie %userreg;
|
2574 |
|
|
|
2575 |
|
|
if (!$isreadonly && $ahash{$domuser} && !($ahash{$domuser} =~ /r/)) { # Check if user is allow to access account
|
2576 |
|
|
my $imgdone;
|
2577 |
|
|
my $netdone;
|
2578 |
|
|
# First move main image
|
2579 |
|
|
$Stabile::Images::user = $user;
|
2580 |
|
|
require "$Stabile::basedir/cgi/images.cgi";
|
2581 |
|
|
$Stabile::Images::console = 1;
|
2582 |
|
|
$main::updateUI->({tab=>"servers", user=>$user, message=>"Moving image $imagename to account: $domuser"});
|
2583 |
|
|
my $nimage = Stabile::Images::Move($image, $domuser);
|
2584 |
48fcda6b
|
Origo
|
chomp $nimage;
|
2585 |
95b003ff
|
Origo
|
if ($nimage) {
|
2586 |
|
|
$main::syslogit->($user, "info", "Moving $nimage to account: $domuser");
|
2587 |
|
|
$register{$uuid}->{'image'} = $nimage;
|
2588 |
|
|
$imgdone = 1;
|
2589 |
|
|
} else {
|
2590 |
|
|
$main::syslogit->($user, "info", "Unable to move image $imagename to account: $domuser");
|
2591 |
|
|
}
|
2592 |
|
|
# Move other attached images
|
2593 |
|
|
my @images = ($image2, $image3, $image4);
|
2594 |
|
|
my @imagenames = ($image2name, $image3name, $image4name);
|
2595 |
|
|
my @imagekeys = ('image2', 'image3', 'image4');
|
2596 |
|
|
for (my $i=0; $i<3; $i++) {
|
2597 |
|
|
my $img = $images[$i];
|
2598 |
|
|
my $imgname = $imagenames[$i];
|
2599 |
|
|
my $imgkey = $imagekeys[$i];
|
2600 |
|
|
if ($img && $img ne '--') {
|
2601 |
|
|
$main::updateUI->({tab=>"servers", user=>$user, message=>"Moving $imgkey $imgname to account: $domuser"});
|
2602 |
|
|
$nimage = Stabile::Images::Move($img, $domuser);
|
2603 |
48fcda6b
|
Origo
|
chomp $nimage;
|
2604 |
95b003ff
|
Origo
|
if ($nimage) {
|
2605 |
|
|
$main::syslogit->($user, "info", "Moving $nimage to account: $domuser");
|
2606 |
|
|
$register{$uuid}->{$imgkey} = $nimage;
|
2607 |
|
|
} else {
|
2608 |
|
|
$main::syslogit->($user, "info", "Unable to move $imagekeys[$i] $img to account: $domuser");
|
2609 |
|
|
}
|
2610 |
|
|
}
|
2611 |
|
|
}
|
2612 |
6fdc8676
|
hq
|
# Then move network(s)
|
2613 |
95b003ff
|
Origo
|
if ($imgdone) {
|
2614 |
|
|
$Stabile::Networks::user = $user;
|
2615 |
|
|
require "$Stabile::basedir/cgi/networks.cgi";
|
2616 |
|
|
$Stabile::Networks::console = 1;
|
2617 |
|
|
my @networks = ($networkuuid1, $networkuuid2, $networkuuid3);
|
2618 |
|
|
my @netkeys = ('networkuuid1', 'networkuuid2', 'networkuuid3');
|
2619 |
|
|
my @netnamekeys = ('networkname1', 'networkname2', 'networkname3');
|
2620 |
|
|
for (my $i=0; $i<scalar @networks; $i++) {
|
2621 |
|
|
my $net = $networks[$i];
|
2622 |
|
|
my $netkey = $netkeys[$i];
|
2623 |
|
|
my $netnamekey = $netnamekeys[$i];
|
2624 |
48fcda6b
|
Origo
|
my $regnet = $networkreg{$net};
|
2625 |
|
|
my $oldid = $regnet->{'id'};
|
2626 |
95b003ff
|
Origo
|
next if ($net eq '' || $net eq '--');
|
2627 |
48fcda6b
|
Origo
|
if ($regnet->{'type'} eq 'gateway') {
|
2628 |
95b003ff
|
Origo
|
if ($oldid > 1) { # Private gateway
|
2629 |
|
|
foreach my $networkvalref (values %networkreg) { # use gateway with same id if it exists
|
2630 |
|
|
if ($networkvalref->{'user'} eq $domuser
|
2631 |
|
|
&& $networkvalref->{'type'} eq 'gateway'
|
2632 |
|
|
&& $networkvalref->{'id'} == $oldid) {
|
2633 |
|
|
# We found an existing gateway with same id - use it
|
2634 |
|
|
$register{$uuid}->{$netkey} = $networkvalref->{'uuid'};
|
2635 |
|
|
$register{$uuid}->{$netnamekey} = $networkvalref->{'name'};
|
2636 |
|
|
$netdone = 1;
|
2637 |
|
|
$main::updateUI->({tab=>"networks", user=>$user, message=>"Using network $networkvalref->{'name'} from account: $domuser"});
|
2638 |
|
|
last;
|
2639 |
|
|
}
|
2640 |
|
|
}
|
2641 |
|
|
if (!($netdone)) {
|
2642 |
|
|
# Make a new gateway
|
2643 |
|
|
my $ug = new Data::UUID;
|
2644 |
|
|
my $newuuid = $ug->create_str();
|
2645 |
48fcda6b
|
Origo
|
Stabile::Networks::save($oldid, $newuuid, $regnet->{'name'}, 'new', 'gateway', '', '', $regnet->{'ports'}, 0, $domuser);
|
2646 |
95b003ff
|
Origo
|
$register{$uuid}->{$netkey} = $newuuid;
|
2647 |
48fcda6b
|
Origo
|
$register{$uuid}->{$netnamekey} = $regnet->{'name'};
|
2648 |
95b003ff
|
Origo
|
$netdone = 1;
|
2649 |
48fcda6b
|
Origo
|
$main::updateUI->({tab=>"networks", user=>$user, message=>"Created gateway $regnet->{'name'} for account: $domuser"});
|
2650 |
|
|
$main::syslogit->($user, "info", "Created gateway $regnet->{'name'} for account: $domuser");
|
2651 |
95b003ff
|
Origo
|
}
|
2652 |
|
|
} elsif ($oldid==0 || $oldid==1) {
|
2653 |
|
|
$netdone = 1; # Use common gateway
|
2654 |
48fcda6b
|
Origo
|
$main::updateUI->({tab=>"networks", user=>$user, message=>"Reused network $regnet->{'name'} for account: $domuser"});
|
2655 |
95b003ff
|
Origo
|
}
|
2656 |
|
|
} else {
|
2657 |
|
|
my $newid = Stabile::Networks::getNextId('', $domuser);
|
2658 |
|
|
$networkreg{$net}->{'id'} = $newid;
|
2659 |
|
|
$networkreg{$net}->{'user'} = $domuser;
|
2660 |
6fdc8676
|
hq
|
# if ($regnet->{'type'} eq 'internalip' || $regnet->{'type'} eq 'ipmapping') {
|
2661 |
95b003ff
|
Origo
|
# Deactivate network and assign new internal ip
|
2662 |
48fcda6b
|
Origo
|
Stabile::Networks::Deactivate($regnet->{'uuid'});
|
2663 |
95b003ff
|
Origo
|
$networkreg{$net}->{'internalip'} =
|
2664 |
48fcda6b
|
Origo
|
Stabile::Networks::getNextInternalIP('',$regnet->{'uuid'}, $newid, $domuser);
|
2665 |
6fdc8676
|
hq
|
# }
|
2666 |
95b003ff
|
Origo
|
$netdone = 1;
|
2667 |
48fcda6b
|
Origo
|
$main::updateUI->({tab=>"networks", user=>$user, message=>"Moved network $regnet->{'name'} to account: $domuser"});
|
2668 |
|
|
$main::syslogit->($user, "info", "Moved network $regnet->{'name'} to account: $domuser");
|
2669 |
95b003ff
|
Origo
|
}
|
2670 |
|
|
}
|
2671 |
|
|
if ($netdone) {
|
2672 |
|
|
# Finally move the server
|
2673 |
|
|
$register{$uuid}->{'user'} = $domuser;
|
2674 |
48fcda6b
|
Origo
|
$postmsg .= "OK Moved server $name to account: $domuser";
|
2675 |
95b003ff
|
Origo
|
$main::syslogit->($user, "info", "Moved server $name ($uuid) to account: $domuser");
|
2676 |
48fcda6b
|
Origo
|
$main::updateUI->({tab=>"servers", user=>$user, type=>"update"});
|
2677 |
95b003ff
|
Origo
|
} else {
|
2678 |
48fcda6b
|
Origo
|
$postmsg .= "ERROR Unable to move network to account: $domuser";
|
2679 |
95b003ff
|
Origo
|
$main::updateUI->({tab=>"image", user=>$user, message=>"Unable to move network to account: $domuser"});
|
2680 |
|
|
}
|
2681 |
|
|
} else {
|
2682 |
|
|
$main::updateUI->({tab=>"image", user=>$user, message=>"Could not move image to account: $domuser"});
|
2683 |
|
|
}
|
2684 |
|
|
} else {
|
2685 |
48fcda6b
|
Origo
|
$postmsg .= "ERROR No access to move server";
|
2686 |
95b003ff
|
Origo
|
}
|
2687 |
|
|
} else {
|
2688 |
48fcda6b
|
Origo
|
$postmsg .= "Error Unable to move $status server";
|
2689 |
95b003ff
|
Origo
|
$main::updateUI->({tab=>"servers", user=>$user, message=>"Please shut down before moving server"});
|
2690 |
|
|
}
|
2691 |
|
|
untie %userreg;
|
2692 |
|
|
}
|
2693 |
|
|
|
2694 |
|
|
if ($console) {
|
2695 |
|
|
$postreply = $postmsg;
|
2696 |
|
|
} else {
|
2697 |
|
|
$postreply = $json_text || $postmsg;
|
2698 |
|
|
}
|
2699 |
|
|
return $postreply;
|
2700 |
|
|
untie %imagereg;
|
2701 |
|
|
}
|
2702 |
|
|
|
2703 |
|
|
|
2704 |
|
|
sub Shutdown {
|
2705 |
|
|
my ($uuid, $action, $obj) = @_;
|
2706 |
|
|
if ($help) {
|
2707 |
|
|
return <<END
|
2708 |
|
|
GET:uuid:
|
2709 |
|
|
Marks a server for shutdown, i.e. send and ACPI shutdown event to the server. If OS supports ACPI, it begins a shutdown.
|
2710 |
|
|
END
|
2711 |
|
|
}
|
2712 |
|
|
$uistatus = "shuttingdown";
|
2713 |
|
|
my $dbstatus = $obj->{status};
|
2714 |
|
|
my $mac = $obj->{mac};
|
2715 |
|
|
my $macname = $obj->{macname};
|
2716 |
|
|
my $name = $obj->{name};
|
2717 |
|
|
if ($dbstatus eq 'running') {
|
2718 |
|
|
my $tasks;
|
2719 |
|
|
$tasks = $nodereg{$mac}->{'tasks'} if ($nodereg{$mac});
|
2720 |
|
|
$nodereg{$mac}->{'tasks'} = $tasks . "SHUTDOWN $uuid $user\n";
|
2721 |
|
|
tied(%nodereg)->commit;
|
2722 |
|
|
$register{$uuid}->{'status'} = $uistatus;
|
2723 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
2724 |
|
|
$uiuuid = $uuid;
|
2725 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for $uistatus by $macname ($mac)");
|
2726 |
|
|
$postreply .= "Status=$uistatus OK $uistatus $name\n";
|
2727 |
|
|
} else {
|
2728 |
|
|
$main::syslogit->($user, "info", "Problem $uistatus a $dbstatus domain: $uuid");
|
2729 |
|
|
$postreply .= "Status=ERROR problem $uistatus $name...\n";
|
2730 |
|
|
}
|
2731 |
|
|
return $postreply;
|
2732 |
|
|
}
|
2733 |
|
|
|
2734 |
|
|
sub Suspend {
|
2735 |
|
|
my ($uuid, $action, $obj) = @_;
|
2736 |
|
|
if ($help) {
|
2737 |
|
|
return <<END
|
2738 |
|
|
GET:uuid:
|
2739 |
|
|
Marks a server for suspend, i.e. pauses the server. Server must be running
|
2740 |
|
|
END
|
2741 |
|
|
}
|
2742 |
|
|
# my $obj = getObj(('uuid', $uuid));
|
2743 |
|
|
$uistatus = "suspending";
|
2744 |
|
|
my $dbstatus = $obj->{status};
|
2745 |
|
|
my $mac = $obj->{mac};
|
2746 |
|
|
my $macname = $obj->{macname};
|
2747 |
|
|
my $name = $obj->{name};
|
2748 |
|
|
if ($dbstatus eq 'running') {
|
2749 |
|
|
my $tasks = $nodereg{$mac}->{'tasks'};
|
2750 |
|
|
$nodereg{$mac}->{'tasks'} = $tasks . "SUSPEND $uuid $user\n";
|
2751 |
|
|
tied(%nodereg)->commit;
|
2752 |
|
|
$register{$uuid}->{'status'} = $uistatus;
|
2753 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
2754 |
|
|
$uiuuid = $uuid;
|
2755 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for $uistatus by $macname ($mac)");
|
2756 |
|
|
$postreply .= "Status=$uistatus OK $uistatus $name.\n";
|
2757 |
|
|
} else {
|
2758 |
|
|
$main::syslogit->($user, "info", "Problem $uistatus a $dbstatus domain: $uuid");
|
2759 |
|
|
$postreply .= "Status=ERROR problem $uistatus $name.\n";
|
2760 |
|
|
}
|
2761 |
|
|
return $postreply;
|
2762 |
|
|
}
|
2763 |
|
|
|
2764 |
|
|
sub Resume {
|
2765 |
|
|
my ($uuid, $action, $obj) = @_;
|
2766 |
|
|
if ($help) {
|
2767 |
|
|
return <<END
|
2768 |
|
|
GET:uuid:
|
2769 |
|
|
Marks a server for resume running. Server must be paused.
|
2770 |
|
|
END
|
2771 |
|
|
}
|
2772 |
|
|
my $dbstatus = $obj->{status};
|
2773 |
|
|
my $mac = $obj->{mac};
|
2774 |
|
|
my $macname = $obj->{macname};
|
2775 |
|
|
my $name = $obj->{name};
|
2776 |
|
|
my $image = $obj->{image};
|
2777 |
|
|
my $image2 = $obj->{image2};
|
2778 |
|
|
my $image3 = $obj->{image3};
|
2779 |
|
|
my $image4 = $obj->{image4};
|
2780 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$posterror = "Unable to access image register"; return;};
|
2781 |
|
|
if ($imagereg{$image}->{'status'} ne "paused"
|
2782 |
|
|
|| ($image2 && $image2 ne '--' && $imagereg{$image}->{'status'} ne "paused")
|
2783 |
|
|
|| ($image3 && $image3 ne '--' && $imagereg{$image3}->{'status'} ne "paused")
|
2784 |
|
|
|| ($image4 && $image4 ne '--' && $imagereg{$image4}->{'status'} ne "paused")
|
2785 |
|
|
) {
|
2786 |
|
|
$postreply .= "Status=ERROR Image $uuid busy ($imagereg{$image}->{'status'}), please wait 30 sec.\n";
|
2787 |
|
|
untie %imagereg;
|
2788 |
|
|
return $postreply ;
|
2789 |
|
|
} else {
|
2790 |
|
|
untie %imagereg;
|
2791 |
|
|
}
|
2792 |
|
|
$uistatus = "resuming";
|
2793 |
|
|
if ($dbstatus eq 'paused') {
|
2794 |
|
|
my $tasks = $nodereg{$mac}->{'tasks'};
|
2795 |
|
|
$nodereg{$mac}->{'tasks'} = $tasks . "RESUME $uuid $user\n";
|
2796 |
|
|
tied(%nodereg)->commit;
|
2797 |
|
|
$register{$uuid}->{'status'} = $uistatus;
|
2798 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
2799 |
|
|
$uiuuid = $uuid;
|
2800 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for $uistatus by $macname ($mac)");
|
2801 |
|
|
$postreply .= "Status=$uistatus OK $uistatus ". $register{$uuid}->{'name'} . "\n";
|
2802 |
|
|
} else {
|
2803 |
|
|
$main::syslogit->($user, "info", "Problem $uistatus a $dbstatus domain: $uuid");
|
2804 |
|
|
$postreply .= "Status=ERROR problem $uistatus ". $register{$uuid}->{'name'} . "\n";
|
2805 |
|
|
}
|
2806 |
|
|
return $postreply;
|
2807 |
|
|
}
|
2808 |
|
|
|
2809 |
|
|
sub Move {
|
2810 |
|
|
my ($uuid, $action, $obj) = @_;
|
2811 |
|
|
if ($help) {
|
2812 |
|
|
return <<END
|
2813 |
|
|
GET:uuid,mac:
|
2814 |
48fcda6b
|
Origo
|
Moves a server to a different node (Qemu live migration). Server must be running
|
2815 |
95b003ff
|
Origo
|
END
|
2816 |
|
|
}
|
2817 |
|
|
my $dbstatus = $obj->{status};
|
2818 |
|
|
my $dmac = $obj->{mac};
|
2819 |
|
|
my $name = $obj->{name};
|
2820 |
|
|
my $mem = $obj->{memory};
|
2821 |
|
|
my $vcpu = $obj->{vcpu};
|
2822 |
|
|
my $image = $obj->{image};
|
2823 |
|
|
my $image2 = $obj->{image2};
|
2824 |
|
|
my $image3 = $obj->{image3};
|
2825 |
|
|
my $image4 = $obj->{image4};
|
2826 |
|
|
$uistatus = "moving";
|
2827 |
|
|
if ($dbstatus eq 'running' && $isadmin) {
|
2828 |
|
|
my $hypervisor = getHypervisor($image);
|
2829 |
|
|
my $mac = $register{$uuid}->{'mac'};
|
2830 |
|
|
$dmac = "" if ($dmac eq "--");
|
2831 |
|
|
$mac = "" if ($mac eq "--");
|
2832 |
|
|
|
2833 |
|
|
if ($image =~ /\/mnt\/stabile\/node\//
|
2834 |
|
|
|| $image2 =~ /\/mnt\/stabile\/node\//
|
2835 |
|
|
|| $image3 =~ /\/mnt\/stabile\/node\//
|
2836 |
|
|
|| $image4 =~ /\/mnt\/stabile\/node\//
|
2837 |
|
|
) {
|
2838 |
|
|
# We do not support moving locally stored VM's yet...
|
2839 |
|
|
$postreply = qq|{"error": 1, "message": "Moving servers with local storage not supported"}|;
|
2840 |
|
|
} else {
|
2841 |
|
|
my ($targetmac, $targetname, $targetip, $port) =
|
2842 |
|
|
locateTargetNode($uuid, $dmac, $mem, $vcpu, $image, $image2, $image3, $image4, $hypervisor, $mac);
|
2843 |
|
|
if ($targetmac) {
|
2844 |
|
|
my $tasks = $nodereg{$targetmac}->{'tasks'};
|
2845 |
|
|
$tasks = $tasks . "RECEIVE $uuid $user\n";
|
2846 |
|
|
# Also update allowed port forwards
|
2847 |
|
|
$nodereg{$targetmac}->{'tasks'} = $tasks . "PERMITOPEN $user\n";
|
2848 |
|
|
$register{$uuid}->{'status'} = "moving";
|
2849 |
|
|
$register{$uuid}->{'statustime'} = $current_time;
|
2850 |
|
|
$uiuuid = $uuid;
|
2851 |
|
|
$uidisplayip = $targetip;
|
2852 |
|
|
$uidisplayport = $port;
|
2853 |
|
|
$main::syslogit->($user, "info", "Marked $name ($uuid) for $uistatus to $targetname ($targetmac)");
|
2854 |
|
|
$postreply .= "Status=OK $uistatus ". $register{$uuid}->{'name'} . "\n";
|
2855 |
|
|
|
2856 |
|
|
if ($params{'PUTDATA'}) {
|
2857 |
|
|
my %jitem = %{$register{$uuid}};
|
2858 |
|
|
my $json_text = to_json(\%jitem);
|
2859 |
|
|
$json_text =~ s/null/"--"/g;
|
2860 |
|
|
$postreply = $json_text;
|
2861 |
|
|
}
|
2862 |
|
|
$main::updateUI->({tab=>"servers", user=>$user, status=>'moving', uuid=>$uuid, type=>'update', message=>"Moving $register{$uuid}->{name} to $targetmac"});
|
2863 |
|
|
} else {
|
2864 |
|
|
$main::syslogit->($user, "info", "Could not find $hypervisor target for $uistatus $uuid ($image)");
|
2865 |
|
|
$postreply = qq|{"error": 1, "message": "Could not find target for $uistatus $register{$uuid}->{'name'}"}|;
|
2866 |
|
|
}
|
2867 |
|
|
}
|
2868 |
|
|
} else {
|
2869 |
|
|
$main::syslogit->($user, "info", "Problem moving a $dbstatus domain: $uuid");
|
2870 |
|
|
$postreply .= qq|{"error": 1, "message": "ERROR problem moving $register{$uuid}->{'name'} ($dbstatus)"}|;
|
2871 |
|
|
}
|
2872 |
|
|
return $postreply;
|
2873 |
|
|
}
|
2874 |
|
|
|
2875 |
c899e439
|
Origo
|
sub Changepassword {
|
2876 |
|
|
my ($uuid, $action, $obj) = @_;
|
2877 |
|
|
if ($help) {
|
2878 |
|
|
return <<END
|
2879 |
|
|
POST:uuid,username,password:
|
2880 |
|
|
Attempts to set password for [username] to [password] using guestfish. If no username is specified, user 'stabile' is assumed.
|
2881 |
|
|
END
|
2882 |
|
|
}
|
2883 |
|
|
my $img = $register{$uuid}->{'image'};
|
2884 |
|
|
my $username = $obj->{'username'} || 'stabile';
|
2885 |
|
|
my $password = $obj->{'password'};
|
2886 |
|
|
return "Status=Error Please supply a password\n" unless ($password);
|
2887 |
|
|
return "Status=Error Please shut down the server before changing password\n" unless ($register{$uuid} && $register{$uuid}->{'status'} eq 'shutoff');
|
2888 |
|
|
return "Status=Error Not allowed\n" unless ($isadmin || $register{$uuid}->{'user'} eq $user);
|
2889 |
|
|
|
2890 |
|
|
unless (tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access images register"}|; return $res;};
|
2891 |
|
|
my $cmd = qq/guestfish --rw -a $img -i command "bash -c 'echo $username:$password | chpasswd'" 2>\&1/;
|
2892 |
|
|
if ($imagereg{$img} && $imagereg{$img}->{'mac'}) {
|
2893 |
|
|
my $mac = $imagereg{$img}->{'mac'};
|
2894 |
|
|
my $macip = $nodereg{$mac}->{'ip'};
|
2895 |
|
|
$cmd = "$sshcmd $macip $cmd";
|
2896 |
|
|
}
|
2897 |
|
|
my $res = `$cmd`;
|
2898 |
|
|
$res = $1 if ($res =~ /guestfish: (.*)/);
|
2899 |
|
|
chomp $res;
|
2900 |
|
|
return "Status=OK Ran chpasswd for user $username in server $register{$uuid}->{'name'}: $res\n";
|
2901 |
|
|
}
|
2902 |
|
|
|
2903 |
|
|
sub Sshaccess {
|
2904 |
|
|
my ($uuid, $action, $obj) = @_;
|
2905 |
|
|
if ($help) {
|
2906 |
|
|
return <<END
|
2907 |
|
|
POST:uuid,address:
|
2908 |
|
|
Attempts to change the ip addresses you can access the server over SSH (port 22) from, by adding [address] to /etc/hosts.allow.
|
2909 |
|
|
[address] should either be an IP address or a range in CIDR notation. Please note that no validation of [address] is performed.
|
2910 |
|
|
END
|
2911 |
|
|
}
|
2912 |
|
|
my $img = $register{$uuid}->{'image'};
|
2913 |
|
|
my $address = $obj->{'address'};
|
2914 |
|
|
return "Status=Error Please supply an aaddress\n" unless ($address);
|
2915 |
|
|
return "Status=Error Please shut down the server before changing SSH access\n" unless ($register{$uuid} && $register{$uuid}->{'status'} eq 'shutoff');
|
2916 |
|
|
return "Status=Error Not allowed\n" unless ($isadmin || $register{$uuid}->{'user'} eq $user);
|
2917 |
|
|
|
2918 |
|
|
unless (tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images', key=>'path'}, $Stabile::dbopts)) ) {$res .= qq|{"status": "Error": "message": "Unable to access images register"}|; return $res;};
|
2919 |
|
|
|
2920 |
|
|
my $isshcmd = '';
|
2921 |
|
|
my $cmd = qq[guestfish --rw -a $img -i command "sed -i -re 's|(sshd: .*)#stabile|\\1 $address #stabile|' /etc/hosts.allow"];
|
2922 |
|
|
# my $cmd = qq[guestfish --rw -a $img -i command "bash -c 'echo sshd: $address >> /etc/hosts.allow'"];
|
2923 |
|
|
if ($imagereg{$img} && $imagereg{$img}->{'mac'}) {
|
2924 |
|
|
my $mac = $imagereg{$img}->{'mac'};
|
2925 |
|
|
my $macip = $nodereg{$mac}->{'ip'};
|
2926 |
|
|
$isshcmd = "$sshcmd $macip ";
|
2927 |
|
|
}
|
2928 |
|
|
my $res = `$isshcmd$cmd`;
|
2929 |
|
|
chomp $res;
|
2930 |
|
|
#$cmd = qq[guestfish --rw -a $img -i command "bash -c 'cat /etc/hosts.allow'"];
|
2931 |
|
|
#$res .= `$isshcmd$cmd`;
|
2932 |
|
|
#chomp $res;
|
2933 |
|
|
return "Status=OK Tried to add sshd: $address to /etc/hosts.allow in server $register{$uuid}->{'name'}\n";
|
2934 |
|
|
}
|
2935 |
|
|
|
2936 |
95b003ff
|
Origo
|
sub Mountcd {
|
2937 |
|
|
my ($uuid, $action, $obj) = @_;
|
2938 |
|
|
if ($help) {
|
2939 |
|
|
return <<END
|
2940 |
|
|
GET:uuid,cdrom:
|
2941 |
|
|
Mounts a cdrom on a server. Server must be running. Mounting the special cdrom named '--' unomunts any currently mounted cdrom.
|
2942 |
|
|
END
|
2943 |
|
|
}
|
2944 |
|
|
my $dbstatus = $obj->{status};
|
2945 |
|
|
my $mac = $obj->{mac};
|
2946 |
|
|
my $cdrom = $obj->{cdrom};
|
2947 |
|
|
unless ($cdrom && $dbstatus eq 'running') {
|
2948 |
|
|
$main::updateUI->({tab=>"servers", user=>$user, uuid=>$uuid, type=>'update', message=>"Unable to mount cdrom"});
|
2949 |
|
|
$postreply = qq|{"Error": 1, "message": "Problem mounting cdrom on $obj->{name}"}|;
|
2950 |
|
|
return;
|
2951 |
|
|
}
|
2952 |
|
|
my $tasks = $nodereg{$mac}->{'tasks'};
|
2953 |
|
|
# $user is in the middle here, because $cdrom may contain spaces...
|
2954 |
|
|
$nodereg{$mac}->{'tasks'} = $tasks . "MOUNT $uuid $user \"$cdrom\"\n";
|
2955 |
|
|
tied(%nodereg)->commit;
|
2956 |
|
|
if ($cdrom eq "--") {
|
2957 |
|
|
$postreply = qq|{"OK": 1, "message": "OK unmounting cdrom from $obj->{name}"}|;
|
2958 |
|
|
} else {
|
2959 |
|
|
$postreply = qq|{"OK": 1, "message": "OK mounting cdrom $cdrom on $obj->{name}"}|;
|
2960 |
|
|
}
|
2961 |
|
|
$register{$uuid}->{'cdrom'} = $cdrom unless ($cdrom eq 'virtio');
|
2962 |
|
|
return $postreply;
|
2963 |
|
|
} |