Skip to content

Commit

Permalink
Support for logon/logoff and named sessions
Browse files Browse the repository at this point in the history
TODOs:

* Add end2end testcases for the new 'session logon/logoff' commands

Details:

* Added new 'zhmc session logon/logoff' commands that manage the session
  in a file '.zhmc_sessions.yaml' in the user's home directory.

* Deprecated the existing 'zhmc session create/delete' commands since they
  are less convenient to use compared to the new logon/logoff commands,
  and cannot be used as intended on Windows due to the displayed export/unset
  commands.

* Added a general option '-s' / '--session-name' for specifying the name
  of the session that is managed in the '.zhmc_sessions.yaml' file.
  This allows having multiple sessions to different HMCs open at the same
  time, and selecting them by name. If not specified, the session name is
  'default'.

* The 'session delete' command was changed to unset all ZHMC_* environment
  variables, instead of just ZHMC_SESSION_ID.

* If logon options and ZHMC_* environment variables are both specified,
  the logon options now have precedence and none of the ZHMC_* environment
  variables is used (except ZHMC_PASSWORD). This changes the earlier
  behavior where ZHMC_SESSION_ID was used even when logon options were
  specified.

* The existing testcases for sessions were adjusted for the new behavior.

* Added function testcases for the new _session_file.py module.

* The end2end testcases for the _cmd_sessions.py module were extended with
  new testcases.

Signed-off-by: Andreas Maier <[email protected]>
  • Loading branch information
