MINI MINI MANI MO
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
#
# NAME
# asmcmdtmpl - ASM CoMmanD line interface TEMPLATE operations
#
# DESCRIPTION
# This module contains the code for ASMCMD/ASM template-related
# operations, such as listing the contents of v$asm_template.
#
# NOTES
# usage: asmcmdcore [-p] [command]
#
# MODIFIED (MM/DD/YY)
# diguzman 05/30/16 - 19654070: Little change at _no_instance_cmd routine
# ykatada 10/03/14 - #19617921: use bind variables to SELECTs
# pvenkatr 02/01/13 - Using asmcmdshare_filter_invisible_cmds
# pvenkatr 10/07/11 - Removed asmcmdtmpl_get_cmd_syntax - unused function.
# pvenkatr 08/24/11 - Removed flags hash table - using from XML
# adileepk 06/20/11 - Connection Pooling.
# adileepk 10/12/10 - Changes made to integrate the parser module with
# asmcmd.
# adileepk 09/01/10 - Bug 8693719 - Added validation for diskgroup name.
# moreddy 05/06/10 - bug 8667038 NLS for error messages
# amitroy 04/21/10 - BUG 8933243 - USE DIFFERENT CHARACTER IN ASMCMD TO
# "HIDE COLUMN DETAILS" INSTEAD OF -H
# pvenkatr 03/31/10 - Syntax, description, example - all from XML
# moreddy 03/22/10 - Adding more tracing
# moreddy 01/18/10 - Adding tracing messages
# pvenkatr 09/03/09 - Help message from xml file
# sanselva 06/17/09 - correct check for --primary and --secondary
# sanselva 04/06/09 - ASMCMD long options and consistency
# heyuen 10/14/08 - use dynamic modules
# heyuen 07/28/08 - use command properties array
# heyuen 05/27/08 - remove entry_number field
# heyuen 04/15/08 - rename zones to regions
# heyuen 07/23/07 - creation
#
#############################################################################
#
############################ Functions List #################################
# asmcmdtmpl_init
# asmcmdtmpl_process_cmd
# asmcmdtmpl_process_lstmpl
# asmcmdtmpl_process_mktmpl
# asmcmdtmpl_process_chtmpl
# asmcmdtmpl_process_rmtmpl
# asmcmdtmpl_is_cmd
# asmcmdtmpl_is_no_instance_cmd
# asmcmdtmpl_parse_int_args
# asmcmdtmpl_syntax_error
# asmcmdtmpl_process_help
# asmcmdtmpl_get_asmcmd_cmds
#############################################################################
package asmcmdtmpl;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(asmcmdtmpl_init
%asmcmdtmpl_cmds
);
use strict;
use DBI qw(:sql_types);
use Getopt::Long qw(:config no_ignore_case bundling);
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;
use List::Util qw[min max];
####################### ASMCMDTMPL Global Constants ######################
# ASMCMD Column Header Names:
# Below are the names of the column headers for lstmpl.
our (%asmcmdtmpl_lstmpl_header) = ('inst_id' , 'Inst_Id',
'group_name' , 'Group_Name',
'name' , 'Name',
'stripe' , 'Stripe',
'system' , 'Sys',
'redundancy' , 'Redund',
'group_number' , 'Group_Num',
'primary_region' , 'PriReg',
'mirror_region' , 'MirrReg'
);
our (%asmcmdtmpl_cmds) = (lstmpl => {},
mktmpl => {},
chtmpl => {},
rmtmpl => {}
);
####################### ASMCMDTMPL Global Variables ######################
sub is_asmcmd
{
return 1;
}
########
# NAME
# asmcmdtmpl_init
#
# DESCRIPTION
# This function initializes the asmcmdtmpl module. For now it simply
# registers its callbacks with the asmcmdglobal module.
#
# PARAMETERS
# None
#
# RETURNS
# Null
#
# NOTES
# Only asmcmdcore_main() calls this routine.
########
sub init
{
push (@asmcmdglobal_command_callbacks, \&asmcmdtmpl_process_cmd);
push (@asmcmdglobal_help_callbacks, \&asmcmdtmpl_process_help);
push (@asmcmdglobal_command_list_callbacks, \&asmcmdtmpl_get_asmcmd_cmds);
push (@asmcmdglobal_is_command_callbacks, \&asmcmdtmpl_is_cmd);
push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdtmpl_is_wildcard_cmd);
push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdtmpl_syntax_error);
push (@asmcmdglobal_no_instance_callbacks, \&asmcmdtmpl_is_no_instance_cmd);
%asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdtmpl_cmds);
#Perform ASMCMD consistency check if enabled
if($asmcmdglobal_hash{'consistchk'} eq 'y')
{
if(!asmcmdshare_check_option_consistency(%asmcmdtmpl_cmds))
{
exit 1;
}
}
}
########
# NAME
# asmcmdtmpl_process_cmd
#
# DESCRIPTION
# This routine calls the appropriate routine to process the command
# specified by $asmcmdglobal_hash{'cmd'}.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# 1 if command is found in the asmcmdtmpl module; 0 if not.
#
# NOTES
# Only asmcmdcore_shell() calls this routine.
########
sub asmcmdtmpl_process_cmd
{
my ($dbh) = @_;
my ($succ) = 0;
# Get current command from global value, which is set by
# asmcmdtemplate_parse_asmcmd_args()and by asmcmdcore_shell().
my ($cmd) = $asmcmdglobal_hash{'cmd'};
# Declare and initialize hash of function pointers, each designating a
# routine that processes an ASMCMDTEMPLATE command.
my (%cmdhash) = ( lstmpl => \&asmcmdtmpl_process_lstmpl,
mktmpl => \&asmcmdtmpl_process_mktmpl,
chtmpl => \&asmcmdtmpl_process_chtmpl,
rmtmpl => \&asmcmdtmpl_process_rmtmpl );
if (defined ( $cmdhash{ $cmd } ))
{ # If user specifies a known command, then call routine to process it. #
$cmdhash{ $cmd }->($dbh);
$succ = 1;
}
return $succ;
}
########
# NAME
# asmcmdtmpl_process_lstmpl
#
# DESCRIPTION
# This function processes the asmcmd command lstmpl.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# Null.
#
# NOTES
# Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_lstmpl
{
my ($dbh) = shift;
my (%args);
my ($qry, $ret);
my (@what , @from, $sth, @where, @order, @binds);
my (@cols, @dgroups, %dgnmap);
my ($dgname, $dgnum, $meta, $vals);
my ($header, $pattern);
my (%as);
my (@tmpl_list);
my ($row, $k, $v, $h);
my (@eargs);
my (%min_col_wid, $print_format, $print_string, @what_print);
# Get option parameters, if any.
$ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
#Set the correct options if deprecated options were used and print WARNING.
asmcmdshare_handle_deprecation($asmcmdglobal_hash{'cmd'},\%args);
# get disk group names
@dgroups = asmcmdshare_get_dg($dbh);
foreach (@dgroups)
{
$dgnmap{$_->{'group_number'}} = $_->{'name'};
}
# if disk group is specified, filter out
if (defined($args{'G'}))
{
$dgname = $args{'G'};
$dgname =~ tr/[a-z]/[A-Z]/;
$dgnum = asmcmdshare_get_gnum_from_gname($dbh, $dgname);
if (!defined($dgnum))
{
@eargs = ($dgname);
asmcmdshare_error_msg(8001, \@eargs);
return;
}
}
# check if -l is specified
$vals = defined($args{'l'});
# check if pattern is specified
if (defined($args{'lstmpl'}))
{
($pattern) = @{$args{'lstmpl'}};
$pattern =~ s,$ASMCMDGLOBAL_WCARD_CHARS,\%,g;
}
push (@what, 'group_number');
push (@what, 'name');
push (@order, 'group_number');
push (@order, 'name');
# add extra columns if specified
if ($vals)
{
push (@what, 'stripe');
push (@what, 'system');
push (@what, 'redundancy');
push (@what, 'primary_region');
push (@what, 'mirror_region');
}
# filter out template name
if ($pattern)
{
my ($like_pattern);
$pattern =~ tr/[a-z]/[A-Z]/;
$like_pattern = '%' . $pattern . '%';
push (@where, 'name LIKE ?');
push (@binds, [$like_pattern, SQL_VARCHAR]);
}
# filter out diskgroup
if (defined($dgnum))
{
push (@where, 'group_number = ?');
push (@binds, [$dgnum, SQL_INTEGER]);
}
push (@from, 'v$asm_template');
$sth = asmcmdshare_do_construct_select($dbh, \@what, \@from, \@where,
\@order, \@binds);
#initialize the min_col_wid array
foreach(@what)
{
$min_col_wid{$_} = 0;
}
$min_col_wid{'group_name'} = 0;
#get the rows
while (defined($row = asmcmdshare_fetch($sth)))
{
my(%tmpl_info) = ();
while(($k, $v) = each(%{$row}))
{
$k =~ tr/[A-Z]/[a-z]/;
$tmpl_info{$k} = $v;
$min_col_wid{$k} = max($min_col_wid{$k}, length($v));
}
if (defined($tmpl_info{'group_number'}))
{
$tmpl_info{'group_name'} = $dgnmap{$tmpl_info{'group_number'}};
$min_col_wid{'group_name'} = max( $min_col_wid{'group_name'},
length($tmpl_info{'group_name'}));
}
push (@tmpl_list, \%tmpl_info);
}
asmcmdshare_finish($sth);
# add the group_name column at the beginning, we do this because it was not
# part of the query
unshift @what, "group_name";
#get the header length
foreach (@what)
{
$min_col_wid{$_} = max($min_col_wid{$_},
length($asmcmdtmpl_lstmpl_header{$_}));
}
#create print format
$print_format = '';
foreach (@what)
{
$print_format .= "%-" . $min_col_wid{$_} . "s ";
}
$print_format .= "\n";
#print header
if (!defined ($args{'suppressheader'}) )
{
@what_print = ();
foreach (@what)
{
push (@what_print, $asmcmdtmpl_lstmpl_header{$_} );
}
$print_string = sprintf($print_format, @what_print);
asmcmdshare_print($print_string);
}
#print rows
foreach $h (@tmpl_list)
{
@what_print = ();
foreach (@what)
{
push (@what_print, $h->{$_});
}
$print_string = sprintf($print_format, @what_print);
asmcmdshare_print($print_string);
}
}
########
# NAME
# asmcmdtmpl_process_mktmpl
#
# DESCRIPTION
# This function processes the asmcmd command mktmpl.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# Null.
#
# NOTES
# Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_mktmpl
{
my ($dbh) = shift;
my (%args);
my ($qry, $ret);
my ($redun, $pri_zn, $sec_zn, $dgname);
my ($name);
my (@attrs);
# Get option parameters, if any.
$ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
$dgname = $args{'G'};
($name) = @{$args{'mktmpl'}};
#striping
if (defined($args{'striping'}))
{
push (@attrs, 'COARSE') if ($args{'striping'} eq 'coarse');
push (@attrs, 'FINE') if ($args{'striping'} eq 'fine');
}
#redundancy
if (defined($args{'redundancy'}))
{
$redun = $args{'redundancy'};
push (@attrs, 'UNPROTECTED') if ($redun eq 'unprotected');
push (@attrs, 'MIRROR') if ($redun eq 'mirror');
push (@attrs, 'HIGH') if ($redun eq 'high');
}
#pri-zone
if (defined($args{'primary'}))
{
$pri_zn = $args{'primary'};
if($pri_zn eq 'hot')
{
push (@attrs, 'HOT');
}
elsif($pri_zn eq 'cold')
{
push (@attrs, 'COLD');
}
}
#sec zone
if (defined($args{'secondary'}))
{
$sec_zn = $args{'secondary'};
if($sec_zn eq 'hot')
{
push (@attrs, 'MIRRORHOT');
}
elsif($sec_zn eq 'cold')
{
push (@attrs, 'MIRRORCOLD');
}
}
$qry = "ALTER DISKGROUP " . $dgname . " ADD TEMPLATE " . $name;
if (@attrs)
{
$qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')';
}
$ret= asmcmdshare_do_stmt($dbh, $qry);
}
########
# NAME
# asmcmdtmpl_process_chtmpl
#
# DESCRIPTION
# This function processes the asmcmd command chtmpl.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# Null.
#
# NOTES
# Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_chtmpl
{
my ($dbh) = @_;
my (%args);
my ($qry, $ret);
my ($redun, $pri_zn, $sec_zn, $dgname);
my ($name);
my (@attrs);
# Get option parameters, if any.
$ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get the diskgroup name
$dgname = $args{'G'};
# get the template name
($name) = @{$args{'chtmpl'}};
$qry = "ALTER DISKGROUP " . $dgname . " MODIFY TEMPLATE " . $name;
#striping
if (defined($args{'striping'}))
{
push (@attrs, 'COARSE') if ($args{'striping'} eq 'coarse');
push (@attrs, 'FINE') if ($args{'striping'} eq 'fine');
}
#redundancy
if (defined($args{'redundancy'}))
{
$redun = $args{'redundancy'};
push (@attrs, 'UNPROTECTED') if ($redun eq 'unprotected');
push (@attrs, 'MIRROR') if ($redun eq 'mirror');
push (@attrs, 'HIGH') if ($redun eq 'high');
}
#pri-zone
if (defined($args{'primary'}))
{
$pri_zn = $args{'primary'};
if($pri_zn eq 'hot')
{
push (@attrs, 'HOT');
}
elsif($pri_zn eq 'cold')
{
push (@attrs, 'COLD');
}
}
#sec zone
if (defined($args{'secondary'}))
{
$sec_zn = $args{'secondary'};
if($sec_zn eq 'hot')
{
push (@attrs, 'MIRRORHOT');
}
elsif($sec_zn eq 'cold')
{
push (@attrs, 'MIRRORCOLD');
}
}
if (@attrs)
{
$qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')';
}
$ret= asmcmdshare_do_stmt($dbh, $qry);
}
########
# NAME
# asmcmdtmpl_process_rmtmpl
#
# DESCRIPTION
# This function processes the asmcmd command rmtmpl.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# Null.
#
# NOTES
# Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_rmtmpl
{
my ($dbh) = shift;
my (%args);
my ($qry, $ret);
my ($dgname, $name);
# Get option parameters, if any.
$ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get the diskgroup name
$dgname = $args{'G'};
# get the template name
($name) = @{$args{'rmtmpl'}};
$qry = "ALTER DISKGROUP " . $dgname . " DROP TEMPLATE " . $name;
$ret= asmcmdshare_do_stmt($dbh, $qry);
}
########
# NAME
# asmcmdtmpl_is_cmd
#
# DESCRIPTION
# This routine checks if a user-entered command is one of the known
# ASMCMD internal commands that belong to the ASMCMDTMPL module.
#
# PARAMETERS
# arg (IN) - user-entered command name string.
#
# RETURNS
# True if $arg is one of the known commands, false otherwise.
########
sub asmcmdtmpl_is_cmd
{
my ($arg) = shift;
return defined ( $asmcmdtmpl_cmds{ $arg } );
}
########
# NAME
# asmcmdtmpl_is_wildcard_cmd
#
# DESCRIPTION
# This routine determines if an ASMCMDTMPL command allows the use
# of wild cards.
#
# PARAMETERS
# arg (IN) - user-entered command name string.
#
# RETURNS
# True if $arg is a command that can take wildcards as part of its argument,
# false otherwise.
########
sub asmcmdtmpl_is_wildcard_cmd
{
my ($arg) = shift;
return defined ($asmcmdtmpl_cmds{ $arg }) &&
(asmcmdshare_get_cmd_wildcard($arg) eq "true");
}
########
# NAME
# asmcmdtmpl_is_no_instance_cmd
#
# DESCRIPTION
# This routine determines if a command can run without an ASM instance.
#
# PARAMETERS
# arg (IN) - user-entered command name string.
#
# RETURNS
# 1 if $arg is a command that can run without an ASM instance or it does not
# belong to this module
# 0 if $arg is a command that needs to connect to an ASM instance
# -1 if $arg is a command that may use an ASM instance.
#
# NOTES
# The asmcmdtmpl module currently supports only the help as a command
# that does not require an ASM instance.
########
sub asmcmdtmpl_is_no_instance_cmd
{
my ($arg) = shift;
my ($rc);
return 1 unless defined($asmcmdtmpl_cmds{$arg});
$rc = asmcmdshare_get_cmd_noinst($arg);
if ($rc eq "true")
{
return 1;
}
elsif ($rc eq "undef")
{
return -1;
}
return 0;
}
########
# NAME
# asmcmdtmpl_parse_int_args
#
# DESCRIPTION
# This routine parses the arguments for flag options for ASMCMD internal
# commands.
#
# PARAMETERS
# cmd (IN) - user-entered command name string.
# args_ref (OUT) - hash of user-specified flag options for a command,
# populated by getopts().
#
# RETURNS
# Zero on success; undefined on error.
#
# NOTES
# $cmd must already be verified as a valid ASMCMD internal command.
########
sub asmcmdtmpl_parse_int_args
{
my ($cmd, $args_ref) = @_;
my @string;
my $key;
#include deprecated options if any
if($asmcmdglobal_deprecated_options{ $cmd })
{
foreach $key(keys %{$asmcmdglobal_deprecated_options{ $cmd }})
{
push(@string, $asmcmdglobal_deprecated_options{$cmd}{$key}[0]);
}
}
# Use asmcmdparser_parse_issued_command() from the asmcmdparser package to parse arguments for
# internal commands. These arguments are stored in @ARGV.
# if (!asmcmdparser_parse_issued_command($cmd, $args_ref, \@string))
if (!asmcmdparser_parse_issued_command($cmd, $args_ref, \@string))
{
# Print correct command format if syntax error. #
asmcmdtmpl_syntax_error($cmd);
return undef;
}
return 0;
}
########
# NAME
# asmcmdtmpl_syntax_error
#
# DESCRIPTION
# This routine prints the correct syntax for a command to STDERR, used
# when there is a syntax error. If the command with bad syntax is asmcmd
# itself, then asmcmdbase_syntax_error also calls exit() to quit out.
#
# PARAMETERS
# cmd (IN) - user-entered command name string.
#
# RETURNS
# 1 if another command that belongs to this module; 0 if command not found.
#
# NOTES
# These errors are user-errors and not internal errors. They are of type
# record, not signal. Thus, even if exit() is called, the exit value is
# zero.
########
sub asmcmdtmpl_syntax_error
{
my ($cmd) = shift;
my ($cmd_syntax); # Correct syntax for $cmd. #
my ($succ) = 0;
if (asmcmdtmpl_is_cmd($cmd))
{
$cmd_syntax = asmcmdshare_get_help_syntax($cmd); # Get syntax for $cmd. #
$cmd_syntax = asmcmdshare_trim_str ($cmd_syntax);
if (defined ($cmd_syntax))
{
asmcmdshare_printstderr 'usage: ' . $cmd_syntax . "\n";
asmcmdshare_printstderr 'help: help ' . $cmd . "\n";
$succ = 1;
}
}
return $succ;
}
########
# NAME
# asmcmdtmpl_process_help
#
# DESCRIPTION
# This function is the help function for the asmcmdtmpl module.
#
# PARAMETERS
# command (IN) - display the help message for this command.
#
# RETURNS
# 1 if command found; 0 otherwise.
########
sub asmcmdtmpl_process_help
{
my ($command) = shift; # User-specified argument; show help on $cmd. #
my ($desc); # Command description for $cmd. #
my ($succ) = 0; # 1 if command found, 0 otherwise. #
if (asmcmdtmpl_is_cmd ($command))
{ # User specified a command name to look up. #
$desc = asmcmdshare_get_help_desc($command);
asmcmdshare_print "$desc\n";
$succ = 1;
}
return $succ;
}
########
# NAME
# asmcmdtmpl_get_asmcmd_cmds
#
# DESCRIPTION
# This routine constructs a string that contains a list of the names of all
# ASMCMD internal commands and returns this string.
#
# PARAMETERS
# None.
#
# RETURNS
# A string contain a list of the names of all ASMCMD internal commands.
#
# NOTES
# Used by the help command and by the error command when the user enters
# an invalid internal command.
########
sub asmcmdtmpl_get_asmcmd_cmds
{
return asmcmdshare_filter_invisible_cmds(%asmcmdtmpl_cmds);
}
1;
OHA YOOOO