Refactor agents processing and add unit tests

Change-Id: I810f7ea8b5d4316c7813552a7fba7703337a4f53
This commit is contained in:
Ilya Shakhat 2015-03-10 15:53:24 +03:00
parent d73c8ad2d4
commit c83fa7375e
10 changed files with 513 additions and 248 deletions

View File

@ -58,17 +58,17 @@ resources:
{remote_ip_prefix: 0.0.0.0/0, {remote_ip_prefix: 0.0.0.0/0,
protocol: icmp}] protocol: icmp}]
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}: {{ agent.id }}:
type: OS::Nova::Server type: OS::Nova::Server
properties: properties:
name: {{ group.master.name }} name: {{ agent.id }}
image: { get_param: image } image: { get_param: image }
flavor: { get_param: flavor } flavor: { get_param: flavor }
availability_zone: "nova:{{ group.master.node }}" availability_zone: "nova:{{ agent.node }}"
networks: networks:
- port: { get_resource: {{ group.master.name }}_port } - port: { get_resource: {{ agent.id }}_port }
user_data_format: RAW user_data_format: RAW
user_data: user_data:
str_replace: str_replace:
@ -77,36 +77,9 @@ resources:
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params: params:
"$SERVER_ENDPOINT": { get_param: server_endpoint } "$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.master.name }} "$AGENT_ID": {{ agent.id }}
{{ group.master.name }}_port: {{ agent.id }}_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: private_net }
fixed_ips:
- subnet_id: { get_resource: private_subnet }
security_groups: [{ get_resource: server_security_group }]
{{ group.slave.name }}:
type: OS::Nova::Server
properties:
name: {{ group.slave.name }}
image: { get_param: image }
flavor: { get_param: flavor }
availability_zone: "nova:{{ group.slave.node }}"
networks:
- port: { get_resource: {{ group.slave.name }}_port }
user_data_format: RAW
user_data:
str_replace:
template: |
#!/bin/sh
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params:
"$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.slave.name }}
{{ group.slave.name }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: private_net } network_id: { get_resource: private_net }
@ -117,13 +90,9 @@ resources:
{% endfor %} {% endfor %}
outputs: outputs:
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}_ip: {{ agent.id }}_instance_name:
value: { get_attr: [ {{ group.master.name }}, networks, { get_attr: [private_net, name] }, 0 ] } value: { get_attr: [ {{ agent.id }}, instance_name ] }
{{ group.master.name }}_instance_name: {{ agent.id }}_ip:
value: { get_attr: [ {{ group.master.name }}, instance_name ] } value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [private_net, name] }, 0 ] }
{{ group.slave.name }}_ip:
value: { get_attr: [ {{ group.slave.name }}, networks, { get_attr: [private_net, name] }, 0 ] }
{{ group.slave.name }}_instance_name:
value: { get_attr: [ {{ group.slave.name }}, instance_name ] }
{% endfor %} {% endfor %}

View File

