from teuthology import misc as teuthology
from teuthology.task import ceph as ceph_task
from teuthology.task.scrub import Scrubber
+from teuthology.task_util.rados import cmd_erasure_code_profile
class Thrasher:
"""
self.config = config
self.controller = controller
self.next_pool_id = 0
- self.created_erasure_pool = False
if (logger):
self.log = lambda x: logger.info(x)
else:
self.log(status)
return status['pgmap']['num_pgs']
- def create_pool_with_unique_name(self, pg_num=16, ec_pool=False, ec_m=1, ec_k=2):
+ def create_erasure_code_profile(self, profile_name, profile):
+ """
+ Create an erasure code profile name that can be used as a parameter
+ when creating an erasure coded pool.
+ """
+ with self.lock:
+ args = cmd_erasure_code_profile(profile_name, profile)
+ self.raw_cluster_cmd(*args)
+
+ def create_pool_with_unique_name(self, pg_num=16, erasure_code_profile_name=None):
"""
Create a pool named unique_pool_X where X is unique.
"""
self.create_pool(
name,
pg_num,
- ec_pool=ec_pool,
- ec_m=ec_m,
- ec_k=ec_k)
+ erasure_code_profile=erasure_code_profile_name)
return name
- def create_pool(self, pool_name, pg_num=16, ec_pool=False, ec_m=1, ec_k=2):
+ def create_pool(self, pool_name, pg_num=16, erasure_code_profile_name=None):
"""
Create a pool named from the pool_name parameter.
:param pool_name: name of the pool being created.
assert isinstance(pg_num, int)
assert pool_name not in self.pools
self.log("creating pool_name %s"%(pool_name,))
- if ec_pool and not self.created_erasure_pool:
- self.created_erasure_pool = True
- self.raw_cluster_cmd('osd', 'erasure-code-profile', 'set', 'teuthologyprofile', 'ruleset-failure-domain=osd', 'm='+str(ec_m), 'k='+str(ec_k))
-
- if ec_pool:
- self.raw_cluster_cmd('osd', 'pool', 'create', pool_name, str(pg_num), str(pg_num), 'erasure', 'teuthologyprofile')
+ if erasure_code_profile_name:
+ self.raw_cluster_cmd('osd', 'pool', 'create', pool_name, str(pg_num), str(pg_num), 'erasure', erasure_code_profile_name)
else:
self.raw_cluster_cmd('osd', 'pool', 'create', pool_name, str(pg_num))
self.pools[pool_name] = pg_num
op_weights: <dictionary mapping operation type to integer weight>
runs: <number of times to run> - the pool is remade between runs
ec_pool: use an ec pool
+ erasure_code_profile: profile to use with the erasure coded pool
pool_snaps: use pool snapshots instead of selfmanaged snapshots
For example::
snap_create: 3
rollback: 2
snap_remove: 0
- ec_pool: true
+ ec_pool: create an ec pool, defaults to False
+ erasure_code_profile:
+ name: teuthologyprofile
+ k: 2
+ m: 1
+ ruleset-failure-domain: osd
pool_snaps: true
runs: 10
- interactive:
clients = ['client.{id}'.format(id=id_) for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')]
log.info('clients are %s' % clients)
+ if config.get('ec_pool', False):
+ profile = config.get('erasure_code_profile', {})
+ profile_name = profile.get('name', 'teuthologyprofile')
+ ctx.manager.create_erasure_code_profile(profile_name, profile)
+ else:
+ profile_name = None
for i in range(int(config.get('runs', '1'))):
log.info("starting run %s out of %s", str(i), config.get('runs', '1'))
tests = {}
if not pool and existing_pools:
pool = existing_pools.pop()
else:
- pool = ctx.manager.create_pool_with_unique_name(ec_pool=config.get('ec_pool', False))
+ pool = ctx.manager.create_pool_with_unique_name(erasure_code_profile_name=profile_name)
created_pools.append(pool)
(remote,) = ctx.cluster.only(role).remotes.iterkeys()
time: <seconds to run>
pool: <pool to use>
unique_pool: use a unique pool, defaults to False
- ec_pool: create ec pool, defaults to False
+ ec_pool: create an ec pool, defaults to False
+ erasure_code_profile:
+ name: teuthologyprofile
+ k: 2
+ m: 1
+ ruleset-failure-domain: osd
example:
id_ = role[len(PREFIX):]
(remote,) = ctx.cluster.only(role).remotes.iterkeys()
+ if config.get('ec_pool', False):
+ profile = config.get('erasure_code_profile', {})
+ profile_name = profile.get('name', 'teuthologyprofile')
+ ctx.manager.create_erasure_code_profile(profile_name, profile)
+ else:
+ profile_name = None
+
pool = 'data'
if config.get('pool'):
pool = config.get('pool')
if pool is not 'data':
- ctx.manager.create_pool(pool, ec_pool=config.get('ec_pool', False))
+ ctx.manager.create_pool(pool, erasure_code_profile_name=profile_name)
else:
- pool = ctx.manager.create_pool_with_unique_name(ec_pool=config.get('ec_pool', False))
+ pool = ctx.manager.create_pool_with_unique_name(erasure_code_profile_name=profile_name)
proc = remote.run(
args=[
else:
return proc
-def create_ec_pool(remote, name, profile_name, pgnum, m=1, k=2):
- remote.run(args=[
- 'ceph', 'osd', 'erasure-code-profile', 'set',
- profile_name, 'm=' + str(m), 'k=' + str(k),
- 'ruleset-failure-domain=osd',
- ])
+def create_ec_pool(remote, name, profile_name, pgnum, profile):
+ remote.run(args=cmd_erasure_code_profile(profile_name, profile))
remote.run(args=[
'ceph', 'osd', 'pool', 'create', name,
str(pgnum), str(pgnum), 'erasure', profile_name,
'ceph', 'osd', 'tier', 'add-cache', base_name, cache_name,
str(size),
])
+
+def cmd_erasure_code_profile(profile_name, profile):
+ """
+ Return the shell command to run to create the erasure code profile
+ described by the profile parameter.
+
+ :param profile_name: a string matching [A-Za-z0-9-_.]+
+ :param profile: a map whose semantic depends on the erasure code plugin
+ :returns: a shell command as an array suitable for Remote.run
+
+ If profile is {}, it is replaced with
+
+ { 'k': '2', 'm': '1', 'ruleset-failure-domain': 'osd'}
+
+ for backward compatibility. In previous versions of teuthology,
+ these values were hardcoded as function arguments and some yaml
+ files were designed with these implicit values. The teuthology
+ code should not know anything about the erasure code profile
+ content or semantic. The valid values and parameters are outside
+ its scope.
+ """
+
+ if profile == {}:
+ profile = {
+ 'k': '2',
+ 'm': '1',
+ 'ruleset-failure-domain': 'osd'
+ }
+ return [
+ 'ceph', 'osd', 'erasure-code-profile', 'set',
+ profile_name
+ ] + [ key + '=' + value for key, value in profile.iteritems() ]
--- /dev/null
+#
+# The MIT License
+#
+# Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
+#
+# Author: Loic Dachary <loic@dachary.org>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+from .. import rados
+
+class TestRados(object):
+
+ def test_cmd_erasure_code_profile(self):
+ name = 'NAME'
+ cmd = rados.cmd_erasure_code_profile(name, {})
+ assert 'k=2' in cmd
+ assert name in cmd
+ cmd = rados.cmd_erasure_code_profile(name, { 'k': '88' })
+ assert 'k=88' in cmd
+ assert name in cmd