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:
Nikolay Mahotkin 2015-10-19 16:58:16 +03:00
parent f17c6a61a5
commit 56f2d5f4b5
8 changed files with 92 additions and 22 deletions

View File

@ -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.

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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
}

View File

@ -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"
)

View File

@ -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"

View File

@ -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)