@ -76,17 +76,17 @@ resources:
{remote_ip_prefix: 0.0.0.0/0, {remote_ip_prefix: 0.0.0.0/0,
protocol: icmp}] protocol: icmp}]
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}: {{ agent.id }}:
type: OS::Nova::Server type: OS::Nova::Server
properties: properties:
name: {{ group.master.name }} name: {{ agent.id }}
image: { get_param: image } image: { get_param: image }
flavor: { get_param: flavor } flavor: { get_param: flavor }
availability_zone: "nova:{{ group.master.node }}" availability_zone: "nova:{{ agent.node }}"
networks: networks:
- port: { get_resource: {{ group.master.name }}_port } - port: { get_resource: {{ agent.id }}_port }
user_data_format: RAW user_data_format: RAW
user_data: user_data:
str_replace: str_replace:
@ -95,53 +95,37 @@ resources:
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params: params:
"$SERVER_ENDPOINT": { get_param: server_endpoint } "$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.master.name }} "$AGENT_ID": {{ agent.id }}
{{ group.master.name }}_port: {% if agent.mode == 'master' %}
{{ agent.id }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: east_private_net } network_id: { get_resource: east_private_net }
fixed_ips: fixed_ips:
- subnet_id: { get_resource: east_private_subnet } - subnet_id: { get_resource: east_private_subnet }
security_groups: [{ get_resource: server_security_group }] security_groups: [{ get_resource: server_security_group }]
{% else %}
{{ group.slave.name }}: {{ agent.id }}_port:
type: OS::Nova::Server
properties:
name: {{ group.slave.name }}
image: { get_param: image }
flavor: { get_param: flavor }
availability_zone: "nova:{{ group.slave.node }}"
networks:
- port: { get_resource: {{ group.slave.name }}_port }
user_data_format: RAW
user_data:
str_replace:
template: |
#!/bin/sh
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params:
"$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.slave.name }}
{{ group.slave.name }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: west_private_net } network_id: { get_resource: west_private_net }
fixed_ips: fixed_ips:
- subnet_id: { get_resource: west_private_subnet } - subnet_id: { get_resource: west_private_subnet }
security_groups: [{ get_resource: server_security_group }] security_groups: [{ get_resource: server_security_group }]
{% endif %}
{% endfor %} {% endfor %}
outputs: outputs:
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}_ip: {{ agent.id }}_instance_name:
value: { get_attr: [ {{ group.master.name }}, networks, { get_attr: [east_private_net, name] }, 0 ] } value: { get_attr: [ {{ agent.id }}, instance_name ] }
{{ group.master.name }}_instance_name: {% if agent.mode == 'master' %}
value: { get_attr: [ {{ group.master.name }}, instance_name ] } {{ agent.id }}_ip:
{{ group.slave.name }}_ip: value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [east_private_net, name] }, 0 ] }
value: { get_attr: [ {{ group.slave.name }}, networks, { get_attr: [west_private_net, name] }, 0 ] } {% else %}
{{ group.slave.name }}_instance_name: {{ agent.id }}_ip:
value: { get_attr: [ {{ group.slave.name }}, instance_name ] } value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [west_private_net, name] }, 0 ] }
{% endif %}
{% endfor %} {% endfor %}

View File

@ -84,17 +84,17 @@ resources:
{remote_ip_prefix: 0.0.0.0/0, {remote_ip_prefix: 0.0.0.0/0,
protocol: icmp}] protocol: icmp}]
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}: {{ agent.id }}:
type: OS::Nova::Server type: OS::Nova::Server
properties: properties:
name: {{ group.master.name }} name: {{ agent.id }}
image: { get_param: image } image: { get_param: image }
flavor: { get_param: flavor } flavor: { get_param: flavor }
availability_zone: "nova:{{ group.master.node }}" availability_zone: "nova:{{ agent.node }}"
networks: networks:
- port: { get_resource: {{ group.master.name }}_port } - port: { get_resource: {{ agent.id }}_port }
user_data_format: RAW user_data_format: RAW
user_data: user_data:
str_replace: str_replace:
@ -103,36 +103,18 @@ resources:
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params: params:
"$SERVER_ENDPOINT": { get_param: server_endpoint } "$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.slave.name }} "$AGENT_ID": {{ agent.id }}
{{ group.master.name }}_port: {% if agent.mode == 'master' %}
{{ agent.id }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: north_private_net } network_id: { get_resource: north_private_net }
fixed_ips: fixed_ips:
- subnet_id: { get_resource: north_private_subnet } - subnet_id: { get_resource: north_private_subnet }
security_groups: [{ get_resource: server_security_group }] security_groups: [{ get_resource: server_security_group }]
{% else %}
{{ group.slave.name }}: {{ agent.id }}_port:
type: OS::Nova::Server
properties:
name: {{ group.slave.name }}
image: { get_param: image }
flavor: { get_param: flavor }
availability_zone: "nova:{{ group.slave.node }}"
networks:
- port: { get_resource: {{ group.slave.name }}_port }
user_data_format: RAW
user_data:
str_replace:
template: |
#!/bin/sh
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params:
"$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.slave.name }}
{{ group.slave.name }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: south_private_net } network_id: { get_resource: south_private_net }
@ -140,22 +122,24 @@ resources:
- subnet_id: { get_resource: south_private_subnet } - subnet_id: { get_resource: south_private_subnet }
security_groups: [{ get_resource: server_security_group }] security_groups: [{ get_resource: server_security_group }]
{{ group.slave.name }}_floating_ip: {{ agent.id }}_floating_ip:
type: OS::Neutron::FloatingIP type: OS::Neutron::FloatingIP
properties: properties:
floating_network: { get_param: external_net } floating_network: { get_param: external_net }
port_id: { get_resource: {{ group.slave.name }}_port } port_id: { get_resource: {{ agent.id }}_port }
{% endif %}
{% endfor %} {% endfor %}
outputs: outputs:
{% for group in groups %} {% for agent in agents.value() %}
{{ group.master.name }}_ip: {{ agent.id }}_instance_name:
value: { get_attr: [ {{ group.master.name }}, networks, { get_attr: [north_private_net, name] }, 0 ] } value: { get_attr: [ {{ agent.id }}, instance_name ] }
{{ group.master.name }}_instance_name: {% if agent.mode == 'master' %}
value: { get_attr: [ {{ group.master.name }}, instance_name ] } {{ agent.id }}_ip:
{{ group.slave.name }}_ip: value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [east_private_net, name] }, 0 ] }
value: { get_attr: [ {{ group.slave.name }}_floating_ip, floating_ip_address ] } {% else %}
{{ group.slave.name }}_instance_name: {{ agent.id }}_ip:
value: { get_attr: [ {{ group.slave.name }}, instance_name ] } value: { get_attr: [ {{ agent.id }}_floating_ip, floating_ip_address ] }
{% endif %}
{% endfor %} {% endfor %}

