#!/usr/bin/env perl # $Copyright: Copyright (c) 2022 Veritas Technologies LLC. All rights reserved $ # # This is a perl script that allows users to manipulate the json file that # NetBackup creates and uses for restore of Individual disks of a virtual # machine. # # Main parameter: -req_type # # Operations include: # 1. modify :- Replace the value for any field specified by the user # Required parameters: -file_path, -field, -value.(see example usage 1) # Valid fields are: # 1. ClientName # 2. StartDate # 3. EndDate # 4. BackupId # 5. vCenterServer # 6. VMwareRecoveryHost # 7. DefaultDiskProvisioning # 8. TransportMode # 9. VMName # 10. Datacenter # 11. ESX # 12. Folder # 13. ResourcePool/Vapp # 14. VmxDatastore # 15. AttachDisksToExistingVM # 16. PowerOn # 17. DeleteRestoredVMOnError # 18. VMShutdownWaitSeconds # 19. Datastore # 20. Path # 21. Provisioning # 22. OverwriteExistingDisk # # Note : if modifying these fields :-(Datastore|Path|Provisioning # |OverwriteExistingDisk) -controller parameter is required as well. # (see example usage 2) # # 2. keep_disks :- Keep the disks specified by the user and delete all the other disks # from the json file. # Required parameters: -file_path, -controller (comma separated list) # See example usage 3 # 3. delete_disks :- Delete the disks specified by the user and keep all the other disks # in the json file. # Required parameters: -file_path, -controller (comma separated list) # See example usage 4 # # Example Usage: # 1. restore_spec_utility.pl -req_type modify -file_path /usr/example.json -field VMName -value new_name # 2. restore_spec_utility.pl -req_type modify -file_path C:\example.json -field Datastore -value new_datastore -controller scsi0-4 # 3. restore_spec_utility.pl -req_type delete_disks -file_path /usr/example.json -controller scsi0-0,scsi0-1 # 4. restore_spec_utility.pl -req_type keep_disks -file_path C:\example.json -controller scsi0-2,scsi0-3 # # ---------------------------------------------------------------------------- # Pragmas use strict; use warnings; use JSON; use Path::Tiny qw(path ); use Getopt::Long qw(GetOptions); use Encode; my ($req_type, $file_path, $field, $value, @all_controllers, $controller, @controllers_in_json); my @all_fields = qw(ClientName StartDate EndDate BackupId vCenterServer VMwareRecoveryHost DefaultDiskProvisioning TransportMode VMName Datacenter ESX Folder ResourcePool/Vapp VmxDatastore AttachDisksToExistingVM PowerOn DeleteRestoredVMOnError VMShutdownWaitSeconds Datastore Path Provisioning OverwriteExistingDisk); if ($^O =~ m/linux/){ umask 022; } GetOptions('req_type=s' => \$req_type, 'file_path=s' => \$file_path, 'field:s' => \$field, 'value:s' => \$value, 'controller:s' => \@all_controllers); @all_controllers = split(/,/,join(',',@all_controllers)); if ((not defined $req_type) || (not defined $file_path)){ die "Need both the required parameters -req_type and -file_path\n"; } if (($req_type ne "modify") && ($req_type ne "delete_disks") && ($req_type ne "keep_disks")){ die "Invalid request type. Valid options are :- modify, delete_disks, keep_disks\n"; } if (($req_type =~ "modify") && (!$field || !$value || !$file_path)){ die "-field, -value and -file_path parameteres are required for the request type [$req_type]\n"; } if((($req_type =~ "modify" && $field =~ /^(Datastore|Path|Provisioning|OverwriteExistingDisk)$/ ) && !@all_controllers)) { die "-controller parameter is required for the request type [$req_type]\n"; } if(($req_type =~ "delete_disks") && (!$file_path || !@all_controllers)) { die "-file_path and -controller parameters are both required for the request type [$req_type]\n"; } if(($req_type =~ "keep_disks") && (!$file_path || !@all_controllers)) { die "-file_path and -controller parameters are both required for the request type [$req_type]\n"; } my $data = path($file_path)->slurp_utf8; #read the file in slurp mode my $data_decoded = decode_json(encode("utf8", $data)); #convert the json file into perl datastructures # Read all the controllers from the json file to validate the controller input from the user my $virtual_disk_destination = $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}; if (ref($virtual_disk_destination) eq "ARRAY") { my @array = @{$virtual_disk_destination}; my $length = scalar @array; my $i; for($i = 0; $i < $length; $i++){ push (@controllers_in_json, $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]{Controller} ); } } # Validate the controller is present in the json file foreach my $controller (@all_controllers){ if (!grep(/^$controller$/, @controllers_in_json)){ die "[$controller] is not present in the json file. Enter a valid controller.\n"; } } if ($req_type =~ "modify") { print "Request type is modify\n"; # Verify the field specified is valid if (not grep( /^$field$/, @all_fields)){ die "Field parameter [$field] is not recognized as " . "a valid parameter. (valid fields are: ClientName|StartDate|EndDate" . "|BackupId|vCenterServer|VMwareRecoveryHost|DefaultDiskProvisioning|TransportMode|VMName" . "|Datacenter|ESX|Folder|ResourcePool/Vapp|VmxDatastore|AttachDisksToExistingVM|PowerOn" . "|DeleteRestoredVMOnError|VMShutdownWaitSeconds|Datastore|Path|Provisioning" . "|OverwriteExistingDisk)\n"; } print "The field to modify is [$field]\n"; print "The value to be replaced with is [$value]\n"; if ($field =~ /^(ClientName)$/){ $data_decoded->{$field} = $value ; # replace the value } if ($field =~ /^(StartDate|EndDate|BackupId)$/){ $data_decoded->{BackupImageSelection}->{$field} = $value; # replace the value } if ($field =~ /^(vCenterServer|VMwareRecoveryHost|DefaultDiskProvisioning|TransportMode)$/){ $data_decoded->{VMwareRestoreParameters}->{$field} = $value; # replace the value } if ($field =~ /^(VMName|Datacenter|ESX|Folder|(ResourcePool\/Vapp)|VmxDatastore|PowerOn)$/){ $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualMachineDestination}->{$field} = $value; } if ($field =~ /^(AttachDisksToExistingVM)$/){ $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualMachineDestination}->{$field} = $value; if ($value =~ /^(DeleteAllDisksAndReplace)$/){ delete $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}; print "Deleted all the disks from the json file\n"; } } if ($field =~ /^(DeleteRestoredVMOnError|VMShutdownWaitSeconds)$/){ $data_decoded->{VMwareRestoreParameters}->{VMwareAdvancedRestoreOptions}->{$field } = $value; } if ($field =~ /^(Datastore|Path|Provisioning|OverwriteExistingDisk)$/){ if (scalar @all_controllers != 1){ die "Specify exactly one controller whose [$field] needs to be modified.\n" } else { $controller = $all_controllers[0]; } print "The controller whose disk is to be modified is [$controller]\n"; my $virtual_disk_destination = $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}; if (ref($virtual_disk_destination) eq "ARRAY") { my @array = @{$virtual_disk_destination}; my $length = scalar @array; my $i; for($i = 0; $i < $length; $i++){ if ($data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]{Controller} eq $controller ) { # replace the value $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]{$field} = $value; last; } } } } print "The field [$field] has been modified with value [$value]\n"; } elsif ($req_type =~ "delete_disks") { # Handle delete_disks request type print "Request type is delete disks\n"; #get the array reference of hashes of disks my $virtual_disk_destination = $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}; if (ref($virtual_disk_destination) eq "ARRAY") { my @array = @{$virtual_disk_destination}; # convert array ref into an array my $length = scalar @array; #get the length of the array my $i; my @array_new; for($i = 0; $i < $length; $i++){ my $delete = 0; foreach my $controller (@all_controllers){ if ($data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]{Controller} eq $controller ) { $delete = 1; print "The disk associated with controller [$controller] is deleted from the json file\n"; next; #exit the loop when the disk matches } } #create a new array of hash of only the disks that aren't to be deleted push (@array_new, $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]) if !$delete; } $virtual_disk_destination = \@array_new; $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination} = $virtual_disk_destination; } } elsif ($req_type =~ "keep_disks") { # Handle keep_disks request type print "Request type is keep disks\n"; #get the array reference of hashes of disks my $virtual_disk_destination = $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}; if (ref($virtual_disk_destination) eq "ARRAY") { my @array = @{$virtual_disk_destination}; # convert array ref into an array my $length = scalar @array; #get the length of the array my $i; my @array_new; for($i = 0; $i < $length; $i++){ my $keep = 0; foreach my $controller (@all_controllers){ if ($data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]{Controller} eq $controller ) { $keep = 1; print "The disk associated with controller [$controller] is kept in the json file\n"; next; #exit the loop when the disk matches } } #create a new array of hash of only the disks that are to be kept push (@array_new, $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination}[$i]) if $keep; } $virtual_disk_destination = \@array_new; $data_decoded->{VMwareRestoreParameters}->{VMwareVirtualDiskDestination} = $virtual_disk_destination; } } my $data_encoded = JSON->new->pretty->encode($data_decoded); # convert the hash into a json format path($file_path) -> spew_utf8($data_encoded); #write the content to the file print "The operation [$req_type] was completed successfully\n"; exit 0;