Permalink
Browse files

run task within instance

  • Loading branch information...
1 parent eb76ecd commit deb2e36d6baead56f5ed7a4e89c7808ccc985363 @hughsaunders committed Dec 3, 2013
@@ -0,0 +1,26 @@
+{
+ "deploy": {
+ "name": "DummyEngine",
+ "cloud_config": {
+ "identity": {
+ "url": "http://162.13.147.41/",
+ "uri": "http://162.13.147.41:5000/v2.0/",
+ "admin_username": "admin",
+ "admin_password": "f05d284dc158860dd5aa",
+ "admin_tenant_name": "demo"
+ }
+ }
+ },
+
+ "tests": {
+ "verify": [],
+ "benchmark": {
+ "NovaServers.boot_runcommand_delete_server": [
+ {"args": {"flavor_id": "2108eda8-101a-4b79-896d-420e7cba613a",
+ "image_id": "c2c55b38-31ee-4283-83bb-b786e61fb801",
+ "command": "sudo apt-get -fy install curl; curl -X POST -d \"hostname=$HOSTNAME\" http://requestb.in/17u886g1"},
+ "times": 2, "concurrent": 1}
+ ]
+ }
+ }
+}
@@ -13,12 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+import json
import jsonschema
+import paramiko
import random
+import socket
+from StringIO import StringIO
from rally.benchmark.scenarios.nova import utils
from rally.benchmark.scenarios import utils as scenario_utils
+from rally.benchmark import utils as benchmark_utils
from rally import exceptions as rally_exceptions
+from rally.openstack.common.gettextutils import _ # noqa
+from rally.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
ACTION_BUILDER = scenario_utils.ActionBuilder(
['hard_reboot', 'soft_reboot', 'stop_start'])
@@ -37,6 +46,60 @@ def boot_and_delete_server(cls, context, image_id, flavor_id,
cls._delete_server(server)
@classmethod
+ def boot_runcommand_delete_server(cls, context, image_id, flavor_id,
+ command, network='private',
+ username='ubuntu', ip_version=4, **kwargs):
+ """Boot server, run a command, delete server.
+
+ Parameters:
+ command: Command to run on the server
+ network: Network to choose address to connect to instance from
+ username: User to SSH to instance as
+ ip_version: Version of ip protocol to use for connection
+ """
+ server_name = cls._generate_random_name(16)
+
+ server = cls._boot_server(server_name, image_id, flavor_id,
+ key_name='rally_ssh_key', **kwargs)
+
+ # NOTE(Hughsaunders): Run command specified by 'command' parameters
+ # within the instance. No output is captured so only the length of
+ # time taken to run is significant. Example uses: IO or CPU benchmark.
+ ssh = paramiko.SSHClient()
@akscram

akscram Dec 15, 2013

Looks like it's better to use rally.sshutils.SSH.

+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+
+ server_ip=[ip for ip in server.addresses[network] if
+ ip['version']==ip_version][0]['addr']
+ for retry in range(60):
+ try:
+ ssh.connect(
+ hostname=server_ip,
+ username=username,
+ pkey=paramiko.RSAKey(
+ file_obj=StringIO(cls.clients['ssh_key_pair']['private'])
+ )
+ )
+ LOG.debug(_('Instance SSH connection succeded %s/%s Attempt:%i'
+ % (server.id, server_ip, retry)))
+ stdin, stderr, stdout = ssh.exec_command(command)
+ stdout_str = stdout.read()
+ stderr_str = stderr.read()
+ LOG.debug(_('Instance SSH command completed %s/%s Attempt:%i'
+ ' Stdout: %s, Stderr: %s' % (server.id, server_ip,
+ retry, stdout_str, stderr_str)))
+ ssh.close()
+ break
+ except socket.error as e:
+ LOG.debug(_('Error running command on instance via SSH. %s/%s'
+ ' Attempt:%i, Error: %s' % (server.id, server_ip, retry,
+ benchmark_utils._format_exc(e))))
+ cls.sleep_between(5,5)
+
+ cls._delete_server(server)
+ print("stdout:,",stdout_str)
+ return {'data':stdout_str}
+
+ @classmethod
def boot_and_bounce_server(cls, context, image_id, flavor_id, **kwargs):
"""Tests booting a server then performing stop/start or hard/soft
reboot a number of times.
View
@@ -25,6 +25,7 @@
from rally.openstack.common.gettextutils import _ # noqa
from rally.openstack.common import log as logging
from rally import osclients
+from rally import sshutils
from rally import utils
@@ -49,14 +50,17 @@ def _run_scenario_loop(args):
cls.idle_time = 0
+ scenario_specific_results = None
try:
with utils.Timer() as timer:
- getattr(cls, method_name)(context, **kwargs)
+ scenario_specific_results = getattr(cls, method_name)(context,
+ **kwargs)
except Exception as e:
return {"time": timer.duration() - cls.idle_time,
"idle_time": cls.idle_time, "error": _format_exc(e)}
return {"time": timer.duration() - cls.idle_time,
- "idle_time": cls.idle_time, "error": None}
+ "idle_time": cls.idle_time, "error": None,
+ "scenario_specific_results":scenario_specific_results}
# NOTE(msdubov): Cleaning up after each scenario loop enables to delete
# the resources of the user the scenario was run from.
@@ -78,6 +82,41 @@ def _create_openstack_clients(users_endpoints, keys):
)) for cl in client_managers
]
+ return _prepare_for_instance_ssh(clients)
+
+
+def _prepare_for_instance_ssh(clients):
+ """Generate and store SSH keys, allow access to port 22.
+
+ In order to run tests on instances it is necessary to have SSH access.
+ This function generates an SSH key pair per user which is stored in the
+ clients dictionary. The public key is also submitted to nova via the
+ novaclient.
+
+ A security group rule is created to allow access to instances on port 22.
+ """
+
+
+ for client_dict in clients:
+ nova_client = client_dict['nova']
+
+ if ('rally_ssh_key' not in
+ [k.name for k in nova_client.keypairs.list()]):
+ client_dict['ssh_key_pair'] = sshutils.generate_ssh_keypair()
+ nova_client.keypairs.create(
+ 'rally_ssh_key',client_dict['ssh_key_pair']['public'])
+
+ default_sec_group = nova_client.security_groups.find(name='default')
+ if not [rule for rule in default_sec_group.rules if
+ rule['ip_protocol']=='tcp'
+ and rule['to_port']==22
+ and rule['from_port']==22
+ and rule['ip_range']=={'cidr':'0.0.0.0/0'}
+ ]:
+ nova_client.security_group_rules.create(
+ default_sec_group.id, from_port=22, to_port=22,
+ ip_protocol='tcp', cidr='0.0.0.0/0')
+
return clients
@@ -107,10 +146,16 @@ def _create_temp_tenants_and_users(self, tenants, users_per_tenant):
username,
tenant.id)
self.users.append(user)
- user_credentials = {"username": username, "password": password,
- "tenant_name": tenant.name,
- "uri": self.endpoints["uri"]}
+ user_credentials = {
+ "username": username,
+ "password": password,
+ "tenant_name": tenant.name,
+ "uri": self.endpoints["uri"],
+ "ssh_key_pair": sshutils.generate_ssh_keypair()
+ }
temporary_endpoints.append(user_credentials)
+
+
return temporary_endpoints
def _delete_temp_tenants_and_users(self):
View
@@ -61,12 +61,16 @@ def status(self, task_id):
print(_("Task %(task_id)s is %(status)s.")
% {'task_id': task_id, 'status': task['status']})
- @cliutils.args('--task-id', type=str, dest='task_id', help='uuid of task')
+ @cliutils.args('--task-id', type=str, dest='task_id', help='uuid of task,'
+ ' if last is specified, details of the last task will be shown')
def detailed(self, task_id):
"""Get detailed information about task
:param task_id: Task uuid
Prints detailed infomration of task.
"""
+
+ if task_id == "last":
+ task_id = db.task_list()[-1].uuid
task = db.task_get_detailed(task_id)
print()
@@ -90,8 +94,31 @@ def detailed(self, task_id):
table = prettytable.PrettyTable(["max", "avg", "min", "ratio"])
table.add_row([max(times), sum(times) / len(times), min(times),
float(len(times)) / len(raw)])
+
+ print("\nTimings:")
print(table)
+ print("\nScenario Specific Results\n"+"-"*80)
+
+
+ pprint.pprint(raw)
+ ssrs=[json.loads(result['scenario_specific_results']) for
+ result in raw]
+
+ sys.stdout.flush()
+ keys=()
+ for ssr in ssrs:
+ keys.update(ssr['data'].keys())
+
+ ssr_table = prettytable.PrettyTable(["Key","max","avg","min"])
+ for key in keys:
+ values = [float(ssr['data'][key]) for ssr in ssrs if
+ key in ssr['data']]
+ ssr_table.add_row([key,max(values),sum(values)/len(values),
+ min(values)])
+
+
+
@cliutils.args('--task-id', type=str, dest='task_id', help='uuid of task')
@cliutils.args('--pretty', type=str, help='uuid of task')
def results(self, task_id, pretty=False):
View
@@ -14,7 +14,9 @@
# under the License.
import eventlet
+import paramiko
import subprocess
+from StringIO import StringIO
from rally import exceptions
from rally.openstack.common.gettextutils import _ # noqa
@@ -28,6 +30,20 @@
class SSHException(Exception):
pass
+def generate_ssh_keypair(key_size=2048):
+ priv_key = paramiko.RSAKey.generate(key_size)
+ priv_key_file = StringIO()
+ priv_key.write_private_key(file_obj=priv_key_file)
+ priv_key_file.seek(0)
+ priv_key_string = priv_key_file.read()
+ priv_key_file.seek(0)
+
+ pub_key = paramiko.RSAKey(file_obj=priv_key_file)
+ pub_key_string = "ssh-rsa %s" %(pub_key.get_base64(),)
+
+ return {'private': priv_key_string,
+ 'public': pub_key_string}
+
def upload_file(user, host, source, destination):
cmd = ['scp'] + DEFAULT_OPTIONS + [source, '%s@%s:%s' % (user, host,
@@ -52,6 +68,7 @@ def execute_command(user, host, cmd):
raise SSHException(se)
+
class SSH(object):
"""SSH common functions."""

0 comments on commit deb2e36

Please sign in to comment.