View File

@ -43,17 +43,17 @@ resources:
router_id: { get_resource: router } router_id: { get_resource: router }
subnet_id: { get_resource: private_subnet } subnet_id: { get_resource: private_subnet }
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}: {{ agent.id }}:
type: OS::Nova::Server type: OS::Nova::Server
properties: properties:
name: {{ group.master.name }} name: {{ agent.id }}
image: { get_param: image } image: { get_param: image }
flavor: { get_param: flavor } flavor: { get_param: flavor }
availability_zone: "nova:{{ group.master.node }}" availability_zone: "nova:{{ agent.node }}"
networks: networks:
- port: { get_resource: {{ group.master.name }}_port } - port: { get_resource: {{ agent.id }}_port }
user_data_format: RAW user_data_format: RAW
user_data: user_data:
str_replace: str_replace:
@ -62,9 +62,9 @@ resources:
screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID screen -dmS shaker-agent-screen shaker-agent --server-endpoint=$SERVER_ENDPOINT --agent-id=$AGENT_ID
params: params:
"$SERVER_ENDPOINT": { get_param: server_endpoint } "$SERVER_ENDPOINT": { get_param: server_endpoint }
"$AGENT_ID": {{ group.slave.name }} "$AGENT_ID": {{ agent.id }}
{{ group.master.name }}_port: {{ agent.id }}_port:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network_id: { get_resource: private_net } network_id: { get_resource: private_net }
@ -74,9 +74,9 @@ resources:
{% endfor %} {% endfor %}
outputs: outputs:
{% for group in groups %} {% for agent in agents.values() %}
{{ group.master.name }}_ip: {{ agent.id }}_instance_name:
value: { get_attr: [ {{ group.master.name }}, networks, { get_attr: [private_net, name] }, 0 ] } value: { get_attr: [ {{ agent.id }}, instance_name ] }
{{ group.master.name }}_instance_name: {{ agent.id }}_ip:
value: { get_attr: [ {{ group.master.name }}, instance_name ] } value: { get_attr: [ {{ agent.id }}, networks, { get_attr: [private_net, name] }, 0 ] }
{% endfor %} {% endfor %}

View File

