Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redfishpower: support setplugs configuration #157

Merged
merged 4 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions man/redfishpower.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ Set path and optional post data to turn on plug.
.I "setoffpath <path> [postdata]"
Set path and optional post data to turn off plug.
.TP
.I "setplugs plugnames hostindices"
Associate a plug name with one of the hostnames specified on the
command line, referred to by its zero origin index Can be called
multiple times to configure all possible plugs.
.TP
.I "settimeout <seconds>"
Set command timeout in seconds.
.TP
Expand Down
114 changes: 114 additions & 0 deletions src/redfishpower/redfishpower.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

static hostlist_t hosts = NULL;
static plugs_t *plugs = NULL;
/* flag to indicate if we wiped initial plugs */
static int initial_plugs_setup = 0;
static char *header = NULL;
static struct curl_slist *header_list = NULL;
static int verbose = 0;
Expand Down Expand Up @@ -155,6 +157,7 @@ void help(void)
printf(" setstatpath path\n");
printf(" setonpath path [postdata]\n");
printf(" setoffpath path [postdata]\n");
printf(" setplugs plugnames hostindices\n");
printf(" settimeout seconds\n");
printf(" stat [plugs]\n");
printf(" on [plugs]\n");
Expand Down Expand Up @@ -754,6 +757,113 @@ static void setpowerpath(char **av, char **path, char **postdata)
}
}

static void remove_initial_plugs(void)
{
hostlist_iterator_t itr;
char *hostname;

if (!initial_plugs_setup)
return;

if (!(itr = hostlist_iterator_create(hosts)))
err_exit(true, "hostlist_iterator_create");

while ((hostname = hostlist_next(itr))) {
plugs_remove(plugs, hostname);
free(hostname);
}

hostlist_iterator_destroy(itr);
initial_plugs_setup = 0;
return;
}

static int setup_plug(const char *plugname, const char *hostindexstr)
{
char *host;
char *endptr;
int hostindex;

errno = 0;
hostindex = strtol (hostindexstr, &endptr, 10);
if (errno
|| endptr[0] != '\0'
|| hostindex < 0) {
printf("setplugs: invalid hostindex %s specified\n", hostindexstr);
return -1;
}

if (!(host = hostlist_nth(hosts, hostindex))) {
printf("setplugs: hostindex %d out of range\n", hostindex);
return -1;
}

plugs_add(plugs, plugname, host);

/* initialize plug to "off" for testing */
if (test_mode)
zhashx_insert(test_power_status, plugname, STATUS_OFF);

free(host);
return 0;
}

static void setplugs(char **av)
{
hostlist_t lplugs = NULL;
hostlist_t hostindices = NULL;
int plugcount, hostindexcount;
hostlist_iterator_t lplugsitr = NULL;
hostlist_iterator_t hostindicesitr = NULL;
char *plug;
char *hostindexstr;

if (!av[0] || !av[1]) {
printf("Usage: setplugs <plugnames> <hostindices>\n");
return;
}

if (!(lplugs = hostlist_create(av[0]))) {
printf("setplugs: illegal plugnames input\n");
goto cleanup;
}
if (!(hostindices = hostlist_create(av[1]))) {
printf("setplugs: illegal hostindices input\n");
goto cleanup;
}

plugcount = hostlist_count(lplugs);
hostindexcount = hostlist_count(hostindices);
if (plugcount != hostindexcount) {
printf("setplugs: plugs count not equal to host index count");
goto cleanup;
}

if (!(lplugsitr = hostlist_iterator_create(lplugs)))
err_exit(true, "hostlist_iterator_create");
if (!(hostindicesitr = hostlist_iterator_create(hostindices)))
err_exit(true, "hostlist_iterator_create");

/* if user is electing to configure their own plugs, we must remove
* all of the initial ones configured in setup_hosts()
*/
remove_initial_plugs();

while ((plug = hostlist_next(lplugsitr))
&& (hostindexstr = hostlist_next(hostindicesitr))) {
if (setup_plug(plug, hostindexstr) < 0)
goto cleanup;
free(plug);
free(hostindexstr);
}

cleanup:
hostlist_iterator_destroy(lplugsitr);
hostlist_iterator_destroy(hostindicesitr);
hostlist_destroy(lplugs);
hostlist_destroy(hostindices);
}

static void settimeout(char **av)
{
if (av[0]) {
Expand Down Expand Up @@ -787,6 +897,8 @@ static void process_cmd(CURLM *mh, char **av, int *exitflag)
setpowerpath(av + 1, &onpath, &onpostdata);
else if (strcmp(av[0], "setoffpath") == 0)
setpowerpath(av + 1, &offpath, &offpostdata);
else if (strcmp(av[0], "setplugs") == 0)
setplugs(av + 1);
else if (strcmp(av[0], "settimeout") == 0)
settimeout(av + 1);
else if (strcmp(av[0], CMD_STAT) == 0)
Expand Down Expand Up @@ -1104,6 +1216,8 @@ static void setup_hosts(void)
}

hostlist_iterator_destroy(itr);

initial_plugs_setup = 1;
}

