# # # osds_acfshanfs.pm # # Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. # # NAME # osds_acfshanfs.pm - Linux OSD component of acfshanfs. # # DESCRIPTION # Install/uninstall ACFS HANFS Locking components. # # NOTES # package osds_acfshanfs; use acfslib; use strict; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( lib_check_nfs_path lib_install_nfs_path lib_uninstall_nfs_path ); use constant NFS_PATH => "/var/lib/nfs"; use constant FALSE => 0; use constant TRUE => 1; my ($ORACLE_HOME) = $ENV{ORACLE_HOME}; my ($hostname) = $ENV{HOSTNAME}; my ($SBIN_DIR) = "/sbin"; my ($ADVMUTIL) = "$SBIN_DIR/advmutil"; my ($MKFS_ACFS) = "$SBIN_DIR/mkfs.acfs"; # lib_check_nfs_path # # Check if /var/lib/nfs is an ACFS File Sytem. # sub lib_check_nfs_path { my ($result) = 0; if (lib_is_mounted(NFS_PATH)) { my ($cmd_out); my $cmd = "$ACFSUTIL info fs " . OPT_CHR . "o ismountpoint " . NFS_PATH; $cmd_out= `$cmd`; if (!defined($cmd_out)) { $cmd_out=""; } if ($? == 0) { # Execution successful, cmd_out will hold 0 or 1. if ($cmd_out != 1 ) { $result = 0; } else { #mount is available. $result = 1; } } else { $result = 0; } } return $result; } #end lib_check_nfs_path # lib_install_nfs_path # # Install HANFS Locking support # sub lib_install_nfs_path { my ($force, $volume) = (@_); my ($result) = USM_FAIL; my ($rc) = 0; my $isNFSPathMounted = FALSE; my $isNFSPathSymlinked = FALSE; my $isVolumeMounted = FALSE; if (lib_is_mounted(NFS_PATH)) { $isNFSPathMounted = TRUE; } if (-l NFS_PATH) { $isNFSPathSymlinked = TRUE; } if (lib_is_mounted($volume)) { $isVolumeMounted = TRUE; } # Ensure that an NFS resource does not already exist. If it does, either # '-addnode' must be run, or NFSv4 locking is already configured in this cluster. my ($volumeResourceDependency, $nfsVolume, $isrunningNFS, $existsNFS) = getNFSResourceStatus(); if ($existsNFS == -1) { return USM_FAIL; } # Check for filesystem resource my $isrunningFS = 0; my $existsFS = 0; open SRVCTL_FS, "$ORACLE_HOME/bin/srvctl status filesystem -d $volume |"; while () { if (/PRKO-2012/) { # "No Oracle Clusterware components configured." lib_error_print_noalert(5219, "Cannot proceed because CRS stack is not up."); $result = USM_FAIL; last; } elsif (/PRCA-1070/) { # "Could not find resource filesystem" $result = USM_SUCCESS; last; } elsif (/ADVM-03180/) { # Unable to obtain ASM volume device information for volume $result = USM_SUCCESS; last; } elsif (/is mounted on nodes/) { $existsFS = 1; $isrunningFS = 1; $result = USM_SUCCESS; } elsif (/is not mounted/) { $existsFS = 1; $isrunningFS = 0; $result = USM_SUCCESS; } } close SRVCTL_FS; if ($result == USM_FAIL) { return $result; } elsif (!$force) { # If !force, warn the user that the following actions will be taken: # Modification of NFS OS Startup scripts so that NFS does not # automatically start. # Modification of /var/lib/nfs to be on stable storage. # Format of the volume. # Creation of a file system resource. # Short message regarding ongoing management of NFS by the CRS stack. i # (Print a list of appropriate srvctl commands to use.) lib_inform_print_noalert(9603, "The script will do the following actions:"); lib_inform_print_noalert(9604, " - Update the operating system startup procedure so that NFS does not automatically start."); lib_inform_print_noalert(9605, " Management of the NFS daemons will be moved to Oracle Clusterware."); lib_inform_print_noalert(9606, " - Format the volume: %s.", $volume); lib_inform_print_noalert(9607, " - Create an ACFS resource for the file system."); lib_inform_print_noalert(9608, " - Mount the ACFS file system on '/var/lib/nfs'."); lib_inform_print_noalert(9609, " Continue the installation? [1=yes,2=no]:"); # Request confirmation of intent to continue, unless –force option # is provided. my $answer = ; chomp($answer); if ($answer == 1) { $result = USM_SUCCESS; } else { return USM_FAIL; } } #Before to start with the installation, will do a couple of validations. my $isFirstNode = 0; if (!$existsNFS && !$existsFS) { $isFirstNode = 1; } elsif ($existsNFS && $existsFS) { $isFirstNode = 0; } elsif ($existsNFS && !$existsFS) { #This is weird but possible, we'll need to create the filesystem resource } elsif (!$existsNFS && $existsFS) { # Possible but file system should be used for any other application # We'll send an error. lib_error_print_noalert( 9610, "Error - the ACFS resource for the specified file system is already in use."); return USM_FAIL; } # (First node) Ensure that an ACFS file system is not mounted on or #symlinked from /var/lib/nfs. if ($isFirstNode && ($isNFSPathMounted || $isNFSPathSymlinked)) { lib_error_print_noalert(9602, "Installation cannot proceed: path '/var/lib/nfs' is mounted or it is a symlink."); return USM_FAIL; } # (First node) Ensure that the volume is not mounted. if ($isFirstNode && $isVolumeMounted) { lib_error_print_noalert(2125, "volume '%s' is already in use", $volume); return USM_FAIL; } # (All nodes) Stop the OS NFS daemons. lib_inform_print_noalert(9612, "Stopping NFS Service."); if (!actionNFSServer("stop")) { $result = USM_FAIL; } my ($disk_group) = ""; my ($vol) = ""; # (All nodes) Verify the volume device is enabled. open ADVMUTIL, "$ADVMUTIL volinfo $volume |"; if ($?) { # It's not enabled or it's not an ADVM Volume lib_error_print_noalert( 520, "%s is not an ADVM volume.", $volume); $result = USM_FAIL; } else { while () { if (/Disk Group/) { $disk_group = ($_); chomp($disk_group); $disk_group = trim(substr($disk_group, index($disk_group, ':') + 1)); $disk_group =~ s/^\s+//; } elsif (/Volume/) { $vol = ($_); chomp($vol); $vol = trim(substr($vol, index($vol, ':') + 1)); $vol =~ s/^\s+//; } } } # If NFS Resource exists, we need to check that # they are using the same Volume Resource Dependency if ($existsNFS && (lc($volumeResourceDependency) ne lc("ora.$disk_group.$vol.acfs"))) { # If the NFS Resource exists, we'll use the dependency from there ($volume, $isrunningFS, $existsFS) = getVolumeName($volumeResourceDependency); if ($existsFS == -1) { $result = USM_FAIL; } # if the filesystem Resource exists and NFS Resource exist # will check the volume path if ($existsFS && (lc($volume) ne lc($nfsVolume))) { $result = USM_FAIL; } } if ($result != USM_FAIL) { # (First node only) Format the volume provided. if (!$existsFS || !$isrunningFS) { lib_inform_print_noalert(9614, "Formatting the volume device."); $rc = system($MKFS_ACFS . " " . OPT_CHR . "f " . $volume); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", $MKFS_ACFS . " " . OPT_CHR . "f " . $volume, ($? >> 8)); if ($rc != 0) { $result = USM_FAIL; } } } if ($result != USM_FAIL) { # (First node only) Create a file system resource for the storage path and # configure it to be mounted on /var/lib/nfs. # Create it globally disabled, enablig it on a node by node basis. if (!$existsFS) { if (!actionFileSystemResource("add", $volume)) { $result = USM_FAIL; } } } # As far I can see, we don't need to use a temporary path. # We can mount directly in /var/lib/nfs and the information will not be lost. # The previous contents (if any), owner, and mode of dir become invisible, # and as long as this filesystem remains mounted, the pathname dir refers # to the root of the filesystem on device. # So maybe, we don't need to run the following steps. # (First node only) Mount the file system in a temporary location. # (First node only) Copy /var/lib/nfs to file system. # (All nodes) Move /var/lib/nfs to /var/lib/nfs.old_before_oracle_hanfs_ # (All nodes) Create a new /var/lib/nfs # (First node only) Unmount the temporary location of the file system. if ($result != USM_FAIL) { # (All nodes) Enable and start the file system resource – on current node only if (!actionFileSystemResource("start", $volume)) { $result = USM_FAIL; } } # (First node only) Call appropriate srvctl command to add the NFS resource # and adjust current export dependencies. if ($result != USM_FAIL) { if (!$existsNFS) { #Add NFS Resouce if (!actionNFSResource("add", $volume)) { $result = USM_FAIL; } } } if ($result != USM_FAIL) { if ($isrunningNFS) { #Stop if (!actionNFSResource("stop")) { $result = USM_FAIL; } } #Start if (!actionNFSResource("start")) { $result = USM_FAIL; } } # (All nodes) Start the NFS resource on current node. lib_inform_print_noalert(9611, "Starting NFS Service."); if (!actionNFSServer("start")) { $result = USM_FAIL; } return $result; } #end lib_install_nfs_path # lib_uninstall_nfs_path # # Uninstall HANFS Locking support # sub lib_uninstall_nfs_path { my ($result) = USM_FAIL; my ($volumeResourceDependency, $nfsVolume, $isrunningNFS, $existsNFS) = getNFSResourceStatus(); if ($existsNFS == -1) { return USM_FAIL; } # Check for filesystem resource my ($volume, $isrunningFS, $existsFS) = ("", 0, 0); if ($existsNFS) { ($volume, $isrunningFS, $existsFS) = getVolumeName($volumeResourceDependency); } if ($existsFS == -1) { $result = USM_FAIL; } else { $result = USM_SUCCESS; } # (All nodes) Stop the NFS service using srvctl with the force option # on the current node. if ($result != USM_FAIL) { if ($isrunningNFS) { #Stop if (!actionNFSResource("stop")) { $result = USM_FAIL; } } } # (All nodes) Stop the ACFS file system for stable storage on # the current node only. if ($result != USM_FAIL) { if ($isrunningFS) { if (!actionFileSystemResource("stop", $volume)) { # It could fail, if not running in this node # or if ACFS Resource can not umount } } } # (All nodes) Disable the NFS service resource on this node. # Just for srvctl # (All nodes) Disable the ACFS file system for stable storage on # the current node only. # It doesn't work for node # We don't need to do these steps. # (All nodes) Move /var/lib/nfs to a temporary directory. # (All nodes) Create a new /var/lib/nfs. # (All nodes) Copy the old /var/lib/nfs files from stable storage to # the new /var/lib/nfs. # If the files don’t exist, use the backup in /var/lib/nfs from # installation. # (Last node) Remove the NFS CRS agent using the appropriate srvctl remove # command. # (Last node) Remove the stable storage ACFS resource. if ($result != USM_FAIL) { if ($existsFS && isLastNode($volume)) { if (!actionNFSResource("remove") || !actionFileSystemResource("remove", $volume)) { $result = USM_FAIL; } } } # (All nodes) Start the NFS services using the OS commands. # (All nodes) Restore the OS management of NFS daemons. lib_inform_print_noalert(9613, "Restarting NFS Service."); if (!actionNFSServer("restart")) { $result = USM_FAIL; } return $result; } #end lib_uninstall_nfs_path # actionNFSServer # start/stop/restart NFS Server. # Parameters # $action - "stop"/"start"/"restart" actions for the NFS Server # Returns TRUE if action was successful or FALSE if it failed sub actionNFSServer { my $action = shift; my $rc = system("/sbin/service nfs " . $action); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", "/sbin/service nfs " . $action, ($? >> 8)); if ($rc != 0) { return FALSE; } return TRUE } #end actionNFSServer # actionFileSystemResource # add/start/stop/disable/remove Filesystem Resource # Parameters # $action - "add"/"start"/"stop"/"disable"/"remove" actions # for the Filesystem Resource # $volume - Device to use # Returns TRUE if action was successful or FALSE if it failed sub actionFileSystemResource { my ($action) = shift; my ($volume) = shift; my ($rc) = 0; if ($action eq "add") { $rc = system("$ORACLE_HOME/bin/srvctl add filesystem -device " . $volume . " -path " . NFS_PATH); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", "$ORACLE_HOME/bin/srvctl add filesystem -device " . $volume . " -path " . NFS_PATH, ($? >> 8)); if ($rc != 0) { return FALSE; } } else { my ($node_command) = ""; if ($action eq "start" || $action eq "stop") { $node_command = " -n $hostname"; } $rc = system("$ORACLE_HOME/bin/srvctl " . $action . " filesystem -device " . $volume . $node_command); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", "$ORACLE_HOME/bin/srvctl " . $action . " filesystem -device " . $volume . $node_command, ($? >> 8)); if ($rc != 0) { return FALSE; } } return TRUE } #end actionFileSystemResource # actionNFSResource # start/stop/remove/add NFS Resource # Parameters # $action - "start"/"stop"/"remove"/"add" actions for the NFS Resource # $attr - Attribute to add or modify. Just for add or modify action. # Returns TRUE if action was successful or FALSE if it was failed sub actionNFSResource { my ($action) = shift; my ($rc) = 0; if ($action eq "add") { my $device = shift; my $command = "$ORACLE_HOME/bin/srvctl add netstorageservice -device " . $device; $rc = system($command); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", $command, ($? >> 8)); if ($rc != 0) { return FALSE; } } else { my $command = "$ORACLE_HOME/bin/srvctl ". $action . " netstorageservice"; $rc = system($command); lib_inform_print_noalert( 9179, "Command executed: '%s', output = '%s'", $command, ($? >> 8)); if ($rc != 0) { return FALSE; } } return TRUE } #end actionNFSResource # getNFSResourceStatus # Status for NFS Resource sub getNFSResourceStatus { my $resource = "ora.netstorageservice"; my $volumeResourceDependency = ""; my $volume = ""; my $isrunningNFS = 0; my $existsNFS = -1; open CRSCTL, "$ORACLE_HOME/bin/crsctl stat res $resource -f |"; while () { if (/CRS-4047/) { # "No Oracle Clusterware components configured." lib_error_print_noalert(5219, "Cannot proceed because CRS stack is not up."); last; } elsif (/CRS-2613/) { # "Could not find resource ora.netstorageservice" $existsNFS = 0; last; } elsif (/STATE=OFFLINE/) { $existsNFS = 1; } elsif (/STATE=ONLINE/) { $existsNFS = 1; $isrunningNFS = 1; } elsif (/START_DEPENDENCIES/) { $existsNFS = 1; if (!(/START_DEPENDENCIES_RTE_INTERNAL/)) { $volumeResourceDependency = ($_); chomp($volumeResourceDependency); $volumeResourceDependency = substr($volumeResourceDependency, index($volumeResourceDependency, '(') + 1); $volumeResourceDependency = substr($volumeResourceDependency, index($volumeResourceDependency, '(') + 1); $volumeResourceDependency = substr($volumeResourceDependency, 0, length($volumeResourceDependency) - 1); } } elsif (/STABLE_STORAGE/) { $volume = ($_); chomp($volume); $volume = substr($volume, index($volume, '=') + 1); } } close CRSCTL; return ($volumeResourceDependency, $volume, $isrunningNFS, $existsNFS); } # end getNFSResourceStatus sub getVolumeName { my ($volumeResourceDependency) = shift; # Check for filesystem resource my $isrunningFS = 0; my $existsFS = -1; my $volume = ''; open CRSCTL, "$ORACLE_HOME/bin/crsctl stat res $volumeResourceDependency -f |"; while () { if (/CRS-4047/) { # "No Oracle Clusterware components configured." lib_error_print_noalert(5219, "Cannot proceed because CRS stack is not up."); last; } elsif (/CRS-2613/) { # "Could not find resource $existsFS = 0; last; } elsif (/STATE=OFFLINE/) { $existsFS = 1; } elsif (/STATE=ONLINE/) { $existsFS = 1; $isrunningFS = 1; } elsif (/VOLUME_DEVICE/) { $volume = ($_); chomp($volume); $volume = substr($volume, index($volume, '=') + 1); } } close CRSCTL; return ($volume, $isrunningFS, $existsFS); } sub isLastNode { my ($volume) = shift; # Check for filesystem resource open SRVCTL_FS, "$ORACLE_HOME/bin/srvctl status filesystem -d $volume |"; while () { if (/PRKO-2012/) { # "No Oracle Clusterware components configured." lib_error_print_noalert(5219, "Cannot proceed because CRS stack is not up."); last; } elsif (/PRCA-1070/) { # "Could not find resource filesystem" last; } elsif (/ADVM-03180/) { # Unable to obtain ASM volume device information for volume last; } elsif (/is mounted on nodes/) #We stop the resource on this node { last; } elsif (/is not mounted/) { return TRUE; } } close SRVCTL_FS; return FALSE; } 1;