diff --git a/cgi-bin/websphere.cgi b/cgi-bin/websphere.cgi deleted file mode 100644 index 8a7bc10..0000000 --- a/cgi-bin/websphere.cgi +++ /dev/null @@ -1,244 +0,0 @@ -#!/bin/sh - -exec "$COMMANDER_HOME/bin/cb-perl" -x "$0" "${@}" - -################################ -#!perl -# esx.cgi - -# -# Get/set EC-WebSphere configuration info for UI -# -# The following special keyword indicates that the "cleanup" script should -# scan this file for formatting errors, even though it doesn't have one of -# the expected extensions. -# CLEANUP: CHECK -# -# Copyright (c) 2007-2009 Electric Cloud, Inc. -# All rights reserved -################################ - -use strict; -use warnings; -use Getopt::Long; -use File::Spec; -use File::Temp; -use ElectricCommander; -use ElectricCommander::PropMod; -use ElectricCommander::PropDB; -use CGI qw(:standard); - -use constant { - SUCCESS => 0, - ERROR => 1, -}; - -# used for output redirection -$::tmpOut = ""; -$::tmpErr = ""; -$::oldout; -$::olderr; - -################################ -# main - Main program for the application. -# -# Arguments: -# - -# -# Returns: -# 0 - Success -# 1 - Error -# -################################ -sub main() { - - ## globals - $::cg = CGI->new(); - print $::cg->header( - -type => 'text/html', - -status => 200, - -Cache_control => 'no-cache, no-store, must-revalidate'); - - $::opts = $::cg->Vars; - $::ec = new ElectricCommander(); - $::ec->abortOnError(0); - - # make sure no libraries print to STDOUT - saveOutErr(); - - # Check for required arguments. - if (!defined $::opts->{cmd} || "$::opts->{cmd}" eq "") { - retError("error: cmd is required parameter"); - } - - # --------------------------------------------------------------- - # Dispatch operation - # --------------------------------------------------------------- - for ($::opts->{cmd}) - { - # modes - /getCfgList/i and do { getCfgList(); last; }; - } - retError("unknown command $::opts->{cmd}"); - - exit SUCCESS; -} - - -################################ -# getCfgList - Return the list of configurations from WebSphere -# -# Arguments: -# - -# -# Returns: -# 0 - Success -# 1 - Error -# -################################ -sub getCfgList { - - my $gcfg = new ElectricCommander::PropDB($::ec,"/projects/@PLUGIN_NAME@/websphere_cfgs"); - - my %cfgs = $gcfg->getRows(); - # print results as XML block - my $xml = ""; - $xml .= "\n"; - foreach my $cfg (keys %cfgs) { - my $url = $gcfg->getCol("$cfg/websphere_url"); - $xml .= " \n"; - $xml .= " $cfg\n"; - $xml .= " " . xmlQuote($url) . "\n"; - $xml .= " \n"; - } - $xml .= "\n"; - - printXML($xml); - exit SUCCESS; -} - -################################ -# retError - Return an error message -# -# Arguments: -# msg - Message to return -# -# Returns: -# 0 - Success -# 1 - Error -# -################################ -sub retError { - my ($msg) = @_; - - printXML("$msg\n"); - exit ERROR; -} - -################################ -# printXML - Print the XML block, add stdout, stderr -# -# Arguments: -# xml - xml string to print -# -# Returns: -# - -# -################################ -sub printXML { - my ($xml) = @_; - - my ($out,$err) = retrieveOutErr(); - - print "\n"; - print "\n"; - print "$xml\n"; - print "" . xmlQuote($out) . "\n"; - print "" . xmlQuote($err) . "\n"; - print ""; -} - -################################ -# saveOutErr - Redirect stdout/stderr to files so that any spurious output from commands does not end up on the return to the cgi caller -# -# Arguments: -# - -# -# Returns: -# - -# -################################ -sub saveOutErr { - # temporarily save STDOUT/STDERR to files - open $::oldout, ">&STDOUT" or die "Can't dup STDOUT: $!"; - open $::olderr, ">&STDERR" or die "Can't dup STDERR: $!"; - close STDOUT; - open STDOUT, '>', \$::tmpOut or die "Can't open STDOUT: $!"; - close STDERR; - open STDERR, '>', \$::tmpErr or die "Can't open STDOUT: $!"; - -} - -################################ -# retrieveOutErr - Reset stdout/sterr back to normal and return the contents of the temp files -# -# Arguments: -# - -# -# Returns: -# tmpOut - Content of out file -# tmpErr - Content of error file -# -################################ -sub retrieveOutErr { - # reconnect to normal STDOUT/STDERR - open STDOUT, ">&", $::oldout or die "can't reinstate $!"; - open STDERR, ">&", $::olderr or die "can't reinstate $!"; - return ($::tmpOut, $::tmpErr); -} - -################################ -# xmlQuote - Quote special characters such as & to generate well-formed XML character data. -# -# Arguments: -# string - String whose contents should be quoted. -# -# Returns: -# string - Quoted string -# -################################ -sub xmlQuote($) { - my ($string) = @_; - - $string =~ s/&/&/g; - $string =~ s//>/g; - $string =~ s{([\0-\x{08}\x{0b}\x{0c}\x{0e}-\x{1f}])}{ - sprintf("%%%02x", ord($1))}ge; - return $string; -} - -# ------------------------------------------------------------------------ -# validateUserSession -# -# Check current session on valid, if not - redirects -# user to the login page. -# ------------------------------------------------------------------------ -sub validateUserSession() { - - my $ec = new ElectricCommander({abortOnError => 0}); - $ec->login(); - if($ec->getError()) { - print "Location: ../../../\n\n"; - exit 0; - } -} - -validateUserSession(); - -main(); - - - - - - diff --git a/cgi-bin/websphereMonitor.cgi b/cgi-bin/websphereMonitor.cgi deleted file mode 100644 index 77d43a3..0000000 --- a/cgi-bin/websphereMonitor.cgi +++ /dev/null @@ -1,226 +0,0 @@ -#!/bin/sh - -exec "$COMMANDER_HOME/bin/cb-perl" -x "$0" "${@}" - -#!perl - -################################ -# monitorJob.cgi -# -# Monitors a job: waits for it to complete and reports on its success or -# failure. -# -################################ -use warnings; -use strict; -use ElectricCommander; -use XML::XPath; -use CGI; - -use constant { - SUCCESS => 0, - ERROR => 1, -}; - -my $gTimeout = 20; - -################################ -# main - Main program for the application. -# -# Arguments: -# - -# -# Returns: -# - -# -################################ -sub main { - - # Get CGI args - my $cgi = CGI->new(); - my $cgiArgs = $cgi->Vars; - - # Check for required args - my $jobId = $cgiArgs->{jobId}; - if (!defined $jobId || "$jobId" eq "") { - reportError($cgi, "jobId is a required parameter"); - } - - # Wait for job - my $ec = ElectricCommander->new({abortOnError => 0}); - $ec->abortOnError(0); - my $xpath = $ec->waitForJob($jobId, $gTimeout); - my $errors = $ec->checkAllErrors($xpath); - - if ("$errors" ne "") { - reportError($cgi, $errors); - } - - my $status = $xpath->findvalue("//status"); - if ("$status" ne "completed") { - - # Abort job and report failure - abortJobAndReportError($cgi, $ec, $jobId); - } - - my $outcome = $xpath->findvalue("//outcome"); - if ("$outcome" ne "success") { - - # Report job errors - reportJobErrors($cgi, $ec, $jobId); - } - - # - # # If the job was successful and the debug flag is not set, delete it - # my $debug = $cgiArgs->{debug}; - # if (!defined $debug || "$debug" ne "1") { - # $ec->deleteJob($jobId); - # } - - # Report the job's success - reportSuccess($cgi); -} ## end sub main - -################################ -# abortJobAndReportError - Abort the job and report the timeout error. -# -# Arguments: -# cgi -# ec - ElectricCommander instance -# jobId - int identifier for the job -# -# Returns: -# - -# -################################ -sub abortJobAndReportError($$$) { - my ($cgi, $ec, $jobId) = @_; - - my $errMsg = "Aborting job after reaching timeout"; - - # Try to abort the job - my $xpath = $ec->abortJob($jobId); - my $errors = $ec->checkAllErrors($xpath); - if ("$errors" ne '') { - reportError($cgi, $errMsg . "\n" . $errors); - } - - # Wait for the job to finish aborting - $xpath = $ec->waitForJob($jobId, $gTimeout); - $errors = $ec->checkAllErrors($xpath); - if ("$errors" ne "") { - reportError($cgi, $errMsg . "\n" . $errors); - } - - # Check to see if the job actually aborted - my $status = $xpath->findvalue("//status"); - if ("$status" ne "completed") { - reportError($cgi, $errMsg . "\nJob still running after abort"); - } - - reportError($cgi, $errMsg . "\nJob successfully aborted"); -} ## end sub abortJobAndReportError($$$) - -################################ -# reportJobErrors - Look for errors in the job to report. -# -# Arguments: -# cgi -# ec - ElectricCommander instance -# jobId - int identifier for the job -# -# Returns: -# - -# -################################ -sub reportJobErrors($$$) { - my ($cgi, $ec, $jobId) = @_; - - # Get job details - my $xpath = $ec->getJobDetails($jobId); - my $procedureName = eval {$xpath->findvalue('//job/procedureName')->string_value();}; - my $errors = $ec->checkAllErrors($xpath); - if ("$errors" ne "") { - reportError($cgi, $errors); - } - - # Look for configError first - my $configError = $xpath->findvalue("//job/propertySheet/property[propertyName='configError']/value"); - if (defined $configError && "$configError" ne "") { - reportError($cgi, $configError) - } - - # Find the first error message and report it - my @errorMessages = $xpath->findnodes("//errorMessage"); - if (@errorMessages > 0) { - my $firstMessage = $errorMessages[0]->string_value(); - reportError($cgi, $firstMessage); - } - - # Report a generic error message if we couldn't find a specific one on the - # job - if ($procedureName && ($procedureName eq 'EditConfiguration')) { - reportError($cgi, "Edit configuration failed"); - } - else { - reportError($cgi, "Configuration creation failed"); - } -} ## end sub reportJobErrors($$$) - -################################ -# reportError - Print the error message and exit. -# -# Arguments: -# cgi -# error - string to print -# -# Returns: -# 0 - Success -# 1 - Error -# -################################ -sub reportError($$) { - my ($cgi, $error) = @_; - - print $cgi->header("text/html"); - print $error; - exit ERROR; -} - -################################ -# reportSuccess - Report success. -# -# Arguments: -# cgi -# -# Returns: -# - -# -################################ -sub reportSuccess($) { - my ($cgi) = @_; - - print $cgi->header("text/html"); - print "Success"; -} - -# ------------------------------------------------------------------------ -# validateUserSession -# -# Check current session on valid, if not - redirects -# user to the login page. -# ------------------------------------------------------------------------ -sub validateUserSession() { - - my $ec = new ElectricCommander({abortOnError => 0}); - $ec->login(); - if($ec->getError()) { - print "Location: ../../../\n\n"; - exit 0; - } -} - -validateUserSession(); - -main(); -exit SUCCESS; diff --git a/help/changelog.yaml b/help/changelog.yaml index 5d9708b..c84b200 100644 --- a/help/changelog.yaml +++ b/help/changelog.yaml @@ -1,5 +1,6 @@ 3.0.0: - Upgraded from Perl 5.8 to Perl 5.32. The plugin is not backward compatible with {PRODUCT} versions prior to 10.3. Starting from this release, a new agent is required to run EC-WebSphere plugin procedures. + - The support of new configurations has been added. 2.9.1: - Added session validation. 2.9.0: diff --git a/help/help.adoc b/help/help.adoc index 09cf274..e377163 100644 --- a/help/help.adoc +++ b/help/help.adoc @@ -4428,6 +4428,8 @@ Discover WebSphere instance configuration on a resources or environment - Upgraded from Perl 5.8 to Perl 5.32. The plugin is not backward compatible with {PRODUCT} versions prior to 10.3. Starting from this release, a new agent is required to run EC-WebSphere plugin procedures. +- The support of new configurations has been added. + === EC-WebSphere 2.9.1 diff --git a/specs/src/test/groovy/com/cloudbees/pdk/hen/WebSphere.groovy b/specs/src/test/groovy/com/cloudbees/pdk/hen/WebSphere.groovy index eff199b..866ae3f 100644 --- a/specs/src/test/groovy/com/cloudbees/pdk/hen/WebSphere.groovy +++ b/specs/src/test/groovy/com/cloudbees/pdk/hen/WebSphere.groovy @@ -8,6 +8,33 @@ import static com.cloudbees.pdk.hen.Utils.env class WebSphere extends Plugin { String resourceName = System.getenv('WAS_HOST') ?: "wsResource" + String wsUsername = System.getenv('WAS_USERNAME') ?: "" + String wsPassword = System.getenv('WAS_PASSWORD') ?: "" + String wsHost = System.getenv('WAS_HOST') ?: "" + String wsPort = System.getenv('WAS_PORT') ?: "" + String wsAdminPath = System.getenv('WSADMIN_PATH') ?: "" + String wsConnType = System.getenv('WAS_CONNTYPE') ?: "" + Credential cred = new Credential(userName: wsUsername, password: wsPassword) + + WebSphereConfig newConfig = WebSphereConfig + .create(this) + .conntype(wsConnType) + .wsadminabspath(wsAdminPath) + .websphereurl(wsHost) + .websphereport(wsPort) + .testconnectionres(wsHost) + .debug("1") + .credential(cred.userName, cred.password) + + WebSphereConfig newWrongConfig = WebSphereConfig + .create(this) + .conntype(wsConnType) + .wsadminabspath(wsAdminPath) + .websphereurl(wsHost + "zxcds") + .websphereport(wsPort) + .testconnectionres(wsHost) + .debug("1") + .credential(cred.userName, cred.password) static WebSphere create() { WebSphere plugin = new WebSphere(name: 'EC-WebSphere') @@ -16,7 +43,34 @@ class WebSphere extends Plugin { } static WebSphere createWithoutConfig() { // todo: possible problem is that different procedures contains different field name for configuration value - WebSphere plugin = new WebSphere(name: 'EC-WebSphere', configPath: 'websphere_cfgs', configFieldName: 'configurationName') + WebSphere plugin = new WebSphere( + name: 'EC-WebSphere', + configPath: 'websphere_cfgs', + configFieldName: 'configurationName', + configurationHandling: ConfigurationHandling.OLD + ) + return plugin + } + + static WebSphere createWithNewConfig() { + WebSphere plugin = new WebSphere( + name: 'EC-WebSphere', + configPath: 'websphere_cfgs', + configFieldName: 'configurationName', + configurationHandling: ConfigurationHandling.NEW + ) + plugin.configure(plugin.newConfig) + return plugin + } + + static WebSphere createWithNewWrongConfig() { + WebSphere plugin = new WebSphere( + name: 'EC-WebSphere', + configPath: 'websphere_cfgs', + configFieldName: 'configurationName', + configurationHandling: ConfigurationHandling.NEW + ) + plugin.configure(plugin.newWrongConfig) return plugin } @@ -153,4 +207,5 @@ class WebSphere extends Plugin { UpdateApp updateApp = UpdateApp.create(this) + TestConfiguration testConfiguration = TestConfiguration.create(this) } \ No newline at end of file diff --git a/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/EditConfiguration.groovy b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/EditConfiguration.groovy index 98bbd56..c635f5c 100644 --- a/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/EditConfiguration.groovy +++ b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/EditConfiguration.groovy @@ -3,7 +3,6 @@ package com.cloudbees.pdk.hen.procedures import groovy.transform.AutoClone import com.cloudbees.pdk.hen.* -@AutoClone //generated class EditConfiguration extends Procedure { @@ -18,9 +17,26 @@ class EditConfiguration extends Procedure { EditConfiguration flush() { this.flushParams() + this.contextUser = null return this } + EditConfiguration withUser(User user) { + this.contextUser = user + return this + } + + + EditConfiguration clone() { + EditConfiguration cloned = new EditConfiguration(procedureName: 'EditConfiguration', plugin: plugin, credentials: [ + + 'credential': null, + + ]) + cloned.parameters = this.parameters.clone() + return cloned + } + //Generated EditConfiguration config(String config) { diff --git a/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/TestConfiguration.groovy b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/TestConfiguration.groovy new file mode 100644 index 0000000..d0e3dbd --- /dev/null +++ b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/TestConfiguration.groovy @@ -0,0 +1,89 @@ +package com.cloudbees.pdk.hen.procedures + +import com.cloudbees.pdk.hen.* + +//generated +class TestConfiguration extends Procedure { + + static TestConfiguration create(Plugin plugin) { + return new TestConfiguration(procedureName: 'TestConfiguration', plugin: plugin, credentials: [ + + 'credential': null, + + ]) + } + + + TestConfiguration flush() { + this.flushParams() + this.contextUser = null + return this + } + + + TestConfiguration withUser(User user) { + this.contextUser = user + return this + } + + + TestConfiguration clone() { + TestConfiguration cloned = new TestConfiguration(procedureName: 'TestConfiguration', plugin: plugin, credentials: [ + + 'credential': null, + + ]) + cloned.parameters = this.parameters.clone() + return cloned + } + + //Generated + + TestConfiguration conntype(String conntype) { + this.addParam('conntype', conntype) + return this + } + + + TestConfiguration debug(boolean debug) { + this.addParam('debug', debug) + return this + } + + + TestConfiguration testconnectionres(String testconnectionres) { + this.addParam('test_connection_res', testconnectionres) + return this + } + + + TestConfiguration websphereport(String websphereport) { + this.addParam('websphere_port', websphereport) + return this + } + + + TestConfiguration websphereurl(String websphereurl) { + this.addParam('websphere_url', websphereurl) + return this + } + + + TestConfiguration wsadminabspath(String wsadminabspath) { + this.addParam('wsadminabspath', wsadminabspath) + return this + } + + + TestConfiguration credential(String user, String password) { + this.addCredential('credential', user, password) + return this + } + + + TestConfiguration credentialReference(String path) { + this.addCredentialReference('credential', path) + return this + } + +} \ No newline at end of file diff --git a/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/WebSphereConfig.groovy b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/WebSphereConfig.groovy index b430cfd..1ea2548 100644 --- a/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/WebSphereConfig.groovy +++ b/specs/src/test/groovy/com/cloudbees/pdk/hen/procedures/WebSphereConfig.groovy @@ -3,7 +3,6 @@ package com.cloudbees.pdk.hen.procedures import groovy.transform.AutoClone import com.cloudbees.pdk.hen.* -@AutoClone //generated class WebSphereConfig extends Procedure { @@ -18,9 +17,26 @@ class WebSphereConfig extends Procedure { WebSphereConfig flush() { this.flushParams() + this.contextUser = null return this } + WebSphereConfig withUser(User user) { + this.contextUser = user + return this + } + + + WebSphereConfig clone() { + WebSphereConfig cloned = new WebSphereConfig(procedureName: 'CreateConfiguration', plugin: plugin, credentials: [ + + 'credential': null, + + ]) + cloned.parameters = this.parameters.clone() + return cloned + } + //Generated WebSphereConfig config(String config) { diff --git a/specs/src/test/groovy/com/cloudbees/plugin/spec/CreateConfigurationWithExtCredsSuite.groovy b/specs/src/test/groovy/com/cloudbees/plugin/spec/CreateConfigurationWithExtCredsSuite.groovy index 070e97d..e61662a 100644 --- a/specs/src/test/groovy/com/cloudbees/plugin/spec/CreateConfigurationWithExtCredsSuite.groovy +++ b/specs/src/test/groovy/com/cloudbees/plugin/spec/CreateConfigurationWithExtCredsSuite.groovy @@ -1,5 +1,6 @@ package com.cloudbees.plugin.spec +import com.cloudbees.pdk.hen.ConfigurationHandling import com.cloudbees.pdk.hen.Credential import com.cloudbees.pdk.hen.ServerHandler import com.cloudbees.pdk.hen.Utils @@ -83,6 +84,7 @@ class CreateConfigurationWithExtCredsSuite extends Specification { def "Sanity. Create Config with credential reference/runtime credentials"() { when: "Create plugin config" WebSphere webSpherePlugin = WebSphere.createWithoutConfig() + webSpherePlugin.configurationHandling = ConfigurationHandling.OLD WebSphereConfig webSphereConfig = WebSphereConfig.create(webSpherePlugin) webSphereConfig.wsadminabspath(wsAdminPath) @@ -304,5 +306,44 @@ class CreateConfigurationWithExtCredsSuite extends Specification { Utils.CredsStates.WRONG_RUNTIME | Utils.CredsStates.RUNTIME | false | true | JobOutcome.SUCCESS | JobOutcome.SUCCESS | JobOutcome.ERROR | JobOutcome.SUCCESS } + @Sanity + @Unroll + def "Sanity. Create new configuration with credential reference/runtime credentials"() { + when: "Create plugin config" + WebSphere webSpherePlugin = WebSphere.createWithNewConfig() + + and: "Run Plugin Procedure - CheckNodeStatus" + def result = webSpherePlugin.checkNodeStatus + .wsadminAbsPath(wsAdminPath) + .nodeName(wsHost + "Node01") + .successCriteria("ALL_RUNNING") + .run() + + then: "Verify that procedure completed as expected and credentials in plugin exist or not exist" + assert result.isSuccessful() + verifyExistenceOfPluginsCredentials(Utils.CredsStates.REFERENCE, webSpherePlugin.configName, webSpherePlugin) + cleanup: + webSpherePlugin.deleteConfiguration(webSpherePlugin.configName) + } + + @Unroll + def "Negative. Create new configuration with credential reference/runtime credentials"() { + when: "Create plugin config" + WebSphere webSpherePlugin = WebSphere.createWithNewWrongConfig() + + and: "Run Plugin Procedure - CheckNodeStatus" + def result = webSpherePlugin.checkNodeStatus + .wsadminAbsPath(wsAdminPath) + .nodeName(wsHost + "Node01") + .successCriteria("ALL_RUNNING") + .run() + + then: "Verify that procedure completed as expected" + assert result.outcome == JobOutcome.ERROR + verifyExistenceOfPluginsCredentials(Utils.CredsStates.REFERENCE, webSpherePlugin.configName, webSpherePlugin) + + cleanup: + webSpherePlugin.deleteConfiguration(webSpherePlugin.configName) + } } diff --git a/specs/src/test/groovy/com/cloudbees/plugin/spec/DeleteConfigurationSuite.groovy b/specs/src/test/groovy/com/cloudbees/plugin/spec/DeleteConfigurationSuite.groovy index 98f5825..b2de5f6 100644 --- a/specs/src/test/groovy/com/cloudbees/plugin/spec/DeleteConfigurationSuite.groovy +++ b/specs/src/test/groovy/com/cloudbees/plugin/spec/DeleteConfigurationSuite.groovy @@ -1,5 +1,6 @@ package com.cloudbees.plugin.spec +import com.cloudbees.pdk.hen.ConfigurationHandling import com.cloudbees.pdk.hen.Credential import com.cloudbees.pdk.hen.JobOutcome import com.cloudbees.pdk.hen.ServerHandler @@ -43,6 +44,7 @@ class DeleteConfigurationSuite extends Specification{ def "Sanity. Delete Configuration"() { when: "Create plugin config" WebSphere webSpherePlugin = WebSphere.createWithoutConfig() + webSpherePlugin.configurationHandling = ConfigurationHandling.OLD WebSphereConfig webSphereConfig = WebSphereConfig.create(webSpherePlugin) webSphereConfig.wsadminabspath(wsAdminPath) diff --git a/specs/src/test/groovy/com/cloudbees/plugin/spec/TestConfigurationSuite.groovy b/specs/src/test/groovy/com/cloudbees/plugin/spec/TestConfigurationSuite.groovy new file mode 100644 index 0000000..c9a32ba --- /dev/null +++ b/specs/src/test/groovy/com/cloudbees/plugin/spec/TestConfigurationSuite.groovy @@ -0,0 +1,58 @@ +package com.cloudbees.plugin.spec + +import com.cloudbees.pdk.hen.ConfigurationHandling +import com.cloudbees.pdk.hen.JobOutcome +import com.cloudbees.pdk.hen.WebSphere +import spock.lang.Specification +import spock.lang.Unroll + +class TestConfigurationSuite extends Specification { + + String wsUsername = System.getenv('WAS_USERNAME') ?: "" + String wsPassword = System.getenv('WAS_PASSWORD') ?: "" + String wsHost = System.getenv('WAS_HOST') ?: "" + String wsPort = System.getenv('WAS_PORT') ?: "" + String wsAdminPath = System.getenv('WSADMIN_PATH') ?: "" + String wsConnType = System.getenv('WAS_CONNTYPE') ?: "" + + WebSphere webSpherePlugin = new WebSphere( + name: 'EC-WebSphere', + configurationHandling: ConfigurationHandling.NEW + ) + + @Unroll + def "Sanity. Test new configuration"() { + when: "Run Plugin Procedure - TestConfiguration" + def result = webSpherePlugin.testConfiguration + .conntype(wsConnType) + .wsadminabspath(wsAdminPath) + .websphereurl(wsHost) + .websphereport(wsPort) + .testconnectionres(wsHost) + .debug(true) + .credential(wsUsername, wsPassword) + .run() + + then: "Verify that procedure completed as expected" + assert result.isSuccessful() + assert result.getJobLog() =~ 'Connection succeeded' + } + + @Unroll + def "Negative. Test new configuration"() { + when: "Run Plugin Procedure - TestConfiguration" + def result = webSpherePlugin.testConfiguration + .conntype(wsConnType) + .wsadminabspath(wsAdminPath) + .websphereurl(wsHost) + .websphereport(wsPort) + .testconnectionres(wsHost) + .debug(true) + .credential(wsUsername, wsPassword + "sgdgdf") + .run() + + then: "Verify that procedure completed as expected" + assert result.outcome == JobOutcome.ERROR + assert result.getJobLog() =~ 'Error occurred while trying to create the configuration' + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index f089dea..8e6c368 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -28,6 +28,7 @@ Application Server 10 + true war/ecplugins.websphere.ConfigurationManagement/ecplugins.websphere.ConfigurationManagement.nocache.js diff --git a/src/main/resources/project/ec_setup.pl b/src/main/resources/project/ec_setup.pl index 611c361..6faffda 100644 --- a/src/main/resources/project/ec_setup.pl +++ b/src/main/resources/project/ec_setup.pl @@ -14,9 +14,28 @@ # limitations under the License. # use ElectricCommander::Util; +use strict; +use warnings; +no warnings 'redefine'; +use Data::Dumper; + +use ElectricCommander; +use JSON qw(decode_json); +use subs qw(debug); +use Time::HiRes qw(time gettimeofday tv_interval); + +my @logs = (); +sub debug($) { + my ($message) = @_; + push @logs, scalar time . ": " . $message; + + if ($ENV{EC_SETUP_DEBUG}) { + print scalar time . ": $message\n"; + } +} + # External Credential Manageent Update: # We're retrieving the steps with attached creds from property sheet -use JSON; my $stepsWithCredentials = getStepsWithCredentials(); # Data that drives the create step picker registration for this plugin. my %checkPageStatus = ( @@ -570,6 +589,116 @@ ); if ($upgradeAction eq "upgrade") { + + ## EC-WebSphere specific code + my $query = $commander->newBatch(); + + # When upgrading from older versions, find steps that call plugins procedures + # and remove extra outdated parameters + my @filterList = ({ 'propertyName' => 'subproject', + 'operator' => 'equals', + 'operand1' => '/plugins/@PLUGIN_KEY@/project' }); + + my $result = $commander->findObjects('procedureStep', { + filter => [ { operator => 'and', filter => \@filterList} ] + }); + + for my $procedureStep ($result->findnodes('//step')) { + my $projectName = $procedureStep->find('projectName')->string_value; + my $procedureName = $procedureStep->find('procedureName')->string_value; + my $stepName = $procedureStep->find('stepName')->string_value; + + if($procedureName eq 'UpdateApp') { + $query->deleteActualParameter($projectName, $procedureName, $stepName, 'isAppOnCluster'); + } + + $query->deleteActualParameter($projectName, $procedureName, $stepName, 'connectionType'); + } + + # Update old configs, set conntype to SOAP if it does not exists + my $old_configs_path = "/plugins/$otherPluginName/project/websphere_cfgs"; + my $configurations = $commander->getProperties({path => $old_configs_path}); + for my $configuration ($configurations->findnodes('//propertyName')) { + my $conntype_path = $old_configs_path.$configuration->string_value."/conntype"; + + my $conntype = $commander->getProperty($conntype_path); + if(!$conntype->find('//value')) { + $query->setProperty($conntype_path, 'SOAP'); + } + } + + my $olddiscovery = $query->getProperty("/plugins/$otherPluginName/project/ec_discovery/discovered_data"); + + local $self->{abortOnError} = 0; + $query->submit(); + + # Copy discovered data + if ($query->findvalue($olddiscovery, "code") ne "NoSuchProperty") { + $batch->clone({ + path => "/plugins/$otherPluginName/project/ec_discovery/discovered_data", + cloneName => "/plugins/$pluginName/project/ec_discovery/discovered_data" + }); + } + + #-------------------------------------------------------------- + # Update Time Limit + + # use Data::Dumper; + + my $oldProjectName = "/plugins/$otherPluginName/project"; + my $newProjectName = "/plugins/$pluginName/project"; + + # print Dumper($oldProjectName); + # print Dumper($newProjectName); + + for my $procedure ($commander->getProcedures({ projectName => $oldProjectName })->findnodes('//procedure')) { + my $procedureName = $procedure->findvalue('procedureName')->string_value; + # print("Procedure: $procedureName\n"); + for my $oldStep ($commander->getSteps({ projectName => $oldProjectName, procedureName => $procedureName })->findnodes('//step')) { + my $stepName = $oldStep->findvalue('stepName')->string_value; + # print("\tStep: $stepName\n"); + + my $oldTimeLimit = $oldStep->findvalue("//timeLimit"); + next unless($oldTimeLimit); + + my $oldTimeLimitUnits = $oldStep->findvalue("//timeLimitUnits"); + next unless($oldTimeLimitUnits); + + my $newStep = $commander->getStep($newProjectName, $procedureName, $stepName); + + my $newTimeLimit = $newStep->findvalue("//timeLimit"); + next unless($newTimeLimit); + + my $newTimeLimitUnits = $newStep->findvalue("//timeLimitUnits"); + next unless($newTimeLimitUnits); + + my $oldLimit = $oldTimeLimit->value; + my $oldLimitUnits = $oldTimeLimitUnits->value; + # print("\t\toldLimit: $oldLimit; $oldLimitUnits\n"); + + my $res = $commander->modifyStep($newProjectName, $procedureName, $stepName, {timeLimit => $oldLimit, timeLimitUnits => $oldLimitUnits}); + + my @errors = $res->findErrors; + if (@errors > 0) { + # print Dumper(\@errors); + next + } + + # print("\t\OK\n"); + } + + } + + ## End of EC-WebSphere specific code + + migrateConfigurations($otherPluginName); + migrateProperties($otherPluginName); + debug "Migrated properties"; + reattachExternalCredentials($otherPluginName); +} + +# Disabling this branch of logic temporary +if (0 && $upgradeAction eq "upgrade") { my $query = $commander->newBatch(); # When upgrading from older versions, find steps that call plugins procedures @@ -726,6 +855,18 @@ } } +if ($promoteAction eq "promote") { + reattachExternalConfigurations($otherPluginName); +} + +sub get_major_minor { + my ($version) = @_; + + if ($version =~ m/^(\d+\.\d+)/) { + return $1; + } + return undef; +} sub reattachExternalCredentials { my ($otherPluginName) = @_; @@ -766,10 +907,9 @@ sub reattachExternalCredentials { sub getConfigLocation { my ($otherPluginName) = @_; - my $configName = 'websphere_cfgs'; - # my $configName = eval { - # $commander->getProperty("/plugins/$otherPluginName/project/ec_configPropertySheet")->findvalue('//value')->string_value - # } || 'ec_plugin_cfgs'; + my $configName = eval { + $commander->getProperty("/plugins/$otherPluginName/project/ec_configPropertySheet")->findvalue('//value')->string_value + } || 'websphere_cfgs'; return $configName; } @@ -782,3 +922,138 @@ sub getStepsWithCredentials { }; return $retval; } + +sub reattachExternalConfigurations { + my ($otherPluginName) = @_; + + my %migrated = (); + # For the configurations that exists while the plugin was deleted + # The api is new so it requires the upgraded version of the agent + eval { + my $cfgs = $commander->getPluginConfigurations({ + pluginKey => '@PLUGIN_KEY@', + }); + my @creds = (); + for my $cfg ($cfgs->findnodes('//pluginConfiguration/credentialMappings/parameterDetail')) { + my $value = $cfg->findvalue('parameterValue')->string_value(); + push @creds, $value; + } + + for my $cred (@creds) { + next if $migrated{$cred}; + for my $stepWithCreds (@$stepsWithCredentials) { + $commander->attachCredential({ + projectName => "/plugins/$pluginName/project", + credentialName => $cred, + procedureName => $stepWithCreds->{procedureName}, + stepName => $stepWithCreds->{stepName} + }); + } + $migrated{$cred} = 1; + debug "Migrated $cred"; + } + 1; + } or do { + debug "getPluginConfiguration API is not supported on the promoting agent, falling back"; + for my $stepWithCreds (@$stepsWithCredentials) { + my $step = $commander->getStep({ + projectName => "/plugins/$otherPluginName/project", + procedureName => $stepWithCreds->{procedureName}, + stepName => $stepWithCreds->{stepName}, + }); + for my $attachedCred ($step->findnodes('//attachedCredentials/credentialName')) { + my $credName = $attachedCred->string_value(); + $commander->attachCredential({ + projectName => "/plugins/$pluginName/project", + credentialName => $credName, + procedureName => $stepWithCreds->{procedureName}, + stepName => $stepWithCreds->{stepName} + }); + $migrated{$credName} = 1; + debug "Migrated credential $credName to $stepWithCreds->{procedureName}"; + } + } + }; +} + +sub migrateConfigurations { + my ($otherPluginName) = @_; + + my $configName = getConfigLocation($otherPluginName); + # my $configName = eval { + # $commander->getProperty("/plugins/$otherPluginName/project/ec_configPropertySheet")->findvalue('//value')->string_value + # } || 'ec_plugin_cfgs'; + + $commander->clone({ + path => "/plugins/$otherPluginName/project/$configName", + cloneName => "/plugins/$pluginName/project/$configName" + }); + + my $xpath = $commander->getCredentials("/plugins/$otherPluginName/project"); + for my $credential ($xpath->findnodes('//credential')) { + my $credName = $credential->findvalue('credentialName')->string_value; + + # If credential name starts with "/", it means that it is a reference. + # We do not need to clone it. + # if ($credName !~ m|^\/|s) { + debug "Migrating old configuration $credName"; + $batch->clone({ + path => "/plugins/$otherPluginName/project/credentials/$credName", + cloneName => "/plugins/$pluginName/project/credentials/$credName" + }); + $batch->deleteAclEntry({ + principalName => "project: $otherPluginName", + projectName => $pluginName, + credentialName => $credName, + principalType => 'user' + }); + $batch->deleteAclEntry({ + principalType => 'user', + principalName => "project: $pluginName", + credentialName => $credName, + projectName => $pluginName, + }); + + $batch->createAclEntry({ + principalType => 'user', + principalName => "project: $pluginName", + projectName => $pluginName, + credentialName => $credName, + objectType => 'credential', + readPrivilege => 'allow', + modifyPrivilege => 'allow', + executePrivilege => 'allow', + changePermissionsPrivilege => 'allow' + }); + #} + + for my $step (@$stepsWithCredentials) { + $batch->attachCredential({ + projectName => $pluginName, + procedureName => $step->{procedureName}, + stepName => $step->{stepName}, + credentialName => $credName, + }); + debug "Attached credential to $step->{stepName}"; + } + } +} + +sub migrateProperties { + my ($otherPluginName) = @_; + my $clonedPropertySheets = eval { + decode_json($commander->getProperty("/plugins/$otherPluginName/project/ec_clonedProperties")->findvalue('//value')->string_value); + }; + unless ($clonedPropertySheets) { + debug "No properties to migrate"; + return; + } + + for my $prop (@$clonedPropertySheets) { + $commander->clone({ + path => "/plugins/$otherPluginName/project/$prop", + cloneName => "/plugins/$pluginName/project/$prop" + }); + debug "Cloned $prop" + } +} diff --git a/src/main/resources/project/manifest.xml b/src/main/resources/project/manifest.xml index e3e7706..821c5f1 100644 --- a/src/main/resources/project/manifest.xml +++ b/src/main/resources/project/manifest.xml @@ -143,6 +143,14 @@ //property[propertyName="ui_forms"]/propertySheet/property[propertyName="WebSphereCreateConfigForm"]/value WebSphereCreateConfigForm.xml + + newConfigForm.xml + //procedure[procedureName="ConfigurationParametersHolder"]/propertySheet/property[propertyName="ec_parameterForm"]/value + + + stepsWithAttachedCredentials.json + //property[propertyName="ec_config"]/propertySheet/property[propertyName="stepsWithAttachedCredentials"]/value + //property[propertyName="ui_forms"]/propertySheet/property[propertyName="WebSphereEditConfigForm"]/value WebSphereEditConfigForm.xml @@ -377,7 +385,7 @@ //procedure[procedureName="CreateConfiguration"]/propertySheet/property[propertyName="ec_stepsWithAttachedCredentials"]/value - procedures_with_credentials.json + stepsWithAttachedCredentials.json @@ -388,6 +396,10 @@ conf/attemptConnection.pl //procedure[procedureName="EditConfiguration"]/step[stepName="AttemptConnection"]/command + + conf/attemptConnection.pl + //procedure[procedureName="TestConfiguration"]/step[stepName="AttemptConnection"]/command + conf/editConfiguration.pl //procedure[procedureName="EditConfiguration"]/step[stepName="EditConfiguration"]/command diff --git a/src/main/resources/project/newConfigForm.xml b/src/main/resources/project/newConfigForm.xml new file mode 100644 index 0000000..c147d05 --- /dev/null +++ b/src/main/resources/project/newConfigForm.xml @@ -0,0 +1,101 @@ + + + + + entry + + wsadminabspath + + Absolute path to wsadmin script. + 1 + + + + select + + conntype + 1 + Specifies type of connection to use to connect to the application server that you want to administer. + + + + + + + + + entry + + websphere_url + + Hostname of the WebSphere Application Server to administer using wsadmin tool. For example: 10.200.1.234 or yourWSServer. + 1 + + + + entry + + websphere_port + + Port of WebSphere Application server to which wsadmin should connect.Give the port number based on the type of connection you choose.For example, if you want to connect to application server using SOAP connection give the port number of SOAP connector of that server. + 0 + + + + credential + true + + credential + + 0 + Credentials used to connect to WebSphere instance. + + + + + debug + Debug level, higher debug level - more debug messages. Warning: on debug level 10 and more passwords will be revealed in a procedure logs. + 0 + select + + + + + + + entry + + test_connection_res + + A resource which is used for the testing connection. + 0 + + + + + diff --git a/src/main/resources/project/pdk/FlowPDF.pm b/src/main/resources/project/pdk/FlowPDF.pm index 4314bcd..6def82c 100644 --- a/src/main/resources/project/pdk/FlowPDF.pm +++ b/src/main/resources/project/pdk/FlowPDF.pm @@ -125,7 +125,7 @@ use FlowPDF::Log::FW; use FlowPDF::Exception::MissingFunctionDefinition; use FlowPDF::Exception::MissingFunctionArgument; -our $VERSION = '1.3.4'; +our $VERSION = '1.5.0'; # We need to do an autoflush for STDOUT and STDERR to not mess up output streams. # $| is a local variable for currently selected file descriptor. diff --git a/src/main/resources/project/pdk/FlowPDF/Component/Proxy.pm b/src/main/resources/project/pdk/FlowPDF/Component/Proxy.pm index 967260b..14bd53c 100644 --- a/src/main/resources/project/pdk/FlowPDF/Component/Proxy.pm +++ b/src/main/resources/project/pdk/FlowPDF/Component/Proxy.pm @@ -125,6 +125,27 @@ and be sure that proxy is set. sub apply { my ($self) = @_; + if ($self->is_legacy_perl()){ + return $self->apply_5_8_9(); + } + + return $self->apply_5_32_1(); + +} + +sub apply_5_32_1 { + my ($self) = @_; + + ## At this moment we do not need to set the proxy envs. + ## but for the reason of backward compatibility, we have to set + ## HTTPS_PROXY_USERNAME and HTTPS_PROXY_PASSWORD + $self->apply_5_8_9(); + return $self; +} + +sub apply_5_8_9 { + my ($self) = @_; + unless ($self->url()) { $self->debug_msg("No proxy url has been provided. Nothing to do."); } @@ -170,6 +191,24 @@ Disables proxy for a whole context. It could be useful sometimes to revert all c sub detach { my ($self) = @_; + if ($self->is_legacy_perl()) { + return $self->detach_5_8_9(); + } + return $self->detach_5_32_1(); +} + + +sub detach_5_32_1 { + my ($self) = @_; + + $self->detach_5_8_9(); + return $self; +} + + +sub detach_5_8_9 { + my ($self) = @_; + while (my $e = pop(@{$self->{__detach_list}})) { $ENV{$e} = '[PROTECTED]' if $e eq 'HTTPS_PROXY_PASSWORD'; $self->debug_msg("Detaching ENV $e value ($ENV{$e})"); @@ -305,6 +344,24 @@ Augments HTTP::Request object with proxy headers. sub augment_request { my ($self, $request_object) = @_; + if ($self->is_legacy_perl()){ + return $self->augment_request_5_8_9($request_object); + } + return $self->augment_request_5_32_1($request_object); +} + + +sub augment_request_5_32_1 { + my ($self, $request_object) = @_; + + $request_object = $self->augment_request_5_8_9($request_object); + return $request_object; +} + + +sub augment_request_5_8_9 { + my ($self, $request_object) = @_; + if (!$request_object) { croak "Request object could not be empty"; } @@ -351,6 +408,41 @@ Augments LWP::UserAgent object with proxy information. sub augment_lwp { my ($self, $ua) = @_; + if ($self->is_legacy_perl()) { + return $self->augment_lwp_5_8_9($ua); + } + return $self->augment_lwp_5_32_1($ua); + +} + + +sub augment_lwp_5_32_1 { + my ($self, $ua) = @_; + + if (!$ua) { + croak "LWP object could not be empty"; + } + if (ref $ua ne 'LWP::UserAgent') { + croak "LWP::UserAgent object expected, got: ", ref $ua; + } + my $proxy_url = $self->url(); + if ($proxy_url) { + $self->debug_msg("Augmenting LWP object with HTTP AND HTPS proxy settings: ", $proxy_url); + if ($proxy_url =~ m/^https:/s) { + $ua->proxy(['https'] => $proxy_url); + } + elsif ($proxy_url =~ m/^http:/s) { + $ua->proxy(['http'] => $proxy_url); + } + } + + return $ua; +} + + +sub augment_lwp_5_8_9 { + my ($self, $ua) = @_; + if (!$ua) { croak "LWP object could not be empty"; } @@ -403,6 +495,16 @@ sub debug_msg { return 1; } +## private +# This function returns whether the perl is legacy or new. The way of handling the proxy settings is completely different +# in these 2 perls. +sub is_legacy_perl { + if ($] <= 5.008009) { + return 1; + } + return 0; +} + 1; =back diff --git a/src/main/resources/project/pdk/FlowPDF/Context.pm b/src/main/resources/project/pdk/FlowPDF/Context.pm index 68016be..eefa474 100644 --- a/src/main/resources/project/pdk/FlowPDF/Context.pm +++ b/src/main/resources/project/pdk/FlowPDF/Context.pm @@ -55,6 +55,7 @@ use Try::Tiny; use FlowPDF::Exception::ConfigDoesNotExist; use FlowPDF::Exception::EntityDoesNotExist; use FlowPDF::Exception::RuntimeException; +use FlowPDF::Exception::UnexpectedEmptyValue; use FlowPDF::Constants qw/ DEBUG_LEVEL_PROPERTY @@ -400,7 +401,7 @@ This method returns a L object that represents plugin configura =over 4 -=item None +=item (Optional) (HASH ref) parameters: configName: Optional configuration to get by name ignoring default autoresolve logic. =back @@ -421,16 +422,30 @@ This method returns a L object that represents plugin configura if ($cred) { print "Secret value is: ", $cred->getSecretValue(), "\n"; } + # or get other config of the current plugin: + my $configValues = $context->getConfigValues({configName => 'myOtherConfig'}); %%%LANG%%% =cut sub getConfigValues { - my ($context, $optionalConfigName) = @_; + my ($context, $params) = @_; - if (my $retval = $context->getCurrentStepConfigValues()) { - return $retval; + my $configName = undef; + my $autoDetectConfig = 1; + + # Get config name. Otherwise the function will determine automatically + # where to get the config and will return it. + if ($params->{configName}) { + $configName = $params->{configName}; + $autoDetectConfig = 0; + fwLogTrace("Optional configName => $configName has been provided to getConfigValues call."); + } + + # TODO: Implement caching for custom configs if required. + if ($autoDetectConfig && $context->getCurrentStepConfigValues()) { + return $context->getCurrentStepConfigValues(); } # This case is special. During CreateConfiguration we don't have config itself. @@ -451,34 +466,59 @@ sub getConfigValues { my $configFields = $po->getConfigFields(); my $configField = undef; - for my $field (@$configFields) { - if ($stepParameters->isParameterExists($field)) { - $configField = $field; - last; + if ($autoDetectConfig) { + for my $field (@$configFields) { + if ($stepParameters->isParameterExists($field)) { + $configField = $field; + last; + } + } + if ($autoDetectConfig && !$configField && $context->getHasConfigField()) { + FlowPDF::Exception::EntityDoesNotExist->new( + "No config field detected in current step parameters" + )->throw(); } - } - - if (!$configField && $context->getHasConfigField()) { - FlowPDF::Exception::EntityDoesNotExist->new( - "No config field detected in current step parameters" - )->throw(); } my $configHash = undef; - if ($context->getHasConfigField()) { - for my $location (@$configLocations) { - my $tempConfig = $context->retrieveConfigByNameAndLocation( - $stepParameters->getParameter($configField)->getValue(), - $location + + if (!$autoDetectConfig || $context->getHasConfigField()) { + my $configNameToGet = undef; + if (defined $configName) { + $configNameToGet = $configName; + } + else { + $configNameToGet = $stepParameters->getParameter($configField)->getValue(); + } + + if ($configNameToGet =~ m|^/|) { + # New configuration object + my $plugin_project_name = sprintf( + '%s-%s', + $po->getPluginName(), + $po->getPluginVersion() ); - if ($tempConfig) { - $configHash = $tempConfig; - last; + $configHash = $context->_readPluginConfiguration($configNameToGet, $po, $plugin_project_name); + } + else { + for my $location (@$configLocations) { + my $tempConfig = $context->retrieveConfigByNameAndLocation( + $configNameToGet, + $location + ); + + if ($tempConfig) { + $configHash = $tempConfig; + last; + } } } } # TODO: Improve this error message. - if (!$configHash && $context->getHasConfigField()) { + # This exception is being thrown in 1 of 2 scenarios: + # 1. When current step has config field and config does not exist. + # 2. When optional config name is provided and config does not exist. + if ((!$autoDetectConfig || $context->getHasConfigField()) && !$configHash) { FlowPDF::Exception::ConfigDoesNotExist->new({ configName => $stepParameters->getParameter($configField)->getValue() })->throw(); @@ -487,26 +527,6 @@ sub getConfigValues { my $configValuesHash = {}; $context->populateDefaultConfigValues($configHash); - # handling user defined default config values. - # my $defaultConfigValues = $po->getDefaultConfigValues(); - # $defaultConfigValues ||= {}; - - # for my $cv (keys %$defaultConfigValues) { - # if (defined $configHash->{$cv}) { - # logWarning("The config field '$cv' that was set to default value in plugin code is present in configuration. Default value from plugin code is ignored."); - # next; - # } - # if ($cv =~ m/_credential$/s) { - # if (!defined $defaultConfigValues->{$cv}->{userName} && !defined $defaultConfigValues->{$cv}->{password}) { - # logWarning("Missing userName and password for the default credential"); - # next; - # } - # } - - # $configHash->{$cv} = $defaultConfigValues->{$cv}; - # } - # end of handling default config values - for my $k (keys %$configHash) { push @$keys, $k; @@ -536,7 +556,11 @@ sub getConfigValues { parameters => $configValuesHash }); - $context->setCurrentStepConfigValues($retval); + # We're caching config values if and only if + # the default logic is being executed. + if ($autoDetectConfig) { + $context->setCurrentStepConfigValues($retval); + } return $retval; } @@ -1085,7 +1109,7 @@ sub isCheckConnectionInCreateConfigurationContext { my $procedureName = $self->getProcedureName(); my $stepName = $self->getStepName(); - if ($stepName eq 'checkConnection' && $procedureName eq 'CreateConfiguration') { + if ($stepName eq 'checkConnection' && ($procedureName eq 'CreateConfiguration' || $procedureName eq 'TestConfiguration') ) { return 1; } return 0; @@ -1193,4 +1217,88 @@ sub isCredential { } return 0; } + +# private +# handling of the new pluginConfiguration object +sub _readPluginConfiguration { + my ($self, $configName, $po, $pluginProjectName) = @_; + + my (undef, undef, $configProjectName, undef, $cfgName) = split(/\// => $configName); + + my $cfg; + eval { + $cfg = $self->getEc()->getPluginConfiguration({ + projectName => $configProjectName, + pluginConfigurationName => $cfgName + }); + 1 + } or do { + my $err = $@; + if ($err =~ /NoSuchPluginConfiguration/) { + FlowPDF::Exception::UnexpectedEmptyValue->new("Plugin configuration '$cfgName' does not exist in the project '$configProjectName'")->throw(); + } + else { + die $err; + } + }; + + # todo procedure does not exist + my $formalParameters = $self->getEc()->getFormalParameters({ + projectName => $pluginProjectName, + procedureName => 'ConfigurationParametersHolder' + }); + + my $fields = {}; + for my $f ($cfg->findnodes('//fields/parameterDetail')) { + my $name = $f->findvalue('parameterName')->string_value(); + my $value = $f->findvalue('parameterValue')->string_value(); + if ($value =~ /\$\[/) { + $value = $self->getEc()->expandString({value => $value, jobId => $ENV{COMMANDER_JOBID}})->findvalue('//value')->string_value(); + } + $fields->{$name} = $value; + } + + my $credentials = {}; + for my $cred ($cfg->findnodes('//credentialMappings/parameterDetail')) { + my $name = $cred->findvalue('parameterName')->string_value(); + my $value = $cred->findvalue('parameterValue')->string_value(); + $credentials->{$name} = $value; + } + + for my $formalParameter ($formalParameters->findnodes('//formalParameter')) { + my $name = $formalParameter->findvalue('formalParameterName')->string_value(); + my $type = $formalParameter->findvalue('type')->string_value(); + my $required = $formalParameter->findvalue('required')->string_value(); + + if ($type eq 'credential') { + my $path = $credentials->{$name}; + unless($path) { + if ($required eq '1' || $required eq 'true') { + FlowPDF::Exception::UnexpectedEmptyValue->new("Credential $name is required but not provided by the configuration")->throw(); + } + else { + next; + } + } + my $cred = $self->getEc()->getFullCredential($path); + $fields->{$name} = { + userName => $cred->findvalue('//userName')->string_value(), + password => $cred->findvalue('//password')->string_value() + }; + + if ($fields->{$name}->{password}) { + FlowPDF::Log->setMaskPatterns($fields->{$name}->{password}); + } + } + + if ($required eq '1' || $required eq 'true') { + unless($fields->{$name}) { + FlowPDF::Exception::UnexpectedEmptyValue->new("Parameter $name is required but not provided by the configuration")->throw(); + } + } + } + + return $fields; +} + 1; diff --git a/src/main/resources/project/pdk/FlowPDF/Log.pm b/src/main/resources/project/pdk/FlowPDF/Log.pm index c0a9128..7e8429c 100644 --- a/src/main/resources/project/pdk/FlowPDF/Log.pm +++ b/src/main/resources/project/pdk/FlowPDF/Log.pm @@ -385,7 +385,7 @@ sub setLogLevel { my ($param1, $param2) = @_; if (ref $param1 and ref $param1 ne __PACKAGE__) { - croak (q|Expected a reference to FlowPDF::Log, not a '| . ref $param1 . q|' reference|); + croak (sprintf(q|Expected a reference to FlowPDF::Log, not a '%s' reference|, ref $param1)); } if (ref $param1) { diff --git a/src/main/resources/project/pdk/FlowPDF/Log/FW.pm b/src/main/resources/project/pdk/FlowPDF/Log/FW.pm index 4170db3..026e688 100644 --- a/src/main/resources/project/pdk/FlowPDF/Log/FW.pm +++ b/src/main/resources/project/pdk/FlowPDF/Log/FW.pm @@ -235,7 +235,7 @@ sub setLogToProperty { # 1st case, when param 1 is a reference, we are going to set log to property for current object. # but if this reference is not a FlowPDF::Log reference, it will bailOut if (ref $param1 and ref $param1 ne __PACKAGE__) { - croak(q|Expected a reference to FlowPDF::Log, not a '| . ref $param1 . q|' reference|); + croak (sprintf(q|Expected a reference to FlowPDF::Log::FW, not a '%s' reference|, ref $param1)); } if (ref $param1) { @@ -274,7 +274,7 @@ sub setLogToFile { # 1st case, when param 1 is a reference, we are going to set log to file for current object. # but if this reference is not a FlowPDF::Log reference, it will bailOut if (ref $param1 and ref $param1 ne __PACKAGE__) { - croak(q|Expected a reference to FlowPDF::Log, not a '| . ref $param1 . q|' reference|); + croak (sprintf(q|Expected a reference to FlowPDF::Log::FW, not a '%s' reference|, ref $param1)); } if (ref $param1) { @@ -322,7 +322,7 @@ sub setLogLevel { my ($param1, $param2) = @_; if (ref $param1 and ref $param1 ne __PACKAGE__) { - croak (q|Expected a reference to FlowPDF::Log, not a '| . ref $param1 . q|' reference|); + croak (sprintf(q|Expected a reference to FlowPDF::Log::FW, not a '%s' reference|, ref $param1)); } if (ref $param1) { diff --git a/src/main/resources/project/project.xml b/src/main/resources/project/project.xml index a2774ef..1e620d0 100644 --- a/src/main/resources/project/project.xml +++ b/src/main/resources/project/project.xml @@ -363,10 +363,19 @@ ec_formXmlCompliant true + + ec_configCompliant + true + ec_config + + stepsWithAttachedCredentials + 0 + + configLocation 0 @@ -13885,5 +13894,345 @@ + + + + + + + ConfigurationParametersHolder + ConfigurationParametersHolder + websphere-holder-$[jobId] + + + @PLUGIN_KEY@-@PLUGIN_VERSION@ + + + ec_parameterForm + + + + ec_customEditorData + + + parameters + + + wsadminabspath + + + formType + 1 + standard + + + + + conntype + + + formType + 1 + standard + + + + + websphere_url + + + formType + 1 + standard + + + + + websphere_port + + + formType + 1 + standard + + + + + credential + + + formType + 1 + standard + + + + + debug + + + formType + 1 + standard + + + + + + + + + + + + + + + + + + + + wsadminabspath + + wsadmin absolute path + 1 + entry + + + conntype + + Specifies type of connection to use to connect to the application server that you want to administer. + 1 + entry + + + websphere_url + + Hostname of the WebSphere Application Server to administer using wsadmin tool. + 1 + entry + + + websphere_port + + Port of WebSphere Application server to which wsadmin should connect.Give the port number based on the type of connection you choose.For example, if you want to connect to application server using SOAP connection give the port number of SOAP connector of that server. + 0 + entry + + + credential + + + 0 + credential + + + debug + + Enable debugging. + 0 + checkbox + + + + + + + + + + test_connection_res + + A resource which is used for the testing connection. + 0 + entry + + + + + + + + + TestConfiguration + TestConfiguration + websphere-test-config-$[jobId] + + + @PLUGIN_KEY@-@PLUGIN_VERSION@ + + + ec_customEditorData + + + parameters + + + wsadminabspath + + + formType + 1 + standard + + + + + conntype + + + formType + 1 + standard + + + + + websphere_url + + + formType + 1 + standard + + + + + websphere_port + + + formType + 1 + standard + + + + + credential + + + formType + 1 + standard + + + + + debug + + + formType + 1 + standard + + + + + test_connection_res + + + formType + 1 + standard + + + + + + + + + + wsadminabspath + + wsadmin absolute path + 1 + entry + + + conntype + + Specifies type of connection to use to connect to the application server that you want to administer. + 1 + entry + + + websphere_url + + Hostname of the WebSphere Application Server to administer using wsadmin tool. + 1 + entry + + + websphere_port + + Port of WebSphere Application server to which wsadmin should connect.Give the port number based on the type of connection you choose.For example, if you want to connect to application server using SOAP connection give the port number of SOAP connector of that server. + 0 + entry + + + credential + + + 0 + credential + + + debug + + Enable debugging. + 0 + checkbox + + + test_connection_res + + A resource which is used for the testing connection. + 0 + entry + + + AttemptConnection + 0 + 0 + + + + abortJob + 0 + + 0 + $[/myProject/postp_loader] + 0 + $[test_connection_res] + 0 + cb-perl + + minutes + + + TestConfiguration + @PLUGIN_KEY@-@PLUGIN_VERSION@ + + + ec_customEditorData + + + formType + 1 + command + + + + + + credential + + + + + + diff --git a/src/main/resources/project/stepsWithAttachedCredentials.json b/src/main/resources/project/stepsWithAttachedCredentials.json new file mode 100644 index 0000000..73fcaf0 --- /dev/null +++ b/src/main/resources/project/stepsWithAttachedCredentials.json @@ -0,0 +1,234 @@ +[ + { + "procedureName": "StopServer", + "stepName": "StopInstance" + }, + { + "procedureName": "CheckServerStatus", + "stepName": "CheckServerStatus" + }, + { + "procedureName": "RunCustomJob", + "stepName": "RunJob" + }, + { + "procedureName": "StartApp", + "stepName": "StartApp" + }, + { + "procedureName": "StopApp", + "stepName": "StopApp" + }, + { + "stepName": "DeployApp", + "procedureName": "DeployApp" + }, + { + "procedureName": "UndeployApp", + "stepName": "UndeployApp" + }, + { + "procedureName": "CheckApp", + "stepName": "CheckApp" + }, + { + "stepName": "DeployEnterpriseApp", + "procedureName": "DeployEnterpriseApp" + }, + { + "stepName": "UpdateApp", + "procedureName": "UpdateApp" + }, + { + "stepName": "ConfigEJBContainer", + "procedureName": "ConfigEJBContainer" + }, + { + "procedureName": "CreateEndToEndMailProvider", + "stepName": "CreateEndToEndMailProvider" + }, + { + "procedureName": "DeployOSGiApp", + "stepName": "DeployOSGiApp" + }, + { + "procedureName": "publishWSDL", + "stepName": "publishWSDL" + }, + { + "procedureName": "RemoveClusterMembers", + "stepName": "RemoveClusterMembers" + }, + { + "stepName": "DeleteCluster", + "procedureName": "DeleteCluster" + }, + { + "procedureName": "ListClusterMembers", + "stepName": "ListClusterMembers" + }, + { + "stepName": "StartCluster", + "procedureName": "StartCluster" + }, + { + "stepName": "StopCluster", + "procedureName": "StopCluster" + }, + { + "stepName": "CreateCluster", + "procedureName": "CreateCluster" + }, + { + "stepName": "ConfigureSession", + "procedureName": "ConfigureSession" + }, + { + "stepName": "CreateJMSProvider", + "procedureName": "CreateJMSProvider" + }, + { + "stepName": "CreateMailSession", + "procedureName": "CreateMailSession" + }, + { + "procedureName": "Discover", + "stepName": "DiscoverResources" + }, + { + "procedureName": "DiscoverResource", + "stepName": "DiscoverResource" + }, + { + "procedureName": "MapSharedLibrary", + "stepName": "MapSharedLibrary" + }, + { + "procedureName": "ModifyApplicationClassLoader", + "stepName": "ModifyApplicationClassLoader" + }, + { + "procedureName": "SyncNodes", + "stepName": "SyncNodes" + }, + { + "stepName": "CheckNodeStatus", + "procedureName": "CheckNodeStatus" + }, + { + "stepName": "CreateJDBCProvider", + "procedureName": "CreateJDBCProvider" + }, + { + "procedureName": "DeleteJDBCProvider", + "stepName": "DeleteJDBCProvider" + }, + { + "procedureName": "CreateDatasource", + "stepName": "CreateDatasource" + }, + { + "procedureName": "DeleteDatasource", + "stepName": "DeleteDatasource" + }, + { + "procedureName": "CreateOrUpdateJMSQueue", + "stepName": "CreateOrUpdateJMSQueue" + }, + { + "stepName": "CreateOrUpdateJMSTopic", + "procedureName": "CreateOrUpdateJMSTopic" + }, + { + "stepName": "DeleteJMSQueue", + "procedureName": "DeleteJMSQueue" + }, + { + "procedureName": "DeleteJMSTopic", + "stepName": "DeleteJMSTopic" + }, + { + "stepName": "CreateOrUpdateWMQJMSActivationSpec", + "procedureName": "CreateOrUpdateWMQJMSActivationSpec" + }, + { + "procedureName": "CreateOrUpdateSIBJMSActivationSpec", + "stepName": "CreateOrUpdateSIBJMSActivationSpec" + }, + { + "stepName": "DeleteJMSActivationSpec", + "procedureName": "DeleteJMSActivationSpec" + }, + { + "procedureName": "CreateOrUpdateWMQJMSConnectionFactory", + "stepName": "CreateOrUpdateWMQJMSConnectionFactory" + }, + { + "stepName": "CreateOrUpdateSIBJMSConnectionFactory", + "procedureName": "CreateOrUpdateSIBJMSConnectionFactory" + }, + { + "stepName": "DeleteJMSConnectionFactory", + "procedureName": "DeleteJMSConnectionFactory" + }, + { + "stepName": "DeleteJMSProvider", + "procedureName": "DeleteJMSProvider" + }, + { + "procedureName": "CreateApplicationServer", + "stepName": "CreateApplicationServer" + }, + { + "procedureName": "CreateApplicationServerTemplate", + "stepName": "CreateApplicationServerTemplate" + }, + { + "procedureName": "DeleteApplicationServerTemplate", + "stepName": "DeleteApplicationServerTemplate" + }, + { + "stepName": "StartApplicationServers", + "procedureName": "StartApplicationServers" + }, + { + "procedureName": "StopApplicationServers", + "stepName": "StopApplicationServers" + }, + { + "procedureName": "ExportApplicationServer", + "stepName": "ExportApplicationServer" + }, + { + "procedureName": "ImportApplicationServer", + "stepName": "ImportApplicationServer" + }, + { + "procedureName": "DeleteApplicationServer", + "stepName": "DeleteApplicationServer" + }, + { + "procedureName": "StartDeploymentManager", + "stepName": "StartDeploymentManager" + }, + { + "procedureName": "StopDeploymentManager", + "stepName": "StopDeploymentManager" + }, + { + "procedureName": "StopNode", + "stepName": "StopNode" + }, + { + "stepName": "StartNode", + "procedureName": "StartNode" + }, + { + "stepName": "CreateFirstClusterMember", + "procedureName": "CreateFirstClusterMember" + }, + { + "stepName": "CreateClusterMembers", + "procedureName": "CreateClusterMembers" + } +]