int main(int argc, char *argv[])
Expand Down
6 changes: 4 additions & 2 deletions t/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ TESTSCRIPTS = \
t0030-heartbeat-stonith.t \
t0031-llnl-mcr-cluster.t \
t0032-list.t \
t0033-valgrind.t
t0033-valgrind.t \
t0034-redfishpower.t

# make check runs these TAP tests directly (both scripts and programs)
TESTS = \
Expand All @@ -59,7 +60,8 @@ EXTRA_DIST= \
sharness.sh \
etc/sierra_plugs.conf \
etc/mcr_plugs.conf \
etc/vpc.dev
etc/vpc.dev \
etc/redfishpower-setplugs.dev


AM_CFLAGS = @WARNING_CFLAGS@
Expand Down
48 changes: 48 additions & 0 deletions t/etc/redfishpower-setplugs.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Variant of redfishpower-cray-r272z30.dev that covers use of setplugs
# configuration
specification "redfishpower-setplugs" {
timeout 60
Comment on lines +1 to +4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to develop a sharness test that runs redfishpower standalone rather than through powerman? This test seems awfully complicated just to check that setplugs works, and presumably we'll eventually have a dev script that uses all the new features in test (like the one I proposed).

Copy link
Member Author

@chu11 chu11 Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, the main reason I ran through powerman is b/c there isn't a facility to run redfishpower somewhat independently of powerman at the moment.

For the time being, I'll splice out the "redfishpower" specific tests into a new file, rather than keep it within the "redfish" set of tests. Since they are clearly of a different beast than the device files in /etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably I'm oversimplifying again :-)

I was vaguely thinking you could write a sharness test that drove redfishpower with a here-is document in a sharness script but maybe that's not practical.


script login {
expect "redfishpower> "
send "auth USER:PASS\n"
expect "redfishpower> "
send "setheader Content-Type:application/json\n"
expect "redfishpower> "
send "setplugs Node[0-15] [0-15]\n"
expect "redfishpower> "
send "setstatpath redfish/v1/Systems/Self\n"
expect "redfishpower> "
send "setonpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n"
expect "redfishpower> "
send "setoffpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n"
expect "redfishpower> "
send "setcyclepath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceRestart\"}\n"
expect "redfishpower> "
send "settimeout 60\n"
expect "redfishpower> "
}
script logout {
send "quit\n"
}
script status_all {
send "stat\n"
foreachnode {
expect "([^\n:]+): ([^\n]+\n)"
setplugstate $1 $2 on="^on\n" off="^off\n"
}
expect "redfishpower> "
}
script on_ranged {
send "on %s\n"
expect "redfishpower> "
}
script off_ranged {
send "off %s\n"
expect "redfishpower> "
}
script cycle_ranged {
send "cycle %s\n"
expect "redfishpower> "
}
}
37 changes: 0 additions & 37 deletions t/t0029-redfish.t
Original file line number Diff line number Diff line change
Expand Up @@ -107,43 +107,6 @@ test_expect_success 'stop powerman daemon' '
wait
'

#
# redfishpower fail hosts coverage
#

test_expect_success 'create powerman.conf for 16 cray redfish nodes (failhosts)' '
cat >powerman_fail_hosts.conf <<-EOT
listen "$testaddr"
include "$devicesdir/redfishpower-cray-r272z30.dev"
device "d0" "redfishpower-cray-r272z30" "$redfishdir/redfishpower -h t[0-15] --test-mode --test-fail-power-cmd-hosts=t[8-15] |&"
node "t[0-15]" "d0"
EOT
'
test_expect_success 'start powerman daemon and wait for it to start (failhosts)' '
$powermand -Y -c powerman_fail_hosts.conf &
echo $! >powermand.pid &&
$powerman --retry-connect=100 --server-host=$testaddr -d
'
test_expect_success 'powerman -q shows t[0-7] off, t[8-15] unknown' '
$powerman -h $testaddr -q >test_failhosts_query.out &&
makeoutput "" "t[0-7]" "t[8-15]" >test_failhosts_query.exp &&
test_cmp test_failhosts_query.exp test_failhosts_query.out
'
test_expect_success 'powerman -1 t[0-15] completes' '
$powerman -h $testaddr -1 t[0-15] >test_failhosts_on.out &&
echo Command completed successfully >test_failhosts_on.exp &&
test_cmp test_failhosts_on.exp test_failhosts_on.out
'
test_expect_success 'powerman -q shows t[0-7] on' '
$powerman -h $testaddr -q >test_failhosts_query2.out &&
makeoutput "t[0-7]" "" "t[8-15]" >test_failhosts_query2.exp &&
test_cmp test_failhosts_query2.exp test_failhosts_query2.out
'
test_expect_success 'stop powerman daemon (failhosts)' '
kill -15 $(cat powermand.pid) &&
wait
'

