# $Header: has/install/crsconfig/oracss.pm /main/51 2016/06/17 12:22:45 xyuan Exp $ # # Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # # NAME # oracss.pm # # # DESCRIPTION # # This package contains functions required for initial configuration # and startup of the CSS component of Oracle clusterware # # # NOTES # # MODIFIED (MM/DD/YY) # xyuan 06/15/16 - Fix bug 23575781 # bbeelamk 04/14/16 - Fix bug 23095140 # luoli 03/31/16 - Fix bug 23000412 # bbeelamk 10/07/15 - Fix bug 21878673 # jmarcias 05/20/15 - Fix bug 21101733 # jmarcias 05/08/15 - Fix bug 20975868 # bbeelamk 04/01/15 - Fix bug 20567041 # jmarcias 03/17/15 - Fix bug 20569941 # xyuan 11/27/14 - Fix bug 20105663 # jachang 04/08/14 - Suppress downgrade_vf stdout printout # muhe 02/27/14 - Fix bug 18227454 # rdasari 02/10/14 - modify CSS package oracss; use Env; use strict; use English; use File::Temp qw/ tempfile /; use File::Spec::Functions; use File::Find (); use File::stat; use crsutils; use constant CSS_EXCL_SUCCESS => 1; use constant CSS_EXCL_FAIL_CLUSTER_ACTIVE => 2; use constant CSS_EXCL_FAIL => 3; use Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK); @ISA = qw(Exporter); my @exp_func = qw(CSS_start_exclusive CSS_start_clustered CSS_start CSS_is_configured CSS_upgrade CSS_get_old_VF_string CSS_add_vfs CSS_delete_vfs CSS_query_vfs CSS_downgrade_VFs CSS_stop CSS_CanRunRealtime CSS_Clean_Local_Endpts CSS_Clean_Ipc_files CSS_set_config_parameter CSS_start_exclusive_112); my @exp_const = qw(CSS_EXCL_SUCCESS CSS_EXCL_FAIL CSS_EXCL_FAIL_CLUSTER_ACTIVE); push @EXPORT, @exp_func, @exp_const; =head1 EXPORTED FUNCTIONS =head2 CSS_start_exclusive Start the CSSD in exclusive mode. The CSSD when started in this mode requires no configuration to have completed. =head3 Parameters None =head3 Returns CSS_EXCL_SUCCESS - The CSSD was started successsfully CSS_EXCL_FAIL_CLUSTER_ACTIVE - The CSSD was not started successsfully because other nodes are alive CSS_EXCL_FAIL - The CSSD was not started successsfully =cut sub CSS_start_exclusive { trace("Starting CSS in exclusive mode"); my $ret; my $crsHome = getCrsHome(); my $CRSCTL = crs_exec_path('crsctl', $crsHome); my @output = system_cmd_capture($CRSCTL, 'start', 'crs', '-excl', '-cssonly'); my $rc = shift @output; # If we had a failure, check to see if it is becasue another node is # up and if it is, we ignore the failure my @node_up = grep(/CRS\-4402/, @output); if (scalar(@node_up) > 0) { $ret = CSS_EXCL_FAIL_CLUSTER_ACTIVE; print_trace_lines(@node_up); CSS_stop(); } elsif (0 == $rc) { $ret = CSS_EXCL_SUCCESS; } else { $ret = CSS_EXCL_FAIL; } for my $line (@output) { # if we were successful, or we failed due to unexpected reasons. # print out the msgs if ($ret == CSS_EXCL_SUCCESS || $ret == CSS_EXCL_FAIL) { print "$line\n"; trace($line); # put to both user and log file } } return $ret; } =head1 EXPORTED FUNCTIONS =head2 CSS_start_exclusive_112 Start the CSSD in exclusive mode. The CSSD when started in this mode requires no configuration to have completed. This subroutine is used in 11.2 =head3 Parameters None =head3 Returns CSS_EXCL_SUCCESS - The CSSD was started successsfully CSS_EXCL_FAIL_CLUSTER_ACTIVE - The CSSD was not started successsfully because other nodes are alive CSS_EXCL_FAIL - The CSSD was not started successsfully =cut sub CSS_start_exclusive_112 { trace("Starting CSS in exclusive mode"); my $ret; my @output = CSS_start("-env", "CSSD_MODE=-X"); my $rc = shift @output; # If we had a failure, check to see if it is becasue another node is # up and if it is, we ignore the failure my @node_up = grep(/CRS\-4402/, @output); if (scalar(@node_up) > 0) { $ret = CSS_EXCL_FAIL_CLUSTER_ACTIVE; print_trace_lines(@node_up); CSS_stop(); } elsif ($rc) { $ret = CSS_EXCL_SUCCESS; } else { $ret = CSS_EXCL_FAIL; } for my $line (@output) { # if we were successful, or we failed due to unexpected reasons. # print out the msgs if ($ret == CSS_EXCL_SUCCESS || $ret == CSS_EXCL_FAIL) { print "$line\n"; trace($line); # put to both user and log file } } return $ret; } =head2 CSS_start_clustered Start the CSSD in clsutered (normal) mode =head3 Parameters None =head3 Returns TRUE - The CSSD was started successsfully FALSE - The CSSD was not started successsfully =cut sub CSS_start_clustered { trace("Starting CSS in clustered mode"); my $rc = start_resource("ora.cssd", "-init"); return $rc; } =head2 CSS_stop Stop the CSSD =head3 Parameters None =head3 Returns TRUE - The CSS component is stopped FALSE - The CSS component is not stopped =cut sub CSS_stop { my $stop_success = TRUE; $stop_success = stop_resource("ora.cssd", "-f", "-init"); if (!$stop_success) { trace("CSS shutdown failed"); } stop_resource("ora.cssdmonitor", "-f", "-init"); return $stop_success; } =head2 CSS_CanRunRealtime Verifies that the CSSD can run realtime =head3 Parameters crsutils class object =head3 Returns TRUE - The CSSD can run realtime FALSE - The CSSD cannot run realtime =cut sub CSS_CanRunRealtime { my $cfg = shift; my $rc = TRUE; if ($OSNAME eq "aix") { my $user = $cfg->params('ORACLE_OWNER'); my @out = system_cmd_capture('/usr/sbin/lsuser', '-a', 'capabilities', $user); my $status = shift @out; chomp @out; my $capstr = (split(' ', $out[0]))[1]; $capstr =~ s/^ *capabilities=//; my %caps = map { lc($_) => 1 } (split(',', $capstr)); my @req_caps = ('CAP_NUMA_ATTACH', 'CAP_BYPASS_RAC_VMM', 'CAP_PROPAGATE'); my @needed_caps; for my $cap (@req_caps) { if (!$caps{lc($cap)}) { push @needed_caps, $cap; $rc = FALSE; } } if ($rc) { my @msg = ("User $user has the required capabilities to run CSSD", "in realtime mode"); print "@msg\n"; trace(@msg); } else { my @msg = ("User $user is missing the following capabilities required to", "run CSSD in realtime:"); print "@msg\n"; trace(@msg); @msg = (" ", join(',', @needed_caps)); print "@msg\n"; trace(@msg); @msg = ("To add the required capabilities, please run:"); print "@msg\n"; trace(@msg); @msg = (" /usr/bin/chuser capabilities=" . join(',', @req_caps), $user); print "@msg\n"; trace(@msg); } } return $rc; } =head2 CSS_Clean_Local_Endpts Start the CSSD in clsutered (normal) mode =head3 Parameters Config Object =head3 Returns TRUE - The CSSD was started successsfully FALSE - The CSSD was not started successsfully =cut sub CSS_Clean_Local_Endpts { my $cfg = shift; if ($cfg->platform_family eq 'unix') { my @epdirs = (catdir('', 'tmp', '.oracle'), catdir('', 'var', 'tmp', '.oracle')); if ($OSNAME eq "aix") { trace("Cleaning the CSS local endpoints"); for my $dir (@epdirs) { File::Find::find({wanted => \&CSS_Local_Endpt}, $dir); } } } return; } =head2 CSS_Clean_Ipc_files Performs cleanup of IPC files for agent/monitor communication in CSS. =head3 Parameters crsutils class object =head3 Returns SUCCESS - IPC files cleaned up successfully FAILED - IPC files cleanup failed =cut sub CSS_Clean_Ipc_files { my $MYNAME="oracss"; my $IPCDIR; my $ipcName1; my $ipcName2; my $rc = SUCCESS; if($OSNAME eq "linux" || $OSNAME eq "solaris" ) { # Linux or Solaris $IPCDIR = catdir('', 'var', 'tmp', '.oracle'); trace ("$MYNAME Using IPC Dir: $IPCDIR\n"); } elsif ($OSNAME eq "aix" || $OSNAME eq "hpux" ) { # AIX or HPUX $IPCDIR = catdir('', 'tmp', '.oracle'); trace ("$MYNAME Using IPC Dir: $IPCDIR\n"); } else { trace ("$MYNAME Warning: No IPC cleanup configured for [$OSNAME]\n"); } $ipcName1 ="ora_gipc_agent_ag"; $ipcName2 ="ora_gipc_monitor_ag"; opendir(DIR, $IPCDIR) or warn("$MYNAME Warning: Unable to read $IPCDIR: $!\n"), return $rc; my @files = grep { $_ ne '.' && $_ ne '..' && (/${ipcName1}/ || /${ipcName2}/) } readdir DIR; chomp(@files); chdir $IPCDIR; for my $file (@files) { trace ("$MYNAME Removing IPC $file \n"); unlink $file; } closedir DIR; return $rc; } =head2 CSS_upgrade Performs operations required for upgrade of CSS =head3 Parameters crsutils class object =head3 Returns SUCCESS - The CSS component has been successfully upgraded FAILED - The CSS component upgrade failed =cut sub CSS_upgrade { my $cfg = shift; my $rc = SUCCESS; my $vfds; trace ("Upgrading the existing voting disks!"); my $cmdrc = run_crs_cmd('cssvfupgd'); if ($cmdrc != 0) { $rc = FAILED; error("Upgrade of voting files failed"); } return $rc; } =head2 CSS_get_old_VF_string Gets old VF list from OCR and updates VF discovery string =head3 Parameters None =head3 Returns The CSS VF list obtained from OCR, or NULL if unable to obtain =cut sub CSS_get_old_VF_string { my $vfds; my $crsctl = crs_exec_path('crsctl'); trace ("Obtaining the existing voting disks"); my @vflist = system_cmd_capture($crsctl, 'get', 'css', 'vfdiscstring'); my $cmdrc = shift @vflist; if ($cmdrc == 0) { $vfds = join(',', @vflist); } else { error("Unable to get voting file list for upgrade, return code $cmdrc"); print_lines(@vflist); } return $vfds; } =head2 CSS_prep_old_VFs Prepares older voting files that may have had the skgfr block cleaned clsfmt has been defunct =cut =head2 CSS_is_configured Checks to see if the CSS component has already been configured. May be run with the CSSD started in exclusive or clustered mode, but is most meaningful when run with the CSSD in exclusive mode, since the CSSD will not start when configuration has not completed and the CSSD is started in clustered mode. =head3 Parameters None =head3 Returns TRUE - The CSS component is configured FALSE - The CSS component is not configured =cut sub CSS_is_configured { my $CRSCTL = crs_exec_path("crsctl"); my $rc = FALSE; trace ("Querying for existing CSS voting disks"); my ($cmdrc, @out) = system_cmd_capture("$CRSCTL query css votedisk"); trace("Command returns $cmdrc"); if (0 != $cmdrc) { print_lines(@out); trace("crsctl query css votedisk failed with status $cmdrc"); die(dieformat(180, "crsctl query css votedisk")); } # remove blank lines and headings my @vflist = grep(!/^ *$/ && !/^\#/ && !/^-/, @out); trace("Configured voting files:\n" . join("\n", @vflist)); foreach my $line (@vflist) { if ($line =~ /Located\s+(\d+)\s+voting disk/) { if ($1 != 0) { trace("Found $1 configured voting files"); $rc = TRUE; } } } return $rc; } sub CSS_query_vfs { my $crsctl = crs_exec_path('crsctl'); my @querycmd = ($crsctl, "query", "css", "votedisk"); trace("Querying CSSD for voting files"); my ($rc, @output) = system_cmd_capture(@querycmd); # Remove blank lines and headings my @vfoutput = grep(!/^ *$/ && !/^\#/ && !/^-/, @output); my @vflist; my $diskgrp; for my $line (@vfoutput) { my ($vfstate, $vfguid, $vfpath, $vfdiskgrp) = ($line=~ m/^\s*\d*.\s*(\S*)\s*([\da-fA-f]{32})\s*\((.*)\)\s*\[.*\]\s*$/); if ($vfguid) { # Repackage the result and push into voting file list my $vfentry = {"id"=>$vfguid, "state"=>$vfstate, "path"=>$vfpath}; push @vflist, $vfentry; # If no diskgroup has been found in the set, see if this entry has info if (!$diskgrp) { $diskgrp = $vfdiskgrp; } } } # Display output for my $vf (@vflist) { trace("Disk: $vf->{id}, path=$vf->{path}, state=$vf->{state}"); } if ($diskgrp) { trace("Diskgroup: $diskgrp"); } else { trace("Diskgroup: "); } my $vfcount = scalar(@vflist); trace("Found $vfcount configured voting files"); return ($diskgrp, @vflist); } =head2 CSS_add_vfs Add voting file(s) to the CSSD configuration. =head3 Parameters A list of voting file paths or a single ASM diskgroup name. If the parameter is an ASM dikgroup name, it must be prefixed with a + =head3 Returns TRUE - The voting file(s) were added FALSE - The voting file(s) were not added =cut sub CSS_add_vfs { my $cfg = shift; my $rc = TRUE; my @addvfcmd; if ($_[0] =~ /^\+/) { my $dg_parm = $_[0]; my $diskgroup = $dg_parm; if ($cfg->platform_family ne "windows") { $dg_parm = "'$dg_parm'"; } $diskgroup =~ s/^\+//; trace("Creating voting files in ASM diskgroup $diskgroup"); @addvfcmd = ("crsctl", "replace", "votedisk", $dg_parm); } else { trace("Adding voting files @_"); my ($diskgrp, @vflist) = CSS_query_vfs($cfg); if ($diskgrp) { @addvfcmd = ("crsctl", "replace", "votedisk", (@_)); } else { @addvfcmd = ("crsctl", "add", "css", "votedisk", (@_)); } } trace("Executing @addvfcmd"); my $status = run_crs_cmd(@addvfcmd); if ($status != 0) { error("Voting file add failed"); $rc = FALSE; } return $rc; } =head2 CSS_add_vfs Delete voting file(s) from the CSSD configuration. =head3 Parameters None! It gets GUIDs from "crsctl query css votedisk" =head3 Returns TRUE - The voting file(s) were deleted FALSE - The voting file(s) were not deleted =cut sub CSS_delete_vfs { my $rc = TRUE; my $crsctl = catfile ($CFG->ORA_CRS_HOME, "bin", "crsctl"); my $CDATA_DISK_GROUP = $CFG->params('CDATA_DISK_GROUP'); # deleting votedisk my @cmd = ("crsctl", "delete", "css", "votedisk", "+$CDATA_DISK_GROUP"); my $status = run_crs_cmd(@cmd); if ($status == 0) { trace ("crsctl delete for vds in $CDATA_DISK_GROUP ... success"); } else { error ("crsctl delete for vds in $CDATA_DISK_GROUP ... failed"); $rc = FALSE; } return $rc; } =head2 CSS_downgrade_VFs Downgrades voting files when downgrading to pre-11.2 clusterware. This function queries for existing voting files, which cannot be on ASM, and deletes and readds them to force proper formatting of the voting files =head3 Parameters None =head3 Notes This function must only be executed in an environment where the clusterware is not active on any nodes, including the node this function is running on. This function is intended for downgrading to pre-11.2 clusterware only. It will return TRUE without performing any operations for 11.2+ clusterware This function will fail if VFs are on ASM, as these files cannot be downgraded; there will not be any voting files found in the OCR configuration =head3 Returns TRUE - Voting files have been downgraded FALSE - One or more voting files has not been downgraded =cut sub CSS_downgrade_VFs { my $cfg = shift; my $crsctl = catfile($cfg->oldconfig('ORA_CRS_HOME'), "bin", "crsctl"); my $rc = TRUE; my ($tempfh, $tempfile); my ($cmdrc, @out); # For version 10.x and 11.1.x, we need to delete and readd VFs if ($cfg->isVersion10 || $cfg->isVersion111) { trace ("Querying for existing CSS voting files for downgrade"); ($cmdrc, @out) = system_cmd_capture($crsctl, "query", "css", "votedisk"); my @vfout = grep(/^ *\d/, @out); chomp @vfout; my @vflist; for my $vfend (@vfout) { push @vflist, (split(' ', $vfend))[2]; } my $vfcount = scalar(@vflist); # If we only have 1 VF, we cannot delete it and re-add, so add a # temporary file if ($vfcount == 1) { ($tempfh, $tempfile) = tempfile(); close($tempfh); ($cmdrc, @out) = system_cmd_capture($crsctl, "add", "css", "votedisk", $tempfile, "-force"); if ($cmdrc != 0) { $rc = FALSE; } } while ($rc && scalar(@vflist) > 0) { my $vf = shift @vflist; my $vfstats; my $uid; my $gid; my $vfmode; $vfstats = stat($vf); if (defined $vfstats) { $uid = $vfstats->uid; $gid = $vfstats->gid; $vfmode = $vfstats->mode; } else { $uid = getpwnam($cfg->params("ORACLE_OWNER")); $gid = getpwnam($cfg->params("ORA_DBA_GROUP")); $vfmode = 0640; # 640 permission == rw-r----- } trace("Recreating CSS voting file $vf"); $cmdrc = system_cmd_capture($crsctl, "delete", "css", "votedisk", $vf, "-force"); if ($cmdrc == 0) { $cmdrc = system_cmd_capture($crsctl, "add", "css", "votedisk", $vf, "-force"); if ($cmdrc == 0) { chown($uid, $gid, $vf); chmod($vfmode, $vf); trace("Changing file ownership for $vf to $uid:$gid, perm=$vfmode"); } } if ($cmdrc != 0) { $rc = FALSE; } } if ($tempfile) { ($cmdrc, @out) = system_cmd_capture($crsctl, "delete", "css", "votedisk", $tempfile, "-force"); if ($cmdrc != 0) { $rc = FALSE; } } } return $rc; } =head2 CSS_set_config_parameter Set the value of a css parameter with crsctl This function calls crsctl set css to set css parameters. =head3 Parameters The name of the parameter and the value to be set. =head3 Returns SUCCESS, dies on failure =cut sub CSS_set_config_parameter { my $config_name = shift; my $config_value = shift; my $crsctl = catfile ($CFG->ORA_CRS_HOME, 'bin', 'crsctl'); my ($rc, @output); ($rc, @output) = system_cmd_capture($crsctl, 'set', 'css', $config_name, $config_value); if ($rc != 0) { print_lines(@output); die(dieformat(611, $config_name)); } return SUCCESS; } sub CSS_start { my $ORA_CRS_HOME = $CFG->params('ORACLE_HOME'); my $crsctl = catfile($ORA_CRS_HOME, "bin", "crsctl"); my $rc = FALSE; my @startcss = ($crsctl, "start", "resource", "ora.cssd", "-init", (@_)); my @output = system_cmd_capture(@startcss); my $status = shift @output; trace("The exit status of " . join(' ', @startcss) . " is $status"); $rc = check_service ("css", 2); trace("The crsctl check css returned with $rc"); # If we found a CRS-4402, we know that the startup failed, but no # need to report status if ($status != 0 && scalar(grep(/CRS\-4402/, @output)) == 0) { push @output, "CSS startup failed with return code $status"; } return ($rc, @output); } # Private subroutines sub CSS_Local_Endpt { our $perms; my $name = $File::Find::name; if ($name =~ /OCSSD_LL/ || $name =~ /Oracle_CSS_LclLstnr/ || $name =~ /DBG_CSSD/) { trace("Removing $name"); unlink $name; } } 1;