diff --git a/config.pl b/config.pl index e25662d..e89d3a4 100644 --- a/config.pl +++ b/config.pl @@ -2,7 +2,7 @@ # Don't modify this file, copy it to config.my.pl and make your changes there. # The log file path -log_file = '/var/log/vn-vmware.log', +log_file => '/var/log/vn-vmware.log', # Hostname or IP address of vCenter host hostname => 'vcenter', diff --git a/debian/changelog b/debian/changelog index e06bc5f..c7d60db 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -vn-vmware (2.0.34) stable; urgency=low +vn-vmware (1.0.0) stable; urgency=low * Initial Release. diff --git a/debian/control b/debian/control index 9d15543..4901a44 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,7 @@ Source: vn-vmware Priority: optional Maintainer: Juan Ferrer Toribio -Build-Depends: build-essential, debhelper +Build-Depends: devscripts Standards-Version: 3.9.3 Section: misc Homepage: https://verdnatura.es diff --git a/debian/links b/debian/links index 19f90eb..5c4d455 100644 --- a/debian/links +++ b/debian/links @@ -1 +1 @@ -usr/share/vn-vmware.pl usr/bin/vn-vmware.pl \ No newline at end of file +usr/share/vn-vmware/vn-vmware.pl usr/bin/vn-vmware.pl \ No newline at end of file diff --git a/debian/rules b/debian/rules index abde6ef..2d33f6a 100755 --- a/debian/rules +++ b/debian/rules @@ -2,4 +2,3 @@ %: dh $@ - diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..cbe751a --- /dev/null +++ b/deploy.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +pkg="vn-vmware_1.0.0" +debPkg="${pkg}_all.deb" +host="root@bacula" + +debuild -us -uc -b +#scp ../$debPkg $host:/root +#ssh $host dpkg -i /root/$debPkg +#ssh $host rm /root/$debPkg +debian/rules clean +rm ../${pkg}* diff --git a/vn-vmware.pl b/vn-vmware.pl index 4ad3e2d..4251476 100755 --- a/vn-vmware.pl +++ b/vn-vmware.pl @@ -23,18 +23,18 @@ use constant true => 1; my %opts = ( operation => { type => "=s", - help => "Operation to perform: backuping, cloning,rotate, backup, clone, snapshot, migrate", + help => "Operation to perform: backuping, cloning, rotate, backup, clone, snapshot, migrate", required => true }, + job => { + type => "=s", + help => "The job name" + }, vmname => { type => "=s", variable => "vmname", help => "Name of the virtual machine" }, - job => { - type => "=s", - help => "The job name" - }, rotation_days => { type => "=i", help => "Rotation days for backups", @@ -108,6 +108,11 @@ my %opts = ( help => "Whether to power on machine after operation", default => 1 }, + show_logs => { + type => "", + help => "Whether to redirect logs to stdout", + default => 0 + }, snapshot_name => { type => "=s", help => "Name of the snapshot", @@ -124,9 +129,9 @@ Opts::add_options(%opts); Opts::parse(); Opts::validate(); -my $vmname = Opts::get_option('vmname'); my $operation = Opts::get_option('operation'); my $job = Opts::get_option('job'); +my $vmname = Opts::get_option('vmname'); my $rotation_days = Opts::get_option('rotation_days'); my $rotation_count = Opts::get_option('rotation_count'); my $dst_name = Opts::get_option('dst_name'); @@ -143,46 +148,77 @@ my $cbt_size = Opts::get_option('cbt_size'); my $cbt = Opts::option_is_set('cbt'); my $overwrite = Opts::option_is_set('overwrite'); my $poweron = Opts::option_is_set('poweron'); +my $show_logs = Opts::option_is_set('show_logs'); my $snapshot_name = Opts::get_option('snapshot_name'); my $snapshot_desc = Opts::get_option('snapshot_desc'); -my $log_fh; -my $vm; -my $remote_host; -my $vm_datastore; -my $time_pattern = '%Y-%m-%d_%H-%M'; -my $local_backup_dir = %config{local_backup_dir}; -my $backup_datastore = %config{backup_datastore}; -my $vcenter_host = %config{hostname}; -my $username = %config{user}; my %config; - -my $config_files = ( - 'config.my.pl', - 'config.pl', +my @config_files = ( '/etc/vn-vmware/config.my.pl', - '/etc/vn-vmware/config.pl' + '/etc/vn-vmware/config.pl', + 'config.my.pl', + 'config.pl' ); -foreach my $config_file (@$config_files) { +foreach my $config_file (@config_files) { if (-e $config_file) { %config = do $config_file; last; } } +unless (%config) { + die "Configuration file not found"; +} + +my $vm; +my $remote_host; +my $vm_datastore; +my $log_fh; +my $time_pattern = '%Y-%m-%d_%H-%M'; +my $local_backup_dir = $config{local_backup_dir}; + +sub log_to_file { + my ($message) = @_; + my $time = Time::Piece->new; + my $timeMark = $time->strftime('%Y-%m-%d %H:%M:%S'); + print $log_fh "$timeMark : $message\n"; +} +sub log_message { + my ($message) = @_; + if ($log_fh) { + log_to_file $message; + } else { + print "$message\n" + } +} +sub log_error { + my ($message) = @_; + print STDERR color("red").$message.color("reset"); + if ($log_fh) { + log_to_file $message; + } +} + +unless ($show_logs) { + open($log_fh, '>', $config{log_file}); +} eval { - &main(); + main(); }; -if (my $err = $@) { - print STDERR color("red").$err.color("reset"); - log $err; +if ($@) { + log_error($@); +} + +if ($log_fh) { + close $log_fh; } sub main { - $log_fh = STDOUT; + my $vcenter_host = $config{hostname}; + my $username = $config{user}; - VMware::VICredStore::init(filename => %config{credentials_file}); + VMware::VICredStore::init(filename => $config{credentials_file}); my $password = VMware::VICredStore::get_password(server => $vcenter_host, username => $username); my $url = "https://$vcenter_host/sdk/vimService"; @@ -201,44 +237,41 @@ sub main { die "Cannot connect to $vcenter_host"; } - log "Connected to $vcenter_host"; + log_message "Connected to $vcenter_host"; eval { given ($operation) { when ('backuping') { - &open_log(); - &backuping(); + backup_job(); } when ('cloning') { - &open_log(); - &cloning(); + clone_job(); } when ('rotate') { - &rotate_backup(); + rotate_backup(); } when ('backup') { - &open_machine(); - &backup_machine(); + open_machine(); + backup_machine(); } when ('clone') { - &open_machine(); - &clone_machine(); + open_machine(); + clone_machine(); } when ('snapshot') { - &open_machine(); - &snapshot_machine(); + open_machine(); + snapshot_machine(); } when ('migrate') { - &open_machine(); - &migrate_machine(); + open_machine(); + migrate_machine(); } } }; my $err = $@; Vim::logout(); - close $log_fh; if ($err) { die $err; @@ -247,53 +280,68 @@ sub main { #--------------------------------- Operations -sub backuping() { - log "Backup job '$job' started"; - - my %schedule = %config{schedules}{$job}; - - my %rotation_cfg = %config{rotations}{%schedule{rotation}} - $rotation_count = %rotation_cfg{count}; - $rotation_days = %rotation_cfg{days}; - - my @machines = %schedule{machines}; - - foreach $vmname (@$machines) { - &open_machine(); - &backup_machine(); - &rotate_backup(); +sub backup_job() { + unless (exists $config{schedules}{$job}) { + die "Backup job '$job' doesn't exists"; } - log "Backup job '$job' finished"; + log_message "Backup job '$job' started"; + + my $schedule = $config{schedules}{friday}; + + my $rotation_cfg = $config{rotations}{$schedule->{rotation}}; + $rotation_count = $rotation_cfg->{count}; + $rotation_days = $rotation_cfg->{days}; + + my @machines = $schedule->{machines}; + + foreach $vmname (@machines) { + eval { + print "$vmname\n"; + #open_machine(); + #backup_machine(); + #rotate_backup(); + }; + if ($@) { + log_error($@); + } + } + + log_message "Backup job '$job' finished"; } -sub cloning() { - log "Clone job '$job' started"; +sub clone_job() { + unless (exists $config{clone}{$job}) { + die "Cloning job '$job' doesn't exists"; + } - my %cfg = %config{clone}{$job}; + log_message "Clone job '$job' started"; - $vmname = %cfg{vm}; - $dst_name = %cfg{dst_name}; - $dst_host = %cfg{dst_host}; - $dst_datastore = %cfg{dst_datastore}; - $memory = %cfg{memory}; - $num_cpus = %cfg{num_cpus}; - $mac = %cfg{mac}; - $poweron = %cfg{poweron}; - $overwrite = %cfg{overwrite}; + my $cfg = $config{clone}{$job}; - &open_machine(); - &clone_machine(); + $vmname = $cfg->{vm}; + $dst_name = $cfg->{dst_name}; + $dst_host = $cfg->{dst_host}; + $dst_datastore = $cfg->{dst_datastore}; + $memory = $cfg->{memory}; + $num_cpus = $cfg->{num_cpus}; + $mac = $cfg->{mac}; + $poweron = $cfg->{poweron}; + $overwrite = $cfg->{overwrite}; - log "Clone job '$job' finished"; + open_machine(); + clone_machine(); + + log_message "Clone job '$job' finished"; } sub backup_machine() { - log "Backup of '$vmname' started"; + log_message "Backup of '$vmname' started"; my $time = Time::Piece->new; my $timeMark = $time->strftime($time_pattern); my $tmpDir = ".$timeMark"; + my $backup_datastore = $config{backup_datastore}; my $dsBackupPath = "[$backup_datastore] $vmname/$tmpDir"; my $local_dir = "$local_backup_dir/$vmname"; my $localTmpDir = "$local_dir/$tmpDir"; @@ -307,7 +355,7 @@ sub backup_machine() { my $fileManager = Vim::get_view(mo_ref => $serviceContent->fileManager); my $dc = Vim::find_entity_view( view_type => "Datacenter", - filter => {'name' => $datacenter} + filter => {'name' => $config{datacenter}} ); $fileManager->MakeDirectory( @@ -361,11 +409,11 @@ sub backup_machine() { die $err; } - log "Backup of '$vmname' successfully created"; + log_message "Backup of '$vmname' successfully created"; } sub rotate_backup() { - log "Rotating '$vmname' backups"; + log_message "Rotating '$vmname' backups"; use List::Util qw[min]; @@ -406,38 +454,38 @@ sub rotate_backup() { splice(@deleteFiles, -min($rotation_count - $keptCount, $removeCount)); } - my $removeCount = scalar(@deleteFiles); + $removeCount = scalar(@deleteFiles); if ($removeCount == $fileCount) { die "Rotation aborted, because is trying to remove all backups"; } foreach my $deleteFile (@deleteFiles) { - log "Removing $deleteFile (Not done until script is tested for a while)"; + log_message "Removing $deleteFile (Not done until script is tested for a while)"; #unlink $deleteFile; } if (scalar(@deleteFiles) == 0) { - log "No backups to clean"; + log_message "No backups to clean"; } else { - log "$removeCount backups cleaned"; + log_message "$removeCount backups cleaned"; } closedir($dh); } sub clone_machine { - log "Cloning '$vmname' to '$dst_name'"; + log_message "Cloning '$vmname' to '$dst_name'"; - &check_datastore(); + check_datastore(); my $vmOriginal = Vim::find_entity_view( view_type => 'VirtualMachine', filter => {'name' => $dst_name} ); - + if ($vmOriginal) { if ($overwrite) { - &set_power_state($vmOriginal, "poweredOff"); + set_power_state($vmOriginal, "poweredOff"); sleep(20); $vmOriginal->Destroy(); } else { @@ -549,7 +597,7 @@ sub clone_machine { my $guest_id = ($vm->guest->guestId =~ m/^other/) ? "debian6_64Guest" : $vm->guest->guestId; my $vm_dev_spec = VirtualDeviceConfigSpec->new(device => $newNetworkDevice, operation => $config_spec_operation); - my $extra_conf = OptionValue->new(key => "guestinfo.hostname", value => $dst_name); + my $extra_conf = OptionValue->new(key => "guestinfo.hostname", value => $dst_name); my $changeSpec = VirtualMachineConfigSpec->new( deviceChange => [$vm_dev_spec], @@ -574,15 +622,15 @@ sub clone_machine { spec => $cloneSpec ); - log "Clone '$dst_name' of '$vmname' successfully created"; + log_message "Clone '$dst_name' of '$vmname' successfully created"; } sub snapshot_machine() { - log "Creating snapshot of '$vmname' with CBT $cbt"; + log_message "Creating snapshot of '$vmname' with CBT $cbt"; if ($cbt) { if ($vm->capability->changeTrackingSupported) { - &setCBT(true); + setCBT(true); } else { die "CBT not supported"; } @@ -613,46 +661,46 @@ sub snapshot_machine() { my $vmFolder = "/vmfs/volumes/$vm_datastore/$vmname"; my $command = "cd $vmFolder && ".q[ls -lhr *-0*-ctk.vmdk|head -n1 |awk '{print $9}' |cut -c].(length($vmname)+2)."-".(length($vmname)+7); - my $fic_snap = &execute_ssh_command($command); + my $fic_snap = execute_ssh_command($command); if (length($fic_snap) > 0) { $command = "cd $vmFolder && ".q[ls -lhr *-0*-delta.vmdk|head -n1 |awk '{print $5}' | sed '$s/...$//']; - my $tamano_snp = &execute_ssh_command($command); + my $tamano_snp = execute_ssh_command($command); if (($tamano_snp + 0) >= $cbt_size) { - &set_power_state($vmbackup, "poweredOff"); + set_power_state($vmbackup, "poweredOff"); $command = "scp -i /etc/ssh/ssh_host_dsa_key $vmFolder/$vmname.vmdk root@"."$dst_host:/vmfs/volumes/$dst_datastore/$vm_dst_datastore"; - &execute_ssh_command($command); + execute_ssh_command($command); - &create_snapshot($vm); - &create_snapshot($vmbackup); + create_snapshot($vm); + create_snapshot($vmbackup); my $fichero = "$vmname-".substr($fic_snap,0,length($fic_snap)-1)."*.vmdk"; - log "Copying snapshot $fichero is less or equal than $cbt_size with a size of ".length($fic_snap).""; + log_message "Copying snapshot $fichero is less or equal than $cbt_size with a size of ".length($fic_snap).""; $command = "scp -i /etc/ssh/ssh_host_dsa_key $vmFolder/$fichero root@"."$dst_host:/vmfs/volumes/$dst_datastore/$vm_dst_datastore"; - &execute_ssh_command($command); + execute_ssh_command($command); # Deletes all snapshots $vm->RemoveAllSnapshots(); - &create_snapshot($vm); + create_snapshot($vm); } else { - log "No snapshot is made since the size of $vmname-$fic_snap-delta.vmdk is less than $cbt_size"; + log_message "No snapshot is made since the size of $vmname-$fic_snap-delta.vmdk is less than $cbt_size"; } } else { - log "Creating first snapshot"; - &create_snapshot($vm); + log_message "Creating first snapshot"; + create_snapshot($vm); } } else { - &create_snapshot($vm); + create_snapshot($vm); } - log "Snapshot of '$vmname' successfully created"; + log_message "Snapshot of '$vmname' successfully created"; } sub migrate_machine { - log "Migrating '$vmname' to $dst_host"; + log_message "Migrating '$vmname' to $dst_host"; unless ($priority) { $priority = "highPriority"; @@ -687,7 +735,7 @@ sub migrate_machine { ); $vm->PowerOnVM(); - log "Migration of '$vmname' successfull"; + log_message "Migration of '$vmname' successfull"; } #--------------------------------- Utils @@ -711,18 +759,7 @@ sub open_machine() { $vm_datastore = $_->{name}; } - log "Found machine '$vmname' at host $remote_host at datastore '$vm_datastore'"; -} - -sub open_log { - open($log_fh, '>', %config{log_file}); -} - -sub log { - my ($message) = @_; - my $time = Time::Piece->new; - my $timeMark = $time->strftime('%Y-%m-%d %H:%M:%S'); - print $log_fh "$timeMark : $message\n"; + log_message "Found machine '$vmname' at host $remote_host at datastore '$vm_datastore'"; } sub setCBT { @@ -731,7 +768,7 @@ sub setCBT { return; } eval { - log "Switching CBT to $enable"; + log_message "Switching CBT to $enable"; my $spec = Vim::VirtualMachineConfigSpec->new(changeTrackingEnabled => $enable); my $task = $vm->ReconfigVM_Task(spec => $spec); }; @@ -756,9 +793,9 @@ sub execute_ssh_command { my ($command) = @_; my $promptEnd = '/\w+[\$\%\#\>]\s{0,1}$/o'; my $ssh = Net::OpenSSH->new($remote_host) or die "Cannot connect to $dst_host via SSH"; - log "SSH: $remote_host: $command"; + log_message "SSH: $remote_host: $command"; my $result = $ssh->capture($command); - log "SSH: Result: $result"; + log_message "SSH: Result: $result"; $ssh->system('exit'); return substr($result, 0, 200); } @@ -771,11 +808,11 @@ sub set_power_state { given ($state) { when ('poweredOff') { $vmPower->ShutdownGuest(); - log "Turning off ".$vmPower->name; + log_message "Turning off ".$vmPower->name; } when ('poweredOn') { $vmPower->PowerOnVM(); - log "Turning on ".$vmPower->name; + log_message "Turning on ".$vmPower->name; } } sleep(50);