test_done

# vi: set ft=sh
104 changes: 104 additions & 0 deletions t/t0034-redfishpower.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/bin/sh

test_description='Cover redfishpower specific configurations'

. `dirname $0`/sharness.sh

powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand
powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman
redfishdir=$SHARNESS_BUILD_DIRECTORY/src/redfishpower
devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices
testdevicesdir=$SHARNESS_TEST_SRCDIR/etc

# Use port = 11000 + test number
# That way there won't be port conflicts with make -j
testaddr=localhost:11034


makeoutput() {
printf "on: %s\n" $1
printf "off: %s\n" $2
printf "unknown: %s\n" $3
}

#
# redfishpower fail hosts coverage
#

test_expect_success 'create powerman.conf for 16 cray redfish nodes (failhosts)' '
cat >powerman_fail_hosts.conf <<-EOT
listen "$testaddr"
include "$devicesdir/redfishpower-cray-r272z30.dev"
device "d0" "redfishpower-cray-r272z30" "$redfishdir/redfishpower -h t[0-15] --test-mode --test-fail-power-cmd-hosts=t[8-15] |&"
node "t[0-15]" "d0"
EOT
'
test_expect_success 'start powerman daemon and wait for it to start (failhosts)' '
$powermand -Y -c powerman_fail_hosts.conf &
echo $! >powermand.pid &&
$powerman --retry-connect=100 --server-host=$testaddr -d
'
test_expect_success 'powerman -q shows t[0-7] off, t[8-15] unknown' '
$powerman -h $testaddr -q >test_failhosts_query.out &&
makeoutput "" "t[0-7]" "t[8-15]" >test_failhosts_query.exp &&
test_cmp test_failhosts_query.exp test_failhosts_query.out
'
test_expect_success 'powerman -1 t[0-15] completes' '
$powerman -h $testaddr -1 t[0-15] >test_failhosts_on.out &&
echo Command completed successfully >test_failhosts_on.exp &&
test_cmp test_failhosts_on.exp test_failhosts_on.out
'
test_expect_success 'powerman -q shows t[0-7] on' '
$powerman -h $testaddr -q >test_failhosts_query2.out &&
makeoutput "t[0-7]" "" "t[8-15]" >test_failhosts_query2.exp &&
test_cmp test_failhosts_query2.exp test_failhosts_query2.out
'
test_expect_success 'stop powerman daemon (failhosts)' '
kill -15 $(cat powermand.pid) &&
wait
'

#
# redfishpower setplugs coverage
#

test_expect_success 'create powerman.conf for 16 cray redfish nodes (setplugs)' '
cat >powerman_setplugs.conf <<-EOT
listen "$testaddr"
include "$testdevicesdir/redfishpower-setplugs.dev"
device "d0" "redfishpower-setplugs" "$redfishdir/redfishpower -h t[0-15] --test-mode |&"
node "t[0-15]" "d0" "Node[0-15]"
EOT
'
test_expect_success 'start powerman daemon and wait for it to start (setplugs)' '
$powermand -Y -c powerman_setplugs.conf &
echo $! >powermand.pid &&
$powerman --retry-connect=100 --server-host=$testaddr -d
'
test_expect_success 'powerman -q shows all off' '
$powerman -h $testaddr -q >test_setplugs_query.out &&
makeoutput "" "t[0-15]" "" >test_setplugs_query.exp &&
test_cmp test_setplugs_query.exp test_setplugs_query.out
'
test_expect_success 'powerman -T -q shows plugs are being used' '
$powerman -h $testaddr -T -q > test_setplugs_query_T.out &&
grep "Node15: off" test_setplugs_query_T.out
'
test_expect_success 'powerman -1 t[0-15] works' '
$powerman -h $testaddr -1 t[0-15] >test_setplugs_on.out &&
echo Command completed successfully >test_setplugs_on.exp &&
test_cmp test_setplugs_on.exp test_setplugs_on.out
'
test_expect_success 'powerman -q shows all on' '
$powerman -h $testaddr -q >test_setplugs_query2.out &&
makeoutput "t[0-15]" "" "" >test_setplugs_query2.exp &&
test_cmp test_setplugs_query2.exp test_setplugs_query2.out
'
test_expect_success 'stop powerman daemon (setplugs)' '
kill -15 $(cat powermand.pid) &&
wait
'

test_done

# vi: set ft=sh
Loading