@ -26,6 +26,85 @@ from shaker.openstack.clients import openstack
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def generate_agents(compute_nodes, vm_accommodation, unique):
cn_count = len(compute_nodes)
iterations = cn_count
if 'single_room' in vm_accommodation and 'pair' in vm_accommodation:
iterations //= 2
node_formulae = lambda x: compute_nodes[x % cn_count]
agents = {}
for i in range(iterations):
if 'pair' in vm_accommodation:
master_id = '%s_master_%s' % (unique, i)
slave_id = '%s_slave_%s' % (unique, i)
master = dict(id=master_id, mode='master', slave_id=slave_id)
slave = dict(id=slave_id, mode='slave', master_id=master_id)
if 'single_room' in vm_accommodation:
master['node'] = node_formulae(i * 2)
slave['node'] = node_formulae(i * 2 + 1)
elif 'double_room' in vm_accommodation:
master['node'] = node_formulae(i)
slave['node'] = node_formulae(i)
elif 'mixed_room' in vm_accommodation:
master['node'] = node_formulae(i)
slave['node'] = node_formulae(i + 1)
agents[master['id']] = master
agents[slave['id']] = slave
else:
if 'single_room' in vm_accommodation:
agent_id = '%s_agent_%s' % (unique, i)
agents[agent_id] = dict(id=agent_id, node=node_formulae(i),
mode='alone')
return agents
def _get_stack_values(stack_outputs, vm_name, params):
result = {}
for param in params:
o = stack_outputs.get(vm_name + '_' + param)
if o:
result[param] = o
return result
def filter_agents(agents, stack_outputs):
deployed_agents = {}
# first pass, ignore non-deployed
for agent in agents.values():
stack_values = _get_stack_values(stack_outputs, agent['id'],
['ip', 'instance_name'])
if not stack_values.get('instance_name'):
LOG.info('Ignore non-deployed agent: %s', agent)
continue
agent.update(stack_values)
# workaround of Nova bug 1422686
if agent.get('mode') == 'slave' and not agent.get('ip'):
LOG.info('IP address is missing in agent: %s', agent)
continue
deployed_agents[agent['id']] = agent
# second pass, check pairs
result = {}
for agent in deployed_agents.values():
if (agent.get('mode') == 'alone' or
(agent.get('mode') == 'master' and
agent.get('slave_id') in deployed_agents) or
(agent.get('mode') == 'slave' and
agent.get('master_id') in deployed_agents)):
result[agent['id']] = agent
return result
class Deployment(object): class Deployment(object):
def __init__(self, os_username, os_password, os_tenant_name, os_auth_url, def __init__(self, os_username, os_password, os_tenant_name, os_auth_url,
os_region_name, server_endpoint, external_net, flavor_name, os_region_name, server_endpoint, external_net, flavor_name,
@ -45,87 +124,15 @@ class Deployment(object):
self.stack_name = 'shaker_%s' % utils.random_string() self.stack_name = 'shaker_%s' % utils.random_string()
self.stack_deployed = False self.stack_deployed = False
def _make_groups(self, vm_accommodation):
compute_nodes = nova.get_available_compute_nodes(
self.openstack_client.nova)
cn_count = len(compute_nodes)
iterations = cn_count
if 'single_room' in vm_accommodation and 'pair' in vm_accommodation:
iterations /= 2
node_formulae = lambda x: compute_nodes[x % cn_count]
groups = []
for i in range(iterations):
group = dict(
master=dict(name=('%s_master_%s' % (self.stack_name, i))),
slave=dict(name=('%s_slave_%s' % (self.stack_name, i))))
if 'pair' in vm_accommodation:
if 'single_room' in vm_accommodation:
group['master']['node'] = node_formulae(i * 2)
group['slave']['node'] = node_formulae(i * 2 + 1)
elif 'double_room' in vm_accommodation:
group['master']['node'] = node_formulae(i)
group['slave']['node'] = node_formulae(i)
elif 'mixed_room' in vm_accommodation:
group['master']['node'] = node_formulae(i)
group['slave']['node'] = node_formulae(i + 1)
else:
if 'single_room' in vm_accommodation:
group['master']['node'] = node_formulae(i)
groups.append(group)
return groups
def _get_outputs(self, stack_outputs, vm_name, params):
result = {}
for param in params:
o = stack_outputs.get(vm_name + '_' + param)
if o:
result[param] = o
return result
def _make_agents(self, groups, outputs):
agents = []
for group in groups:
master = self._get_outputs(outputs, group['master']['name'],
['ip', 'instance_name'])
if not master.get('instance_name'):
LOG.info('Group is not deployed: %s. Ignoring', group)
continue
master.update(group['master'])
master.update(dict(mode='master', id=group['master']['name']))
slave = self._get_outputs(outputs, group['slave']['name'],
['ip', 'instance_name'])
# workaround of Nova bug 1422686
if slave.get('instance_name') and not slave.get('ip'):
LOG.info('Ignoring group because of missing IP: %s', group)
continue
agents.append(master)
if slave.get('instance_name'):
# slave is deployed
slave.update(group['slave'])
slave.update(dict(mode='slave', id=group['slave']['name']))
master['slave_id'] = slave['id']
slave['master_id'] = master['id']
agents.append(slave)
return agents
def _deploy_from_hot(self, specification): def _deploy_from_hot(self, specification):
groups = self._make_groups(specification['vm_accommodation']) agents = generate_agents(
nova.get_available_compute_nodes(self.openstack_client.nova),
specification['vm_accommodation'],
self.stack_name)
# render template by jinja # render template by jinja
vars_values = { vars_values = {
'groups': groups, 'agents': agents,
'unique': self.stack_name, 'unique': self.stack_name,
} }
heat_template = utils.read_file(specification['template']) heat_template = utils.read_file(specification['template'])
@ -160,19 +167,18 @@ class Deployment(object):
outputs = heat.get_stack_outputs(self.openstack_client.heat, outputs = heat.get_stack_outputs(self.openstack_client.heat,
stack['id']) stack['id'])
# convert groups into agents return filter_agents(agents, outputs)
return self._make_agents(groups, outputs)
def deploy(self, deployment): def deploy(self, deployment):
agents = [] agents = {}
if deployment.get('template'): if deployment.get('template'):
# deploy topology specified by HOT # deploy topology specified by HOT
agents += self._deploy_from_hot(deployment) agents.update(self._deploy_from_hot(deployment))
if deployment.get('agents'): if deployment.get('agents'):
# agents are specified statically # agents are specified statically
agents += deployment.get('agents') agents.update(dict((a['id'], a) for a in deployment.get('agents')))
return agents return agents

View File

@ -129,29 +129,28 @@ def read_scenario():
return scenario return scenario
def _resolve_agent_ids(agents): def _extend_agents(agents):
id_to_agent = dict((ag['id'], ag) for ag in agents) for agent in agents.values():
for agent in agents:
if agent.get('slave_id'): if agent.get('slave_id'):
agent['slave'] = id_to_agent[agent['slave_id']] agent['slave'] = utils.copy_dict_kv(agents[agent['slave_id']])
if agent.get('master_id'): if agent.get('master_id'):
agent['master'] = id_to_agent[agent['master_id']] agent['master'] = utils.copy_dict_kv(agents[agent['master_id']])
def _pick_agents(agents, size): def _pick_agents(agents, size):
# tests are executed on master agents only # slave agents do not execute any tests
agents = [a for a in agents if a['mode'] == 'master'] agents = [a for a in agents.values() if a.get('mode') != 'slave']
if not size or size == 'full': if not size or size == 'full':
yield agents yield agents
elif size == 'linear_progression': elif size == 'linear_progression':
for i in range(len(agents)): for i in range(len(agents)):
yield agents[:i] yield agents[:i + 1]
elif size == 'quadratic_progression': elif size == 'quadratic_progression':
n = len(agents) n = len(agents)
seq = [n] seq = [n]
while n > 1: while n > 1:
n /= 2 n //= 2
seq.append(n) seq.append(n)
seq.reverse() seq.reverse()
for i in seq: for i in seq:
@ -159,12 +158,12 @@ def _pick_agents(agents, size):
def execute(execution, agents): def execute(execution, agents):
_resolve_agent_ids(agents) _extend_agents(agents)
message_queue = MessageQueue(cfg.CONF.server_endpoint) message_queue = MessageQueue(cfg.CONF.server_endpoint)
quorum = Quorum(message_queue) quorum = Quorum(message_queue)
quorum.wait_join(set(a['id'] for a in agents)) quorum.wait_join(set(agents.keys()))
result = [] result = []
@ -216,34 +215,37 @@ def main():
LOG.info('Logging enabled') LOG.info('Logging enabled')
conf.log_opt_values(LOG, std_logging.DEBUG) conf.log_opt_values(LOG, std_logging.DEBUG)
scenario = read_scenario() deployment = None
deployment = deploy.Deployment(cfg.CONF.os_username, try:
cfg.CONF.os_password, scenario = read_scenario()
cfg.CONF.os_tenant_name, deployment = deploy.Deployment(cfg.CONF.os_username,
cfg.CONF.os_auth_url, cfg.CONF.os_password,
cfg.CONF.os_region_name, cfg.CONF.os_tenant_name,
cfg.CONF.server_endpoint, cfg.CONF.os_auth_url,
cfg.CONF.external_net, cfg.CONF.os_region_name,
cfg.CONF.flavor_name, cfg.CONF.server_endpoint,
cfg.CONF.image_name) cfg.CONF.external_net,
agents = deployment.deploy(scenario['deployment']) cfg.CONF.flavor_name,
cfg.CONF.image_name)
agents = deployment.deploy(scenario['deployment'])
if not agents: if not agents:
LOG.info('No agents deployed. Terminating.') LOG.info('No agents deployed. Terminating.')
return return
LOG.debug('Agents: %s', agents) LOG.debug('Agents: %s', agents)
result = execute(scenario['execution'], agents) result = execute(scenario['execution'], agents)
LOG.debug('Result: %s', result) LOG.debug('Result: %s', result)
report.generate_report(cfg.CONF.report_template, report.generate_report(cfg.CONF.report_template,
cfg.CONF.report, cfg.CONF.report,
dict(scenario=yaml.dump(scenario), dict(scenario=yaml.dump(scenario),
agents=agents, agents=agents.values(),
result=result)) result=result))
finally:
deployment.cleanup() if deployment:
deployment.cleanup()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -71,3 +71,7 @@ def read_uri(uri):
def random_string(length=6): def random_string(length=6):
return ''.join(random.sample('adefikmoprstuz', length)) return ''.join(random.sample('adefikmoprstuz', length))
def copy_dict_kv(source):
return dict((k, v) for k, v in source.items())

View File

@ -3,6 +3,7 @@
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
# Hacking already pins down pep8, pyflakes and flake8 # Hacking already pins down pep8, pyflakes and flake8
coverage>=3.6
hacking>=0.8.0,<0.9 hacking>=0.8.0,<0.9
mock>=1.0 mock>=1.0
python-subunit>=0.0.18 python-subunit>=0.0.18

227
tests/test_deploy.py Normal file
View File

@ -0,0 +1,227 @@
# Copyright (c) 2015 Mirantis Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import testtools
from shaker.engine import deploy
class TestDeploy(testtools.TestCase):
def test_generate_agents_alone_single_room(self):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'node': 'dos'},
}
actual = deploy.generate_agents(['uno', 'dos'],
['single_room'],
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_single_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
}
actual = deploy.generate_agents(['uno', 'dos', 'tre'],
['pair', 'single_room'],
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_double_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'uno'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'node': 'dos',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'node': 'dos'},
'UU1D_master_2': {
'id': 'UU1D_master_2',
'mode': 'master',
'node': 'tre',
'slave_id': 'UU1D_slave_2'},
'UU1D_slave_2': {
'id': 'UU1D_slave_2',
'master_id': 'UU1D_master_2',
'mode': 'slave',
'node': 'tre'},
}
actual = deploy.generate_agents(['uno', 'dos', 'tre'],
['pair', 'double_room'],
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_mixed_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'node': 'dos',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'node': 'uno'},
}
actual = deploy.generate_agents(['uno', 'dos'],
['pair', 'mixed_room'],
unique)
self.assertEqual(expected, actual)
def test_filter_agents_all_deployed(self):
agents = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'node': 'dos'},
}
stack_outputs = {
'UU1D_agent_0_ip': '10.0.0.1',
'UU1D_agent_0_instance_name': 'i-000001',
'UU1D_agent_1_ip': '10.0.0.2',
'UU1D_agent_1_instance_name': 'i-000002',
}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(agents, filtered)
def test_filter_agents_partial_deployed(self):
agents = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'node': 'dos'},
}
stack_outputs = {
'UU1D_agent_0_ip': '10.0.0.1',
'UU1D_agent_0_instance_name': 'i-000001',
}
expected = {'UU1D_agent_0': agents['UU1D_agent_0']}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)
def test_filter_agents_pair_single_room(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
}
stack_outputs = {
'UU1D_master_0_ip': '10.0.0.1',
'UU1D_master_0_instance_name': 'i-000001',
'UU1D_slave_0_ip': '10.0.0.2',
'UU1D_slave_0_instance_name': 'i-000002',
}
expected = {'UU1D_master_0': agents['UU1D_master_0'],
'UU1D_slave_0': agents['UU1D_slave_0']}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)
def test_filter_agents_pair_double_room_partially_deployed(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'uno'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'node': 'dos',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'node': 'dos'},
}
stack_outputs = {
'UU1D_master_0_ip': '10.0.0.1',
'UU1D_master_0_instance_name': 'i-000001',
'UU1D_slave_0_ip': '10.0.0.2',
'UU1D_slave_0_instance_name': 'i-000002',
'UU1D_master_1_ip': '10.0.0.3',
'UU1D_master_1_instance_name': 'i-000003',
'UU1D_slave_1_instance_name': 'i-000004',
}
expected = {'UU1D_master_0': agents['UU1D_master_0'],
'UU1D_slave_0': agents['UU1D_slave_0'], }
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)

