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 version 3 or later.
10 use VMware
::VmPerl
::VM
;
11 use VMware
::VmPerl
::ConnectParams
;
14 use VMware
::Vix
::Simple
;
15 use VMware
::Vix
::API
::Constants
;
17 # Create a class to abstract from the Vix and VMPerl APIs.
19 my $perl_vm = VMware
::VmPerl
::VM
::new
();
20 my $perl_vm_credentials;
32 my $guest_admin_username;
33 my $guest_admin_password;
36 my $old_err_code = $err_code;
37 my $old_err_str = $err_str;
40 return ($old_err_code, $old_err_str);
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.
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();
52 if ($vm_power_state == VMware
::VmPerl
::VM_EXECUTION_STATE_OFF
54 VMware
::VmPerl
::VM_EXECUTION_STATE_SUSPENDED
)
56 if (!$perl_vm->start()) {
57 ($err_code, $err_str) =
58 $perl_vm->get_last_error();
61 while ($perl_vm->get_tools_last_active() == 0) {
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.
73 ($hostname, $port, $username, $password, $vm_cfg_path,
74 $guest_admin_username, $guest_admin_password) = @_;
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();
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
) {
95 VMware
::Vix
::Simple
::GetErrorText
($err_code);
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;
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
) {
119 VMware
::Vix
::Simple
::GetErrorText
($err_code);
126 # Login to $vix_vm guest OS.
127 $err_code = VMware
::Vix
::Simple
::VMLoginInGuest
($vix_vm,
128 $guest_admin_username, $guest_admin_password,
130 if ($err_code != VMware
::Vix
::Simple
::VIX_OK
) {
132 VMware
::Vix
::Simple
::GetErrorText
($err_code);
141 sub host_disconnect
{
144 $perl_vm = VMware
::VmPerl
::VM
::new
();
147 $err_str = "Error creating new VmPerl object";
151 VMware
::Vix
::Simple
::HostDisconnect
($vix_vm_host);
152 VMware
::Vix
::Simple
::ReleaseHandle
($vix_vm_host);
157 $err_code = host_disconnect
();
158 if ($err_code != 0) {
159 my $old_err_str = $err_str;
160 $err_str = "Disconnecting from host failed: " .
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: " .
177 sub create_snapshot
{
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
);
185 VMware
::Vix
::Simple
::ReleaseHandle
($snapshot);
187 if ($err_code != VMware
::Vix
::Simple
::VIX_OK
) {
189 VMware
::Vix
::Simple
::GetErrorText
($err_code);
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;
203 sub revert_snapshot
{
204 # Because of problems with VMRevertToSnapshot(), we have to
205 # rely on the guest having set 'Revert to Snapshot' following
207 $err_code = VMware
::Vix
::Simple
::VMPowerOff
($vix_vm, 0);
208 if ($err_code != VMware
::Vix
::Simple
::VIX_OK
) {
210 VMware
::Vix
::Simple
::GetErrorText
($err_code);
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;
225 # $dest_path must exist. It doesn't get created.
226 sub copy_files_to_guest
{
233 foreach $src_file (keys(%files)) {
234 $dest_file = $files{$src_file};
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
(
250 # Read parameters $src_path, $dest_path.
252 my ($src_path, $dest_dir) = @_;
254 my $len = length($dest_dir);
255 my $idx = rindex($dest_dir, '\\');
256 if ($idx != ($len - 1)) {
258 $err_str = "Destination $dest_dir must be a " .
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: " .
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);
280 $idx = rindex($src_path, '/');
281 if ($idx == ($len - 1)) {
282 # $src_path is a directory.
283 if (!opendir (DIR_HANDLE
, $src_path)) {
285 $err_str = "Error opening directory $src_path";
289 foreach $file (readdir DIR_HANDLE
) {
290 my $src_file = $src_path . $file;
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;
297 closedir(DIR_HANDLE2
);
301 # Strip if preceding path from $src_path.
302 my $src_file = substr($src_path, ($idx + 1), $len);
303 my $dest_path = $dest_dir . $src_file;
305 # Add $src_path => $dest_path to %files.
306 $files{$src_path} = $dest_path;
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;
320 # Read parameters $cmd, $cmd_args.
322 my ($cmd, $cmd_args) = @_;
324 $err_code = VMware
::Vix
::Simple
::VMRunProgramInGuest
($vix_vm,
326 VMware
::Vix
::Simple
::VIX_INVALID_HANDLE
);
327 if ($err_code != VMware
::Vix
::Simple
::VIX_OK
) {
328 $err_str = VMware
::Vix
::Simple
::GetErrorText
(
337 my $guest_ip = $perl_vm->get_guest_info('ip');
339 if (!defined($guest_ip)) {
340 ($err_code, $err_str) = $perl_vm->get_last_error();
346 $err_str = "Guest did not set the 'ip' variable";