diff --git a/oswin_tempest_plugin/clients/wsman.py b/oswin_tempest_plugin/clients/wsman.py index 3ccb55d..3a0806d 100644 --- a/oswin_tempest_plugin/clients/wsman.py +++ b/oswin_tempest_plugin/clients/wsman.py @@ -13,24 +13,39 @@ # License for the specific language governing permissions and limitations # under the License. +import os + from oslo_log import log as logging from winrm import protocol +from oswin_tempest_plugin import config from oswin_tempest_plugin import exceptions LOG = logging.getLogger(__name__) +CONF = config.CONF protocol.Protocol.DEFAULT_TIMEOUT = "PT3600S" -def run_wsman_cmd(host, username, password, cmd, fail_on_error=False): +def run_wsman_cmd(host, cmd, username, password=None, + cert_pem_path=None, cert_key_pem_path=None, + transport_method='plaintext', fail_on_error=True): url = 'https://%s:5986/wsman' % host + + if transport_method == 'ssl': + if not (os.path.exists(cert_pem_path) and + os.path.exists(cert_key_pem_path)): + raise exceptions.WSManException('Could not find certificate path ' + 'or certificate key path.') + LOG.debug('Connecting to: %s', host) p = protocol.Protocol(endpoint=url, - transport='plaintext', + transport=transport_method, server_cert_validation='ignore', username=username, - password=password) + password=password, + cert_pem=cert_pem_path, + cert_key_pem=cert_key_pem_path) shell_id = p.open_shell() LOG.debug('Running command on host %(host)s: %(cmd)s', @@ -54,7 +69,21 @@ def run_wsman_cmd(host, username, password, cmd, fail_on_error=False): return (std_out, std_err, return_code) -def run_wsman_ps(host, username, password, cmd, fail_on_error=False): +def run_wsman_ps(host, cmd, username, password, cert_pem_path=None, + cert_key_pem_path=None, transport='plaintext', + fail_on_error=True): + cmd = ("powershell -NonInteractive -ExecutionPolicy RemoteSigned " "-Command \"%s\"" % cmd) - return run_wsman_cmd(host, username, password, cmd, fail_on_error) + return run_wsman_cmd(host, cmd, username, password, cert_pem_path, + cert_key_pem_path, fail_on_error) + + +def run_hv_host_wsman_ps(host, cmd, fail_on_error=True): + return run_wsman_ps( + host, cmd, + username=CONF.hyperv_host_auth.username, + password=CONF.hyperv_host_auth.password, + cert_pem_path=CONF.hyperv_host_auth.cert_pem_path, + cert_key_pem_path=CONF.hyperv_host_auth.cert_key_pem_path, + transport='plaintext', fail_on_error=fail_on_error) diff --git a/oswin_tempest_plugin/config.py b/oswin_tempest_plugin/config.py index c76981f..082147f 100644 --- a/oswin_tempest_plugin/config.py +++ b/oswin_tempest_plugin/config.py @@ -45,11 +45,6 @@ HyperVGroup = [ cfg.BoolOpt('cluster_enabled', default=False, help="The compute nodes are joined into a Hyper-V Cluster."), - cfg.StrOpt('username', - help="The username of the Hyper-V hosts."), - cfg.StrOpt('password', - secret=True, - help='The password of the Hyper-V hosts.'), cfg.IntOpt('failover_timeout', default=120, help='The maximum amount of time to wait for a failover to ' @@ -68,9 +63,33 @@ HyperVGroup = [ "vNUMA will be skipped."), ] +hyperv_host_auth_group = cfg.OptGroup(name='hyperv_host_auth', + title='Hyper-V host ' + 'authentication options') + +hyperv_host_auth_opts = [ + cfg.StrOpt('username', + help="The username of the Hyper-V hosts."), + cfg.StrOpt('password', + secret=True, + help='The password of the Hyper-V hosts.'), + cfg.StrOpt('cert_pem_path', + default=None, + help='SSL certificate for WinRM remote PS connection.'), + cfg.StrOpt('cert_key_pem_path', + default=None, + help='SSL key paired with cert_pem_path for WinRM remote PS ' + 'connection.'), + cfg.StrOpt('transport_method', + default='plaintext', + choices=('ssl', 'ntlm', 'plaintext'), + help='The method that should be used to establish a connection ' + 'to a Hyper-V host.') +] _opts = [ (hyperv_group, HyperVGroup), + (hyperv_host_auth_group, hyperv_host_auth_opts), ] diff --git a/oswin_tempest_plugin/tests/scenario/test_cluster.py b/oswin_tempest_plugin/tests/scenario/test_cluster.py index 5dec3d4..b9a1485 100644 --- a/oswin_tempest_plugin/tests/scenario/test_cluster.py +++ b/oswin_tempest_plugin/tests/scenario/test_cluster.py @@ -64,12 +64,14 @@ class HyperVClusterTest(test_base.TestBase, super(HyperVClusterTest, cls).skip_checks() # check if the cluster Tests can be run. - conf_opts = ['cluster_enabled', 'username', 'password'] - for conf_opt in conf_opts: - if not getattr(CONF.hyperv, conf_opt): - msg = ('The config option "hyperv.%s" has not been set. ' - 'Skipping.' % conf_opt) - raise cls.skipException(msg) + if not CONF.hyperv.cluster_enabled: + msg = 'Hyper-V cluster tests are disabled.' + raise cls.skipException(msg) + + if not CONF.hyperv_host_auth.username: + msg = ('No Hyper-V host username has been provided. ' + 'Skipping cluster tests.') + raise cls.skipException(msg) if not CONF.compute.min_compute_nodes >= 2: msg = 'Expected at least 2 compute nodes.' @@ -86,11 +88,9 @@ class HyperVClusterTest(test_base.TestBase, # succeed. On the 2nd failure, the VM will failover to another # node. Also, there needs to be a delay between commands, so the # original failover has time to finish. - wsman.run_wsman_ps(host_ip, CONF.hyperv.username, - CONF.hyperv.password, cmd, True) + wsman.run_hv_host_wsman_ps(host_ip, cmd) time.sleep(CONF.hyperv.failover_sleep_interval) - wsman.run_wsman_ps(host_ip, CONF.hyperv.username, - CONF.hyperv.password, cmd, True) + wsman.run_hv_host_wsman_ps(host_ip, cmd) def _wait_for_failover(self, server, original_host): """Waits for the given server to failover to another host.