2011-09-15 15:30:15 +00:00
# IBM(c) 2011 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
= head 1
xCAT plugin to handle xCAT UI service portal commands
= cut
#-------------------------------------------------------
package xCAT_plugin::webportal ;
use strict ;
require xCAT::Utils ;
require xCAT::MsgUtils ;
require xCAT::DBobjUtils ;
require IO::Socket::INET ;
use Getopt::Long ;
use Data::Dumper ;
use xCAT::Table ;
use xCAT::NodeRange ;
use XML::Simple ;
require XML::Parser ;
sub handled_commands {
# In order for this to work, you need to run: ln -s /opt/xcat/bin/xcatclientnnr /opt/xcat/bin/webportal
# xcatclientnnr allows command to run without a node range
return { webportal = > "webportal" } ;
}
sub process_request {
my $ request = shift ;
my $ callback = shift ;
my $ sub_req = shift ;
my % authorized_cmds = (
2011-10-12 18:27:12 +00:00
'lszvm' = > \ & lszvm ,
'provzlinux' = > \ & provzlinux ,
2011-11-17 04:23:53 +00:00
'clonezlinux' = > \ & clonezlinux ,
'genhostip' = > \ & genhostip ,
2012-04-02 04:08:30 +00:00
'getmaxvm' = > \ & getmaxvm ,
'getuserprivilege' = > \ & getuserprivilege
2011-09-15 15:30:15 +00:00
) ;
# Check if the request is authorized
split ' ' , $ request - > { arg } - > [ 0 ] ;
my $ cmd = $ _ [ 0 ] ;
if ( grep { $ _ eq $ cmd } keys % authorized_cmds ) {
my $ func = $ authorized_cmds { $ cmd } ;
$ func - > ( $ request , $ callback , $ sub_req ) ;
}
else {
$ callback - > (
{ error = > "$cmd is not authorized!\n" , errorcode = > [ 1 ] } ) ;
}
}
sub println {
my $ callback = shift ;
my $ msg = shift ;
my % rsp ;
push @ { $ rsp { info } } , $ msg ;
xCAT::MsgUtils - > message ( 'I' , \ % rsp , $ callback ) ;
return ;
}
sub lszvm {
my ( $ request , $ callback , $ sub_req ) = @ _ ;
# List the zVM and their respective HCP
my $ out = "" ;
my % pair ;
# Look in 'zvm' table
my $ tab = xCAT::Table - > new ( 'zvm' , - create = > 1 , - autocommit = > 0 ) ;
my @ results = $ tab - > getAllAttribsWhere ( "nodetype='vm'" , 'hcp' , 'parent' ) ;
foreach ( @ results ) {
if ( $ _ - > { 'hcp' } && $ _ - > { 'parent' } && ! $ pair { $ _ - > { 'hcp' } } ) {
# Save zVM:HCP pairing
$ pair { $ _ - > { 'hcp' } } = $ _ - > { 'parent' } ;
# Print out zVM:HCP
$ out . = $ _ - > { 'parent' } . ":" . $ _ - > { 'hcp' } . "\n" ;
}
}
$ callback - > ( { data = > $ out } ) ;
}
sub provzlinux {
my ( $ request , $ callback , $ sub_req ) = @ _ ;
my $ group = $ request - > { arg } - > [ 1 ] ;
my $ hcp = $ request - > { arg } - > [ 2 ] ;
my $ img = $ request - > { arg } - > [ 3 ] ;
my $ owner = $ request - > { arg } - > [ 4 ] ;
2011-12-20 18:10:28 +00:00
# Exit if missing inputs
if ( ! $ group || ! $ hcp || ! $ img || ! $ owner ) {
println ( $ callback , '(Error) Missing group, HCP, image, or owner' ) ;
return ;
}
2012-02-20 18:10:34 +00:00
# Check the max # of virtual machines allowed
my $ out = `tabdump nodetype -w nodetype.comments=~"owner:$owner"` ;
my @ tmp = split ( /\n/ , $ out ) ;
my $ usrVM = scalar ( @ tmp ) - 1 ;
$ out = `webportal getmaxvm $owner` ;
$ out =~ s/Max allowed: //g ;
my $ maxVM = int ( $ out ) ;
# Do not continue if the max # is reached
if ( $ usrVM >= $ maxVM ) {
println ( $ callback , "You have reached the maximum number of virtual machines allowed ($maxVM). Delete unused virtual machines or contact your system administrator request more virtual machines." ) ;
return ;
}
2011-09-15 15:30:15 +00:00
2011-12-20 18:10:28 +00:00
# Get node OS base
my $ profile ;
my $ arch ;
my $ os ;
( $ profile , $ arch , $ os ) = getosimagedef ( $ callback , $ img ) ;
if ( $ os =~ m/sp/i ) {
@ tmp = split ( /sp/ , $ os ) ;
} else {
@ tmp = split ( /\./ , $ os ) ;
}
my $ os_base = $ tmp [ 0 ] ;
2011-09-15 15:30:15 +00:00
# Read in default disk pool and disk size /opt/zhcp/conf/default.conf on zHCP
# pool = POOL3
# eckd_size = 10016
my $ disk_pool ;
my $ eckd_size ;
my $ fba_size ;
my $ default_conf = '/opt/zhcp/conf/default.conf' ;
2011-12-20 18:10:28 +00:00
my $ default_direct = "/opt/zhcp/conf/profiles/$profile.direct" ;
2011-10-14 00:02:12 +00:00
# Check if a group based directory entry exists, else use default one
2011-12-20 18:10:28 +00:00
if ( ! ( `ssh $hcp "test -e /opt/zhcp/conf/profiles/$profile.direct && echo Exists"` ) ) {
println ( $ callback , "$profile.direct does not exist. Using default.direct to generate directory entry." ) ;
2011-10-14 00:02:12 +00:00
# Exit if default.direct does not exist
2011-12-20 18:10:28 +00:00
$ default_direct = '/opt/zhcp/conf/profiles/default.direct' ;
if ( ! ( `ssh $hcp "test -e /opt/zhcp/conf/profiles/default.direct && echo Exists"` ) ) {
2011-10-14 00:02:12 +00:00
println ( $ callback , '(Error) $default_direct does not exists' ) ;
return ;
}
}
2011-09-15 15:30:15 +00:00
# Exit if default.conf does not exist
if ( ! ( `ssh $hcp "test -e $default_conf && echo Exists"` ) ) {
println ( $ callback , '(Error) $default_conf does not exists' ) ;
return ;
}
# Exit if default.direct does not exist
if ( ! ( `ssh $hcp "test -e $default_direct && echo Exists"` ) ) {
println ( $ callback , '(Error) $default_direct does not exists' ) ;
return ;
}
2012-02-20 18:10:34 +00:00
$ out = `ssh $hcp "cat $default_conf"` ;
2011-12-20 18:10:28 +00:00
@ tmp = split ( /\n/ , $ out ) ;
# default.conf should contain:
# Default configuration for virtual machines handled by this zHCP
# default_diskpool=POOL3
# default_eckd_size=10016
# compute_diskpool=POOL3
# compute_eckd_size=10016
my $ profile_diskpool_parm = $ profile . "_diskpool" ;
my $ profile_eckd_size_parm = $ profile . "_eckd_size" ;
my $ profile_fba_size_parm = $ profile . "_fba_size" ;
2011-12-20 19:38:21 +00:00
my $ default_disk_pool ;
my $ default_eckd_size ;
my $ default_fba_size ;
2011-09-15 15:30:15 +00:00
foreach ( @ tmp ) {
2011-12-20 18:10:28 +00:00
# Get disk pool (default)
if ( $ _ =~ m/default_diskpool=/i ) {
2011-12-20 19:38:21 +00:00
$ default_disk_pool = $ _ ;
$ default_disk_pool =~ s/default_diskpool=//g ;
2011-12-20 18:10:28 +00:00
}
# Get disk size (default)
elsif ( $ _ =~ m/default_eckd_size=/i ) {
2011-12-20 19:38:21 +00:00
$ default_eckd_size = $ _ ;
$ default_eckd_size =~ s/default_eckd_size=//g ;
2011-09-15 15:30:15 +00:00
}
2011-12-20 18:10:28 +00:00
elsif ( $ _ =~ m/default_fba_size=/i ) {
2011-12-20 19:38:21 +00:00
$ default_fba_size = $ _ ;
$ default_fba_size =~ s/default_fba_size=//g ;
2011-12-20 18:10:28 +00:00
}
# Get profile disk pool (default)
elsif ( $ _ =~ m/$profile_diskpool_parm=/i ) {
$ disk_pool = $ _ ;
$ disk_pool =~ s/$profile_diskpool_parm=//g ;
}
# Get profile disk size (default)
elsif ( $ _ =~ m/$profile_eckd_size_parm=/i ) {
2011-09-15 15:30:15 +00:00
$ eckd_size = $ _ ;
2011-12-20 18:10:28 +00:00
$ eckd_size =~ s/$profile_eckd_size_parm=//g ;
2011-09-15 15:30:15 +00:00
}
2011-12-20 18:10:28 +00:00
elsif ( $ _ =~ m/$profile_fba_size_parm=/i ) {
2011-09-15 15:30:15 +00:00
$ fba_size = $ _ ;
2011-12-20 18:10:28 +00:00
$ fba_size =~ s/$profile_fba_size_parm=//g ;
2011-09-15 15:30:15 +00:00
}
}
2011-12-20 19:38:21 +00:00
# Use default configuration if profile configuration does not exist
2011-12-20 19:50:31 +00:00
if ( ! $ disk_pool && ( ! $ eckd_size || ! $ fba_size ) ) {
2011-12-20 19:38:21 +00:00
println ( $ callback , "$profile configuration for disk pool and size does not exist. Using default configuration." ) ;
$ disk_pool = $ default_disk_pool ;
$ eckd_size = $ default_eckd_size ;
$ fba_size = $ default_fba_size ;
}
2011-09-15 15:30:15 +00:00
my $ site_tab = xCAT::Table - > new ( 'site' ) ;
my $ hash = $ site_tab - > getAttribs ( { key = > "installdir" } , 'value' ) ;
my $ install_dir = $ hash - > { 'value' } ;
# Get autoyast/kickstart template
# Count the number of disks needed
my $ tmpl ;
if ( $ os =~ m/sles/i ) {
$ tmpl = "$install_dir/custom/install/sles/$profile.$os_base.$arch.tmpl" ;
} elsif ( $ os =~ m/rhel/i ) {
$ tmpl = "$install_dir/custom/install/rh/$profile.$os_base.$arch.tmpl" ;
}
# Create VM
# e.g. webportal provzlinux [group] [hcp] [image]
2011-12-06 00:47:06 +00:00
my ( $ node , $ ip , $ base_digit ) = gennodename ( $ callback , $ group ) ;
if ( ! $ base_digit ) {
println ( $ callback , "(Error) Failed to generate node name" ) ;
return ;
}
2012-02-20 03:12:54 +00:00
my $ userid = $ node ;
2011-09-15 15:30:15 +00:00
# Set node definitions
2011-12-06 00:47:06 +00:00
# Also put node into all group
2012-02-13 20:56:12 +00:00
if ( $ group eq 'all' ) {
$ out = `mkdef -t node -o $node userid=$userid hcp=$hcp mgt=zvm groups=$group` ;
} else {
# Put node in all group
$ out = `mkdef -t node -o $node userid=$userid hcp=$hcp mgt=zvm groups=$group,all` ;
}
2011-09-15 15:30:15 +00:00
println ( $ callback , "$out" ) ;
# Set nodetype definitions
2011-10-07 20:10:32 +00:00
$ out = `chtab node=$node noderes.netboot=zvm nodetype.nodetype=osi nodetype.provmethod=install nodetype.os=$os nodetype.arch=$arch nodetype.profile=$profile nodetype.comments="owner:$owner"` ;
2011-09-15 15:30:15 +00:00
# Update hosts table and DNS
`makehosts` ;
`makedns` ;
# Create user directory entry replacing LXUSR with user ID
# Use /opt/zhcp/conf/default.direct on zHCP as the template
# USER LXUSR PSWD 512M 1G G
# INCLUDE LNXDFLT
# COMMAND SET VSWITCH VSW2 GRANT LXUSR
$ out = `ssh $hcp "sed $default_direct -e s/LXUSR/$userid/g" > /tmp/$node-direct.txt` ;
$ out = `mkvm $node /tmp/$node-direct.txt` ;
`rm -rf /tmp/$node-direct.txt` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i ) {
return ;
}
# Add MDISKs to user directory entry
# Use /opt/zhcp/conf/default.conf on zHCP to determine disk pool and disk size
# pool = POOL3
# eckd_size = 10016
2011-10-04 20:08:55 +00:00
my $ type ;
my $ virt_addr ;
2011-09-30 18:29:27 +00:00
if ( $ os =~ m/sles/i ) {
# Create XML object
my $ xml = new XML:: Simple ;
# Read XML file
my $ data = $ xml - > XMLin ( $ tmpl ) ;
2011-10-04 20:08:55 +00:00
2011-09-30 18:29:27 +00:00
my $ devices = $ data - > { 'dasd' } - > { 'devices' } - > { 'listentry' } ;
foreach ( @$ devices ) {
# Get disk virtual address and disk type
$ type = $ _ - > { 'drivers' } - > { 'listentry' } - > { 'modules' } - > { 'module_entry' } - > { 'listentry' } ;
$ virt_addr = $ _ - > { 'sysfs_bus_id' } ;
$ virt_addr =~ s/0\.0\.//g ;
foreach ( @$ type ) {
# Add ECKD disk
if ( $ _ =~ m/dasd_eckd_mod/i ) {
$ out = `chvm $node --add3390 $disk_pool $virt_addr $eckd_size MR` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i ) {
return ;
}
}
# Add FBA disk
elsif ( $ _ =~ m/dasd_fba_mod/i ) {
# To be continued
# $out = `chvm $node --add9336 $disk_pool $virt_addr $fba_size MR`;
2011-09-15 15:30:15 +00:00
}
}
2011-09-30 18:29:27 +00:00
} # End of foreach
} elsif ( $ os =~ m/rhel/i ) {
2011-10-04 20:08:55 +00:00
my % devices ;
my $ dev ;
$ virt_addr = 100 ;
# Read in kickstart file
$ out = `cat $tmpl | egrep "part /"` ;
@ tmp = split ( /\n/ , $ out ) ;
foreach ( @ tmp ) {
$ out = substr ( $ out , index ( $ out , '--ondisk=' ) + 9 ) ;
$ out =~ s/\s*$// ; # Trim right
$ out =~ s/^\s*// ; # Trim left
$ devices { $ out } = 1 ;
}
# Add ECKD disk for each device found
for $ dev ( keys % devices ) {
$ out = `chvm $node --add3390 $disk_pool $virt_addr $eckd_size MR` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i ) {
return ;
}
# Increment virtual address
$ virt_addr = $ virt_addr + 1 ;
}
2011-09-30 18:29:27 +00:00
}
2011-09-15 15:30:15 +00:00
# Update DHCP
`makedhcp -a` ;
# Toggle node power so COMMAND SET will get executed
`rpower $node on` ;
`rpower $node off` ;
# Punch kernel, initrd, and ramdisk to node reader
$ out = `nodeset $node install` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i ) {
return ;
}
# IPL reader and begin installation
$ out = `rnetboot $node ipl=00C` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i ) {
return ;
}
2011-10-07 20:10:32 +00:00
# Configure Ganglia monitoring
$ out = `moncfg gangliamon $node -r` ;
2011-09-15 15:30:15 +00:00
# Show node information, e.g. IP, hostname, and root password
$ out = `lsdef $node | egrep "ip=|hostnames="` ;
my $ rootpw = getsysrootpw ( ) ;
2011-10-07 20:10:32 +00:00
println ( $ callback , "Your virtual machine is ready. It may take a few minutes before you can logon using VNC ($node:1). Below is your VM attributes." ) ;
2011-09-15 15:30:15 +00:00
println ( $ callback , "$out" ) ;
println ( $ callback , " rootpw = $rootpw" ) ;
}
sub getsysrootpw {
# Get the default root password for all xCAT provisioned VM
my ( $ callback ) = @ _ ;
my $ tab = xCAT::Table - > new ( 'passwd' ) ;
my $ hash = $ tab - > getAttribs ( { key = > "system" } , 'password' ) ;
my $ passwd = $ hash - > { 'password' } ;
return $ passwd ;
}
sub getosimagedef {
# Get osimage definitions based on image name
my ( $ callback , $ img_name ) = @ _ ;
my $ profile ;
my $ arch ;
my $ os ;
# Get profile, osarch, and osver in 'osimage' table based on imagename
my $ tab = xCAT::Table - > new ( 'osimage' , - create = > 1 , - autocommit = > 0 ) ;
my @ results = $ tab - > getAllAttribsWhere ( "imagename='" . $ img_name . "'" ,
'profile' , 'osarch' , 'osvers' ) ;
foreach ( @ results ) {
# It should return: |gpok(\d+)|10.1.100.($1+0)|
$ profile = $ _ - > { 'profile' } ;
$ arch = $ _ - > { 'osarch' } ;
$ os = $ _ - > { 'osvers' } ;
}
return ( $ profile , $ arch , $ os ) ;
}
sub gennodename {
# Generate node name based on given group
my ( $ callback , $ group ) = @ _ ;
2011-12-06 03:04:47 +00:00
# Only use the 1st group
if ( $ group =~ m/,/ ) {
my @ groups = split ( ',' , $ group ) ;
$ group = @ groups [ 0 ] ;
}
2011-12-19 14:44:24 +00:00
# Hostname and IP address regular expressions
2011-12-06 00:47:06 +00:00
my $ hostname_regex ;
my $ ipaddr_regex ;
2011-12-19 05:03:27 +00:00
my @ comments ;
2011-09-15 15:30:15 +00:00
my $ base_digit = 0 ;
my $ base_hostname ;
2011-12-06 00:47:06 +00:00
my $ base_ipaddr ;
2011-12-19 14:44:24 +00:00
# Network, submask, submask prefix, and host ranges
2011-12-19 05:03:27 +00:00
my $ network = "" ;
my $ mask ;
2011-12-19 14:44:24 +00:00
my $ prefix ;
my $ hosts_count ;
my $ range_low = 1 ;
my $ range_high = 254 ;
# Hostname and IP address generated
2011-09-15 15:30:15 +00:00
my $ hostname ;
2011-12-06 00:47:06 +00:00
my $ ipaddr ;
my $ tmp ;
2011-09-15 15:30:15 +00:00
my @ args ;
# Get regular expression for hostname in 'hosts' table
my $ tab = xCAT::Table - > new ( 'hosts' , - create = > 1 , - autocommit = > 0 ) ;
2011-12-19 05:03:27 +00:00
my @ results = $ tab - > getAllAttribsWhere ( "node='" . $ group . "'" , 'ip' , 'comments' ) ;
2011-09-15 15:30:15 +00:00
foreach ( @ results ) {
2011-12-06 00:47:06 +00:00
# It should return: |gpok(\d+)|10.1.100.($1+0)|
2011-09-15 15:30:15 +00:00
@ args = split ( /\|/ , $ _ - > { 'ip' } ) ;
2011-12-06 00:47:06 +00:00
$ hostname_regex = $ args [ 1 ] ;
$ ipaddr_regex = $ args [ 2 ] ;
$ base_hostname = $ args [ 1 ] ;
$ base_hostname =~ s/\(\S*\)/#/g ;
# Get the 10.1.100.
$ base_ipaddr = $ args [ 2 ] ;
$ base_ipaddr =~ s/\(\S*\)//g ;
# Get the ($1+0)
$ ipaddr_regex =~ s/$base_ipaddr//g ;
2011-12-19 05:03:27 +00:00
# Get the network within comments
# It should return: "description: All machines; network: 10.1.100.0/24;"
# This will help determine the 1st node in the group if none exists
@ comments = split ( /;/ , $ _ - > { 'comments' } ) ;
foreach ( @ comments ) {
if ( $ _ =~ m/network:/i ) {
$ network = $ _ ;
# Remove network header
$ network =~ s/network://g ;
# Trim network section
$ network =~ s/\s*$// ;
$ network =~ s/^\s*// ;
# Extract network
$ tmp = rindex ( $ network , '/' ) ;
if ( $ tmp > - 1 ) {
2011-12-19 14:44:24 +00:00
# Get submask prefix
$ prefix = substr ( $ network , $ tmp ) ;
$ prefix =~ s | / || g ;
# Get the number of hosts possible using submask
$ hosts_count = 32 - int ( $ prefix ) ;
# Minus network and broadcast addresses
$ hosts_count = 2 ** $ hosts_count - 2 ;
# Get network
2011-12-19 05:03:27 +00:00
$ network = substr ( $ network , 0 , $ tmp ) ;
2011-12-19 14:44:24 +00:00
}
2011-12-19 05:03:27 +00:00
# Extract base digit, which depends on the netmask used
$ base_digit = substr ( $ network , rindex ( $ network , '.' ) + 1 ) ;
2011-12-19 14:44:24 +00:00
# 1st number in range is network
$ range_low = $ base_digit + 1 ;
# Get hosts range
if ( $ tmp > - 1 ) {
$ range_high = $ base_digit + $ hosts_count ;
}
2011-12-19 05:03:27 +00:00
}
} # End of foreach
} # End of foreach
2011-12-19 14:44:24 +00:00
2011-09-15 15:30:15 +00:00
# Are there nodes in this group already?
2011-12-19 05:03:27 +00:00
# If so, use the existing nodes as a base
2011-09-15 15:30:15 +00:00
my $ out = `nodels $group` ;
@ args = split ( /\n/ , $ out ) ;
foreach ( @ args ) {
2011-12-06 00:47:06 +00:00
$ _ =~ s/$hostname_regex/$1/g ;
2011-09-15 15:30:15 +00:00
# Take the greatest digit
if ( int ( $ _ ) > $ base_digit ) {
$ base_digit = int ( $ _ ) ;
}
}
# +1 to base digit to obtain next hostname
$ base_digit = $ base_digit + 1 ;
# Generate hostname
$ hostname = $ base_hostname ;
2011-12-06 00:47:06 +00:00
$ hostname =~ s/#/$base_digit/g ;
# Generate IP address
$ ipaddr = $ hostname ;
$ ipaddr =~ s/$hostname_regex/$ipaddr_regex/gee ;
$ ipaddr = $ base_ipaddr . $ ipaddr ;
2011-12-19 05:03:27 +00:00
# Get networks in 'networks' table
$ tab = xCAT::Table - > new ( 'networks' , - create = > 1 , - autocommit = > 0 ) ;
my $ entries = $ tab - > getAllEntries ( ) ;
# Go through each network
my $ iprange ;
foreach ( @$ entries ) {
# Get network, mask, and range
$ network = $ _ - > { 'net' } ;
$ mask = $ _ - > { 'mask' } ;
$ iprange = $ _ - > { 'dynamicrange' } ;
# If the host IP address is in this subnet, return
if ( xCAT::NetworkUtils - > ishostinsubnet ( $ ipaddr , $ mask , $ network ) ) {
# Exit loop
last ;
} else {
$ network = "" ;
}
}
# Exit if no network exist for group
if ( ! $ network ) {
return ;
}
2011-12-19 14:44:24 +00:00
# Find the network range for this group based on networks table
2011-12-19 05:03:27 +00:00
my @ ranges ;
if ( $ iprange ) {
@ args = split ( /;/ , $ iprange ) ;
foreach ( @ args ) {
# If a network range exists
if ( $ _ =~ m/-/ ) {
@ ranges = split ( /-/ , $ _ ) ;
2011-12-19 14:44:24 +00:00
$ range_low = $ ranges [ 0 ] ;
$ range_high = $ ranges [ 1 ] ;
2011-12-19 05:03:27 +00:00
# Get the low and high ends digit
2011-12-19 14:44:24 +00:00
$ range_low =~ s/$base_ipaddr//g ;
$ range_high =~ s/$base_ipaddr//g ;
2011-12-19 05:03:27 +00:00
}
}
} # End of if ($iprange)
# If no nodes exist in group
# Set the base digit to the low end of the network range
2011-12-19 14:44:24 +00:00
if ( $ range_low && $ base_digit == 1 ) {
$ base_digit = $ range_low ;
2011-12-19 05:03:27 +00:00
# Generate hostname
$ hostname = $ base_hostname ;
$ hostname =~ s/#/$base_digit/g ;
# Generate IP address
$ ipaddr = $ hostname ;
$ ipaddr =~ s/$hostname_regex/$ipaddr_regex/gee ;
$ ipaddr = $ base_ipaddr . $ ipaddr ;
}
2011-12-06 00:47:06 +00:00
# Check xCAT tables, /etc/hosts, and ping to see if hostname is already used
2011-12-19 05:03:27 +00:00
while ( `nodels $hostname` || `cat /etc/hosts | grep "$ipaddr "` || ! ( `ping -c 4 $ipaddr` =~ m/100% packet loss/ ) ) {
2011-12-06 00:47:06 +00:00
# Base digit invalid if over 254
2011-12-19 14:44:24 +00:00
if ( $ base_digit > $ range_high ) {
2011-12-06 00:47:06 +00:00
last ;
}
2011-09-15 15:30:15 +00:00
# +1 to base digit to obtain next hostname
$ base_digit = $ base_digit + 1 ;
2011-12-06 00:47:06 +00:00
$ hostname = $ base_hostname ;
$ hostname =~ s/#/$base_digit/g ;
$ ipaddr = $ hostname ;
$ ipaddr =~ s/$hostname_regex/$ipaddr_regex/gee ;
$ ipaddr = $ base_ipaddr . $ ipaddr ;
2011-09-15 15:30:15 +00:00
}
2011-12-06 00:47:06 +00:00
2011-12-19 05:03:27 +00:00
# Range must be within network range
2011-12-19 14:44:24 +00:00
if ( $ base_digit > $ range_high ) {
2011-12-06 00:47:06 +00:00
return ;
} else {
return ( $ hostname , $ ipaddr , $ base_digit ) ;
2011-12-19 14:44:24 +00:00
}
2011-09-15 15:30:15 +00:00
}
2011-10-12 18:27:12 +00:00
sub clonezlinux {
my ( $ request , $ callback , $ sub_req ) = @ _ ;
# webportal clonezlinux [src node] [group] [owner]
my $ src_node = $ request - > { arg } - > [ 1 ] ;
my $ group = $ request - > { arg } - > [ 2 ] ;
my $ owner = $ request - > { arg } - > [ 3 ] ;
2012-02-20 18:10:34 +00:00
# Check the max # of virtual machines allowed
my $ out = `tabdump nodetype -w nodetype.comments=~"owner:$owner"` ;
my @ tmp = split ( /\n/ , $ out ) ;
my $ usrVM = scalar ( @ tmp ) - 1 ;
$ out = `webportal getmaxvm $owner` ;
$ out =~ s/Max allowed: //g ;
my $ maxVM = int ( $ out ) ;
# Do not continue if the max # is reached
if ( $ usrVM >= $ maxVM ) {
println ( $ callback , "You have reached the maximum number of virtual machines allowed ($maxVM). Delete unused virtual machines or contact your system administrator request more virtual machines." ) ;
return ;
}
2011-12-06 03:04:47 +00:00
2011-10-12 18:27:12 +00:00
# Get source node's HCP
my $ props = xCAT::zvmUtils - > getNodeProps ( 'zvm' , $ src_node , ( 'hcp' ) ) ;
my $ hcp = $ props - > { 'hcp' } ;
2011-10-12 19:10:24 +00:00
# Get source node's nodetype
$ props = xCAT::zvmUtils - > getNodeProps ( 'nodetype' , $ src_node , ( 'os' , 'arch' , 'profile' ) ) ;
my $ os = $ props - > { 'os' } ;
my $ arch = $ props - > { 'arch' } ;
my $ profile = $ props - > { 'profile' } ;
2011-10-12 18:27:12 +00:00
2011-10-12 19:10:24 +00:00
# Read in default disk pool from /opt/zhcp/conf/default.conf on zHCP
2011-10-12 18:27:12 +00:00
# pool = POOL3
# eckd_size = 10016
my $ disk_pool ;
my $ default_conf = '/opt/zhcp/conf/default.conf' ;
2012-01-23 17:52:34 +00:00
my $ default_direct = '/opt/zhcp/conf/profiles/default.direct' ;
2011-10-12 18:27:12 +00:00
# Exit if default.conf does not exist
if ( ! ( `ssh $hcp "test -e $default_conf && echo Exists"` ) ) {
println ( $ callback , '(Error) $default_conf does not exists' ) ;
return ;
}
# Exit if default.direct does not exist
if ( ! ( `ssh $hcp "test -e $default_direct && echo Exists"` ) ) {
println ( $ callback , '(Error) $default_direct does not exists' ) ;
return ;
}
2012-02-20 18:10:34 +00:00
$ out = `ssh $hcp "cat $default_conf"` ;
@ tmp = split ( /\n/ , $ out ) ;
2012-01-23 17:52:34 +00:00
# default.conf should contain:
# Default configuration for virtual machines handled by this zHCP
# default_diskpool=POOL3
# compute_diskpool=POOL3
my $ profile_diskpool_parm = '' ;
if ( $ profile ) {
$ profile_diskpool_parm = $ profile . "_diskpool" ;
}
2011-10-12 18:27:12 +00:00
foreach ( @ tmp ) {
2012-01-23 17:52:34 +00:00
# Get disk pool (default)
if ( $ _ =~ m/default_diskpool=/i ) {
2011-10-12 18:27:12 +00:00
$ disk_pool = $ _ ;
2012-01-23 17:52:34 +00:00
$ disk_pool =~ s/default_diskpool=//g ;
}
# Get profile disk pool (default)
elsif ( $ _ =~ m/$profile_diskpool_parm=/i && $ profile_diskpool_parm ) {
$ disk_pool = $ _ ;
$ disk_pool =~ s/$profile_diskpool_parm=//g ;
2011-10-12 18:27:12 +00:00
}
}
2012-01-23 17:52:34 +00:00
# Trim disk pool of white space
$ disk_pool =~ s/\s*$// ; # Trim right
$ disk_pool =~ s/^\s*// ; # Trim left
2011-10-12 19:10:24 +00:00
# Create VM
# e.g. webportal provzlinux [group] [hcp] [image]
2011-12-06 03:04:47 +00:00
my ( $ node , $ ip , $ base_digit ) = gennodename ( $ callback , $ group ) ;
2012-02-20 03:12:54 +00:00
my $ userid = $ node ;
2011-12-06 03:04:47 +00:00
2011-10-12 19:10:24 +00:00
# Set node definitions
$ out = `mkdef -t node -o $node userid=$userid hcp=$hcp mgt=zvm groups=$group` ;
println ( $ callback , "$out" ) ;
2011-10-12 18:27:12 +00:00
2011-10-12 19:10:24 +00:00
# Set nodetype definitions
$ out = `chtab node=$node noderes.netboot=zvm nodetype.nodetype=osi nodetype.provmethod=install nodetype.os=$os nodetype.arch=$arch nodetype.profile=$profile nodetype.comments="owner:$owner"` ;
2011-10-12 18:27:12 +00:00
2011-10-12 19:10:24 +00:00
# Update hosts table and DNS
`makehosts` ;
`makedns` ;
2011-10-12 18:27:12 +00:00
2011-10-12 19:10:24 +00:00
# Update DHCP
`makedhcp -a` ;
2011-10-14 00:02:12 +00:00
println ( $ callback , "hosts table, DHCP, and DNS updated" ) ;
2011-10-12 18:27:12 +00:00
2011-10-12 19:10:24 +00:00
# Clone virtual machine
$ out = `mkvm $node $src_node pool=$disk_pool` ;
println ( $ callback , "$out" ) ;
if ( $ out =~ m/Error/i || $ out =~ m/Failed/i ) {
return ;
}
# Configure Ganglia monitoring
$ out = `moncfg gangliamon $node -r` ;
# Show node information, e.g. IP, hostname, and root password
$ out = `lsdef $node | egrep "ip=|hostnames="` ;
my $ rootpw = getsysrootpw ( ) ;
println ( $ callback , "Your virtual machine is ready. It may take a few minutes before you can logon. Below is your VM attributes." ) ;
println ( $ callback , "$out" ) ;
println ( $ callback , " rootpw = Same as source node" ) ;
2011-10-12 18:27:12 +00:00
}
2011-11-17 04:23:53 +00:00
sub genhostip {
my ( $ request , $ callback , $ sub_req ) = @ _ ;
my $ group = $ request - > { arg } - > [ 1 ] ;
2011-12-06 00:47:06 +00:00
my ( $ node , $ ip , $ base_digit ) = gennodename ( $ callback , $ group ) ;
println ( $ callback , "$node: $ip" ) ;
2011-11-17 04:23:53 +00:00
}
sub getmaxvm {
my ( $ request , $ callback , $ sub_req ) = @ _ ;
my $ user = $ request - > { arg } - > [ 1 ] ;
my @ args ;
my $ max ;
# Look in 'policy' table
my $ tab = xCAT::Table - > new ( 'policy' , - create = > 1 , - autocommit = > 0 ) ;
my @ results = $ tab - > getAllAttribsWhere ( "name='" . $ user . "'" , 'comments' ) ;
foreach ( @ results ) {
if ( $ _ - > { 'comments' } ) {
@ args = split ( ';' , $ _ - > { 'comments' } ) ;
# Extract max VM
foreach ( @ args ) {
if ( $ _ =~ m/max-vm:/i ) {
$ _ =~ s/max-vm://g ;
$ max = $ _ ;
last ;
}
}
}
}
$ callback - > ( { data = > "Max allowed: $max" } ) ;
}
2012-04-02 04:08:30 +00:00
sub getuserprivilege {
# Get the user privilege
my ( $ request , $ callback , $ sub_req ) = @ _ ;
my $ user = $ request - > { arg } - > [ 1 ] ;
if ( ! $ user ) {
$ callback - > ( { data = > "(Error) No user name is specified" } ) ;
return ;
}
my @ args ;
my $ privilege = "user" ;
# Look in 'policy' table
my $ tab = xCAT::Table - > new ( 'policy' , - create = > 1 , - autocommit = > 0 ) ;
my @ results = $ tab - > getAllAttribsWhere ( "name='" . $ user . "'" , 'comments' ) ;
foreach ( @ results ) {
if ( $ _ - > { 'comments' } ) {
@ args = split ( ';' , $ _ - > { 'comments' } ) ;
# Extract user privilege
foreach ( @ args ) {
if ( $ _ =~ m/privilege:/i ) {
$ _ =~ s/privilege://g ;
$ privilege = $ _ ;
$ privilege =~ s/\s*$// ; # Trim right
$ privilege =~ s/^\s*// ; # Trim left
last ;
}
}
}
}
$ callback - > ( { data = > "Privilege: $privilege" } ) ;
}
2011-10-12 18:27:12 +00:00
1 ;