andy-maier committed Dec 30, 2024
1 parent b70aed0 commit 3403ba8
Show file tree
Hide file tree
Showing 14 changed files with 2,075 additions and 109 deletions.
7 changes: 7 additions & 0 deletions changes/544.2.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Added support for creating multiple named sessions with a new global option
'-s' / '--session-name'. It is optional and defaults to the name 'default'.
This option can be used with 'zhmc session logon/logoff' to create or delete a
named session, and with any other zhmc command to use a session that has
previously been created. The 'zhmc session create/delete' commands do not
support named sessions, because the environment variables that are used to
store the session data support only a single session.
4 changes: 4 additions & 0 deletions changes/544.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The 'zhmc session create/delete' commands are now deprecated. They were
inconvenient to use and did not support Windows out of the box since they
displayed the export/unset commands to manage the session. Use the new
'zhmc session logon/logoff' commands instead.
6 changes: 6 additions & 0 deletions changes/544.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
New 'zhmc session logon/logoff' commands are provided. They manage the session
in a '.zhmc_sessions.yaml' file in the user's home directory. This is more
convenient for users compared to the existing 'zhmc session create/delete'
commands which store the session in environment variables and display the
export/unset commands to do that. The new commands also support Windows out
of the box.
5 changes: 5 additions & 0 deletions changes/544.incompatible.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
If logon options and ZHMC_* environment variables are both provided, the
logon options now take precedence, and the environment variables are ignored.
As a result, a provided ZHMC_SESSION_ID variable is now ignored when logon
options are also provided. Previously, a provided ZHMC_SESSION_ID variable was
used when logon options were also provided.
102 changes: 76 additions & 26 deletions tests/end2end/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,16 @@ def assert_session_delete(
continue
raise AssertionError(f"Unexpected line on stdout: {line!r}")

assert 'ZHMC_HOST' in unset_vars
del unset_vars['ZHMC_HOST']
assert 'ZHMC_USERID' in unset_vars
del unset_vars['ZHMC_USERID']
assert 'ZHMC_SESSION_ID' in unset_vars
del unset_vars['ZHMC_SESSION_ID']
assert 'ZHMC_NO_VERIFY' in unset_vars
del unset_vars['ZHMC_NO_VERIFY']
assert 'ZHMC_CA_CERTS' in unset_vars
del unset_vars['ZHMC_CA_CERTS']

assert not export_vars
assert not unset_vars
Expand Down Expand Up @@ -371,6 +379,17 @@ def test_utils_invalid_session(hmc_definition): # noqa: F811
0, None,
True
),
(
"no env vars and logon opts with only -h",
# If logon opts are used (detected by presence of -h), a userid is
# required.
{},
{
'-h': 'valid',
},
1, "Required option not specified: --userid",
True
),
(
"no env vars and logon opts with invalid pw",
# Since there is no session ID in the env vars, a new session is created
Expand All @@ -394,7 +413,7 @@ def test_utils_invalid_session(hmc_definition): # noqa: F811
'ZHMC_SESSION_ID': 'valid',
},
{},
1, 'No HMC host provided',
1, 'No HMC host or session in HMC session file provided',
True
),
(
Expand Down Expand Up @@ -436,7 +455,7 @@ def test_utils_invalid_session(hmc_definition): # noqa: F811
),
(
"all env vars (valid session) and valid logon opts",
# The valid session in the env var is successfully deleted on the HMC.
# The logon opts take precedence.
# A new session is created on the HMC, using the valid password.
{
'ZHMC_HOST': 'valid',
Expand Down Expand Up @@ -568,9 +587,16 @@ def test_session_create(
exp_rc, exp_err, pdb_)

# If a valid session ID was provided to the command in env vars,
# verify that that session was deleted on the HMC
# verify the state of its session on the HMC.
if env_session_id and rc == 0:
assert not is_valid_hmc_session(hmc_definition, env_session_id)
if '-h' in logon_opts or '--host' in logon_opts:
# logon options take precedence over env vars, so the
# session ID in the env vars was ignored and is still valid.
assert is_valid_hmc_session(hmc_definition, env_session_id)
else:
# logon was done from the env vars, and the session provided
# in the env vars was deleted.
assert not is_valid_hmc_session(hmc_definition, env_session_id)

finally:
for session_id in cleanup_session_ids:
Expand Down Expand Up @@ -635,6 +661,17 @@ def test_session_create(
0, None,
True
),
(
"no env vars and logon opts with only -h",
# If logon opts are used (detected by presence of -h), a userid is
# required.
{},
{
'-h': 'valid',
},
1, "Required option not specified: --userid",
True
),
(
"no env vars and logon opts with invalid pw",
# Since there is no session ID in the env vars, no session will be
Expand All @@ -658,7 +695,7 @@ def test_session_create(
'ZHMC_SESSION_ID': 'valid',
},
{},
1, 'No HMC host provided',
1, 'No HMC host or session in HMC session file provided',
True
),
(
Expand Down Expand Up @@ -817,9 +854,16 @@ def test_session_delete(
exp_rc, exp_err, pdb_)

# If a valid session ID was provided to the command in env vars,
# verify that that session was deleted on the HMC
# verify the state of its session on the HMC.
if env_session_id and rc == 0:
assert not is_valid_hmc_session(hmc_definition, env_session_id)
if '-h' in logon_opts or '--host' in logon_opts:
# logon options take precedence over env vars, so the
# session ID in the env vars was ignored and is still valid.
assert is_valid_hmc_session(hmc_definition, env_session_id)
else:
# logon was done from the env vars, and the session provided
# in the env vars was deleted.
assert not is_valid_hmc_session(hmc_definition, env_session_id)

finally:
for session_id in cleanup_session_ids:
Expand Down Expand Up @@ -886,6 +930,17 @@ def test_session_delete(
0, None,
True
),
(
"no env vars and logon opts with only -h",
# If logon opts are used (detected by presence of -h), a userid is
# required.
{},
{
'-h': 'valid',
},
1, "Required option not specified: --userid",
True
),
(
"no env vars and logon opts with invalid pw",
# Since there is no session ID in the env vars, a new session is created
Expand All @@ -909,7 +964,7 @@ def test_session_delete(
'ZHMC_SESSION_ID': 'valid',
},
{},
1, 'No HMC host provided',
1, 'No HMC host or session in HMC session file provided',
True
),
(
Expand Down Expand Up @@ -950,9 +1005,9 @@ def test_session_delete(
),
(
"all env vars (valid session) and valid logon opts",
# The valid session ID in the env vars is used to execute the command
# on the HMC. The session is not deleted after the command. The
# credentials in the options are not used.
# Logon options take precedence over env vars, so the valid session ID
# in the env vars is ignored, and the logon opts are used to create a
# new session on the HMC.
{
'ZHMC_HOST': 'valid',
'ZHMC_USERID': 'valid',
Expand All @@ -972,12 +1027,9 @@ def test_session_delete(
),
(
"all env vars (invalid session) and valid logon opts",
# The invalid session ID in the env vars is attempted to be used to
# execute the command, which fails, which causes a session renewal.
# A new session is created on the HMC using the valid password,
# and then the command is successfully executed. The session is
# deleted after the command (because it cannot be stored for reuse
# anyway).
# Logon options take precedence over env vars, so the invalid session ID
# in the env vars is ignored, and the logon opts are used to create a
# new session on the HMC.
{
'ZHMC_HOST': 'valid',
'ZHMC_USERID': 'valid',
Expand All @@ -997,10 +1049,9 @@ def test_session_delete(
),
(
"all env vars (valid session) and logon opts with invalid pw",
# The valid session ID in the env vars is used to execute the command
# on the HMC. The session is not deleted after the command. The
# credentials in the options are not used, so it does not matter
# that the password is invalid.
# Logon options take precedence over env vars, so the valid session ID
# in the env vars is ignored, and the logon opts are used to create a
# new session on the HMC, which fails due to the invalid password.
{
'ZHMC_HOST': 'valid',
'ZHMC_USERID': 'valid',
Expand All @@ -1015,15 +1066,14 @@ def test_session_delete(
'-n': 'valid',
'-c': 'valid',
},
0, None,
1, "ServerAuthError: HTTP authentication failed with 403,0",
True
),
(
"all env vars (invalid session) and logon opts with invalid pw",
# The invalid session ID in the env vars is attempted to be used to
# execute the command, which fails, which causes a session renewal.
# A new session is attempted to be created on the HMC using the invalid
# password, which fails.
# Logon options take precedence over env vars, so the invalid session ID
# in the env vars is ignored, and the logon opts are used to create a
# new session on the HMC, which fails due to the invalid password.
{
'ZHMC_HOST': 'valid',
'ZHMC_USERID': 'valid',
Expand Down
18 changes: 11 additions & 7 deletions tests/function/test_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def test_info_error_no_host(self):
assert_rc(1, rc, stdout, stderr)
assert stdout == ""
assert stderr.startswith(
"Error: No HMC host provided\n"), \
"Error: No HMC host or session in HMC session file provided\n"), \
f"stderr={stderr!r}"

def test_info_error_no_conn(self):
Expand All @@ -80,7 +80,7 @@ def test_info_error_no_conn(self):
# Invoke the command to be tested
rc, stdout, stderr = call_zhmc_child(
['info'],
{'ZHMC_HOST': 'invalid_host'}
{'ZHMC_HOST': 'invalid_host', 'ZHMC_USERID': 'user'}
)

assert_rc(1, rc, stdout, stderr)
Expand Down Expand Up @@ -205,7 +205,8 @@ def test_option_outputformat_table(
"""

faked_session = FakedSession(
'fake-host', hmc_name, hmc_version, api_version)
'fake-host', hmc_name, hmc_version, api_version,
userid='fake-user')
api_version_parts = [int(vp) for vp in api_version.split('.')]
exp_values = {
'hnam': hmc_name,
Expand Down Expand Up @@ -266,7 +267,8 @@ def test_option_outputformat_json(
"""

faked_session = FakedSession(
'fake-host', hmc_name, hmc_version, api_version)
'fake-host', hmc_name, hmc_version, api_version,
userid='fake-user')

args = [out_opt, 'json']
if transpose_opt is not None:
Expand Down Expand Up @@ -325,7 +327,7 @@ def test_option_errorformat(self, err_opt, err_format, exp_stderr_patterns):
# Invoke the command to be tested
rc, stdout, stderr = call_zhmc_child(
err_args + ['info'],
{'ZHMC_HOST': 'invalid_host'}
{'ZHMC_HOST': 'invalid_host', 'ZHMC_USERID': 'user'}
)

assert_rc(1, rc, stdout, stderr)
Expand Down Expand Up @@ -371,7 +373,8 @@ def test_option_log(
"""Test 'zhmc info' with global option --log"""

faked_session = FakedSession(
'fake-host', hmc_name, hmc_version, api_version)
'fake-host', hmc_name, hmc_version, api_version,
userid='fake-user')

# Invoke the command to be tested
rc, stdout, stderr = call_zhmc_inline(
Expand Down Expand Up @@ -404,7 +407,8 @@ def test_option_logdest(
"""Test 'zhmc info' with global option --log-dest (and --log)"""

faked_session = FakedSession(
'fake-host', hmc_name, hmc_version, api_version)
'fake-host', hmc_name, hmc_version, api_version,
userid='fake-user')

args = ['--log', 'api=debug']
logger_name = 'zhmcclient.api' # corresponds to --log option
Expand Down
Loading

0 comments on commit 3403ba8

Please sign in to comment.