# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # # NAME # crsgpnp.pm # # DESCRIPTION # This module contains gPnP related functions # # NOTES # # # MODIFIED (MM/DD/YY) # muhe 07/19/16 - Fix bug 23855801 # yilhu 06/14/16 - Fix bug 23201370 # xyuan 04/07/16 - Fix bug 23016188 # ssprasad 04/04/16 - Fix bug 22964480 # bbeelamk 03/17/16 - Fix bug 22927215 # muhe 03/16/16 - Fix bug 22936276 # bbeelamk 03/11/16 - Fix bug 22856205 # bbeelamk 02/07/16 - Fix bug 22642839 # muhe 12/23/15 - Fix RTI 18860282 # xyuan 11/18/15 - Fix bug 22223328 # muhe 10/21/15 - Fix bug 21886212 # jmarcias 10/16/15 - Move cluutil calls to crsutils # bbeelamk 10/06/15 - Fix bug 21878673 # xyuan 09/04/15 - Fix bug 21470281 # luoli 08/14/15 - Fix bug 20861530 # jmarcias 07/06/15 - Fix bug 21186706 # jmarcias 06/25/15 - Fix bug 21137634 # jinjche 04/29/15 - Back out change for bug 18006526 # jinjche 04/14/15 - Add common base directory nodedata to gpnp local # home # jmarcias 04/04/15 - Fix bug 20818194 # jmarcias 03/09/15 - Fix bug 20614790 # muhe 01/05/15 - Fix bug 20278222 # jmarcias 12/22/14 - Fix bug 20042014 # samjo 12/12/14 - Bug 20201434. Display kfod error stack on failure # muhe 12/10/14 - Modify sub create_gpnp_peer_profile # muhe 11/30/14 - Fix bug 18844632 # atellaku 09/23/14 - Bug 19370739 GUID is not set when upgrading from # 11107 to 12102 # atellaku 09/04/14 - Bug 18751987 - Remove left over tmpfile # samjo 06/18/14 - Bug 19021575. Get CLUSTER_GUID not ASM_CLUSTER_GUID # from credential file during Client Cluster config # xyuan 06/11/14 - Fix bug 18493053 # muhe 06/11/14 - Fix bug 16003413 # atellaku 03/04/14 - Bug 18231759 - make asm and cluster guids same in # asm client cluster # ssprasad 01/14/14 - add gpnp_get_param_value to get GPNP # parameter's value from gpnp profile # rdasari 10/11/13 - Fix bug 17364048 # xyuan 08/25/13 - Fix lrg#9646541 # xyuan 08/22/13 - Remove compilation warnings # xyuan 08/09/13 - Fix bug 17058867 # rdasari 07/09/13 - die if profile copy fails # ysharoni 03/18/13 - bug 15853970 cleanup stale wallet lock files # rdasari 02/21/13 - set asm mode based on ASM_CONFIG # sidshank 01/17/13 - fix bug 16072444. # sidshank 10/23/12 - add oraclehome option to copy gpnp setup to nodes # xyuan 10/14/12 - Fix bug 14156740 # ysharoni 10/03/12 - add profile ops functions, exteralize some consts # xyuan 09/06/12 - Fix bug 14584770 # ysharoni 06/25/12 - bug 14222328 set explicit asm mode # rtamezd 05/24/12 - Export define_gpnp_consts # xyuan 05/16/12 - New function to copy ASM credentials file from a # remote node # xyuan 04/20/12 - Add few subroutines that pull the gpnp setup # ysharoni 03/27/12 - fix gpnp wallet ACLs for windows for LP users # xyuan 10/10/11 - Support Private and ASM networks # rdasari 09/07/11 - modify asm seed dir name # ysharoni 08/24/11 - add online check in wait_for_gpnpd # xyuan 08/04/11 - XbranchMerge xyuan_bug-12795595 from # st_has_11.2.0.3.0 # xyuan 07/17/11 - BC commands for 12c # rdasari 06/17/11 - add push_seed_dir # ysharoni 06/02/11 - bug12605752 incomplete gpnp setup requires reconfig # dpham 03/28/11 - New for 12c # package crsgpnp; use strict; use English; use File::Copy; use File::Path qw(remove_tree); use File::Find; use File::Basename; use File::Spec::Functions; use File::Temp qw/tempfile/; use Sys::Hostname; use POSIX qw(tmpnam); use Carp; use Socket; use Env qw(NLS_LANG); use Term::ANSIColor; # root script modules use crsutils; use s_crsutils; # use Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK); @ISA = qw(Exporter); my @exp_const = qw(GPNP_SETUP_BAD GPNP_SETUP_NONE GPNP_SETUP_GOTCLUSTERWIDE GPNP_SETUP_CLUSTERWIDE GPNP_SETUP_LOCAL GPNP_ELT_STATE_UNDEF GPNP_ELT_STATE_ORIGINAL GPNP_ELT_STATE_CREATED GPNP_ELT_STATE_DELETED GPNP_ELT_STATE_EDITED ); my @exp_func = qw(verify_gpnp_dirs check_gpnp_setup initialize_local_gpnp take_clusterwide_gpnp_setup push_clusterwide_gpnp_setup wait_for_gpnpd_start gpnp_sign_profile instlststr_to_gpnptoolargs gpnp_update_profile_seqnum copy_gpnpfiles push_seed_dir get_asm_cred_file copy_gpnpglobalfiles copy_gpnpnodefiles check_gpnp_home_setup pull_cluserwide_gpnp_setup define_gpnp_consts check_clusterwide_gpnp_profile pull_cluserwide_gpnp_setup2 pull_asm_cred_file restoreGPNPProfile get_peer_profile_file backupGPNPProfile get_peer_wallet_file get_peer_wallet_WRL gpnp_get_profile_identity gpnp_find_best_local_setup_dir gpnp_check_setup_dir gpnp_update_config run_gpnptool_getpnet run_gpnptool_getpval run_gpnptool run_gpnptool_gethnets run_gpnptool_verifysig gpnp_get_asm_mode gpnp_get_param_value remove_gpnp_profiles_wallets_files ); push @EXPORT, @exp_const, @exp_func; use constant GPNP_SETUP_BAD => "-1"; # invalid/error use constant GPNP_SETUP_NONE => '0'; # none use constant GPNP_SETUP_LOCAL => '1'; # good local setup use constant GPNP_SETUP_GOTCLUSTERWIDE => '2'; # good clusterwide; that just made local use constant GPNP_SETUP_CLUSTERWIDE => '3'; # good local same as clusterwide # --- gpnp string constants: use constant GPNP_DIRNAME => 'gpnp'; use constant GPNP_W_DIRNAME => 'wallets'; use constant GPNP_W_ROOT_DIRNAME => 'root'; use constant GPNP_W_PRDR_DIRNAME => 'prdr'; use constant GPNP_W_PEER_DIRNAME => 'peer'; use constant GPNP_W_PA_DIRNAME => 'pa'; use constant GPNP_P_DIRNAME => 'profiles'; use constant GPNP_P_PEER_DIRNAME => 'peer'; use constant GPNP_PROFILE_NAME => 'profile.xml'; use constant GPNP_PROFSAV_NAME => 'profile_orig.xml'; use constant GPNP_WRL_FILE_PFX => 'file:'; use constant GPNP_WALLET_NAME => 'ewallet.p12'; use constant GPNP_SSOWAL_NAME => 'cwallet.sso'; use constant GPNP_WALLET_LOCK_EXT => '.lck'; use constant GPNP_CERT_NAME => 'cert.txt'; use constant GPNP_CERTRQ_NAME => 'certreq.txt'; use constant GPNP_RTCERT_NAME => 'b64certificate.txt'; use constant GPNP_PDUMMY => 'gpnp_wallet1'; use constant GPNP_W_ROOT_DN => '"CN=GPnP_root"'; use constant GPNP_W_PA_DN => '"CN=GPnP_pa"'; use constant GPNP_W_PEER_DN => '"CN=GPnP_peer"'; use constant GPNP_W_KEYSZ => '1024'; use constant GPNP_W_EXPDT => '"01/01/2099"'; use constant GPNP_W_CVALID => '9999'; use constant GPNP_SEED_DIRNANE => 'seed'; use constant GPNP_S_ASM_DIRNAME => 'asm'; use constant GPNP_S_CRED_FILENAME => 'credentials.xml'; # state constants for element editing use constant GPNP_ELT_STATE_UNDEF => '0'; use constant GPNP_ELT_STATE_ORIGINAL => '1'; use constant GPNP_ELT_STATE_CREATED => '2'; use constant GPNP_ELT_STATE_DELETED => '3'; use constant GPNP_ELT_STATE_EDITED => '4'; # state constants for backup used during upgrade/downgarde use constant GPNP_PROFILE_FOR_DOWNGRADE => "profile4downgrade.xml"; use constant SIGNED_GPNP_PROFILE_FOR_DOWNGRADE => "signedprofile4downgrade.xml"; ####--------------------------------------------------------- #### Package-wide GPnP constants. # # --- constant result codes: # gpnp setup result # gpnp global pars my ($GPNP_CRSHOME_DIR, $GPNP_HOST, $GPNP_ORAUSER, $GPNP_ORAGROUP); # gpnp directories my ($GPNP_GPNPHOME_DIR, $GPNP_WALLETS_DIR, $GPNP_PROFILES_DIR, $GPNP_P_PEER_DIR, $GPNP_GPNPLOCALHOME_DIR, $GPNP_SEED_DIR); my ($GPNP_W_ROOT_DIR, $GPNP_W_PRDR_DIR, $GPNP_W_PEER_DIR, $GPNP_W_PA_DIR); my ($GPNP_L_WALLETS_DIR, $GPNP_L_W_ROOT_DIR, $GPNP_L_W_PRDR_DIR, $GPNP_L_W_PEER_DIR, $GPNP_L_W_PA_DIR, $GPNP_L_PROFILES_DIR, $GPNP_L_P_PEER_DIR); my ($GPNP_S_ASM_DIR); # gpnp files my $GPNP_ORIGIN_FILE; my ($GPNP_W_ROOT_FILE, $GPNP_WS_PA_FILE, $GPNP_WS_PEER_FILE, $GPNP_WS_PRDR_FILE); my ($GPNP_W_PA_FILE, $GPNP_W_PEER_FILE, $GPNP_W_PRDR_FILE); my ($GPNP_C_ROOT_FILE, $GPNP_C_PA_FILE, $GPNP_C_PEER_FILE); my ($GPNP_P_PEER_FILE, $GPNP_P_SAVE_FILE); my ($GPNP_L_W_ROOT_FILE, $GPNP_L_W_PA_FILE, $GPNP_L_WS_PA_FILE, $GPNP_L_W_PEER_FILE, $GPNP_L_WS_PEER_FILE, $GPNP_L_W_PRDR_FILE, $GPNP_L_WS_PRDR_FILE); my ($GPNP_L_CRQ_PA_FILE, $GPNP_L_CRQ_PEER_FILE); my ($GPNP_L_C_ROOT_FILE, $GPNP_L_C_PA_FILE, $GPNP_L_C_PEER_FILE); my ($GPNP_L_P_PEER_FILE, $GPNP_L_P_SAVE_FILE); my ($GPNP_S_ASM_CRED_FILE); # gpnp peer wrls my ($GPNP_W_PEER_WRL, $GPNP_L_W_PEER_WRL); # gpnp prdr wrls my ($GPNP_W_PRDR_WRL, $GPNP_L_W_PRDR_WRL); # package tools my ($GPNP_E_GPNPTOOL); ####--------------------------------------------------------- #### Define and verify GPnP local/cluster-wide gpnp directories #### This sub MUST be called before any gpnp setup handling takes place. # ARGS: 6 # ARG1 : Path for Oracle CRS home # ARG2 : Path for directory containing gpnp dir with a cluster-wide setup # ARG3 : Path for directory containing gpnp dir with a local setup # ARG4 : Hostname, must be given # ARG5 : OracleOwner user # ARG6 : OracleDBA group # @returns SUCCESS or $FAILURE # #static sub verify_gpnp_dirs { my $crshome = $_[0]; my $gpnpdir = $_[1]; my $gpnplocdir = $_[2]; my $host = $_[3]; my $orauser = $_[4]; my $oragroup = $_[5]; #------------- # Check pars if (!$crshome) { print_error(4); return FAILED; } if (!(-d $crshome)) { print_error(5, $crshome); return FAILED; } trace ("Oracle CRS home = " . $crshome); if (!$host) { print_error(15); trace("Hostname is required for GPnP setup"); return FAILED; } trace ("GPnP host = " . $host); check_dir( $gpnpdir ) or return FAILED; check_dir( $gpnplocdir ) or return FAILED; # define package-wide dir names on validated params define_gpnp_consts( $crshome, $gpnpdir, $gpnplocdir, $host, $orauser, $oragroup ) or return FAILED; trace ("Oracle GPnP home = $GPNP_GPNPHOME_DIR"); trace ("Oracle GPnP local home = $GPNP_GPNPLOCALHOME_DIR"); # Check defined const dirs: # 1) mandatory check_dir( $GPNP_GPNPHOME_DIR ) or return FAILED; check_dir( $GPNP_W_PEER_DIR ) or return FAILED; check_dir( $GPNP_P_PEER_DIR ) or return FAILED; check_dir( $GPNP_GPNPLOCALHOME_DIR ) or return FAILED; check_dir( $GPNP_L_W_PEER_DIR ) or return FAILED; check_dir( $GPNP_L_P_PEER_DIR ) or return FAILED; # 2) optional check_dir( $GPNP_W_ROOT_DIR ); check_dir( $GPNP_W_PA_DIR ); check_dir( $GPNP_L_W_ROOT_DIR ); check_dir( $GPNP_L_W_PA_DIR ); trace("GPnP directories verified. "); return SUCCESS; } ####--------------------------------------------------------- #### Define package-wide GPnP constants. Values validated separately. #### This sub MUST be called before any gpnp setup handling takes place. # ARGS: 6 # ARG1 : Path for Oracle CRS home # ARG2 : Path for directory containing gpnp dir with a cluster-wide setup # ARG3 : Path for directory containing gpnp dir with a local setup # ARG4 : Current Hostname # ARG5 : OracleOwner user # ARG6 : OracleDBA group # @returns SUCCESS or $FAILURE # #static sub define_gpnp_consts { my $crshome = $_[0]; my $gpnpdir = $_[1]; my $gpnplocdir = $_[2]; my $host = $_[3]; my $orauser = $_[4]; my $oragroup = $_[5]; # gpnp directories: $GPNP_CRSHOME_DIR = $crshome; $GPNP_HOST = $host; $GPNP_ORAUSER = $orauser; $GPNP_ORAGROUP = $oragroup; # -- cluster-wide $GPNP_GPNPHOME_DIR = catdir( $gpnpdir, GPNP_DIRNAME ); $GPNP_WALLETS_DIR = catdir( $GPNP_GPNPHOME_DIR, GPNP_W_DIRNAME ); $GPNP_W_ROOT_DIR = catdir( $GPNP_WALLETS_DIR, GPNP_W_ROOT_DIRNAME ); $GPNP_W_PRDR_DIR = catdir( $GPNP_WALLETS_DIR, GPNP_W_PRDR_DIRNAME ); $GPNP_W_PEER_DIR = catdir( $GPNP_WALLETS_DIR, GPNP_W_PEER_DIRNAME ); $GPNP_W_PA_DIR = catdir( $GPNP_WALLETS_DIR, GPNP_W_PA_DIRNAME ); $GPNP_PROFILES_DIR = catdir( $GPNP_GPNPHOME_DIR, GPNP_P_DIRNAME ); $GPNP_P_PEER_DIR = catdir( $GPNP_PROFILES_DIR, GPNP_P_PEER_DIRNAME ); $GPNP_SEED_DIR = catdir( $GPNP_GPNPHOME_DIR, GPNP_SEED_DIRNANE); $GPNP_S_ASM_DIR = catdir( $GPNP_SEED_DIR, GPNP_S_ASM_DIRNAME); # -- local $GPNP_GPNPLOCALHOME_DIR = catdir( $gpnplocdir, GPNP_DIRNAME, $host ); $GPNP_L_WALLETS_DIR = catdir( $GPNP_GPNPLOCALHOME_DIR, GPNP_W_DIRNAME ); $GPNP_L_W_ROOT_DIR = catdir( $GPNP_L_WALLETS_DIR, GPNP_W_ROOT_DIRNAME ); $GPNP_L_W_PRDR_DIR = catdir( $GPNP_L_WALLETS_DIR, GPNP_W_PRDR_DIRNAME ); $GPNP_L_W_PEER_DIR = catdir( $GPNP_L_WALLETS_DIR, GPNP_W_PEER_DIRNAME ); $GPNP_L_W_PA_DIR = catdir( $GPNP_L_WALLETS_DIR, GPNP_W_PA_DIRNAME ); $GPNP_L_PROFILES_DIR = catdir( $GPNP_GPNPLOCALHOME_DIR, GPNP_P_DIRNAME ); $GPNP_L_P_PEER_DIR = catdir( $GPNP_L_PROFILES_DIR, GPNP_P_PEER_DIRNAME ); # gpnp files: # -- cluster-wide $GPNP_ORIGIN_FILE = catfile( $GPNP_GPNPHOME_DIR, 'manifest.txt' ); $GPNP_W_ROOT_FILE = catfile( $GPNP_W_ROOT_DIR, GPNP_WALLET_NAME ); $GPNP_W_PA_FILE = catfile( $GPNP_W_PA_DIR, GPNP_WALLET_NAME ); $GPNP_WS_PA_FILE = catfile( $GPNP_W_PA_DIR, GPNP_SSOWAL_NAME ); $GPNP_W_PEER_FILE = catfile( $GPNP_W_PEER_DIR, GPNP_WALLET_NAME ); $GPNP_WS_PEER_FILE = catfile( $GPNP_W_PEER_DIR, GPNP_SSOWAL_NAME ); $GPNP_W_PRDR_FILE = catfile( $GPNP_W_PRDR_DIR, GPNP_WALLET_NAME ); $GPNP_WS_PRDR_FILE = catfile( $GPNP_W_PRDR_DIR, GPNP_SSOWAL_NAME ); $GPNP_C_ROOT_FILE = catfile( $GPNP_W_ROOT_DIR, GPNP_RTCERT_NAME ); $GPNP_C_PA_FILE = catfile( $GPNP_W_PA_DIR, GPNP_CERT_NAME ); $GPNP_C_PEER_FILE = catfile( $GPNP_W_PEER_DIR, GPNP_CERT_NAME ); $GPNP_P_PEER_FILE = catfile( $GPNP_P_PEER_DIR, GPNP_PROFILE_NAME ); $GPNP_P_SAVE_FILE = catfile( $GPNP_P_PEER_DIR, GPNP_PROFSAV_NAME ); $GPNP_S_ASM_CRED_FILE = catfile( $GPNP_S_ASM_DIR, GPNP_S_CRED_FILENAME ); # -- local $GPNP_L_W_ROOT_FILE = catfile( $GPNP_L_W_ROOT_DIR, GPNP_WALLET_NAME ); $GPNP_L_W_PA_FILE = catfile( $GPNP_L_W_PA_DIR, GPNP_WALLET_NAME ); $GPNP_L_WS_PA_FILE = catfile( $GPNP_L_W_PA_DIR, GPNP_SSOWAL_NAME ); $GPNP_L_W_PEER_FILE = catfile( $GPNP_L_W_PEER_DIR, GPNP_WALLET_NAME ); $GPNP_L_WS_PEER_FILE = catfile( $GPNP_L_W_PEER_DIR, GPNP_SSOWAL_NAME ); $GPNP_L_W_PRDR_FILE = catfile( $GPNP_L_W_PRDR_DIR, GPNP_WALLET_NAME ); $GPNP_L_WS_PRDR_FILE = catfile( $GPNP_L_W_PRDR_DIR, GPNP_SSOWAL_NAME ); $GPNP_L_CRQ_PA_FILE = catfile( $GPNP_L_W_PA_DIR, GPNP_CERTRQ_NAME ); $GPNP_L_CRQ_PEER_FILE = catfile( $GPNP_L_W_PEER_DIR, GPNP_CERTRQ_NAME ); $GPNP_L_C_ROOT_FILE = catfile( $GPNP_L_W_ROOT_DIR, GPNP_RTCERT_NAME ); $GPNP_L_C_PA_FILE = catfile( $GPNP_L_W_PA_DIR, GPNP_CERT_NAME ); $GPNP_L_C_PEER_FILE = catfile( $GPNP_L_W_PEER_DIR, GPNP_CERT_NAME ); $GPNP_L_P_PEER_FILE = catfile( $GPNP_L_P_PEER_DIR, GPNP_PROFILE_NAME ); $GPNP_L_P_SAVE_FILE = catfile( $GPNP_L_P_PEER_DIR, GPNP_PROFSAV_NAME ); # gpnp peer wrls $GPNP_W_PEER_WRL = "".GPNP_WRL_FILE_PFX.$GPNP_W_PEER_DIR; $GPNP_L_W_PEER_WRL = "".GPNP_WRL_FILE_PFX.$GPNP_L_W_PEER_DIR; # gpnp prdr wrls $GPNP_W_PRDR_WRL = "".GPNP_WRL_FILE_PFX.$GPNP_W_PRDR_DIR; $GPNP_L_W_PRDR_WRL = "".GPNP_WRL_FILE_PFX.$GPNP_L_W_PRDR_DIR; # package tools $GPNP_E_GPNPTOOL = catfile( $crshome, 'bin', 'gpnptool' ); return SUCCESS; } ####--------------------------------------------------------- #### Get gpnp peer profile fully-qualified filename. #### Assumes define_gpnp_consts() was called previously # ARGS: 1 # ARG1 : Boolean islocal (TRUE - local home (node-specific, FALSE - global # home (clusterwide seed) # @returns path or undef # sub get_peer_profile_file { my $islocal = $_[0]; # boolean (TRUE - local, FALSE - seed) my $profile = $GPNP_P_PEER_FILE; if ($islocal) { $profile = $GPNP_L_P_PEER_FILE; } return $profile; } ####--------------------------------------------------------- #### Get gpnp peer SSO wallet fully-qualified filename. #### Assumes define_gpnp_consts() was called previously # ARGS: 1 # ARG1 : Boolean islocal (TRUE - local home (node-specific, FALSE - global # home (clusterwide seed) # @returns path or undef # sub get_peer_wallet_file { my $islocal = $_[0]; # boolean (TRUE - local, FALSE - seed) my $wallet = $GPNP_WS_PEER_FILE; if ($islocal) { $wallet = $GPNP_L_WS_PEER_FILE; } return $wallet; } ####--------------------------------------------------------- #### Get gpnp peer wallet WRL (wallet URL-like string used by orapki). #### Assumes define_gpnp_consts() was called previously # ARGS: 1 # ARG1 : Boolean islocal (TRUE - local home (node-specific, FALSE - global # home (clusterwide seed) # @returns WRL or undef # sub get_peer_wallet_WRL { my $islocal = $_[0]; # boolean (TRUE - local, FALSE - seed) my $wrl = $GPNP_W_PEER_WRL; if ($islocal) { $wrl = $GPNP_L_W_PEER_WRL; } return $wrl; } ####--------------------------------------------------------- #### Verify GPnP local/cluster-wide file setup (wallet(s)/profiles) #### Note: verify_gpnp_dirs must be called prior calling this function # All parameters validated elsewhere # ARGS: 6 # ARG1 : Path for Oracle CRS home # ARG2 : Path for directory containing gpnp dir with a cluster-wide setup # ARG3 : Path for directory containing gpnp dir with a local setup # ARG4 : Current Hostname # ARG5 : OracleOwner user # ARG6 : OracleDBA group # @returns # GPNP_SETUP_BAD - if local setup is bad/inconsistent, or error of some # kind occured - local setup must be created # GPNP_SETUP_NONE - if local setup must be created # GPNP_SETUP_LOCAL - if local setup already valid, but not cluster-wide # (i.e. there is no cluster-wide setup found; # -x, if succeeded, must push the setup) # GPNP_SETUP_GOTCLUSTERWIDE # if local setup is valid, and was just promoted # from a valid cluster-wide setup # GPNP_SETUP_CLUSTERWIDE # if local setup is valid, and matches cluster-wide # sub check_gpnp_setup { my $crshome = $GPNP_CRSHOME_DIR; # validated my $gpnpdir = $GPNP_GPNPHOME_DIR; # validated my $gpnplocdir = $GPNP_GPNPLOCALHOME_DIR; # validated my $host = $GPNP_HOST; my $orauser = $GPNP_ORAUSER; my $oragroup = $GPNP_ORAGROUP; my $rc = 0; my @program ; # 1) Make sure global (seed) and local (node-specific) gpnp dirs # are distinct if ($GPNP_GPNPLOCALHOME_DIR eq $GPNP_GPNPHOME_DIR) { print_error(29, $GPNP_GPNPHOME_DIR, $GPNP_GPNPLOCALHOME_DIR); trace( "Invalid GPnP home locations: " ."cluster-wide \"$GPNP_GPNPHOME_DIR\", " ."node-specific \"$GPNP_GPNPLOCALHOME_DIR\". " ."Must be different." ); } # 2) check local setup exists and valid trace( "---Checking local gpnp setup..."); my $gpnploc_valid = check_gpnp_home_setup( TRUE ); # 3) check cluster-wide setup exists and valid trace( "---Checking cluster-wide gpnp setup..."); my $gpnp_valid = check_gpnp_home_setup( FALSE ); trace( "gpnp setup checked: local valid? $gpnploc_valid ". "cluster-wide valid? $gpnp_valid" ); # 4) see if we can assume cluster-wide setup, return current # type of gpnpsetup accordingly # if ( $gpnp_valid && $gpnploc_valid) { # if both setups valid, check local setup verifies against # cluster-wide wallet (wallet owner or peer) $rc = run_gpnptool_verifysig( $GPNP_L_P_PEER_FILE, $GPNP_W_PEER_WRL, $orauser ); if ($rc <= 0) { trace("Failed to veirfy a local peer profile \"$GPNP_L_P_PEER_FILE\" ". "against cluster-wide wallet \"$GPNP_W_PEER_WRL\" ". "rc=$rc (0==invalid,<0==error).\n". "Will try to take a cluster-wide setup." ); # promote cluster-wide setup if (take_clusterwide_gpnp_setup()) { trace( "gpnp setup: GOTCLUSTERWIDE" ); return GPNP_SETUP_GOTCLUSTERWIDE; } else # copy was not successfull - stick with local setup { trace( "Failed to copy cluster-wide setup.\n". "gpnp setup: LOCAL" ); return GPNP_SETUP_LOCAL; } } else { trace( "Local and Cluster-wide setups signed with same wallet.\n". "gpnp setup: CLUSTERWIDE" ); return GPNP_SETUP_CLUSTERWIDE; # identical setups } } elsif ( $gpnp_valid ) { # cluster-wide setup only, just try to take that if (take_clusterwide_gpnp_setup()) { trace( "gpnp setup: GOTCLUSTERWIDE" ); return GPNP_SETUP_GOTCLUSTERWIDE; } else # copy was not successfull - no good setup or no setup { trace( "Failed to copy cluster-wide setup.\n". "gpnp setup: BAD" ); return GPNP_SETUP_BAD; } } elsif ( $gpnploc_valid ) { # local setup only trace( "gpnp setup: LOCAL" ); return GPNP_SETUP_LOCAL; } else { trace( "gpnp setup: NONE" ); return GPNP_SETUP_NONE; } return GPNP_SETUP_BAD; # neverreached } ####--------------------------------------------------------- #### Check gpnp setup in given home is complete and valid # Note: osd-type failure (perms, etc.) will cause invalid # setup and attempt to recreate local setup later # static sub check_gpnp_home_setup { my $islocal = $_[0]; # boolean (TRUE - local home (node-specific), # FALSE - global home (seed) my $skip_setperm = $_[1]; my $gpnphome; my $gpnp_p_peer; my $gpnp_w_peer; my $gpnp_w_prdr; my $gpnp_wrl_peer; my $gpnp_wrl_prdr; my $orauser = $GPNP_ORAUSER; # assign appropriate gpnp home if ($islocal) { $gpnphome = $GPNP_GPNPLOCALHOME_DIR; # validated $gpnp_p_peer = $GPNP_L_P_PEER_FILE; $gpnp_w_peer = $GPNP_L_WS_PEER_FILE; $gpnp_wrl_peer = $GPNP_L_W_PEER_WRL; $gpnp_w_prdr = $GPNP_L_WS_PRDR_FILE; $gpnp_wrl_prdr = $GPNP_L_W_PRDR_WRL; } else { $gpnphome = $GPNP_GPNPHOME_DIR; # validated $gpnp_p_peer = $GPNP_P_PEER_FILE; $gpnp_w_peer = $GPNP_WS_PEER_FILE; $gpnp_wrl_peer = $GPNP_W_PEER_WRL; $gpnp_w_prdr = $GPNP_WS_PRDR_FILE; $gpnp_wrl_prdr = $GPNP_W_PRDR_WRL; } # check for mandatory peer profile and wallet, my $profile_ok = check_file( $gpnp_p_peer ); my $wallet_ok = check_file( $gpnp_w_peer ); my $rwallet_ok = check_file( $gpnp_w_prdr ); trace( "chk gpnphome $gpnphome: profile_ok $profile_ok ". "wallet_ok $wallet_ok r/o_wallet_ok $rwallet_ok" ); if (! $profile_ok || ! $wallet_ok ) { trace("chk gpnphome $gpnphome: INVALID (bad profile/wallet)"); return FAILED; } # now check profile sig against wallet (wallet owner or peer) my $rc = run_gpnptool_verifysig( $gpnp_p_peer, $gpnp_wrl_peer, $orauser ); if ($rc <= 0) { trace("chk gpnphome $gpnphome: INVALID (bad profile signature)"); return FAILED; } # now check profile sig against r/o wallet if (! $rwallet_ok ) { trace("chk gpnphome $gpnphome: INCOMPLETE (base gpnp config is ok, but ". "gpnp config reader wallet is missing)"); return FAILED; } else { # Note: prdr wallet does not have an owner, must be validated against peer my $rc = run_gpnptool_verifysig( $gpnp_p_peer, $gpnp_wrl_prdr, $orauser ); if ($rc <= 0) { $rwallet_ok = FAILED; trace("chk gpnphome $gpnphome: INVALID (base gpnp config is ok, but ". "gpnp config reader wallet is invalid - ". "does not verify peer profile signature)"); return FAILED; } } if ( $rwallet_ok ) { # if no errors noticed on r/o wallet trace("chk gpnphome $gpnphome: OK"); } # Now that gpnp setup is verified as valid, # get and log profile vitals - cname, cguid, sequence, PA # Note: order is significant and used in @pvals array below my @ppars = ( '-prf_cn', '-prf_cid', '-prf_sq', '-prf_pa' ); my @pvals = run_gpnptool_getpval( $gpnp_p_peer, \@ppars, $orauser ); $rc = shift @pvals; if ($rc < 0) { trace("chk gpnphome $gpnphome: INVALID ". "(failed to get vital profile parameters)"); return FAILED; } # verify profile cname with cname set in script environment, # make sure they are the same. my $p_cname = shift @pvals; # 1st par in @ppars array above my $t_cname = $CFG->params('CLUSTER_NAME'); if (! ($p_cname eq $t_cname)) { trace("chk gpnphome $gpnphome: INVALID ". "(target clustername \"$t_cname\" is different from ". "\"$p_cname\" in existing gpnp profile \"$gpnp_p_peer\")"); return FAILED; } # make sure profile permissions are correct, ignore res if (! $skip_setperm) { trace("setting profile permissions"); gpnp_wallets_set_ownerperm($islocal); # error(s) logged } return SUCCESS; } =head2 gpnp_update_config Check cluster-wide stage gpnp profile, if exist, Check any node-local gpnp setups on local node, pick best one and update cluster-wide stage gpnp setup (profile and wallets). If local node gpnp configuration is not latest, update it too. =head3 Parameters none =head3 Returns none =cut sub gpnp_update_config { my $cname = $CFG->params('CLUSTER_NAME'); my $host = tolower_host(); # check cluster-wide stage: my $gpnphome = catdir($CFG->params('GPNPGCONFIGDIR'), GPNP_DIRNAME); my $gpnp_wallets_dir = catdir( $gpnphome, GPNP_W_DIRNAME ); my $gpnp_profiles_dir = catdir( $gpnphome, GPNP_P_DIRNAME ); my $gpnp_p_peer_dir = catdir( $gpnp_profiles_dir, GPNP_P_PEER_DIRNAME ); my $gpnp_p_peer_file = catfile( $gpnp_p_peer_dir, GPNP_PROFILE_NAME ); # Check cluster-wide stage profile exists. It must exist or return. my $profile_ok = check_file( $gpnp_p_peer_file ); if (! $profile_ok) { trace( "Cluster-wide stage gpnp profile does not exist. ". "No gpnp configuration update will be attempted. ". "(checked stage profilename $gpnp_p_peer_file)" ); return; } # pick directory with best setup, if any, preferring local node my $gpnplochome = catdir($CFG->params('GPNPCONFIGDIR'), GPNP_DIRNAME); my $gpnpdir; my $gpnpseq; if (gpnp_find_best_local_setup_dir( $gpnplochome, $cname, undef, $host, \$gpnpdir, \$gpnpseq )) { trace( "Best gpnp node configuration is \"$gpnpdir\""); my $gpnpdir_fqp = catdir( $gpnplochome, $gpnpdir ); my $gpnphostdir_fqp = catdir( $gpnplochome, $host ); # Create backup diretories in $gpnphome { # Get op timestamp my ($sec, $min, $hour, $day, $month, $year) = (tz_localtime()) [0, 1, 2, 3, 4, 5]; $month = $month + 1; $year = $year + 1900; my $sfx = "\__$year\_$month\_$day\_$hour$min$sec"; my $bcpnm = "gpnp_bcp$sfx"; my $bcpdir = catdir($gpnphome, $bcpnm); trace( "Creating backup directory \"$bcpdir\" " ); my $bcpdirold = catdir($bcpdir, "stg__$host"); my $bcpdirow = catdir($bcpdirold, GPNP_W_DIRNAME); my $bcpdirop = catdir($bcpdirold, GPNP_P_DIRNAME); my $bcpdirnew = catdir($bcpdir, "new__$gpnpdir"); my $dirok = TRUE; if ($dirok && ! -d $bcpdir) { $dirok &= mkdir($bcpdir); } if ($dirok && ! -d $bcpdirold) { $dirok &= mkdir($bcpdirold); } if ($dirok && ! -d $bcpdirow) { $dirok &= mkdir($bcpdirow); } if ($dirok && ! -d $bcpdirop) { $dirok &= mkdir($bcpdirop); } if ($dirok && ! -d $bcpdirnew) { $dirok &= mkdir($bcpdirnew); } if ($dirok) { trace( "Saving old cluster-wide stage in \"$bcpdirold\" " ); copydir( $gpnp_wallets_dir, $bcpdirow ); copydir( $gpnp_profiles_dir, $bcpdirop ); trace( "Saving new setup in \"$bcpdirnew\" " ); copydir( $gpnpdir_fqp, $bcpdirnew ); } } # if best setup is not our local node, update local node setup if (! ($gpnpdir eq $host)) { trace( "Updating local node ($host) gpnp configuration from ". "node $gpnpdir" ); copydir( $gpnpdir_fqp, $gpnphostdir_fqp ); } # update cluster-wide stage dir always trace( "Updating cluster-wide stage gpnp configuration from ". "node $gpnpdir" ); copydir(catdir($gpnpdir_fqp,GPNP_P_DIRNAME), #to $gpnp_profiles_dir); copydir(catdir($gpnpdir_fqp,GPNP_W_DIRNAME), #to $gpnp_wallets_dir); } else { # bad error print_error(17); trace( "Failed to inspect gpnp home \"$gpnplochome\", ". "cname=$cname, host=$host" ); } # dirbackup return; } =head2 gpnp_find_best_local_setup_dir Find best local gpnp setup in given gpnp home gpnp_find_best_local_setup_dir( IN $gpnp_dir, OPTIONAL IN $gpnp_cname, OPTIONAL IN $gpnp_cuid, OPTIONAL IN $gpnp_prefhost, OUT \$gpnphostdir_ref, OUT \$gpnphostdir_prf_seq_ref ) =head3 Parameters gpnp_dir - gpnp home directory to check gpnp_cname - gpnp clustername to validate against, or undef gpnp_cguid - gpnp clusterguid to validate against, or undef Note: either gpnp_cname, or gpnp_cguid, or both MUST be defined gpnp_prefhost - gpnp preferred host (typically local host name) or undef if given, if will be preferred if best valid setup exist on local node gpnphostdir_ref - out reference of gpnp directory (dir in gpnp home, not fully-qualified path) with best setup gpnphostdir_prf_seq_ref - out reference of best profile sequence =head3 Returns @returns retcode plust output parameters above SUCCESS gpnp directory with best setup was picked FAILED no gpnp setup directory found =cut sub gpnp_find_best_local_setup_dir { my $gpnphome = $_[0]; # gpnp home directory my $gpnpcname = $_[1]; # gpnp cluster name or undef my $gpnpcuid = $_[2]; # gpnp cluster guid or undef my $gpnpprefhost = $_[3]; # gpnp preferred host name or undef my $gpnphostdir_ref = $_[4]; # outer best gpnp host dir name ref my $gpnphostdir_prf_seq_ref = $_[5]; # outer best profile sequence ref # init outers ${$gpnphostdir_ref} = undef; ${$gpnphostdir_prf_seq_ref} = undef; trace( "Pick best local setup for home \"$gpnphome\" of cname=$gpnpcname, ". "cguid=$gpnpcuid, prefhost=$gpnpprefhost" ); # make sure cluster name and/or guid defined if (! (defined $gpnpcname || defined $gpnpcuid)) { trace( "cluster identity is undefined ($gpnpcname, $gpnpcuid)" ); return FAILED; } # check_dir( $gpnphome ) or return FAILED; if (!(-d $gpnphome)) { trace( "Gpnp home $gpnphome does not exist or not a dir!" ); return FAILED; } # open gpnp home and traverse it, picking directories that # look like gpnp setup if (! opendir(DIR, $gpnphome)) { trace( "Unable to open gpnp home $gpnphome:$! "); return FAILED; } my @gpnpdirs; if (! (@gpnpdirs = readdir(DIR))) { trace( "Unable to read gpnp home $gpnphome:$! "); return FAILED; } closedir(DIR); trace( "gpnp dir candidates: ".join ",",@gpnpdirs ); # for all entries in gpnp home my $best_dir; my $best_seq = 0; foreach my $name (@gpnpdirs) { my $prf_cname; my $prf_cuid; my $prf_seq; # skip special next if ($name eq '.'); next if ($name eq '..'); # if directory, evaluate it as gpnp setup directory if (gpnp_check_setup_dir( $gpnphome, $name, $gpnpcname, $gpnpcuid, undef, undef, undef, \$prf_seq )) { # if directory validation passed, see if sequence we got is better # if so, pick directory if ($best_seq < $prf_seq) { $best_seq = $prf_seq; $best_dir = $name; } # preferred host, if qualified, takes precedence elsif (($best_seq == $prf_seq) && ($name eq $gpnpprefhost)) { $best_seq = $prf_seq; $best_dir = $name; } } } # if best directory found, success if (defined $best_dir) { # pass result to outers ${$gpnphostdir_ref} = $best_dir; ${$gpnphostdir_prf_seq_ref} = $best_seq; trace( "best gpnp directory in home \"$gpnphome\" is \"$best_dir\" ". " new seq=$best_seq for cname=$gpnpcname, cguid=$gpnpcuid" ); return SUCCESS; } trace( "NO qualified gpnp directory found in home \"$gpnphome\" ". " for cname=$gpnpcname, cguid=$gpnpcuid" ); return FAILED; } =head2 gpnp_check_setup_dir Check consistancy of given gpnp setup directory gpnp_check_setup_dir( IN $gpnp_dir, OPTIONAL IN $gpnp_host, OPTIONAL IN $gpnp_cname, OPTIONAL IN $gpnp_cuid, OPTIONAL IN $gpnp_prfseq, OPTIONAL OUT \$prf_cname_ref, OPTIONAL OUT \$prf_cguid_ref, OPTIONAL OUT \$prf_seq_ref ) =head3 Parameters gpnp_dir - gpnp directory to check, or gpnp home gpnp_host - gpnp host to append to passed gpnp home, or undef gpnp_cname - gpnp clustername to validate against, or undef gpnp_cguid - gpnp clusterguid to validate against, or undef gpnp_prfseq - gpnp profile sequence number to validate against, or undef If given, profile in gpnp directory must have a better sequence for directory to qualify. prf_cname_ref - optional out reference of gpnp directory profile cname prf_cguid_ref - optional out reference of gpnp directory profile cguid prf_seq_ref - optional out reference of gpnp directory profile sequence =head3 Returns @returns retcode plust output parameters above SUCCESS gpnp directory is consistent and qualifies to given parameters FAILED gpnp setup directory is not ok to use =cut sub gpnp_check_setup_dir { my $gpnphome = $_[0]; # gpnp home directory my $gpnphost = $_[1]; # gpnp host (subdirectory) or undef my $gpnpcname = $_[2]; # gpnp cluster name or undef my $gpnpcuid = $_[3]; # gpnp cluster guid or undef my $gpnppseq = $_[4]; # gpnp profile sequence or undef my $prf_cname_ref = $_[5]; # outer profile clustername or undef my $prf_cuid_ref = $_[6]; # outer profile cluster guid or undef my $prf_seq_ref = $_[7]; # outer profile sequence of undef my $orauser = $CFG->params('ORACLE_OWNER'); my $rc; my $prf_cname; my $prf_cuid; my $prf_seq; # set outer params, if given if (defined $prf_cname_ref) { ${ $prf_cname_ref } = undef; } if (defined $prf_cuid_ref) { ${ $prf_cuid_ref } = undef; } if (defined $prf_seq_ref) { ${ $prf_seq_ref } = undef; } # check_dir( $gpnphome ) or return FAILED; if (!(-d $gpnphome)) { trace( "$gpnphome does not exist or not a dir!" ); return FAILED; } my $gpnpdir = $gpnphome; if (defined $gpnphost) { $gpnpdir = catdir( $gpnphome, $gpnphost ); # check_dir( $gpnpdir ) or return FAILED; if (!(-d $gpnpdir)) { trace( "$gpnpdir is not a dir" ); return FAILED; } } trace( "---> chk gpnp dir \"$gpnpdir\" ". " for cname=$gpnpcname, cguid=$gpnpcuid, pseq=$gpnppseq" ); # setup directories my $gpnp_wallets_dir = catdir( $gpnpdir, GPNP_W_DIRNAME ); my $gpnp_w_root_dir = catdir( $gpnp_wallets_dir, GPNP_W_ROOT_DIRNAME ); my $gpnp_w_prdr_dir = catdir( $gpnp_wallets_dir, GPNP_W_PRDR_DIRNAME ); my $gpnp_w_peer_dir = catdir( $gpnp_wallets_dir, GPNP_W_PEER_DIRNAME ); my $gpnp_w_pa_dir = catdir( $gpnp_wallets_dir, GPNP_W_PA_DIRNAME ); my $gpnp_profiles_dir = catdir( $gpnpdir, GPNP_P_DIRNAME ); my $gpnp_p_peer_dir = catdir( $gpnp_profiles_dir, GPNP_P_PEER_DIRNAME ); # cluster-wide only my $gpnp_seed_dir = catdir( $gpnpdir, GPNP_SEED_DIRNANE); my $gpnp_s_asm_dir = catdir( $gpnp_seed_dir, GPNP_S_ASM_DIRNAME); # Check defined const dirs: # 1) mandatory # check_dir( $gpnp_w_peer_dir ) or return FAILED; if (!(-d $gpnp_w_peer_dir)) { trace( "$gpnp_w_peer_dir does not exist!" ); return FAILED; } # check_dir( $gpnp_w_prdr_dir ) or return FAILED; if (!(-d $gpnp_w_prdr_dir)) { trace( "$gpnp_w_prdr_dir does not exist!" ); return FAILED; } # check_dir( $gpnp_p_peer_dir ) or return FAILED; if (!(-d $gpnp_p_peer_dir)) { trace( "$gpnp_p_peer_dir does not exist!" ); return FAILED; } # 2) optional # check_dir( $gpnp_w_root_dir ); if (!(-d $gpnp_w_root_dir)) { trace( "$gpnp_w_root_dir does not exist" ); } # check_dir( $gpnp_w_pa_dir ); if (!(-d $gpnp_w_pa_dir)) { trace( "$gpnp_w_pa_dir does not exist" ); } # setup files my $gpnp_origin_file = catfile( $gpnpdir, 'manifest.txt' ); my $gpnp_w_root_file = catfile( $gpnp_w_root_dir, GPNP_WALLET_NAME ); my $gpnp_ws_pa_file = catfile( $gpnp_w_pa_dir, GPNP_SSOWAL_NAME ); my $gpnp_ws_peer_file = catfile( $gpnp_w_peer_dir, GPNP_SSOWAL_NAME ); my $gpnp_ws_prdr_file = catfile( $gpnp_w_prdr_dir, GPNP_SSOWAL_NAME ); my $gpnp_c_root_file = catfile( $gpnp_w_root_dir, GPNP_RTCERT_NAME ); my $gpnp_c_pa_file = catfile( $gpnp_w_pa_dir, GPNP_CERT_NAME ); my $gpnp_c_peer_file = catfile( $gpnp_w_peer_dir, GPNP_CERT_NAME ); my $gpnp_p_peer_file = catfile( $gpnp_p_peer_dir, GPNP_PROFILE_NAME ); # cluster-wide only my $gpnp_p_save_file = catfile( $gpnp_p_peer_dir, GPNP_PROFSAV_NAME ); my $gpnp_s_asm_cred_file = catfile( $gpnp_s_asm_dir, GPNP_S_CRED_FILENAME ); # gpnp peer/prdr wrls my $gpnp_w_peer_wrl = "".GPNP_WRL_FILE_PFX.$gpnp_w_peer_dir; my $gpnp_w_prdr_wrl = "".GPNP_WRL_FILE_PFX.$gpnp_w_prdr_dir; # check for mandatory peer profile and wallet, my $profile_ok = check_file( $gpnp_p_peer_file ); my $wallet_ok = check_file( $gpnp_ws_peer_file ); my $rwallet_ok = check_file( $gpnp_ws_prdr_file ); trace( "chk gpnp dir $gpnpdir: profile_ok $profile_ok ". "wallet_ok $wallet_ok r/o_wallet_ok $rwallet_ok" ); if (! $profile_ok || ! $wallet_ok) { trace("chk gpnp dir $gpnpdir: INVALID (bad profile/wallet)"); return FAILED; } # make sure gpnptool is available if (! defined $GPNP_E_GPNPTOOL) { my $crshome = $CFG->params('ORACLE_HOME'); $GPNP_E_GPNPTOOL = catfile( $crshome, 'bin', 'gpnptool' ); } # now check profile sig against wallet (wallet owner or peer) $rc = run_gpnptool_verifysig( $gpnp_p_peer_file,$gpnp_w_peer_wrl,$orauser ); if ($rc <= 0) { trace("chk gpnp dir $gpnpdir: INVALID (bad profile signature)"); return FAILED; } # now check profile sig against r/o wallet if (! $rwallet_ok ) { trace("chk gpnp dir $gpnpdir: INCOMPLETE (base gpnp config is ok, but ". "gpnp config reader wallet is missing)"); return FAILED; } # Note: prdr wallet does not have an owner, must be validated against peer $rc = run_gpnptool_verifysig( $gpnp_p_peer_file,$gpnp_w_prdr_wrl,$orauser ); if ($rc <= 0) { $rwallet_ok = FAILED; trace("chk gpnp dir $gpnpdir: INVALID (base gpnp config is ok, but ". "gpnp config reader wallet is invalid - ". "does not verify peer profile signature)"); return FAILED; } # if no errors noticed on r/o wallet dir is ok if ( $rwallet_ok ) { trace("chk gpnp dir $gpnpdir: OK"); } # Now that gpnp setup is verified as valid, # get and log profile vitals - cname, cguid, sequence, ($rc, $prf_seq, $prf_cname, $prf_cuid) = gpnp_get_profile_identity( $gpnp_p_peer_file ); if ($rc != 0) { trace("chk gpnp dir $gpnpdir: INVALID ". "(failed to get vital profile parameters)"); return FAILED; } # set outer params, if given if (defined $prf_cname_ref) { ${ $prf_cname_ref } = $prf_cname; } if (defined $prf_cuid_ref) { ${ $prf_cuid_ref } = $prf_cuid; } if (defined $prf_seq_ref) { ${ $prf_seq_ref } = $prf_seq; } # verify profile cname, cguid with passed params, if any # make sure they are the same. if (defined $gpnpcuid && ! ($gpnpcuid eq $prf_cuid)) { trace("chk gpnp dir $gpnpdir: INVALID ". "(target cluster UID \"$gpnpcuid\" is different from ". "\"$prf_cuid\" in existing gpnp profile \"$gpnp_p_peer_file\")"); return FAILED; } if (defined $gpnpcname && ! ($gpnpcname eq $prf_cname)) { trace("chk gpnp dir $gpnpdir: INVALID ". "(target cluster name \"$gpnpcname\" is different from ". "\"$prf_cname\" in existing gpnp profile \"$gpnp_p_peer_file\")"); return FAILED; } # verify profile sequence is better than one passed if (defined $gpnppseq && ! ($gpnppseq >= $prf_seq)) { trace("chk gpnp dir $gpnpdir: INVALID ". "(target profile sequence \"$gpnppseq\" >= ". "\"$prf_seq\" in existing gpnp profile \"$gpnp_p_peer_file\")"); return FAILED; } trace("ok chk gpnp dir $gpnpdir: (prf_seq=$prf_seq, prf_cname=$prf_cname, ". "prf_cguid=$prf_cuid)"); return SUCCESS; } ####--------------------------------------------------------- #### Run gpnptool verify for given profile and wallet loc (WRL) # ARGS: 3 # ARG1 : profile filepath (verified) # ARG2 : WRL (gpnptool-recognized wallet locator string, e.g. # 'file:/mypath/') # ARG3 : user to run gpnptool as (or undef if don't care) # @returns numeric result: # <0 error occured # ==0 profile signature does not matches against given wallet # ==1 profile signature matches against given wallet # sub run_gpnptool_verifysig { my $gpnp_p = $_[0]; # validated my $gpnp_wrl = $_[1]; # validated my $orauser = $_[2]; my @gpnptool_args = ( 'verify', "-p=\"$gpnp_p\"", "-w=\"$gpnp_wrl\"", '-wu=peer' ); my @gpnptool_out = (); # run gpnptool verify as orauser, capturing stdout/err my $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out ); if (0 != $rc) { trace("Failed to verify a \"$gpnp_p\" profile against ". "cluster-wide wallet \"$gpnp_wrl\" gpnptool rc=$rc" ); return -1; } # TOBEREVISED - gpnptool error code - now suc on invalid sig my $gpnptool_res = join('', @gpnptool_out ); if ($gpnptool_res =~ m/signature is valid/i) { trace("Profile \"$gpnp_p\" signature is VALID ". "for wallet \"$gpnp_wrl\"" ); return 1; } elsif ($gpnptool_res =~ m/signature is not valid/i) { trace("Profile \"$gpnp_p\" signature is INVALID". " for wallet \"$gpnp_wrl\"" ); return 0; } else { print_error(31); trace("Profile \"$gpnp_p\" signature verified, ". "but no signature status string ". "found in \"\n$gpnptool_res\n\""); return -2; } return -1; } ####--------------------------------------------------------- #### Run gpnptool with options # ARGS: 3 # ARG1 : ref to array of gpnptool arguments (verb + switches) # ARG2 : user to run gpnptool as (or undef if don't care) # ARG3 : if reference to an array var passed, return captured output # (stderr in case of gpnptool) value (strings are "as is", not chomped); # if undefined, no capture takes place. # @returns numeric exit code from gpnptool (0 on success) # sub run_gpnptool { my $argsref = $_[0]; #ref my $user = $_[1]; my $capoutref = $_[2]; #ref my $rc = -1; my @program = ($GPNP_E_GPNPTOOL, @{$argsref}); # run as specific user, if requested trace ('gpnptool: run '.join(' ', @program)); $rc = run_as_user2($user, $capoutref, @program); trace ("gpnptool: rc=$rc"); if (defined($capoutref)) { trace ("gpnptool output:\n". join('', @{$capoutref}) ); } return $rc; } ####--------------------------------------------------------- #### Run gpnptool to get param value(s) for given profile # ARGS: 3 # ARG1 : profile filepath (verified) # ARG2 : reference to an array of gpnptool cmdline switches of # profile params to get their value. # e.g. -prf_sq (for ProfileSequence, see "gpnptool help getpval") # Invalid switch will result in general gpnptool error. # Passing a valid switch that has no representation in the profile # will result in special "" value, but no cmd error. # ARG3 : user to run gpnptool as (or undef if don't care) # @returns array of elements, # first being a numeric result code: # <0 error occured # ==0 values successfully obtained from a specified profile # rest of elements are requested string parameter values, # or an error message, if error returned. # sub run_gpnptool_getpval { my $gpnp_p = $_[0]; # validated my $gpnp_pr = $_[1]; # ref my $orauser = $_[2]; my @gpnp_pars = @{$gpnp_pr}; if ((! defined $gpnp_pr) || (0 == scalar @gpnp_pars)) { print_error(30, $gpnp_p); return ( -2, "No parameters" ); } # capture gpnptool getpval output into a temp file, to ensure # no shell errors get into the results my $gpnptool_res_file; (undef, $gpnptool_res_file) = tempfile(OPEN => 0); my @gpnptool_args = ( 'getpval', "-p=\"$gpnp_p\"", "-o=\"$gpnptool_res_file\"", @gpnp_pars ); my @gpnptool_out = (); # stdout/stderr out discarded by this fn my @gpnptool_getpval_res = (); # run gpnptool getpval as orauser, capturing stdout/err my $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out ); if (0 != $rc) { print_error(147, $gpnp_p); } else { # read getpval results from temp file @gpnptool_getpval_res = read_file( $gpnptool_res_file ); chomp(@gpnptool_getpval_res); # remove newlines (output one par per line) } # delete results temp file s_remove_file($gpnptool_res_file); return ($rc, @gpnptool_getpval_res); } =head2 run_gpnptool_getpnet Run gpnptool getpnet for a given profile =head3 Parameters Profile filename to get net info from Boolean Match - if TRUE, ask gpnptool to match netinfo on local node Boolean Parse - if TRUE parse gpnptool getpnet output to network items =head3 Returns @returns an array of ($rc, \@(), \@(arrayofinterfaceinfo-if-parsed)) where arrayofinterfaceinfo is an array of refs to elements: ($netid, $state, ($adapter_name,$network,$node_name,$type_list[,$mask])) Where: netid network id in profile if known (here known always) state GPNP_ELT_STATE_* const indicating orig|new|deleted|altered defn - here GPNP_ELT_STATE_ORIGINAL adapter_name is the name of net adapter, unquoted; network is a network bits of adapter address; node_name is '*' for cluster-wide config, or node name if node-specific; type_list is a comma-separated list of network types (valid values are unknown|local|public|private|cluster_interconnect); mask is a mask bits; If any of the parameters was not defined, undef returned in its place. =cut sub run_gpnptool_getpnet { my $gpnp_p = $_[0]; # validated my $gpnp_mch = $_[1]; # if TRUE, ask gpnptool to match interfaces my $parseitfs = $_[2]; # if TRUE, parse returned interface definitions my $orauser = $CFG->params('ORACLE_OWNER'); # capture gpnptool getpval output into a temp file, to ensure # no shell errors get into the results my $gpnptool_res_file = tmpnam(); # concurrency not an issue here my @parsed_interfaces = (); my @gpnptool_out = (); # stdout/stderr out discarded by this fn my @gpnptool_getpnet_res = (); my @gpnptool_args = ( 'getpnet', '-ovr', "-p=\"$gpnp_p\"", "-o=\"$gpnptool_res_file\"" ); if ($gpnp_mch) { push @gpnptool_args, "-match"; } # run gpnptool getpval as orauser, capturing stdout/err my $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out ); if (0 != $rc) { my $nonets = FALSE; foreach (0..$#gpnptool_out) { if ($gpnptool_out[$_] =~ m/profile has no network information/i) { $nonets = TRUE; $rc = -1; last; } } if (! $nonets) { print_error(147, $gpnp_p); } } else { # read getpval results from temp file @gpnptool_getpnet_res = read_file( $gpnptool_res_file ); # delete results temp file s_remove_file($gpnptool_res_file); # if we were asked to parse getpnet output, see to it. if ($parseitfs) { foreach (0..$#gpnptool_getpnet_res) { my @idef_parsed = (); my $idef = $gpnptool_getpnet_res[$_]; # total failure should return rc, else filter out # error messages, if any, e.g. "Error....." if (($idef !~ /^Error/) && ($idef !~ /^Warning/) && ($idef !~ /^Fatal/) && ($idef !~ /MATCH: /) && ($idef !~ /BCVIP: /)) { my $nid; my $ada; my $net; my $nod; my $typ; my $msk; # extract profile network id $idef =~ s/^\s+|\s+$//g; my $n = index( $idef, ' ' ); # double-space separators $nid = substr( $idef, 0, $n ); $nid =~ s/\s+$//; $idef = substr( $idef, $n ); # parse network definition string into standard components my @net = oifcfg_intf_parse( $idef ); ($ada, $net, $nod, $typ, $msk ) = @net; # if all is well, push data into output array if ((defined $typ) && (defined $net) && (defined $ada)) { push @idef_parsed, $nid; push @idef_parsed, GPNP_ELT_STATE_ORIGINAL; push @idef_parsed, \@net; trace " prf net: $nid, def: $ada $net $nod $typ $msk\n"; # save network interface info into output array push @parsed_interfaces, \@idef_parsed; } } } # each line } # if parse } # log what we've got trace "gpnptool getpnet output: ".join ('\n', @gpnptool_getpnet_res)."\n"; return ($rc, \@gpnptool_getpnet_res, \@parsed_interfaces); } =head2 run_gpnptool_gethnets Run gpnptool getpnet for a given profile =head3 Parameters Profile filename to get host net info from =head3 Returns @returns an array of ($rc, \%hnethash, $true_if_globalhnet_present, $true_if_nodespecifichnet_present) where hnethash is a perl reference of hash in form $hnettbl{ $hostname_or_star } = $hnet_prf_id if $rc is non-0, hash table is empty and booleans are FALSE =cut sub run_gpnptool_gethnets { my $gpnp_p = $_[0]; # validated my $orauser = $CFG->params('ORACLE_OWNER'); my $hnet_gen = FALSE; my $hnet_hos = FALSE; my %hnets = (); my @hnet_arr = (); # capture gpnptool getpval output into a temp file, to ensure # no shell errors get into the results my $gpnptool_res_file = tmpnam(); # concurrency not an issue here my @gpnptool_args = ( 'getpval', "-p=\"$gpnp_p\"", "-o=\"$gpnptool_res_file\"", '-hnet' ); my @gpnptool_out = (); # stdout/stderr out discarded by this fn my @gpnptool_getpval_res = (); # run gpnptool getpval as orauser, capturing stdout/err my $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out ); if (0 == $rc) { # read getpval results from temp file @gpnptool_getpval_res = read_file( $gpnptool_res_file ); # delete results temp file s_remove_file($gpnptool_res_file); chomp(@gpnptool_getpval_res); # remove newlines (output one par per line) trace "Got ".scalar @gpnptool_getpval_res." hnets: ". join " ", @gpnptool_getpval_res; } if (0 != $rc || 0 == scalar @gpnptool_getpval_res) { print_error(147, $gpnp_p); } else { # parse results, create new cmd line to get host names $gpnptool_res_file = tmpnam(); # concurrency not an issue here @gpnptool_args = ( 'getpval', "-p=\"$gpnp_p\"", "-o=\"$gpnptool_res_file\"" ); @gpnptool_out = (); # stdout/stderr out discarded by this fn # parse results my $i; my $j; for ($i=0; $i<=$#gpnptool_getpval_res; $i++) { my $hnets_out = $gpnptool_getpval_res[$i]; # total failure should return rc, else filter out # error messages, if any, e.g. "Error....." if (($hnets_out !~ /^Error/) && ($hnets_out !~ /^Warning/) && ($hnets_out !~ /^Fatal/)) { my @hnetids = split( ' ', $hnets_out); for ($j=0; $j<=$#hnetids; $j++) { my $hnetid = $hnetids[$j]; push @gpnptool_args, "-$hnetid:hnet_nm"; push @hnet_arr, $hnetid; } } } # run gpnptool getpval as orauser, capturing stdout/err $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out ); if (0 != $rc) { print_error(147, $gpnp_p); } else { # read getpval results from temp file @gpnptool_getpval_res = read_file( $gpnptool_res_file ); # delete results temp file s_remove_file($gpnptool_res_file); chomp(@gpnptool_getpval_res); # remove newlines (output one par/line) # parse results, create new cmd line to get host names for ($i=0; $i<=$#gpnptool_getpval_res; $i++) { my $nodnm = $gpnptool_getpval_res[$i]; # create hash as tbl{ honame } = hnetid; $hnets{ $nodnm } = $hnet_arr[$i]; # note presense of global hnet and host-specific nets if ($nodnm eq '*') { $hnet_gen = TRUE; } else { $hnet_hos = TRUE; } } trace "hnets hash: gen=$hnet_gen, hos=$hnet_hos "; for (keys %hnets) { trace " $_=$hnets{$_} "; } } } return ($rc, \%hnets, $hnet_gen, $hnet_hos); } =head2 gpnp_get_profile_identity Get profile sequence, cluster name, uid, from a given profile, =head3 Parameters profile filename to alter, a fully-qualified filename. =head3 Returns array of (gpnptool_retcode, psequence, cname, cuid ) SUCCESS Profile altered FAILED Profile is not changed, or error occurred =cut sub gpnp_get_profile_identity { my $gpnp_p = $_[0]; # profile filename to query/edit my $rc = 99; my $prfseq; my $prfcnm; my $prfcid; # Get profile sequence clustername, and cluster guid my @gpnptool_args = ( '-prf_sq', '-prf_cn', '-prf_cid' ); my $orauser = $CFG->params('ORACLE_OWNER'); # run profile getpval command to get values my @gpnptool_out = run_gpnptool_getpval( $gpnp_p, \@gpnptool_args, $orauser ); $rc = shift @gpnptool_out; if ($rc != 0) { # print_error called by run_gpnptool_getpval trace("Failed to get Oracle Cluster GPnP profile identity values. ". "gpnptool rc=$rc" ); print_error(147, $gpnp_p); } else { # set current profile values to the table $prfseq = shift @gpnptool_out; $prfcnm = shift @gpnptool_out; $prfcid = shift @gpnptool_out; trace( "Profile seq=$prfseq, cname=$prfcnm, cguid=$prfcid" ); } return ($rc, $prfseq, $prfcnm, $prfcid); } # delete stale wallet lock files (.lck), if any sub gpnp_wallets_clean_locks { my $islocal = $_[0]; # boolean (TRUE - local home (node-specific), # FALSE - global home (seed) my $status = SUCCESS; trace ("Checking for stale GPnP wallet locks. [node-local=$islocal]"); my $gpnp_wl_root; my $gpnp_wl_peer; my $gpnp_wsl_peer; my $gpnp_wl_pa; my $gpnp_wsl_pa; my $gpnp_wl_prdr; my $gpnp_wsl_prdr; if ($islocal) { $gpnp_wl_root = $GPNP_L_W_ROOT_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_peer = $GPNP_L_W_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_peer = $GPNP_L_WS_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_pa = $GPNP_L_W_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_pa = $GPNP_L_WS_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_prdr = $GPNP_L_W_PRDR_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_prdr = $GPNP_L_WS_PRDR_FILE . GPNP_WALLET_LOCK_EXT; } else { $gpnp_wl_root = $GPNP_W_ROOT_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_peer = $GPNP_W_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_peer = $GPNP_WS_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_pa = $GPNP_W_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_pa = $GPNP_WS_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wl_prdr = $GPNP_W_PRDR_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_prdr = $GPNP_WS_PRDR_FILE . GPNP_WALLET_LOCK_EXT; } my $lock; my $rmstat; # delete stale lock file(s) if exist, traced - optional wallets foreach $lock (($gpnp_wl_root, $gpnp_wl_pa, $gpnp_wsl_pa )) { s_remove_file($lock) or print_error(168, $lock, $!); # non-fatal } # delete stale lock file(s) if exist, traced - mandatory wallets foreach $lock (($gpnp_wl_peer, $gpnp_wl_prdr, $gpnp_wsl_peer, $gpnp_wsl_prdr)) { if (SUCCESS != ($rmstat = s_remove_file($lock))) { print_error(168, $lock, $!); $status = FAILED; } } # make sure .sso.lck files do exist (bug16500302/15853970) # create an empty file, perm/ownership taken care by caller foreach $lock (( $gpnp_wsl_peer, $gpnp_wsl_prdr, $gpnp_wsl_pa )) { if (! (-f $lock)) { # if lock file does not exist, create empty lock file trace("creating new $lock"); if (! open(FH,">$lock")) { print_error(255, $lock, $!); $status = FAILED; } close(FH); } } if (SUCCESS == $status) { trace ("GPnP wallet locks cleaned. [node-local=$islocal]"); } return $status; } # set gpnp wallet/certs ownership and permissions, delete stale wallet locks sub gpnp_wallets_set_ownerperm { my $islocal = $_[0]; # boolean (TRUE - local home (node-specific), # FALSE - global home (seed) my $orauser = $CFG->params('ORACLE_OWNER'); my $status = SUCCESS; my $haderr = FALSE; my $fileNotExistErr = FALSE; # delete stale wallet lock files (.lck), if any # for peer/preader gpnp wallets, locks must be successfully cleaned, # otherwise there may be wallet access issues for non-crsuser. if (($status &= gpnp_wallets_clean_locks( $islocal )) != SUCCESS) { $haderr = TRUE; } # set permissions, according to platform if ($CFG->platform_family eq "windows") { my $gpnp_w_root_dir; my $gpnp_w_prdr_dir; my $gpnp_w_peer_dir; my $gpnp_w_pa_dir; # assign appropriate gpnp home if ($islocal) { # ACLs will be set on well-known subdirs in # $GPNP_WALLETS_DIR or $GPNP_L_WALLETS_DIR; $gpnp_w_root_dir = $GPNP_L_W_ROOT_DIR; $gpnp_w_prdr_dir = $GPNP_L_W_PRDR_DIR; $gpnp_w_peer_dir = $GPNP_L_W_PEER_DIR; $gpnp_w_pa_dir = $GPNP_L_W_PA_DIR; } else { $gpnp_w_root_dir = $GPNP_W_ROOT_DIR; $gpnp_w_prdr_dir = $GPNP_W_PRDR_DIR; $gpnp_w_peer_dir = $GPNP_W_PEER_DIR; $gpnp_w_pa_dir = $GPNP_W_PA_DIR; } # Wallet directories with root/crsuser access only my @gpnp_w_pvt_dirs = ( $gpnp_w_root_dir, $gpnp_w_peer_dir, $gpnp_w_pa_dir ); # Wallet directories with added public read access my @gpnp_w_pub_dirs = ( $gpnp_w_prdr_dir ); # Set appropriate access on public and private wallets # Re: bug16500302/15853970, icacl will set proper .lck file access if (( $status &= s_gpnp_wallets_set_access_win( $orauser, \@gpnp_w_pvt_dirs, \@gpnp_w_pub_dirs )) != SUCCESS) { $haderr = TRUE; } } else { # Linux, posix my $oragroup = $CFG->params('ORA_DBA_GROUP'); # file paths are validated my $gpnp_c_root; my $gpnp_w_root; my $gpnp_c_peer; my $gpnp_w_peer; my $gpnp_c_pa; my $gpnp_w_pa; my $gpnp_w_prdr; # wallet .sso.lck my $gpnp_wsl_peer; my $gpnp_wsl_prdr; my $gpnp_wsl_pa; # assign appropriate gpnp home if ($islocal) { $gpnp_c_root = $GPNP_L_C_ROOT_FILE; $gpnp_w_root = $GPNP_L_W_ROOT_FILE; $gpnp_c_peer = $GPNP_L_C_PEER_FILE; $gpnp_w_peer = $GPNP_L_WS_PEER_FILE; $gpnp_c_pa = $GPNP_L_C_PA_FILE; $gpnp_w_pa = $GPNP_L_WS_PA_FILE; $gpnp_w_prdr = $GPNP_L_WS_PRDR_FILE; $gpnp_wsl_peer = $GPNP_L_WS_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_pa = $GPNP_L_WS_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_prdr = $GPNP_L_WS_PRDR_FILE . GPNP_WALLET_LOCK_EXT; } else { $gpnp_c_root = $GPNP_C_ROOT_FILE; $gpnp_w_root = $GPNP_W_ROOT_FILE; $gpnp_c_peer = $GPNP_C_PEER_FILE; $gpnp_w_peer = $GPNP_WS_PEER_FILE; $gpnp_c_pa = $GPNP_C_PA_FILE; $gpnp_w_pa = $GPNP_WS_PA_FILE; $gpnp_w_prdr = $GPNP_WS_PRDR_FILE; $gpnp_wsl_peer = $GPNP_WS_PEER_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_pa = $GPNP_WS_PA_FILE . GPNP_WALLET_LOCK_EXT; $gpnp_wsl_prdr = $GPNP_WS_PRDR_FILE . GPNP_WALLET_LOCK_EXT; } # Change file ownership to non-root # Cert files are now not kept: $gpnp_c_root, $gpnp_c_peer, $gpnp_c_pa, # Wallet .sso.lck files are kept with fixed perms (bug16500302/15853970) my @resfiles = ( $gpnp_w_root, $gpnp_w_peer, $gpnp_w_prdr, $gpnp_w_pa, $gpnp_wsl_peer, $gpnp_wsl_pa, $gpnp_wsl_prdr ); trace("resfiles are @resfiles"); foreach (@resfiles) { if (-f $_) { # set permissions/owner on wallets/certs if (($status &= s_set_perms ("700", $_)) != SUCCESS) { print_error(153, $_); $haderr = TRUE; } if (($status &= s_set_ownergroup($orauser, $oragroup, $_)) != SUCCESS) { print_error(152, $_); $haderr = TRUE; } } else { # resfile doesn't exist because the previous run of root.sh was # aborted while pushing optional local gpnpsetup to cluster wide. trace("resfile $_ doesn't exist."); $fileNotExistErr = TRUE; } } # ease permissions/owner on config reader wallet if (-f $gpnp_w_prdr) { if (($status &= s_set_perms ("750", $gpnp_w_prdr)) != SUCCESS) { print_error(153, $gpnp_w_prdr); $haderr = TRUE; } } else { $fileNotExistErr = TRUE; } # ease permissions/owner on prdr wallet .sso.lck (bug16500302/15853970) if (-f $gpnp_wsl_prdr) { if (($status &= s_set_perms ("770", $gpnp_wsl_prdr)) != SUCCESS) { print_error(153, $gpnp_wsl_prdr); $haderr = TRUE; } } else { $fileNotExistErr = TRUE; } } # head out if ($fileNotExistErr) { $status = FAILED; trace ("The permissions of some files were not modified " ."because the files didn't exist."); return $status; } if ( $haderr ) { print_error(148); } else { trace ("GPnP Wallets ownership/permissions successfully set. [node-local=$islocal]"); } return $status; } ####--------------------------------------------------------- #### Copy cluster-wide GPnP file setup to be node-local #### (Copy local wallet(s)/profiles from global stage area on current node) # # NOTE: for use by check_gpnp_setup() # # @returns SUCCESS or $FAILURE # #static sub take_clusterwide_gpnp_setup { my $crshome = $GPNP_CRSHOME_DIR; # validated my $gpnpdir = $GPNP_GPNPHOME_DIR; # validated my $gpnplocdir = $GPNP_GPNPLOCALHOME_DIR; # validated my $usr = $GPNP_ORAUSER; my $grp = $GPNP_ORAGROUP; # copy cluster-wide setup files trace("Taking cluster-wide setup as local"); # mandatory my $status = copy_file( $GPNP_P_PEER_FILE, # peer profile $GPNP_L_P_PEER_FILE, $usr, $grp ); if ($status == SUCCESS) { $status = copy_file( $GPNP_WS_PEER_FILE, # peer wallet $GPNP_L_WS_PEER_FILE, $usr, $grp ); } # optional if ($status == SUCCESS) { copy_file( $GPNP_WS_PRDR_FILE, # prdr wallet $GPNP_L_WS_PRDR_FILE, $usr, $grp ); copy_file( $GPNP_P_SAVE_FILE, # saved profile $GPNP_L_P_SAVE_FILE, $usr, $grp ); copy_file( $GPNP_W_ROOT_FILE, # root wallet $GPNP_L_W_ROOT_FILE, $usr, $grp ); copy_file( $GPNP_WS_PA_FILE, # pa wallet $GPNP_L_WS_PA_FILE, $usr, $grp ); # Make sure copied local wallet permissions changed, ignore res my $islocal = TRUE; gpnp_wallets_set_ownerperm( $islocal ); # error(s) logged } unless ($status == SUCCESS) { print_error(146); } return $status; } sub initialize_local_gpnp { my $hostname = $_[0]; my $gpnp_setup_type = $_[1]; my $gpnp_descr = "unknown"; my $status; my $ckptgpnp; my $ckptName = "ROOTCRS_GPNPSETUP"; if (isCkptexist($ckptName)) { $ckptgpnp = getCkptStatus($ckptName); trace("'$ckptName' state is $ckptgpnp"); if ($ckptgpnp eq CKPTSUC) { trace("Local GPNP is already initialized"); $CFG->wipCkptName('ROOTCRS_STACK'); return SUCCESS; } } writeCkpt($ckptName, CKPTSTART); $CFG->wipCkptName('ROOTCRS_GPNPSETUP'); SWITCH: { $gpnp_setup_type == GPNP_SETUP_BAD and $gpnp_descr = "dirty", last; $gpnp_setup_type == GPNP_SETUP_NONE and $gpnp_descr = "none", last; $gpnp_setup_type == GPNP_SETUP_LOCAL and $gpnp_descr = "local", last; $gpnp_setup_type == GPNP_SETUP_GOTCLUSTERWIDE and $gpnp_descr = "new-cluster-wide", last; $gpnp_setup_type == GPNP_SETUP_CLUSTERWIDE and $gpnp_descr = "cluster-wide", last; $gpnp_descr = "unknown"; # default case } trace ("GPnP setup state: $gpnp_descr"); if ($gpnp_setup_type == GPNP_SETUP_BAD) { trace("Forcing re-creation of gpnp setup."); $gpnp_setup_type = GPNP_SETUP_NONE; } # unless GPnP configuration we running is cluster-wide, or on good local # gpnp profile/wallet config, create local setup if ($gpnp_setup_type == GPNP_SETUP_GOTCLUSTERWIDE || $gpnp_setup_type == GPNP_SETUP_CLUSTERWIDE) { trace("GPnP cluster configuration already performed"); } elsif ($gpnp_setup_type == GPNP_SETUP_LOCAL) { trace("GPnP cluster configuration not required for non-clustered ", "config"); } elsif ($gpnp_setup_type == GPNP_SETUP_NONE) { trace ("Creating local GPnP setup for clustered node..."); $status = create_gpnp_wallets($hostname, TRUE ); if ($status != SUCCESS) { writeCkpt($ckptName, CKPTFAIL); die(dieformat(149, $hostname)); } trace ("<--- GPnP wallets successfully created"); # gpnp: Create gpnp peer profile for host (force) with given pars trace ("Creating GPnP peer profile --->"); $status = create_gpnp_peer_profile($hostname, TRUE, # force (create, not edit) TRUE # sign with peer wallet ); if ($status != SUCCESS) { writeCkpt($ckptName, CKPTFAIL); die(dieformat(150, $hostname)); } trace ("<--- GPnP peer profile successfully created"); trace ("GPnP local setup successfully created\n"); } writeCkpt($ckptName, CKPTSUC); $CFG->wipCkptName("ROOTCRS_STACK"); return; } ####--------------------------------------------------------- #### Create GPnP wallet(s) # ARGS: 6 # ARG1 : Parameter hash # ARG2 : Hostname, can be null for non-host specific setup # ARG3 : Force wallet creation (if FALSE, wallet won't be created if exists) # @returns SUCCESS or $FAILURE # sub create_gpnp_wallets { my $host = $_[0]; my $force = $_[1]; my $crshome = $CFG->ORA_CRS_HOME; # validated my $gpnpdir = $CFG->params('GPNPCONFIGDIR'); # validated my $orauser = $CFG->params('ORACLE_OWNER'); my $oragroup = $CFG->params('ORA_DBA_GROUP'); my $islocal = FALSE; my $status = SUCCESS; my $rc = 0; my @program ; my @output; #------------- # Check existing setup, if any my $GPNPHOME_DIR = catdir( $gpnpdir, 'gpnp'); my $WALLETS_DIR = catdir( $GPNPHOME_DIR, 'wallets' ); if ($host) { $WALLETS_DIR = catdir( $GPNPHOME_DIR, $host, 'wallets' ); $islocal = TRUE; } trace ("Oracle CRS home = " . $crshome); trace ("Oracle GPnP wallets home = $WALLETS_DIR"); my $W_ROOT_DIR = catdir( $WALLETS_DIR, 'root' ); my $W_PA_DIR = catdir( $WALLETS_DIR, 'pa' ); my $W_PEER_DIR = catdir( $WALLETS_DIR, 'peer' ); my $W_PRDR_DIR = catdir( $WALLETS_DIR, 'prdr' ); my $WALLET_NAME = 'ewallet.p12'; my $SSOWAL_NAME = 'cwallet.sso'; my $W_ROOT_FILE = catfile( $W_ROOT_DIR, $WALLET_NAME ); my $W_PEER_FILE = catfile( $W_PEER_DIR, $SSOWAL_NAME ); my $W_PRDR_FILE = catfile( $W_PRDR_DIR, $SSOWAL_NAME ); my $W_PA_FILE = catfile( $W_PA_DIR, $SSOWAL_NAME ); trace ("Checking if GPnP setup exists"); if (!(-d $W_ROOT_DIR)) { print_error(22, $W_ROOT_DIR); return FAILED; } if (!(-d $W_PEER_DIR)) { print_error(22, $W_PEER_DIR); return FAILED; } if (!(-d $W_PRDR_DIR)) { print_error(22, $W_PRDR_DIR); return FAILED; } if (!(-d $W_PA_DIR)) { print_error(22, $W_PA_DIR); return FAILED; } if (-f $W_PEER_FILE) { trace ("$W_PEER_FILE wallet exists"); if (! $force) { trace ("$W_PEER_FILE exists and force is not requested. Done."); return SUCCESS; } } trace ("$W_PEER_FILE wallet must be created"); if (-f $W_PRDR_FILE) { trace ("Warning: existing $W_PRDR_FILE wallet will be deleted."); } if (-f $W_PA_FILE) { trace ("Warning: existing $W_PA_FILE wallet will be deleted."); } #------------- # Create wallet(s) my $E_ORAPKI = catfile( $crshome, 'bin', 'orapki' ); my $CERT_NAME = 'cert.txt'; my $CERTRQ_NAME = 'certreq.txt'; my $RTCERT_NAME = 'b64certificate.txt'; my $PDUMMY = 'gpnp_wallet1'; my $W_ROOT_DN = '"CN=GPnP_root"'; my $W_PA_DN = '"CN=GPnP_pa"'; my $W_PEER_DN = '"CN=GPnP_peer"'; my $W_KEYSZ = '1024'; my $W_EXPDT = '"01/01/2099"'; my $W_CVALID = '9999'; my $CRQ_PA_FILE = catfile( $W_PA_DIR, $CERTRQ_NAME ); my $CRQ_PEER_FILE = catfile( $W_PEER_DIR, $CERTRQ_NAME ); my $C_ROOT_FILE = catfile( $W_ROOT_DIR, $RTCERT_NAME ); my $C_PA_FILE = catfile( $W_PA_DIR, $CERT_NAME ); my $C_PEER_FILE = catfile( $W_PEER_DIR, $CERT_NAME ); # Delete old wallets/certificats, if they exist. { trace ("Removing old wallets/certificates, if any"); $status &= s_remove_file( $W_ROOT_FILE ); $status &= s_remove_file( $W_PA_FILE ); $status &= s_remove_file( $W_PEER_FILE ); $status &= s_remove_file( $W_PRDR_FILE ); $status &= s_remove_file( catfile( $W_PEER_DIR, $WALLET_NAME ) ); $status &= s_remove_file( catfile( $W_PRDR_DIR, $WALLET_NAME ) ); $status &= s_remove_file( catfile( $W_PA_DIR, $WALLET_NAME ) ); $status &= s_remove_file( $CRQ_PA_FILE ); $status &= s_remove_file( $CRQ_PEER_FILE ); $status &= s_remove_file( $C_ROOT_FILE ); $status &= s_remove_file( $C_PA_FILE ); $status &= s_remove_file( $C_PEER_FILE ); } #------------- # 1.a Create root wallet if (SUCCESS == $status) { trace( "Creating GPnP Root Wallet..." ); @program = ( $E_ORAPKI, 'wallet', 'create', '-wallet', "\"$W_ROOT_DIR\"", '-pwd', $PDUMMY, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to create a root wallet for Oracle Cluster GPnP. ". "orapki rc=$rc, output: @output." ); print_lines(@output); print_error(122); $status = FAILED; } } # 1.b Create self-signed root wallet certificate if (SUCCESS == $status) { trace( "Creating GPnP Root Certificate..." ); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_ROOT_DIR\"", '-pwd', $PDUMMY, '-self_signed', '-dn', $W_ROOT_DN, '-keysize', $W_KEYSZ, '-validity', $W_CVALID, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to create a root certificate for Oracle Cluster GPnP.". " orapki rc=$rc, output: @output." ); print_lines(@output); print_error(123); $status = FAILED; } } # 1.c Export root wallet certificate if (SUCCESS == $status) { trace( "Exporting GPnP Root Certificate..." ); @program = ( $E_ORAPKI, 'wallet', 'export', '-wallet', "\"$W_ROOT_DIR\"", '-pwd', $PDUMMY, '-dn', $W_ROOT_DN, '-cert', "\"$C_ROOT_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to export root certificate for Oracle Cluster GPnP. ". "orapki rc=$rc, output: @output." ); print_lines(@output); print_error(124); $status = FAILED; } } #------------- # 2. Create empty wallets for peer, prdr & pa (cwallet.sso ewallet.p12) # a) peer if (SUCCESS == $status) { trace( "Creating GPnP Peer Wallet..." ); @program = ( $E_ORAPKI, 'wallet', 'create', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-auto_login', '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to create a peer wallet for Oracle Cluster GPnP. ". "orapki rc=$rc, output: @output" ); print_lines(@output); print_error(125); $status = FAILED; } } # b) prdr if (SUCCESS == $status) { trace( "Creating GPnP Profile Reader Wallet..." ); @program = ( $E_ORAPKI, 'wallet', 'create', '-wallet', "\"$W_PRDR_DIR\"", '-pwd', $PDUMMY, '-auto_login', '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to create a profile reader wallet for ". "Oracle Cluster GPnP. orapki rc=$rc, output: @output." ); print_lines(@output); print_error(126); $status = FAILED; } } # c) pa if (SUCCESS == $status) { trace( "Creating GPnP PA Wallet..." ); @program = ( $E_ORAPKI, 'wallet', 'create', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-auto_login', '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to create a PA wallet for Oracle Cluster GPnP. ". "orapki rc=$rc, output: @output." ); print_lines(@output); print_error(127); $status = FAILED; } } #------------- # 3. Add private key to a wallet # a) peer if (SUCCESS == $status) { trace("Adding private key to GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-dn', $W_PEER_DN, '-keysize', $W_KEYSZ, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot add private key to a wallet. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(128); $status = FAILED; } } # b) pa if (SUCCESS == $status) { trace("Adding private key to GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-dn', $W_PA_DN, '-keysize', $W_KEYSZ, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot add private key to a wallet. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(129); $status = FAILED; } } #------------- # 4. Create cert request (B64) for each (certreq.txt) # a) peer if (SUCCESS == $status) { trace("Creating certificate request for GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'export', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-dn', $W_PEER_DN, '-request', "\"$CRQ_PEER_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot export a certificate request from a wallet. ". "orapki rc=$rc, output: @output." ); print_lines(@output); print_error(130); $status = FAILED; } } # b) pa if (SUCCESS == $status) { trace("Creating certificate request for GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'export', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-dn', $W_PA_DN, '-request', "\"$CRQ_PA_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot export a certificate request from a wallet. ". "orapki rc=$rc, output: @output." ); print_lines(@output); print_error(131); $status = FAILED; } } #------------- # 5. Create certificate files (B64) for each # (cert.txt signed with same root wallet (valid 27yrs)) # a) peer if (SUCCESS == $status) { trace("Creating certificate for GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'cert', 'create', '-wallet', "\"$W_ROOT_DIR\"", '-pwd', $PDUMMY, '-request', "\"$CRQ_PEER_FILE\"", '-cert', "\"$C_PEER_FILE\"", '-validity', $W_CVALID, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot create a peer certificate. orapki rc=$rc, ". "output: @output."); print_lines(@output); print_error(132); $status = FAILED; } } # b) pa if (SUCCESS == $status) { trace("Creating certificate for GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'cert', 'create', '-wallet', "\"$W_ROOT_DIR\"", '-pwd', $PDUMMY, '-request', "\"$CRQ_PA_FILE\"", '-cert', "\"$C_PA_FILE\"", '-validity', $W_CVALID, '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot create a PA certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(133); $status = FAILED; } } #------------- # 6. Add root certificate as trusted cert to all user wallets # (to allow import certificates not only as self-signed) # a) peer if (SUCCESS == $status) { trace("Adding Root Certificate TP to GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_ROOT_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot add a root TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(134); $status = FAILED; } } # b) prdr if (SUCCESS == $status) { trace("Adding Root Certificate TP to GPnP Profile Reader Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PRDR_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_ROOT_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a Profile Reader Wallet ". "for Oracle Cluster GPnP. ". "Cannot add a root TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(135); $status = FAILED; } } # c) pa if (SUCCESS == $status) { trace("Adding Root Certificate TP to GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_ROOT_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot add a root TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(136); $status = FAILED; } } #------------- # 7. Add cross certificates as trust points # a) peer - add pa if (SUCCESS == $status) { trace("Adding PA Certificate as a TP into a GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_PA_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot add a PA TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(137); $status = FAILED; } } # b) pa - add peer if (SUCCESS == $status) { trace("Adding peer Certificate as a TP into a GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_PEER_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot add a peer TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(138); $status = FAILED; } } # c) prdr - add peer if (SUCCESS == $status) { trace("Adding PA Certificate as a TP into a GPnP ". "Profile Reader Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PRDR_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_PA_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a Profile Reader Wallet ". "for Oracle Cluster GPnP. ". "Cannot add a PA TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(139); $status = FAILED; } } # c) prdr - add pa if (SUCCESS == $status) { trace("Adding peer Certificate as a TP into a GPnP ". "Profile Reader Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PRDR_DIR\"", '-pwd', $PDUMMY, '-trusted_cert', '-cert', "\"$C_PEER_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a Profile Reader Wallet ". "for Oracle Cluster GPnP. ". "Cannot add a peer TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(140); $status = FAILED; } } #------------- # 8. Finally, add user certificate to user wallets (to add public key cert) # a) peer if (SUCCESS == $status) { trace("Adding PA Certificate as a TP into a GPnP Peer Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PEER_DIR\"", '-pwd', $PDUMMY, '-user_cert', '-cert', "\"$C_PEER_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a peer wallet for Oracle Cluster GPnP. ". "Cannot add a PA TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(141); $status = FAILED; } } # b) pa if (SUCCESS == $status) { trace("Adding peer Certificate as a TP into a GPnP PA Wallet..."); @program = ( $E_ORAPKI, 'wallet', 'add', '-wallet', "\"$W_PA_DIR\"", '-pwd', $PDUMMY, '-user_cert', '-cert', "\"$C_PA_FILE\"", '-nologo' ); trace( join(' ', @program) ); $rc = run_as_user2( $orauser, \@output, "@program" ); if (0 != $rc) { trace("Failed to make a PA wallet for Oracle Cluster GPnP. ". "Cannot add a peer TP certificate. orapki rc=$rc, ". "output: @output." ); print_lines(@output); print_error(142); $status = FAILED; } } # Delete intermediate files and non-sso wallets, if they exist. { $status &= s_remove_file( catfile( $W_PEER_DIR, $WALLET_NAME ) ); $status &= s_remove_file( catfile( $W_PRDR_DIR, $WALLET_NAME ) ); $status &= s_remove_file( catfile( $W_PA_DIR, $WALLET_NAME ) ); $status &= s_remove_file( $CRQ_PA_FILE ); $status &= s_remove_file( $CRQ_PEER_FILE ); $status &= s_remove_file( $C_ROOT_FILE ); $status &= s_remove_file( $C_PA_FILE ); $status &= s_remove_file( $C_PEER_FILE ); } if (SUCCESS == $status) { # Change file ownership to non-root $status = gpnp_wallets_set_ownerperm( $islocal ); # error(s) logged } if (SUCCESS == $status) { trace ("GPnP Wallets successfully created."); } return $status; } ##----------------------------------------------------------------- ## Get ASM GUID value by parsing out 'kfod op=getasmguid wrap=' # # ARGS: None # @returns guid. ##----------------------------------------------------------------- sub getASMGUID { my $KFOD = catfile($CFG->ORA_CRS_HOME, 'bin', 'kfod'); # This function can be used only during install. my $credfile = $CFG->params('ASM_CREDENTIALS'); my $wrap = 'wrap=' . $credfile; my @cmd = ($KFOD, 'op=getasmguid', $wrap); my @guid = (); trace("Extracting ASM Server Cluster GUID. Cmd : @cmd"); my $rc = run_as_user2($CFG->params('ORACLE_OWNER'), \@guid, @cmd); trace("kfod op=getasmguid rc : $rc, guid : @guid"); if (0 != $rc) { die(dieformat(180, join(' ', @cmd))); } chomp(@guid); # Remove newline. return @guid; } ##----------------------------------------------------------------- ### Get Cluster GUID value by parsing output of ### 'mgmtca queryClusterGUID -wrap ' command ### The line '#@=result[0]:cluster_guid={}' ### contains the Member Cluster GUID ## ## Used during GIMR Member Cluster configuration ## ARGS: None ## @returns guid. ###----------------------------------------------------------------- sub getClusterGUIDFromGIMR { my $MGMTCA = catfile($CFG->ORA_CRS_HOME, 'bin', 'mgmtca'); my $credfile = $CFG->params('GIMR_CREDENTIALS'); my @cmd = ($MGMTCA, 'queryClusterGUID', '-wrap', $credfile); my @output; my $guid = ""; trace("Extracting Member Cluster GUID. Cmd : @cmd"); my $rc = run_as_user2($CFG->params('ORACLE_OWNER'), \@output, @cmd); trace("mgmtca queryClusterGUID -wrap $credfile rc : $rc"); if (0 != $rc) { print_lines(@output); die(dieformat(180, join(' ', @cmd))); } foreach my $line (@output) { if ($line =~ /cluster_guid/) { trace("Cluster GUID line: '$line'"); my $result = (split(/[:\s]+/, $line))[1]; $result =~ s/\{//g; $result =~ s/\}//g; $guid = (split(/=/, $result))[1]; trace("Cluster GUID:$guid"); last; } } return $guid; } ##----------------------------------------------------------------- ## Get Cluster GUID value by parsing output of ## 'kfod op=credverify wrap= _boot=TRUE' command ## The line 'KFOD-01001: CLUSTER_GUID: ' ## contains the Client Cluster GUID # # Used during ASM Client Cluster configuration # ARGS: None # @returns guid. ##----------------------------------------------------------------- sub getClusterGUIDFromASM { my $KFOD = catfile($CFG->ORA_CRS_HOME, 'bin', 'kfod'); # This function can be used only during install. my $credfile = $CFG->params('ASM_CREDENTIALS'); my $wrap = 'wrap=' . $credfile; my @cmd = ($KFOD, 'op=credverify', $wrap, '_boot=TRUE'); my @output; my $guid = ""; trace("Extracting Client Cluster GUID. Cmd : @cmd"); my $rc = run_as_user2($CFG->params('ORACLE_OWNER'), \@output, @cmd); trace("kfod op=credverify wrap=$credfile _boot=TRUE rc : $rc"); if (0 != $rc) { # Bug 20201434. Display kfod error stack on failure print_lines(@output); die(dieformat(180, join(' ', @cmd))); } foreach my $line (@output) { if ($line =~ /KFOD-01001: CLUSTER_GUID: /) { trace("Cluster GUID line: '$line'"); my @tokens = split(/:/, $line); $guid = trim($tokens[2]); trace("Cluster GUID:$guid"); last; } } if ($guid eq "") { trace("Cluster GUID not found"); } return $guid; } #### Create GPnP peer profile # ARG1 : Parameter hash # ARG1 : Hostname, can be null for non-host specific setup # ARG2 : Force profile creation (if FALSE, won't be created if exists) # ARG3 : If 1, attempt to sign a profile with a peer wallet # @returns SUCCESS or $FAILURE # sub create_gpnp_peer_profile { my $host = $_[0]; my $force = $_[1]; my $sign = $_[2]; my $status = SUCCESS; my $rc = 0; my @gpnptool_args; my @gpnptool_out ; my $edit = FALSE; my $verb = 'create'; my $crshome = $CFG->ORA_CRS_HOME; # validated my $gpnpdir = $CFG->params('GPNPCONFIGDIR'); # validated my $orauser = $CFG->params('ORACLE_OWNER'); my $oragroup = $CFG->params('ORA_DBA_GROUP'); my $p_paloc = $CFG->params('GPNP_PA'); my $p_cname = $CFG->params('CLUSTER_NAME'); my $p_cssdis = $CFG->VF_DISCOVERY_STRING; my $p_cssld = $CFG->params('CSS_LEASEDURATION'); my $p_asmdis = $CFG->params('ASM_DISCOVERY_STRING'); my $p_asmspf = $CFG->params('ASM_SPFILE'); my $p_ocrid = $CFG->oldconfig('OCRID'); my $p_nets = $CFG->params('NETWORKS'); my $p_clstid = $CFG->oldconfig('CLUSTER_GUID'); # if old set of networks defined, use them instead my $p_oldnets = $CFG->oldconfig('NETWORKS'); if ((defined $p_oldnets) && !($p_nets eq $p_oldnets)) { $p_nets = $p_oldnets; } my $p_extcluster = CLUSTER_NOTEXTENDED; # if params is 'true' then set p_extcluster to CLUSTER_EXTENDED if (CLUSTER_EXTENDED eq lc($CFG->params('EXTENDED_CLUSTER'))) { $p_extcluster = CLUSTER_EXTENDED } #------------- # Check existing setup, if any my $GPNPHOME_DIR = catdir( $gpnpdir, 'gpnp' ); my $PROFILES_DIR; if ($host) { $PROFILES_DIR = catdir( $GPNPHOME_DIR, $host, 'profiles' ); } else { $PROFILES_DIR = catdir( $GPNPHOME_DIR, 'profiles' ); } trace ("Oracle CRS home = " . $crshome); trace ("Oracle GPnP profiles home = $PROFILES_DIR"); trace ("Oracle GPnP profiles parameters: "); trace (" paloc=$p_paloc="); trace (" cname=$p_cname="); trace (" cssdisco=$p_cssdis="); trace (" cssld=$p_cssld="); trace (" asmdisco=$p_asmdis="); trace (" asmspf=$p_asmspf="); trace (" netlst=$p_nets="); trace (" ocrid=$p_ocrid="); trace (" clusterguid=$p_clstid="); my $P_PEER_DIR = catdir( $PROFILES_DIR, 'peer' ); my $P_PEER_FILE = catfile( $P_PEER_DIR, 'profile.xml' ); my $P_SAVE_FILE = catfile( $P_PEER_DIR, 'profile_orig.xml' ); my $SSOWAL_NAME ; my $WALLETS_DIR ; my $W_PEER_DIR ; my $W_PEER_FILE ; my $W_PEER_WRL ; if (0 != $sign) { if ($host) { $WALLETS_DIR = catdir( $GPNPHOME_DIR, $host, 'wallets' ); } else { $WALLETS_DIR = catdir( $GPNPHOME_DIR, 'wallets' ); } $SSOWAL_NAME = 'cwallet.sso'; $W_PEER_DIR = catdir( $WALLETS_DIR, 'peer' ); $W_PEER_FILE = catfile( $W_PEER_DIR, $SSOWAL_NAME ); $W_PEER_WRL = 'file:'.$W_PEER_DIR; } trace ("Checking if GPnP setup exists"); if (0 != $sign) { if (!(-d $W_PEER_DIR)) { print_error(22, $W_PEER_DIR); return FAILED; } if (!(-r $W_PEER_FILE)) { print_error(18, $W_PEER_FILE); return FAILED; } } if (!(-d $P_PEER_DIR)) { print_error(22, $P_PEER_DIR); return FAILED; } if (-f $P_PEER_FILE) { trace ("$P_PEER_FILE wallet exists"); if (! $edit) { if (! $force) { trace ("GPnP peer profile \"".$P_PEER_FILE. "\" exists and force is not requested. Done."); return SUCCESS; } unlink ($P_PEER_FILE, $P_SAVE_FILE); } } else { $edit = FALSE; trace ("$P_PEER_FILE profile must be created"); } #------------- # Create/edit profile(s) { # make sure asmdis is not empty (replace empty value with # a predefined value (see bug 8557547) if (!$p_asmdis || $p_asmdis eq "") { $p_asmdis = "++no-value-at-profile-creation--never-updated-through-ASM++"; } # convert netinfo into cmdline pars my @netprogram = instlststr_to_gpnptoolargs(compact_instlststr($p_nets)); my @ocridparam; if (!$p_ocrid || $p_ocrid == -1) { trace("OCRID is not available, hence not set in GPnP Profile"); } else { @ocridparam = ('-ocr=ocr', "-ocr:ocr_oid=\"$p_ocrid\"" ); } my @clstidparam; # Check if this is an ASM client cluster # Issue new operation 'kfod op=credverify ..' # Parse output, and pass the GUID as the cluster guid to gpnptool my $asm_mode = ASM_MODE_LEGACY; my $cluguid_GIMR; my $cluguid_ASM; my $cluclass = getClusterClass(); my $isfarasm = isFarASM(); my $manifest_file; if ($isfarasm) { $asm_mode = ASM_MODE_CLIENT; } if(($cluclass eq CLUSTER_CLASS_MEMBER) || $isfarasm) { # The gimr credentials should be looked up # only on environment where mgmtdb is configured. if(($CFG->params('MGMT_DB') =~ m/true/i) && ($cluclass eq CLUSTER_CLASS_MEMBER)) { # For member clusters, get the cluster guid from the # GIMR_CREDENTIALS file $manifest_file = $CFG->params('GIMR_CREDENTIALS'); $cluguid_GIMR = getClusterGUIDFromGIMR(); } if($isfarasm) { # For ASM client clusters, get the cluster guid from the # ASM_CREDENTIALS File $manifest_file = $CFG->params('ASM_CREDENTIALS'); $cluguid_ASM = getClusterGUIDFromASM(); } if($cluguid_ASM && $cluguid_GIMR) { if(lc($cluguid_ASM) ne lc($cluguid_GIMR)) { trace("The member cluster GUID $cluguid_ASM in the ASM section ". "is different than the member cluster GUID $cluguid_GIMR ". "in the GIMR section of the Cluster Manifest File"); die(dieformat(652 ,$cluguid_ASM, $cluguid_GIMR, $manifest_file)); } } $p_clstid = $cluguid_GIMR ? $cluguid_GIMR : $cluguid_ASM; if (($p_clstid eq "") || ($p_clstid == -1)) { trace("Failed to retrieve Cluster GUID from Cluster Manifest File"); die(dieformat(653, $manifest_file)); } @clstidparam = ("-prf_cid=\"$p_clstid\""); trace("Cluster GUID $p_clstid retrieved from Cluster Manifest ". "File \"$manifest_file\" generated in the Domain Services Cluster"); } else { if (!$p_clstid || $p_clstid == -1) { trace("ClusterGUID is not available, hence not set in GPnP Profile"); } else { @clstidparam = ("-prf_cid=\"$p_clstid\""); trace("Cluster GUID $p_clstid retrieved from old config"); } } # cmdline $verb = 'edit' if $edit; @gpnptool_args = ( $verb, "-o=\"$P_PEER_FILE\"", '-ovr', '-prf', "-prf_sq=1", "-prf_cn=$p_cname", "-prf_pa=\"$p_paloc\"", @netprogram, '-css=css', "-css:css_dis=\"$p_cssdis\"", "-css:css_ld=$p_cssld", '-asm=asm', "-asm:asm_dis=\"$p_asmdis\"", "-asm:asm_spf=\"$p_asmspf\"", "-asm:asm_m=\"$asm_mode\"" ); if ($p_extcluster) { push(@gpnptool_args, "-asm:asm_ext=\"$p_extcluster\""); } if ($edit) { push(@gpnptool_args, "-p=\"$P_PEER_FILE\""); } if (@ocridparam) { push(@gpnptool_args, @ocridparam); } if (@clstidparam) { push(@gpnptool_args, @clstidparam); } # Set the GNS address in the profile if GNS_CONF is TRUE # and GNS is not shared if ($CFG->params('GNS_CONF') eq "true" && lc($CFG->params('GNS_TYPE')) ne "shared") { trace("Set BC discovery address with the GNS address"); my $p_bcvip = $CFG->params('GNS_ADDR_LIST'); trace("BC discovery address: {$p_bcvip}"); if ($p_bcvip) { push(@gpnptool_args, "-bc=bc", "-bc:bc_vip=\"$p_bcvip\""); } else { trace("GNS address not found during the BC configuration"); print_error(367); return FAILED; } } @gpnptool_out = () ; $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out); if (0 != $rc) { trace("Failed to $verb a peer profile for Oracle Cluster GPnP. ". "gpnptool rc=$rc" ); print_error(143, ,$verb, $rc); $status = FAILED; } } # sign profile if req if ((SUCCESS == $status) && (0 != $sign)) { @gpnptool_args = ( 'sign', "-p=\"$P_PEER_FILE\"", "-o=\"$P_PEER_FILE\"", '-ovr', "-w=\"$W_PEER_WRL\"", '-rmws' # compact; or format, e.g. '-fmt=0,2' ); @gpnptool_out = () ; $rc = run_gpnptool( \@gpnptool_args, $orauser, \@gpnptool_out); if (0 != $rc) { print_error(144, $rc); $status = FAILED; } } # save created profile on success if (SUCCESS == $status) { copy( $P_PEER_FILE, $P_SAVE_FILE ) or # non-fatal print_error(105, $P_PEER_FILE, $P_SAVE_FILE, $!); } # change file ownership to non-root if (SUCCESS == $status) { if ( -f $P_PEER_FILE ) { if ($CFG->DEBUG) { trace (" s_set_ownergroup($orauser, $oragroup, $P_PEER_FILE)");} if (FAILED == ($status = s_set_ownergroup ($orauser, $oragroup, $P_PEER_FILE))) { print_error(152, $P_PEER_FILE); } } if ( -f $P_SAVE_FILE ) { if ($CFG->DEBUG) { trace (" s_set_ownergroup($orauser, $oragroup, $P_SAVE_FILE)");} s_set_ownergroup ($orauser, $oragroup, $P_SAVE_FILE) or # non-fatal print_error(152, $P_SAVE_FILE); } } # for extra check, verify created peer profile against wallet # after chown if (SUCCESS == $status) { if ($CFG->DEBUG) { $rc = run_gpnptool_verifysig( $P_PEER_FILE, $W_PEER_WRL, $orauser ); if ($rc <= 0) { trace("Failed to verify a peer profile \"$P_PEER_FILE\"". " with WRL=$W_PEER_WRL. rc=$rc"); print_error(145, $P_PEER_FILE, $W_PEER_WRL, $rc); $status = FAILED; } } } if (SUCCESS == $status) { trace("GPnP peer profile $verb successfully completed."); } return $status; } =head2 instlststr_to_gpnptoolargs Get list of gpnptool net info params based on current list of networks in installer-style network list, see oifcfgiflst_to_instlststr. =head3 Parameters =head4 A string with installer-style networks list. =head3 Returns returns a string with gpnptool profile create/edit net generating params. =cut sub instlststr_to_gpnptoolargs { my $networks = $_[0]; my @intfs = (); my @program = ( '-hnet=gen', '-gen:hnet_nm="*"' ); trace ("iflist: '".$networks."'"); #$networks =~ s/^{|}$//g; push(@intfs, $+) while $networks =~ m{ ("[^\"\\]*(?:\\.[^\"\\]*)*"[^,]+)[,]? # groups def inside quotes | ([^,]+)[,]? | [,\s] }gx; push(@intfs, undef) if substr($networks,-1,1) eq '\s'; trace ("iflist: ".join("\n", @intfs)); my $i=0; foreach (0..$#intfs) { my $idef = $intfs[$_]; my ($an_, $ada, $net, $typ, $styp, $n); trace ("idef=$idef"); if ($idef !~ m/(^.+)[:]((public|cluster_interconnect|asm)([|](public|cluster_interconnect|asm))*)$/) { print_error(20, $idef); next; } else { $an_ = $1; $typ = $2; $typ =~ s/[|]/,/g; # make std list $styp = $typ; $n = rindex( $an_, '/' ); if (1 <= $n) { $ada = substr( $an_, 0, $n ); $net = substr( $an_, ($n+1) ); } if ($idef =~ m/"([^\"]+)"/) { $ada = $1; } $i++; trace ("$i => '".$ada."','".$net."','".$styp."'"); push( @program, '-gen:net=net'.$i ); push( @program, '-net'.$i.':net_ip="'. $net .'"' ); push( @program, '-net'.$i.':net_ada="'. $ada .'"' ); push( @program, '-net'.$i.':net_use="'. lc($styp) .'"' ); } } trace ("gpnptool pars: ".join(' ', @program)); return @program; } ##----------------------------------------------------------------- ## Pull GPnP cluster-wide setup from an existing node # ARGS: 1 # ARG1: the remote node # @returns SUCCESS or FAILED ##----------------------------------------------------------------- sub pull_cluserwide_gpnp_setup { my $rmtNode = $_[0]; my $orauser = $GPNP_ORAUSER; trace("Copying GPnP cluster-wide setup from the remote node $rmtNode ..."); # mainfest file copy_file_from_node($GPNP_ORIGIN_FILE, $rmtNode, $GPNP_ORIGIN_FILE); # Mandatory # peer profile my $status = copy_file_from_node($GPNP_P_PEER_FILE, $rmtNode, $GPNP_P_PEER_FILE); if (SUCCESS == $status) { # peer wallet $status = copy_file_from_node($GPNP_WS_PEER_FILE, $rmtNode, $GPNP_WS_PEER_FILE); } # Optional if (SUCCESS == $status) { # saved profile copy_file_from_node($GPNP_P_SAVE_FILE, $rmtNode, $GPNP_P_SAVE_FILE); # root wallet copy_file_from_node($GPNP_W_ROOT_FILE, $rmtNode, $GPNP_W_ROOT_FILE); # prdr (r/o) wallet copy_file_from_node($GPNP_WS_PRDR_FILE, $rmtNode, $GPNP_WS_PRDR_FILE); # pa wallet copy_file_from_node($GPNP_WS_PA_FILE, $rmtNode, $GPNP_WS_PA_FILE); } if ($status != SUCCESS) { trace("An error happened when pulling GPnP cluster-wide setup"); } return $status; } ####--------------------------------------------------------- #### Push GPnP local file setup to be cluster-wide #### (Copy local wallet(s)/profiles to global stage area on current node as well #### as list of cluster nodes) # # NOTE: check_gpnp_setup() MUST be called prior calling this sub # # ARGS: 1 # ARG1 : List of comma-separated cluster node names to push gpnp file setup to # (inclusion of current node is ok) # @returns SUCCESS or $FAILURE # sub push_clusterwide_gpnp_setup { my $nodelist = $_[0]; my $crshome = $GPNP_CRSHOME_DIR; # validated my $gpnpdir = $GPNP_GPNPHOME_DIR; # validated my $gpnplocdir = $GPNP_GPNPLOCALHOME_DIR; # validated my $host = $GPNP_HOST; my $orauser = $GPNP_ORAUSER; my $oragroup = $GPNP_ORAGROUP; # TOBEREVISED - normally, current node is a part of a node list # and cluster-wide setup pushed through localhost rmtcopy # Perhaps current node can be treated specially (order,local) $nodelist =~ s/ //g; trace("Pushing local gpnpsetup to cluster nodes: {$nodelist}"); # opt manifest 1st my $origout; (undef, $origout) = tempfile(); open( MFT, ">$origout" ) or # non-fatal print_error(185, $origout, $!); print MFT "---GPnP cluster-wide configuration---\n"; print MFT "origin: $host\n"; print MFT "push_list: {$nodelist}\n"; print MFT "owner: $GPNP_ORAUSER,". "$GPNP_ORAGROUP\n"; print MFT "TS: ".gmtime()." UTC (".localtime()." local)\n"; close( MFT ); # set MFT owner to orauser, to make sure rmt copy succeeds s_set_ownergroup ($orauser, $oragroup, $origout) or # non-fatal print_error(152, $origout); s_set_perms ("0640", $origout) or # non-fatal print_error(153, $origout); my $status = FAILED; if (isOracleHomeShared()) { # push config manifest copy_file($origout, $GPNP_ORIGIN_FILE); # mandatory $status = copy_file($GPNP_L_P_PEER_FILE, # peer profile $GPNP_P_PEER_FILE) && copy_file($GPNP_L_WS_PEER_FILE, # peer wallet $GPNP_WS_PEER_FILE); # optional if ($status) { # saved profile copy_file($GPNP_L_P_SAVE_FILE, $GPNP_P_SAVE_FILE); # root wallet copy_file($GPNP_L_W_ROOT_FILE, $GPNP_W_ROOT_FILE); # prdr (r/o) wallet copy_file($GPNP_L_WS_PRDR_FILE, $GPNP_WS_PRDR_FILE); # pa wallet copy_file($GPNP_L_WS_PA_FILE, $GPNP_WS_PA_FILE); } } else { # push config manifest copy_file_to_nodes($origout, $GPNP_ORIGIN_FILE, TRUE, $nodelist); # mandatory $status = copy_file_to_nodes($GPNP_L_P_PEER_FILE, # peer profile $GPNP_P_PEER_FILE, TRUE, $nodelist) && copy_file_to_nodes($GPNP_L_WS_PEER_FILE, # peer wallet $GPNP_WS_PEER_FILE, TRUE, $nodelist); # optional if ($status) { # saved profile copy_file_to_nodes($GPNP_L_P_SAVE_FILE, $GPNP_P_SAVE_FILE, TRUE, $nodelist); # root wallet copy_file_to_nodes($GPNP_L_W_ROOT_FILE, $GPNP_W_ROOT_FILE, TRUE, $nodelist); # prdr (r/o) wallet copy_file_to_nodes($GPNP_L_WS_PRDR_FILE, $GPNP_WS_PRDR_FILE, TRUE, $nodelist); # pa wallet copy_file_to_nodes($GPNP_L_WS_PA_FILE, $GPNP_WS_PA_FILE, TRUE, $nodelist); } } # remove temporal config manifest unlink($origout); # Set clusterwide permissions as well on local node, although on unix # wallet permissions properly copied. my $islocal = FALSE; gpnp_wallets_set_ownerperm( $islocal ); # error(s) logged unless ($status == SUCCESS) { print_error(344); } return $status; } sub copy_gpnpfiles { my $sourcedir = $_[0]; my $destdir = $_[1]; copy_gpnpglobalfiles($sourcedir, $destdir); copy_gpnpnodefiles($sourcedir, $destdir); } sub copy_gpnpglobalfiles { my $sourcedir = $_[0]; my $destdir = $_[1]; copydir(catdir($sourcedir,'gpnp','profiles'), catdir($destdir,'gpnp','profiles')); copydir(catdir($sourcedir,'gpnp','wallets'), catdir($destdir,'gpnp','wallets')); } sub copy_gpnpnodefiles { my $sourcedir = $_[0]; my $destdir = $_[1]; my $host = tolower_host(); copydir(catdir($sourcedir,'gpnp',$host), catdir($destdir,'gpnp',$host)); } =head2 wait_for_gpnpd_start Wait for the gpnpd to open local endpoint This will be revised after start_cluster_resource allow PENDING handling. =head3 Returns SUCCESS Gpnpd is up FAILED Gpnpd is not up =head3 Usage =cut sub wait_for_gpnpd_start { my $is_up = FALSE; my $is_running = FALSE; my $retries = 10; my $gpnptool = crs_exec_path('gpnptool'); my @output; my $rc; # wait until intermediate state, if any, becomes online. if (!check_service("ora.gpnpd", 150)) { trace("Resource \"ora.gpnpd\" is not running.\n"); } else { $is_running = TRUE; } # Wait until the gpnpd start and open local endpoint while ($is_running && $retries) { @output = system_cmd_capture($gpnptool, 'lfind'); $rc = shift @output; if ($rc == 0) { $is_up = TRUE; last; } trace ("Waiting for GPNPD to start"); sleep (5); $retries--; } if ($is_up) { } else { print_error(121); } return $is_up; } sub push_seed_dir { my $nodelist = $_[0]; my $orauser = $GPNP_ORAUSER; unless (isOracleHomeShared()) { copy_file_to_nodes($GPNP_S_ASM_CRED_FILE, # ASM credentials $GPNP_S_ASM_CRED_FILE, TRUE, $nodelist) || die(dieformat(364)); } } sub get_asm_cred_file { # If GPnP constants are not yet set, do it now. # Bug 22964480 : Required to get the value of GPNP_S_ASM_CRED_FILE # if (check_dir($GPNP_GPNPHOME_DIR) == FAILED) { trace("Initializing GPnP constants :"); verify_gpnp_dirs($CFG->ORA_CRS_HOME, $CFG->params('GPNPGCONFIGDIR'), $CFG->params('GPNPCONFIGDIR'), $CFG->HOST, $CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP')); } return $GPNP_S_ASM_CRED_FILE; } sub pull_asm_cred_file { my $rmtNodeList = $_[0]; my $orauser = $GPNP_ORAUSER; if (-e $GPNP_S_ASM_CRED_FILE) { return SUCCESS; } trace("Copying ASM credentials file from a reachable node ..."); my $status = copy_file_from_livenode($GPNP_S_ASM_CRED_FILE, $GPNP_S_ASM_CRED_FILE, $rmtNodeList); if ($status != SUCCESS) { trace("An error happened when pulling ASM credentials file"); } return $status; } ##----------------------------------------------------------------- ## Pull GPnP cluster-wide setup from a reachable node # ARGS: 1 # ARG1: remote node list # @returns SUCCESS or FAILED ##----------------------------------------------------------------- sub pull_cluserwide_gpnp_setup2 { my $rmtNodeList = $_[0]; my $orauser = $GPNP_ORAUSER; trace("Copying GPnP cluster-wide setup from a reachable node ..."); # mainfest file copy_file_from_livenode($GPNP_ORIGIN_FILE, $GPNP_ORIGIN_FILE, $rmtNodeList); # Mandatory # peer profile my $status = copy_file_from_livenode($GPNP_P_PEER_FILE, $GPNP_P_PEER_FILE, $rmtNodeList); if (SUCCESS == $status) { # peer wallet $status = copy_file_from_livenode($GPNP_WS_PEER_FILE, $GPNP_WS_PEER_FILE, $rmtNodeList); } # Optional if (SUCCESS == $status) { # saved profile copy_file_from_livenode($GPNP_P_SAVE_FILE, $GPNP_P_SAVE_FILE, $rmtNodeList); # root wallet copy_file_from_livenode($GPNP_W_ROOT_FILE, $GPNP_W_ROOT_FILE, $rmtNodeList); # prdr (r/o) wallet copy_file_from_livenode($GPNP_WS_PRDR_FILE, $GPNP_WS_PRDR_FILE, $rmtNodeList); # pa wallet copy_file_from_livenode($GPNP_WS_PA_FILE, $GPNP_WS_PA_FILE, $rmtNodeList); } if ($status != SUCCESS) { trace("An error happened when pulling GPnP cluster-wide setup"); } return $status; } ##----------------------------------------------------------------- ## Check if the cluster-wide gpnp profile exists # ARGS: None # @returns TRUE or FALSE ##----------------------------------------------------------------- sub check_clusterwide_gpnp_profile { my $isPresent = (-e $GPNP_WS_PA_FILE) ? TRUE : FALSE; trace("$GPNP_WS_PA_FILE : $isPresent"); return $isPresent; } ##----------------------------------------------------------------- ## Get the ASM mode property (-asm_m) value # ARGS: None # @returns ASM mode (legacy or remote) ##----------------------------------------------------------------- sub gpnp_get_asm_mode { my $gpnp_p = $_[0]; my @gpnptool_args = ( '-asm_m' ); my $orauser = $CFG->params('ORACLE_OWNER'); my $asmmode; my @gpnptool_out = run_gpnptool_getpval($gpnp_p, \@gpnptool_args, $orauser ); my $rc = shift @gpnptool_out; if ($rc != 0) { trace("Failed to get ASM mode from Oracle Cluster GPnP profile ". "gpnptool rc=$rc" ); print_error(147, $gpnp_p); } else { $asmmode = shift @gpnptool_out; trace( "ASM mode = $asmmode"); } return ($rc, $asmmode); } =head1 EXPORTED FUNCTIONS =head2 gpnp_update_profile_seqnum Update a peer profile with a given sequence number using 'gpnptool edit' =head3 Parameters [0] The peer profile to be updated [1] The sequence number [2] The output file that saves the result =head3 Returns SUCCESS or FAILED =cut sub gpnp_update_profile_seqnum { my $P_PEER_FILE = $_[0]; my $seq_num = $_[1]; my $P_PEER_FILE_OUT = $_[2]; my $rc = 0; my @gpnptool_out = (); my $orauser = $CFG->params('ORACLE_OWNER'); my @gpnptool_args = ('edit', "-prf_sq=$seq_num", "-p=\"$P_PEER_FILE\"", "-o=\"$P_PEER_FILE_OUT\"", '-ovr' ); $rc = run_gpnptool(\@gpnptool_args, $orauser, \@gpnptool_out); if (0 != $rc) { trace("Failed to update a peer profile '$P_PEER_FILE' with ". "the sequence number $seq_num"); return FAILED; } return SUCCESS; } =head1 EXPORTED FUNCTIONS =head2 gpnp_sign_profile Sign a peer profile with wallet's private key using 'gpnptool sign' =head3 Parameters [0] The peer profile to be signed [1] The path to the wallet directory [2] The output file that saves the result =head3 Returns SUCCESS or FAILED =cut sub gpnp_sign_profile { my $P_PEER_FILE = $_[0]; my $P_PEER_WRL = $_[1]; my $P_PEER_FILE_OUT = $_[2]; my $rc = 0; my @gpnptool_out = (); my $orauser = $CFG->params('ORACLE_OWNER'); my @gpnptool_args = ('sign', "-p=\"$P_PEER_FILE\"", "-o=\"$P_PEER_FILE_OUT\"", '-ovr', "-w=\"$P_PEER_WRL\"", '-rmws' ); $rc = run_gpnptool(\@gpnptool_args, $orauser, \@gpnptool_out); if (0 != $rc) { trace("Failed to sign a peer profile '$P_PEER_FILE' with ". "wallet's private key from '$P_PEER_WRL'"); return FAILED; } return SUCCESS; } ###################################################################### # At the point when 'kfod op=credremote' is issued on the first node # to upgrade, the higher version profile gets updated with # 'Mode="remote"' added, and this updated profile is synced to the # lower version GI home on all remote nodes because it has a later # sequence number. # The first step in this function is to retrieve that bigger sequence # number and advance it. The second step is to generate a backup of # profile by updating the lower version profile with the incremented # sequence number. The last step is to push the backup to the higher # version GI home on all remote nodes. ###################################################################### sub backupGPNPProfile { trace("Back up the lower version GPnP profile and push the backup " . "to the higher version home on the remote nodes"); my $nodename = $CFG->HOST; my $profile4Dwng = catfile($CFG->ORA_CRS_HOME, 'crs', 'install', GPNP_PROFILE_FOR_DOWNGRADE); my $gpnpconfigdir_old = (is_dev_env()) ? $CFG->params('GPNPCONFIGDIR') : $CFG->OLD_CRS_HOME; my $gpnpconfigdir_new = (is_dev_env()) ? $CFG->params('GPNPCONFIGDIR') : $CFG->ORA_CRS_HOME; if (-e $profile4Dwng) { trace("The backup of lower version profile already exists"); } else { # Retrieve the sequence number of the profile that has been synced to # the lower version GI home on remote nodes my $profile = catfile($gpnpconfigdir_new, 'gpnp', $nodename, 'profiles', 'peer', 'profile.xml'); my ($rc, $prf_seq, $prf_cname, $prf_cuid) = gpnp_get_profile_identity($profile); if (0 != $rc) { trace("Failed to get the sequence number of profile '$profile'"); return FAILED; } else { trace("The sequence number of profile '$profile' is: $prf_seq"); } # Update the lower version profile with a better sequence number $prf_seq += 10; $profile = catfile($gpnpconfigdir_old, 'gpnp', $nodename, 'profiles', 'peer', 'profile.xml'); $rc = gpnp_update_profile_seqnum($profile, $prf_seq, $profile4Dwng); if (SUCCESS != $rc) { trace("Failed to update the profile '$profile4Dwng' with the sequence " . "number of $prf_seq"); print_error(637, $profile, $prf_seq); return FAILED; } } # Push the backup to remote nodes my $nodelist = $CFG->oldconfig('NODENAME_LIST'); my $ret = copy_file_to_nodes($profile4Dwng, $profile4Dwng, TRUE, $nodelist); if (SUCCESS != $ret) { trace("Failed to copy the backup of profile '$profile4Dwng' " . "to remote nodes"); print_error(186, $profile4Dwng, $profile4Dwng, $nodelist, $ret); return FAILED; } return SUCCESS; } ############################################################### # Steps in this function: # 1) Sign a peer profile backed up during the upgrade with # lower version wallets # 2) Verify that signed profile with lower version wallets # 3) Overwrite the lower version profile with the valid backup ################################################################ sub restoreGPNPProfile { trace("Restore the lower version GPnP profile"); my $rc = FAILED; my $nodename = $CFG->HOST; my $profile4Dwng = catfile($CFG->ORA_CRS_HOME, 'crs', 'install', GPNP_PROFILE_FOR_DOWNGRADE); my $signedProfile4Dwng = catfile($CFG->ORA_CRS_HOME, 'crs', 'install', SIGNED_GPNP_PROFILE_FOR_DOWNGRADE); my $gpnpconfigdir_old = (is_dev_env()) ? $CFG->params('GPNPCONFIGDIR') : $CFG->OLD_CRS_HOME; if (-e $profile4Dwng) { trace("Sign the GPnP profile backup that was taken for downgrade"); my $p_peer_wrl = catdir($gpnpconfigdir_old, 'gpnp', $nodename, 'wallets', 'peer'); $rc = gpnp_sign_profile($profile4Dwng, $p_peer_wrl, $signedProfile4Dwng); if (SUCCESS != $rc) { trace("Failed to sign the profile '$profile4Dwng'"); print_error(144, $rc); return FAILED; } $rc = run_gpnptool_verifysig($signedProfile4Dwng, $p_peer_wrl, $CFG->params('ORACLE_OWNER')); if ($rc <= 0) { trace("Failed to verify a peer profile '$signedProfile4Dwng' " . "with WRL=$p_peer_wrl. rc=$rc"); print_error(145, $signedProfile4Dwng, $p_peer_wrl, $rc); return FAILED; } trace("Rmove the backup of GPnP profile"); unlink($profile4Dwng) or print_error(168, $profile4Dwng, $!);; } if (-e $signedProfile4Dwng) { trace("Replace the lower version profile with the backup profile " . "that has a better sequence number"); my $profile = catfile($gpnpconfigdir_old, 'gpnp', $nodename,'profiles', 'peer', 'profile.xml'); $rc = copy_file($signedProfile4Dwng, $profile, $CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP')); if (SUCCESS != $rc) { trace("Error in copying from '$signedProfile4Dwng' to '$profile'"); return FAILED; } trace("Rmove the backup of GPnP profile which has been signed"); unlink($signedProfile4Dwng) or print_error(168, $signedProfile4Dwng, $!); } return SUCCESS; } ##----------------------------------------------------------------- ## Get a GPNP Parameter's value # ARGS: GPNP profile path, parameter name # @returns GPNP parameter's value ##----------------------------------------------------------------- sub gpnp_get_param_value { my $gpnp_p = $_[0]; my @gpnptool_args = ( $_[1] ); my $orauser = $CFG->params('ORACLE_OWNER'); my $param_value = ""; my @gpnptool_out = run_gpnptool_getpval($gpnp_p, \@gpnptool_args, $orauser ); my $rc = shift @gpnptool_out; if ($rc != 0) { trace("Failed to get $_[1] from Oracle Cluster GPnP profile". " gpnptool rc=$rc" ); print_error(147, $gpnp_p); } else { $param_value = shift @gpnptool_out; trace( "$_[1] = $param_value"); } return ($rc, $param_value); } # Function: remove all contents under the following directories: # gpnp/profiles/peer, # gpnp/wallets/peer, # gpnp/wallets/prdr, # gpnp/wallets/pa, # gpnp/wallets/root. # It's called at the end of deconfiguration. # Fix bug 21886212 sub remove_gpnp_profiles_wallets_files { my $gpnphome = catdir($CFG->params('GPNPGCONFIGDIR'), GPNP_DIRNAME); my $gpnp_profiles_peer_dir = catdir($gpnphome, GPNP_P_DIRNAME, GPNP_P_PEER_DIRNAME); my $gpnp_wallets_peer_dir = catdir($gpnphome, GPNP_W_DIRNAME, GPNP_W_PEER_DIRNAME); my $gpnp_wallets_prdr_dir = catdir($gpnphome, GPNP_W_DIRNAME, GPNP_W_PRDR_DIRNAME); my $gpnp_wallets_pa_dir = catdir($gpnphome, GPNP_W_DIRNAME, GPNP_W_PA_DIRNAME); my $gpnp_wallets_root_dir = catdir($gpnphome, GPNP_W_DIRNAME, GPNP_W_ROOT_DIRNAME); my @dirs; push @dirs, $gpnp_profiles_peer_dir, $gpnp_wallets_peer_dir, $gpnp_wallets_prdr_dir, $gpnp_wallets_pa_dir, $gpnp_wallets_root_dir; foreach my $dir (@dirs) { if (-d $dir) { trace("removing all contents under $dir"); remove_tree($dir, {keep_root=>1}); } } } 1;