359d8df3155684cde6dd3760e2ca0b16aef9c69b
[tprouty/samba.git] / source4 / selftest / win / VMHost.pm
1 #!/usr/bin/perl -w
2
3 # A perl object to provide a simple, unified method of handling some
4 # VMware Server VM management functions using the perl and VIX API's.
5 # Copyright Brad Henry <brad@samba.org> 2006
6 # Released under the GNU GPL v2 or later.
7
8 # VMware Perl API
9 use VMware::VmPerl;
10 use VMware::VmPerl::VM;
11 use VMware::VmPerl::ConnectParams;
12
13 # VMware C bindings
14 use VMware::Vix::Simple;
15 use VMware::Vix::API::Constants;
16
17 # Create a class to abstract from the Vix and VMPerl APIs.
18 { package VMHost;
19         my $perl_vm = VMware::VmPerl::VM::new();
20         my $perl_vm_credentials;
21         my $vix_vm;
22         my $vix_vm_host;
23
24         my $err_code = 0;
25         my $err_str = "";
26
27         my $hostname;
28         my $port;
29         my $username;
30         my $password;
31         my $vm_cfg_path;
32         my $guest_admin_username;
33         my $guest_admin_password;
34
35         sub error {
36                 my $old_err_code = $err_code;
37                 my $old_err_str = $err_str;
38                 $err_code = 0;
39                 $err_str = "";
40                 return ($old_err_code, $old_err_str);
41         }
42
43         # Power on the guest if it isn't already running.
44         # Returns 0 when the guest is already running, and
45         # if not, it waits until it is started.
46         sub start_guest {
47                 my $vm_power_state = $perl_vm->get_execution_state();
48                 if (!defined($vm_power_state)) {
49                         ($err_code, $err_str) = $perl_vm->get_last_error();
50                         return ($err_code);
51                 }
52                 if ($vm_power_state == VMware::VmPerl::VM_EXECUTION_STATE_OFF
53                         || $vm_power_state ==
54                                 VMware::VmPerl::VM_EXECUTION_STATE_SUSPENDED)
55                 {
56                         if (!$perl_vm->start()) {
57                                 ($err_code, $err_str) =
58                                         $perl_vm->get_last_error();
59                                 return ($err_code);
60                         }
61                         while ($perl_vm->get_tools_last_active() == 0) {
62                                 sleep(60);
63                         }
64                 }
65                 return ($err_code);
66         }
67
68         sub host_connect {
69                 # When called as a method, the first parameter passed is the
70                 # name of the method. Called locally, this function will lose
71                 # the first parameter.
72                 shift @_;
73                 ($hostname, $port, $username, $password, $vm_cfg_path,
74                         $guest_admin_username, $guest_admin_password) = @_;
75
76                 # Connect to host using vmperl api.
77                 $perl_vm_credentials =
78                         VMware::VmPerl::ConnectParams::new($hostname, $port,
79                                 $username, $password);
80                 if (!$perl_vm->connect($perl_vm_credentials, $vm_cfg_path)) {
81                         ($err_code, $err_str) = $perl_vm->get_last_error();
82                         undef $perl_vm;
83                         return ($err_code);
84                 }
85
86                 # Connect to host using vix api.
87                 ($err_code, $vix_vm_host) =
88                         VMware::Vix::Simple::HostConnect(
89                                 VMware::Vix::Simple::VIX_API_VERSION,
90                                 VMware::Vix::Simple::VIX_SERVICEPROVIDER_VMWARE_SERVER,
91                                 $hostname, $port, $username, $password,
92                                 0, VMware::Vix::Simple::VIX_INVALID_HANDLE);
93                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
94                         $err_str =
95                                 VMware::Vix::Simple::GetErrorText($err_code);
96                         undef $perl_vm;
97                         undef $vix_vm;
98                         undef $vix_vm_host;
99                         return ($err_code);
100                 }
101
102                 # Power on our guest os if it isn't already running.
103                 $err_code = start_guest();
104                 if ($err_code != 0) {
105                         my $old_err_str = $err_str;
106                         $err_str = "Starting guest power after connect " .
107                                         "failed: " . $old_err_str;
108                         undef $perl_vm;
109                         undef $vix_vm;
110                         undef $vix_vm_host;
111                         return ($err_code);
112                 }
113
114                 # Open VM.
115                 ($err_code, $vix_vm) =
116                         VMware::Vix::Simple::VMOpen($vix_vm_host, $vm_cfg_path);
117                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
118                         $err_str =
119                                 VMware::Vix::Simple::GetErrorText($err_code);
120                         undef $perl_vm;
121                         undef $vix_vm;
122                         undef $vix_vm_host;
123                         return ($err_code);
124                 }
125
126                 # Login to $vix_vm guest OS.
127                 $err_code = VMware::Vix::Simple::VMLoginInGuest($vix_vm,
128                                 $guest_admin_username, $guest_admin_password,
129                                 0);
130                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
131                         $err_str =
132                                 VMware::Vix::Simple::GetErrorText($err_code);
133                         undef $perl_vm;
134                         undef $vix_vm;
135                         undef $vix_vm_host;
136                         return ($err_code);
137                 }
138                 return ($err_code);
139         }
140
141         sub host_disconnect {
142                 undef $perl_vm;
143
144                 $perl_vm = VMware::VmPerl::VM::new();
145                 if (!$perl_vm) {
146                         $err_code = 1;
147                         $err_str = "Error creating new VmPerl object";
148                 }
149
150                 undef $vix_vm;
151                 VMware::Vix::Simple::HostDisconnect($vix_vm_host);
152                 VMware::Vix::Simple::ReleaseHandle($vix_vm_host);
153                 return ($err_code);
154         }
155
156         sub host_reconnect {
157                 $err_code = host_disconnect();
158                 if ($err_code != 0) {
159                         my $old_err_str = $err_str;
160                         $err_str = "Disconnecting from host failed: " .
161                                         $old_err_str;
162                         return ($err_code);
163                 }
164
165                 $err_code = host_connect(NULL, $hostname, $port, $username,
166                                 $password, $vm_cfg_path, $guest_admin_username,
167                                 $guest_admin_password);
168                 if ($err_code != 0) {
169                         my $old_err_str = $err_str;
170                         $err_str = "Re-connecting to host failed: " .
171                                         $old_err_str;
172                         return ($err_code);
173                 }
174                 return ($err_code);
175         }
176
177         sub create_snapshot {
178                 my $snapshot;
179
180                 ($err_code, $snapshot) =
181                         VMware::Vix::Simple::VMCreateSnapshot($vix_vm,
182                         "Snapshot", "Created by vm_setup.pl", 0,
183                         VMware::Vix::Simple::VIX_INVALID_HANDLE);
184
185                 VMware::Vix::Simple::ReleaseHandle($snapshot);
186
187                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
188                         $err_str =
189                                 VMware::Vix::Simple::GetErrorText($err_code);
190                         return $err_code;
191                 }
192
193                 $err_code = host_reconnect();
194                 if ($err_code != 0) {
195                         my $old_err_str = $err_str;
196                         $err_str = "Reconnecting to host after creating " .
197                                         "snapshot: " . $old_err_str;
198                         return ($err_code);
199                 }
200                 return ($err_code);
201         }
202
203         sub revert_snapshot {
204                 # Because of problems with VMRevertToSnapshot(), we have to
205                 # rely on the guest having set 'Revert to Snapshot' following
206                 # a power-off event.
207                 $err_code = VMware::Vix::Simple::VMPowerOff($vix_vm, 0);
208                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
209                         $err_str =
210                                 VMware::Vix::Simple::GetErrorText($err_code);
211                         return $err_code;
212                 }
213
214                 # host_reconnect() will power-on a guest in a non-running state.
215                 $err_code = host_reconnect();
216                 if ($err_code != 0) {
217                         my $old_err_str = $err_str;
218                         $err_str = "Reconnecting to host after reverting " .
219                                         "snapshot: " . $old_err_str;
220                         return ($err_code);
221                 }
222                 return ($err_code);
223         }
224
225         # $dest_path must exist. It doesn't get created.
226         sub copy_files_to_guest {
227                 shift @_;
228                 my (%files) = @_;
229
230                 my $src_file;
231                 my $dest_file;
232
233                 foreach $src_file (keys(%files)) {
234                         $dest_file = $files{$src_file};
235                         $err_code =
236                                 VMware::Vix::Simple::VMCopyFileFromHostToGuest(
237                                         $vix_vm, $src_file, $dest_file, 0,
238                                         VMware::Vix::Simple::VIX_INVALID_HANDLE);
239                         if ($err_code != VMware::Vix::Simple::VIX_OK) {
240                                 $err_str = "Copying $src_file: " .
241                                         VMware::Vix::Simple::GetErrorText(
242                                                 $err_code);
243                                 return $err_code;
244                         }
245                 }
246                 return $err_code;
247         }
248
249         sub copy_to_guest {
250                 # Read parameters $src_path, $dest_path.
251                 shift @_;
252                 my ($src_path, $dest_dir) = @_;
253
254                 my $len = length($dest_dir);
255                 my $idx = rindex($dest_dir, '\\');
256                 if ($idx != ($len - 1)) {
257                         $err_code = -1;
258                         $err_str = "Destination $dest_dir must be a " .
259                                         "directory path";
260                         return ($err_code);
261                 }
262
263                 # Create the directory $dest_path on the guest VM filesystem.
264                 my $cmd = "cmd.exe ";
265                 my $cmd_args = "/C MKDIR " . $dest_dir;
266                 $err_code = run_on_guest(NULL, $cmd, $cmd_args);
267                 if ( $err_code != 0) {
268                         my $old_err_str = $err_str;
269                         $err_str = "Creating directory $dest_dir on host: " .
270                                         $old_err_str;
271                         return ($err_code);
272                 }
273
274                 # If $src_filepath specifies a file, create it in $dest_path
275                 # and keep the same name.
276                 # If $src_path is a directory, create the files it contains in
277                 # $dest_path, keeping the same names.
278                 $len = length($src_path);
279                 my %files;
280                 $idx = rindex($src_path, '/');
281                 if ($idx == ($len - 1)) {
282                         # $src_path is a directory.
283                         if (!opendir (DIR_HANDLE, $src_path)) {
284                                 $err_code = -1;
285                                 $err_str = "Error opening directory $src_path";
286                                 return $err_code;
287                         }
288
289                         foreach $file (readdir DIR_HANDLE) {
290                                 my $src_file = $src_path . $file;
291
292                                 if (!opendir(DIR_HANDLE2, $src_file)) {
293                                         # We aren't interested in subdirs.
294                                         my $dest_path = $dest_dir . $file;
295                                         $files{$src_file} = $dest_path;
296                                 } else {
297                                         closedir(DIR_HANDLE2);
298                                 }
299                         }
300                 } else {
301                         # Strip if preceeding path from $src_path.
302                         my $src_file = substr($src_path, ($idx + 1), $len);
303                         my $dest_path = $dest_dir . $src_file;
304
305                         # Add $src_path => $dest_path to %files.
306                         $files{$src_path} = $dest_path;
307                 }
308
309                 $err_code = copy_files_to_guest(NULL, %files);
310                 if ($err_code != 0) {
311                         my $old_err_str = $err_str;
312                         $err_str = "Copying files to host after " .
313                                 "populating %files: " . $old_err_str;
314                         return ($err_code);
315                 }
316                 return ($err_code);
317         }
318
319         sub run_on_guest {
320                 # Read parameters $cmd, $cmd_args.
321                 shift @_;
322                 my ($cmd, $cmd_args) = @_;
323
324                 $err_code = VMware::Vix::Simple::VMRunProgramInGuest($vix_vm,
325                                 $cmd, $cmd_args, 0,
326                                 VMware::Vix::Simple::VIX_INVALID_HANDLE);
327                 if ($err_code != VMware::Vix::Simple::VIX_OK) {
328                         $err_str = VMware::Vix::Simple::GetErrorText(
329                                         $err_code);
330                         return ($err_code);
331                 }
332
333                 return ($err_code);
334         }
335
336         sub get_guest_ip {
337                 my $guest_ip = $perl_vm->get_guest_info('ip');
338
339                 if (!defined($guest_ip)) {
340                         ($err_code, $err_str) = $perl_vm->get_last_error();
341                         return NULL;
342                 }
343
344                 if (!($guest_ip)) {
345                         $err_code = 1;
346                         $err_str = "Guest did not set the 'ip' variable";
347                         return NULL;
348                 }
349                 return $guest_ip;
350         }
351
352         sub DESTROY {
353                 host_disconnect();
354                 undef $perl_vm;
355                 undef $vix_vm_host;
356         }
357 }
358
359 return TRUE;