Fixing SSH actions to use names of private keys
* SSH action uses private key names instead of private keys themself. All private keys now should be in <user-home>/.ssh/, e.g. searching of key 'my_key.pem' will be at <user-home>/.ssh/my_key.pem * Fixed functional tests * Remove sudo while running tests Closes-Bug: #1507600 Depends-On: Idc4340cda80d02f4ee88c91600b72d0f914c4084 Change-Id: I503d78ff541183ce850476229842fa6f20061a00
This commit is contained in:
parent
f17c6a61a5
commit
56f2d5f4b5
@ -765,7 +765,9 @@ Input parameters:
|
||||
*Required*.
|
||||
- **username** - User name to authenticate on the host.
|
||||
- **password** - User password to to authenticate on the host. *Optional.*
|
||||
- **private_key** - Private key string which will be used for authentication on remote host. *Optional.*
|
||||
- **private_key_filename** - Private key file name which will be used for authentication on remote host.
|
||||
All private keys should be on executor host in **<home-user-directory>/.ssh/**.
|
||||
**<home-user-directory>** should refer to user directory under which service is running. *Optional.*
|
||||
|
||||
**NOTE**: Authentication using key pairs is supported, key should be
|
||||
on Mistral Executor server machine.
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
RETVAL=0
|
||||
|
||||
sudo chmod -R a+rw /opt/stack/new/
|
||||
cd /opt/stack/new/
|
||||
|
||||
echo "Repository: $ZUUL_PROJECT"
|
||||
@ -25,7 +26,7 @@ echo "Repository: $ZUUL_PROJECT"
|
||||
if [[ "$ZUUL_PROJECT" == "openstack/mistral" ]]; then
|
||||
cd mistral/
|
||||
echo "Run mistral API tests"
|
||||
sudo bash ./functionaltests/run_tests.sh
|
||||
./functionaltests/run_tests.sh
|
||||
RETVAL=$?
|
||||
fi
|
||||
|
||||
@ -33,7 +34,7 @@ fi
|
||||
if [[ RETVAL -eq 0 ]]; then
|
||||
cd /opt/stack/new/python-mistralclient/
|
||||
echo "Run mistralclient tests"
|
||||
sudo bash ./functionaltests/run_tests.sh
|
||||
./functionaltests/run_tests.sh
|
||||
RETVAL=$?
|
||||
fi
|
||||
|
||||
|
@ -32,8 +32,5 @@ MISTRALCLIENT_DIR=/opt/stack/new/python-mistralclient
|
||||
# Define PYTHONPATH
|
||||
export PYTHONPATH=$PYTHONPATH:$TEMPEST_DIR
|
||||
|
||||
#installing requirements for tempest
|
||||
pip install -r $TEMPEST_DIR/requirements.txt
|
||||
|
||||
pwd
|
||||
nosetests -sv mistral/tests/functional/
|
||||
|
@ -330,19 +330,20 @@ class SSHAction(base.Action):
|
||||
def _execute_cmd_method(self):
|
||||
return ssh_utils.execute_command
|
||||
|
||||
def __init__(self, cmd, host, username, password=None, private_key=None):
|
||||
def __init__(self, cmd, host, username,
|
||||
password=None, private_key_filename=None):
|
||||
self.cmd = cmd
|
||||
self.host = host
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.private_key = private_key
|
||||
self.private_key_filename = private_key_filename
|
||||
|
||||
self.params = {
|
||||
'cmd': self.cmd,
|
||||
'host': self.host,
|
||||
'username': self.username,
|
||||
'password': self.password,
|
||||
'private_key': self.private_key
|
||||
'private_key_filename': self.private_key_filename
|
||||
}
|
||||
|
||||
def run(self):
|
||||
@ -386,14 +387,15 @@ class SSHProxiedAction(SSHAction):
|
||||
def _execute_cmd_method(self):
|
||||
return ssh_utils.execute_command_via_gateway
|
||||
|
||||
def __init__(self, cmd, host, username, private_key, gateway_host,
|
||||
gateway_username=None, password=None, proxy_command=None):
|
||||
def __init__(self, cmd, host, username, private_key_filename,
|
||||
gateway_host, gateway_username=None,
|
||||
password=None, proxy_command=None):
|
||||
super(SSHProxiedAction, self).__init__(
|
||||
cmd,
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
private_key
|
||||
private_key_filename
|
||||
)
|
||||
|
||||
self.gateway_host = gateway_host
|
||||
|
@ -13,6 +13,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import os
|
||||
from os import path
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
@ -27,6 +29,7 @@ from mistral.utils import ssh_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = config.CONF
|
||||
SSH_KEYS_DIRECTORY = path.expanduser("~/.ssh/")
|
||||
|
||||
|
||||
class SSHActionsTestsV2(base.TestCaseAdvanced):
|
||||
@ -138,6 +141,27 @@ class SSHActionsTestsV2(base.TestCaseAdvanced):
|
||||
cls.private_key, cls.public_key = utils.generate_key_pair()
|
||||
cls.key_name = 'mistral-functional-tests-key'
|
||||
|
||||
# If ZUUL_PROJECT is specified, it means
|
||||
# tests are running on Jenkins gate.
|
||||
|
||||
if os.environ.get('ZUUL_PROJECT'):
|
||||
cls.key_dir = "/opt/stack/new/.ssh/"
|
||||
|
||||
if not path.exists(cls.key_dir):
|
||||
os.mkdir(cls.key_dir)
|
||||
else:
|
||||
cls.key_dir = SSH_KEYS_DIRECTORY
|
||||
|
||||
utils.save_text_to(
|
||||
cls.private_key,
|
||||
cls.key_dir + cls.key_name,
|
||||
overwrite=True
|
||||
)
|
||||
|
||||
LOG.info(
|
||||
"Private key saved to %s" % cls.key_dir + cls.key_name
|
||||
)
|
||||
|
||||
# Create keypair in nova.
|
||||
cls.mgr.keypairs_client.create_keypair(
|
||||
name=cls.key_name,
|
||||
@ -184,6 +208,7 @@ class SSHActionsTestsV2(base.TestCaseAdvanced):
|
||||
cls.mgr.security_group_rules_client.delete_security_group_rule(
|
||||
cls.ssh_rule_id
|
||||
)
|
||||
os.remove(cls.key_dir + cls.key_name)
|
||||
|
||||
super(SSHActionsTestsV2, cls).resource_cleanup()
|
||||
|
||||
@ -193,7 +218,7 @@ class SSHActionsTestsV2(base.TestCaseAdvanced):
|
||||
'cmd': 'hostname',
|
||||
'host': self.public_vm_ip,
|
||||
'username': CONF.scenario.ssh_user,
|
||||
'private_key': self.private_key
|
||||
'private_key_filename': self.key_name
|
||||
}
|
||||
|
||||
resp, body = self.client.create_action_execution(
|
||||
@ -217,7 +242,7 @@ class SSHActionsTestsV2(base.TestCaseAdvanced):
|
||||
'cmd': 'hostname',
|
||||
'host': guest_vm_ip,
|
||||
'username': CONF.scenario.ssh_user,
|
||||
'private_key': self.private_key,
|
||||
'private_key_filename': self.key_name,
|
||||
'gateway_host': self.public_vm_ip,
|
||||
'gateway_username': CONF.scenario.ssh_user
|
||||
}
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
import copy
|
||||
|
||||
from mistral import exceptions as exc
|
||||
from mistral.tests import base
|
||||
from mistral import utils
|
||||
from mistral.utils import ssh_utils
|
||||
|
||||
LEFT = {
|
||||
'key1': {
|
||||
@ -117,3 +119,15 @@ class UtilsTest(base.BaseTest):
|
||||
self.assertEqual(2, input_dict.get('param2'))
|
||||
self.assertEqual('var3', input_dict.get('param3'))
|
||||
self.assertIs(input_dict.get('param1'), utils.NotDefined)
|
||||
|
||||
def test_paramiko_to_private_key(self):
|
||||
self.assertRaises(
|
||||
exc.DataAccessException,
|
||||
ssh_utils._to_paramiko_private_key,
|
||||
"../dir"
|
||||
)
|
||||
self.assertRaises(
|
||||
exc.DataAccessException,
|
||||
ssh_utils._to_paramiko_private_key,
|
||||
"..\\dir"
|
||||
)
|
||||
|
@ -267,6 +267,7 @@ def tempdir(**kwargs):
|
||||
|
||||
if 'dir' not in argdict:
|
||||
argdict['dir'] = '/tmp/'
|
||||
|
||||
tmpdir = tempfile.mkdtemp(**argdict)
|
||||
|
||||
try:
|
||||
@ -281,6 +282,16 @@ def tempdir(**kwargs):
|
||||
)
|
||||
|
||||
|
||||
def save_text_to(text, file_path, overwrite=False):
|
||||
if os.path.exists(file_path) and not overwrite:
|
||||
raise exc.DataAccessException(
|
||||
"Cannot save data to file. File %s already exists."
|
||||
)
|
||||
|
||||
with open(file_path, 'w') as f:
|
||||
f.write(text)
|
||||
|
||||
|
||||
def generate_key_pair(key_length=2048):
|
||||
"""Create RSA key pair with specified number of bits in key.
|
||||
Returns tuple of private and public keys.
|
||||
@ -295,15 +306,20 @@ def generate_key_pair(key_length=2048):
|
||||
'-f', keyfile, # filename of the key file
|
||||
'-C', 'Generated-by-Mistral' # key comment
|
||||
]
|
||||
|
||||
if key_length is not None:
|
||||
args.extend(['-b', key_length])
|
||||
|
||||
processutils.execute(*args)
|
||||
|
||||
if not os.path.exists(keyfile):
|
||||
raise exc.DataAccessException(
|
||||
"Private key file hasn't been created"
|
||||
)
|
||||
|
||||
private_key = open(keyfile).read()
|
||||
public_key_path = keyfile + '.pub'
|
||||
|
||||
if not os.path.exists(public_key_path):
|
||||
raise exc.DataAccessException(
|
||||
"Public key file hasn't been created"
|
||||
|
@ -14,12 +14,17 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from os import path
|
||||
|
||||
import six
|
||||
|
||||
from oslo_log import log as logging
|
||||
import paramiko
|
||||
|
||||
from mistral import exceptions as exc
|
||||
|
||||
|
||||
KEY_PATH = path.expanduser("~/.ssh/")
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -33,9 +38,17 @@ def _read_paramimko_stream(recv_func):
|
||||
return result
|
||||
|
||||
|
||||
def _to_paramiko_private_key(private_key_raw, password):
|
||||
def _to_paramiko_private_key(private_key_filename, password=None):
|
||||
if '../' in private_key_filename or '..\\' in private_key_filename:
|
||||
raise exc.DataAccessException(
|
||||
"Private key filename must not contain '..'. "
|
||||
"Actual: %s" % private_key_filename
|
||||
)
|
||||
|
||||
private_key_path = KEY_PATH + private_key_filename
|
||||
|
||||
return paramiko.RSAKey(
|
||||
file_obj=six.StringIO(private_key_raw),
|
||||
filename=private_key_path,
|
||||
password=password
|
||||
)
|
||||
|
||||
@ -87,13 +100,12 @@ def _execute_command(ssh_client, cmd, get_stderr=False,
|
||||
_cleanup(ssh_client)
|
||||
|
||||
|
||||
def execute_command_via_gateway(cmd, host, username, private_key,
|
||||
def execute_command_via_gateway(cmd, host, username, private_key_filename,
|
||||
gateway_host, gateway_username=None,
|
||||
proxy_command=None, password=None):
|
||||
LOG.debug('Creating SSH connection')
|
||||
|
||||
if isinstance(private_key, six.string_types):
|
||||
private_key = _to_paramiko_private_key(private_key, password)
|
||||
private_key = _to_paramiko_private_key(private_key_filename, password)
|
||||
|
||||
proxy = None
|
||||
|
||||
@ -138,9 +150,10 @@ def execute_command_via_gateway(cmd, host, username, private_key,
|
||||
_cleanup(_proxy_ssh_client)
|
||||
|
||||
|
||||
def execute_command(cmd, host, username, password=None, private_key=None,
|
||||
get_stderr=False, raise_when_error=True):
|
||||
ssh_client = _connect(host, username, password, private_key)
|
||||
def execute_command(cmd, host, username, password=None,
|
||||
private_key_filename=None, get_stderr=False,
|
||||
raise_when_error=True):
|
||||
ssh_client = _connect(host, username, password, private_key_filename)
|
||||
|
||||
LOG.debug("Executing command %s" % cmd)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user