OpenStack Rally 使用小结
- OpenStack 版本: Mitaka
- OpenStack Server OS: CentOS 7
0x00 Rally 安装
安装
yum install gcc libffi-devel python-devel openssl-devel gmp-devel libxml2-devel libxslt-devel postgresql-devel redhat-rpm-config git python-pip wget -q -O- https://raw.githubusercontent.com/openstack/rally/master/install_rally.sh | bash
配置
建立 Rally 的数据库
rally-manage db recreate
通过环境变量,注册一个 Openstack deployment,注册成功后,将会默认使用这个 deployment,同时在主目录下会有一个新的目录出现:.rally
rally deployment create --fromenv --name=NAME
也可以将认证信息放到一个 JSON 配置文件来注册 Openstack deployment
rally deployment create --file=JSONFILE.json --name=NAME
检查环境是否可行
rally deployment check
0x01 Rally Benchmark
Rally 安装完会在 /usr/share/rally/samples/tasks/scenarios
生成基准测试用例,可以编辑修改相对应的 Json 或者 Yaml 格式的配置文件来修改测试用例。
通过命令rally task start SCENARIOSFILENAME.yaml
来启动基准测试任务(-v 选项来获取更多日志信息)。
通过命令rally task report TASK_UUID --out output.html
来生成 html 格式的测试结果报告。
测试报告模板使用的 Angular JS 可能无法访问,可以修改使用别的 Angular JS 镜像,修改文件/PATH/TO/rally/ui/templates/task/report.html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.1.15-beta/nv.d3.min.css">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.3/angular.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.1.15-beta/nv.d3.min.js"></script>
替换成
<link rel="stylesheet" href="http://cdn.bootcss.com/nvd3/1.1.15-beta/nv.d3.css">
<script type="text/javascript" src="http://cdn.bootcss.com/angular.js/1.3.3/angular.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/d3/3.4.13/d3.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/nvd3/1.1.15-beta/nv.d3.min.js"></script>
0x02 编写 Rally Plugins
来看看基准测试用例,以 /usr/share/rally/samples/tasks/scenarios/neutron/create_and_delete_security_groups.yaml
为例
---
NeutronSecurityGroup.create_and_delete_security_groups:
-
args:
security_group_create_args: {}
runner:
type: "constant"
times: 100
concurrency: 10
context:
users:
tenants: 3
users_per_tenant: 3
quotas:
neutron:
security_group: -1
第二行 NeutronSecurityGroup.create_and_delete_security_groups
其中 NeutronSecurityGroup
是 /PATH/TO/rally/plugins/openstack/scenarios/neutron/security_groups.py
的类NeutronSecurityGroup
, create_and_delete_security_groups
是 NeutronSecurityGroup
类的方法 create_and_delete_security_groups
。
/PATH/TO/rally/plugins/openstack/scenarios/neutron/security_groups.py
class NeutronSecurityGroup(utils.NeutronScenario):
"""Benchmark scenarios for Neutron Security Groups."""
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_delete_security_groups(self,
security_group_create_args=None):
"""Create and delete Neutron security-groups.
Measure the "neutron security-group-create" and "neutron
security-group-delete" command performance.
:param security_group_create_args: dict, POST /v2.0/security-groups
request options
"""
security_group_create_args = security_group_create_args or {}
security_group = self._create_security_group(
**security_group_create_args)
self._delete_security_group(security_group)
............
方法 _create_security_group
和 _delete_security_groups
分别完成安全组的 create 和 delete ,现在来看下这2个方法具体是怎么实现的。
/PATH/TO/rally/plugins/openstack/scenarios/neutron/utils.py
class NeutronScenario(scenario.OpenStackScenario):
............
@atomic.action_timer("neutron.create_security_group")
def _create_security_group(self, **security_group_create_args):
"""Create Neutron security-group.
param: security_group_create_args: dict, POST /v2.0/security-groups
request options
return: dict, neutron security-group
"""
security_group_create_args["name"] = self.generate_random_name()
return self.clients("neutron").create_security_group(
{"security_group": security_group_create_args})
@atomic.action_timer("neutron.delete_security_group")
def _delete_security_group(self, security_group):
"""Delete Neutron security group.
param: security_group: dict, neutron security_group
"""
return self.clients("neutron").delete_security_group(
security_group["security_group"]["id"])
............
security_group_create_args
即测试用例中 args
里的 security_group_create_args
_create_security_group
调用的 self.clients("neutron").create_security_group
相当于是调用 OpenStack 的 Restful API POST /v2.0/security-groups
_delete_security_group
调用的 self.clients("neutron").delete_security_group
相当于是调用 OpenStack 的 Restful API DELETE /v2.0/security-groups
self.clients("neutron").create_security_group
的参数和 Restful API 一样。
self.clients("neutron").create_security_group
参数如下
{
"security_group": {
"name": self.generate_random_name()
}
}
再来看方法_delete_security_group
,传入的参数 security_group
就是 方法 _create_security_group
的返回值,即调用 Restful API POST /v2.0/security-groups
的 Respone,具体可看上图。只需要将 security group 的 id 传入 self.clients("neutron").delete_security_group
即可删除对应的 security group 。
再来看看 list 部分的代码
/PATH/TO/rally/plugins/openstack/scenarios/neutron/security_groups.py
class NeutronSecurityGroup(utils.NeutronScenario):
"""Benchmark scenarios for Neutron Security Groups."""
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_list_security_groups(self, security_group_create_args=None):
"""Create and list Neutron security-groups.
Measure the "neutron security-group-create" and "neutron
security-group-list" command performance.
:param security_group_create_args: dict, POST /v2.0/security-groups
request options
"""
security_group_create_args = security_group_create_args or {}
self._create_security_group(**security_group_create_args)
self._list_security_groups()
............
/PATH/TO/rally/plugins/openstack/scenarios/neutron/utils.py
class NeutronScenario(scenario.OpenStackScenario):
............
@atomic.action_timer("neutron.list_security_groups")
def _list_qos_policies(self, **kwargs):
"""Return list of Neutron qos policies."""
return self.clients("neutron").list_security_groups(**kwargs)
...........
list 部分的代码最简单,utils.py
部分代码只需要调用self.clients("neutron")
相对应的 list 方法即self.clients("neutron").list_security_groups
。在 security_groups.py
中只需要调用刚刚在 utils.py
中定义的 _list_qos_policies
即可。
最后再看下 update 部分的代码
/PATH/TO/rally/plugins/openstack/scenarios/neutron/security_groups.py
class NeutronSecurityGroup(utils.NeutronScenario):
"""Benchmark scenarios for Neutron Security Groups."""
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_update_security_groups(self,
security_group_create_args=None,
security_group_update_args=None):
"""Create and update Neutron security-groups.
Measure the "neutron security-group-create" and "neutron
security-group-update" command performance.
:param security_group_create_args: dict, POST /v2.0/security-groups
request options
:param security_group_update_args: dict, PUT /v2.0/security-groups
update options
"""
security_group_create_args = security_group_create_args or {}
security_group_update_args = security_group_update_args or {}
security_group = self._create_security_group(
**security_group_create_args)
self._update_security_group(security_group,
**security_group_update_args)
/PATH/TO/rally/plugins/openstack/scenarios/neutron/utils.py
class NeutronScenario(scenario.OpenStackScenario):
............
@atomic.action_timer("neutron.update_security_group")
def _update_security_group(self, security_group,
**security_group_update_args):
"""Update Neutron security-group.
param: security_group: dict, neutron security_group
param: security_group_update_args: dict, POST /v2.0/security-groups
update options
return: dict, updated neutron security-group
"""
security_group_update_args["name"] = self.generate_random_name()
body = {"security_group": security_group_update_args}
return self.clients("neutron").update_security_group(
security_group["security_group"]["id"], body)
同样,utils.py
中的 _update_security_group
的参数 security_group
也是 _create_security_group
的返回值。security_group["security_group"]["id"]
即 刚创建的 security_group 的 id,与之前 delete 部分一样。 body
与 Restful API POST /v2.0/security-groups
的 Request一样,即:
body = {
"security_group": {
"name": self.generate_random_name()
}
}
按照 security_group 部分的代码,来写 qos_policy 的 plugins。
先在 utils.py
部分添加 qos_policy 的 create, delete, list, update 相关方法。
/PATH/TO/rally/plugins/openstack/scenarios/neutron/utils.py
class NeutronScenario(scenario.OpenStackScenario):
............
@atomic.action_timer("neutron.create_qos_policy")
def _create_qos_policy(self, **qos_policy_create_args):
"""Create Neutron qos-policy.
param: qos_policy_create_args: dict, POST /v2.0/qos/policies
request options
return: dict, neutron qos-policy
"""
qos_policy_create_args["name"] = self.generate_random_name()
return self.clients("neutron").create_qos_policy(
{"policy": qos_policy_create_args})
@atomic.action_timer("neutron.delete_qos_policy")
def _delete_qos_policy(self, qos_policy):
"""Delete Neutron qos policy.
param: qos_policy: dict, neutron qos_policy
"""
return self.clients("neutron").delete_qos_policy(
qos_policy["policy"]["id"])
@atomic.action_timer("neutron.list_qos_policies")
def _list_qos_policies(self, **kwargs):
"""Return list of Neutron qos policies."""
return self.clients("neutron").list_qos_policies(**kwargs)
@atomic.action_timer("neutron.update_qos_policy")
def _update_qos_policy(self, qos_policy,
**qos_policy_update_args):
"""Update Neutron qos_policy.
param: qos_policy: dict, neutron qos_policy
param: qos_policy_update_args: dict, POST /v2.0/qos/policies
update options
return: dict, updated neutron qos_policy
"""
qos_policy_update_args["name"] = self.generate_random_name()
body = {"policy": qos_policy_update_args}
return self.clients("neutron").update_qos_policy(
qos_policy["policy"]["id"], body)
- create: 和前面的 security_group 差不多,只需要将变量名和方法名改成 qos_policy 的,调用的 Restful API 变成了
POST /v2.0/qos/policies
,传入的参数按照 Restful API 的 request 进行构造。 - delete: 和前面 security_group 一样,将变量名和方法名改成 qos_policy 的。
- list: 和前面 security_group 一样,将变量名和方法名改成 qos_policy 的。
- update: 和前面 security_group 一样,body数据结构和 Restful API
POST /v2.0/qos/policies
的 request 一样。
然后在 /PATH/TO/rally/plugins/openstack/scenarios/neutron/
创建 qos_policies.py
编写 create_and_delete, create_and_list, create_and_update 相关方法。
from rally import consts
from rally.plugins.openstack import scenario
from rally.plugins.openstack.scenarios.neutron import utils
from rally.task import validation
class NeutronQosPolicy(utils.NeutronScenario):
"""Benchmark scenarios for Neutron Qos Policies."""
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_list_qos_policies(self, qos_policy_create_args=None):
"""Create and list Neutron qos-policies.
Measure the "neutron qos-policy-create" and "neutron
qos-policy-list" command performance.
:param qos_policy_create_args: dict, POST /v2.0/qos/policies
request options
"""
qos_policy_create_args = qos_policy_create_args or {}
self._create_qos_policy(**qos_policy_create_args)
self._list_qos_policies()
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_delete_qos_policies(self, qos_policy_create_args=None):
"""Create and delete Neutron qos-policies.
Measure the "neutron qos-policy-create" and "neutron
qos-policy-delete" command performance.
:param qos_policy_create_args: dict, POST /v2.0/qos-policies
request options
"""
qos_policy_create_args = qos_policy_create_args or {}
qos_policy = self._create_qos_policy(
**qos_policy_create_args)
self._delete_qos_policy(qos_policy)
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_update_qos_policies(self,
qos_policy_create_args=None,
qos_policy_update_args=None):
"""Create and update Neutron qos-policies.
Measure the "neutron qos-policy-create" and "neutron
qos-policy-update" command performance.
:param qos_policy_create_args: dict, POST /v2.0/qos-policies
request options
:param qos_policy_update_args: dict, PUT /v2.0/qos-policies
update options
"""
qos_policy_create_args = qos_policy_create_args or {}
qos_policy_update_args = qos_policy_update_args or {}
qos_policy = self._create_qos_policy(
**qos_policy_create_args)
self._update_qos_policy(qos_policy,
**qos_policy_update_args)
这一部分只需要将 security_groups.py
的变量名和方法名,还有类名进行下替换即可。这里的类名将在测试用例里用到。
最后再编写测试用例,以 create_and_delete 为例
---
NeutronQosPolicy.create_and_delete_qos_policies:
-
args:
qos_policy_create_args: {}
runner:
type: "constant"
times: 100
concurrency: 10
context:
users:
tenants: 3
users_per_tenant: 3
其中的 NeutronQosPolicy
为刚刚创建的 /PATH/TO/rally/plugins/openstack/scenarios/neutron/qos_policies.py
的类名。
args
中的 qos_policy_create_args
为传入方法 _create_qos_policy
的参数。
很好的博客。能知道你的联系方式吗?谢谢