88
tests/test_server.py Normal file
View File

@ -0,0 +1,88 @@
# Copyright (c) 2015 Mirantis Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import testtools
from shaker.engine import server
class TestServer(testtools.TestCase):
def test_extend_agents(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
}
server._extend_agents(agents)
self.assertDictContainsSubset(agents['UU1D_master_0']['slave'],
agents['UU1D_slave_0'])
self.assertDictContainsSubset(agents['UU1D_slave_0']['master'],
agents['UU1D_master_0'])
def test_pick_agents_full(self):
agents = {}
for i in range(10):
agents[i] = {
'id': i, 'mode': 'alone', 'node': 'uno',
}
picked = [set(a['id'] for a in arr)
for arr in server._pick_agents(agents, 'full')]
self.assertEqual([set(range(10))], picked)
def test_pick_agents_full_filter_slaves(self):
agents = {}
for i in range(10):
agents['master_%s' % i] = {
'id': 'master_%s' % i, 'mode': 'master', 'node': 'uno',
}
agents['slave_%s' % i] = {
'id': 'slave_%s' % i, 'mode': 'slave', 'node': 'uno',
}
picked = [set(a['id'] for a in arr)
for arr in server._pick_agents(agents, 'full')]
self.assertEqual([set('master_%s' % i for i in range(10))],
picked)
def test_pick_agents_linear(self):
agents = {}
for i in range(10):
agents[i] = {
'id': i, 'mode': 'alone', 'node': 'uno',
}
picked = [set(a['id'] for a in arr)
for arr in server._pick_agents(agents, 'linear_progression')]
self.assertEqual([set(range(i + 1)) for i in range(0, 10)],
picked)
def test_pick_agents_quadratic(self):
agents = {}
for i in range(10):
agents[i] = {
'id': i, 'mode': 'alone', 'node': 'uno',
}
picked = [set(a['id'] for a in arr)
for arr in server._pick_agents(agents,
'quadratic_progression')]
self.assertEqual([set(range(1)), set(range(2)),
set(range(5)), set(range(10))],
picked)