Skip to content

Commit

Permalink
Merge PR #31064 into master
Browse files Browse the repository at this point in the history
* refs/pull/31064/head:
	test: Test balancer module commands
	mgr: Improve balancer module status
	mgr: Release GIL before calling OSDMap::calc_pg_upmaps()

Reviewed-by: Josh Durgin <jdurgin@redhat.com>
Reviewed-by: Kefu Chai <kchai@redhat.com>
  • Loading branch information
liewegas committed Nov 7, 2019
2 parents b7fb76e + 3a0e2c8 commit 5def1df
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 6 deletions.
125 changes: 125 additions & 0 deletions qa/standalone/mgr/balancer.sh
@@ -0,0 +1,125 @@
#!/usr/bin/env bash
#
# Copyright (C) 2019 Red Hat <contact@redhat.com>
#
# Author: David Zafman <dzafman@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library Public License for more details.
#
source $CEPH_ROOT/qa/standalone/ceph-helpers.sh

function run() {
local dir=$1
shift

export CEPH_MON="127.0.0.1:7102" # git grep '\<7102\>' : there must be only one
export CEPH_ARGS
CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
CEPH_ARGS+="--mon-host=$CEPH_MON "

local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')}
for func in $funcs ; do
$func $dir || return 1
done
}

TEST_POOL1=test1
TEST_POOL2=test2

function TEST_balancer() {
local dir=$1

setup $dir || return 1
run_mon $dir a || return 1
run_mgr $dir x || return 1
run_osd $dir 0 || return 1
run_osd $dir 1 || return 1
run_osd $dir 2 || return 1
create_pool $TEST_POOL1 8
create_pool $TEST_POOL2 8

wait_for_clean || return 1

ceph pg dump pgs
ceph osd set-require-min-compat-client luminous
ceph balancer status || return 1
eval MODE=$(ceph balancer status | jq '.mode')
test $MODE = "none" || return 1
ACTIVE=$(ceph balancer status | jq '.active')
test $ACTIVE = "false" || return 1

ceph balancer ls || return 1
PLANS=$(ceph balancer ls)
test "$PLANS" = "[]" || return 1
ceph balancer eval || return 1
EVAL="$(ceph balancer eval)"
test "$EVAL" = "current cluster score 0.000000 (lower is better)"
ceph balancer eval-verbose || return 1

ceph balancer pool add $TEST_POOL1 || return 1
ceph balancer pool add $TEST_POOL2 || return 1
ceph balancer pool ls || return 1
eval POOL=$(ceph balancer pool ls | jq '.[0]')
test "$POOL" = "$TEST_POOL1" || return 1
eval POOL=$(ceph balancer pool ls | jq '.[1]')
test "$POOL" = "$TEST_POOL2" || return 1
ceph balancer pool rm $TEST_POOL1 || return 1
ceph balancer pool rm $TEST_POOL2 || return 1
ceph balancer pool ls || return 1
ceph balancer pool add $TEST_POOL1 || return 1

ceph balancer mode crush-compat || return 1
ceph balancer status || return 1
eval MODE=$(ceph balancer status | jq '.mode')
test $MODE = "crush-compat" || return 1
! ceph balancer optimize plan_crush $TEST_POOL1 || return 1
ceph balancer status || return 1
eval RESULT=$(ceph balancer status | jq '.optimize_result')
test "$RESULT" = "Distribution is already perfect" || return 1

ceph balancer on || return 1
ACTIVE=$(ceph balancer status | jq '.active')
test $ACTIVE = "true" || return 1
sleep 2
ceph balancer status || return 1
ceph balancer off || return 1
ACTIVE=$(ceph balancer status | jq '.active')
test $ACTIVE = "false" || return 1
sleep 2

ceph balancer reset || return 1

ceph balancer mode upmap || return 1
ceph balancer status || return 1
eval MODE=$(ceph balancer status | jq '.mode')
test $MODE = "upmap" || return 1
! ceph balancer optimize plan_upmap $TEST_POOL || return 1
ceph balancer status || return 1
eval RESULT=$(ceph balancer status | jq '.optimize_result')
test "$RESULT" = "Unable to find further optimization, or pool(s)' pg_num is decreasing, or distribution is already perfect" || return 1

ceph balancer on || return 1
ACTIVE=$(ceph balancer status | jq '.active')
test $ACTIVE = "true" || return 1
sleep 2
ceph balancer status || return 1
ceph balancer off || return 1
ACTIVE=$(ceph balancer status | jq '.active')
test $ACTIVE = "false" || return 1

teardown $dir || return 1
}

main balancer "$@"

# Local Variables:
# compile-command: "make -j4 && ../qa/run-standalone.sh balancer.sh"
# End:
18 changes: 18 additions & 0 deletions qa/suites/rados/standalone/workloads/mgr.yaml
@@ -0,0 +1,18 @@
roles:
- - mon.a
- mgr.x
- osd.0
- osd.1
- osd.2
- client.0
openstack:
- volumes: # attached to each instance
count: 3
size: 10 # GB
tasks:
- install:
- workunit:
basedir: qa/standalone
clients:
all:
- mgr
2 changes: 2 additions & 0 deletions src/mgr/PyOSDMap.cc
Expand Up @@ -147,11 +147,13 @@ static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args)
<< " max_iterations " << max_iterations
<< " pools " << pools
<< dendl;
PyThreadState *tstate = PyEval_SaveThread();
int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
max_deviation,
max_iterations,
pools,
incobj->inc);
PyEval_RestoreThread(tstate);
dout(10) << __func__ << " r = " << r << dendl;
return PyInt_FromLong(r);
}
Expand Down
47 changes: 41 additions & 6 deletions src/pybind/mgr/balancer/module.py
Expand Up @@ -13,6 +13,7 @@
from mgr_module import MgrModule, CommandResult
from threading import Event
from mgr_module import CRUSHMap
import datetime

TIME_FORMAT = '%Y-%m-%d_%H:%M:%S'

Expand Down Expand Up @@ -407,6 +408,12 @@ class Module(MgrModule):
run = True
plans = {}
mode = ''
optimizing = False
last_optimize_started = ''
last_optimize_duration = ''
optimize_result = ''
success_string = 'Optimization plan created successfully'
in_progress_string = 'in progress'

def __init__(self, *args, **kwargs):
super(Module, self).__init__(*args, **kwargs)
Expand All @@ -418,6 +425,9 @@ def handle_command(self, inbuf, command):
s = {
'plans': list(self.plans.keys()),
'active': self.active,
'last_optimize_started': self.last_optimize_started,
'last_optimize_duration': self.last_optimize_duration,
'optimize_result': self.optimize_result,
'mode': self.get_module_option('mode'),
}
return (0, json.dumps(s, indent=4), '')
Expand Down Expand Up @@ -519,6 +529,11 @@ def handle_command(self, inbuf, command):
'current cluster')
return (0, self.evaluate(ms, pools, verbose=verbose), '')
elif command['prefix'] == 'balancer optimize':
# The GIL can be release by the active balancer, so disallow when active
if self.active:
return (-errno.EINVAL, '', 'Balancer enabled, disable to optimize manually')
if self.optimizing:
return (-errno.EINVAL, '', 'Balancer finishing up....try again')
pools = []
if 'pools' in command:
pools = command['pools']
Expand All @@ -531,11 +546,18 @@ def handle_command(self, inbuf, command):
if len(invalid_pool_names):
return (-errno.EINVAL, '', 'pools %s not found' % invalid_pool_names)
plan = self.plan_create(command['plan'], osdmap, pools)
self.last_optimize_started = time.asctime(time.localtime())
self.optimize_result = self.in_progress_string
start = time.time()
r, detail = self.optimize(plan)
# remove plan if we are currently unable to find an optimization
# or distribution is already perfect
if r:
self.plan_rm(command['plan'])
end = time.time()
self.last_optimize_duration = str(datetime.timedelta(seconds=(end - start)))
if r == 0:
# Add plan if an optimization was created
self.optimize_result = self.success_string
self.plans[command['plan']] = plan
else:
self.optimize_result = detail
return (r, '', detail)
elif command['prefix'] == 'balancer rm':
self.plan_rm(command['plan'])
Expand All @@ -556,6 +578,11 @@ def handle_command(self, inbuf, command):
return (-errno.ENOENT, '', 'plan %s not found' % command['plan'])
return (0, plan.show(), '')
elif command['prefix'] == 'balancer execute':
# The GIL can be release by the active balancer, so disallow when active
if self.active:
return (-errno.EINVAL, '', 'Balancer enabled, disable to execute a plan')
if self.optimizing:
return (-errno.EINVAL, '', 'Balancer finishing up....try again')
plan = self.plans.get(command['plan'])
if not plan:
return (-errno.ENOENT, '', 'plan %s not found' % command['plan'])
Expand Down Expand Up @@ -625,10 +652,19 @@ def serve(self):
final = [int(p) for p in final]
final = [pool_name_by_id[p] for p in final if p in pool_name_by_id]
plan = self.plan_create(name, osdmap, final)
self.optimizing = True
self.last_optimize_started = time.asctime(time.localtime())
self.optimize_result = self.in_progress_string
start = time.time()
r, detail = self.optimize(plan)
end = time.time()
self.last_optimize_duration = str(datetime.timedelta(seconds=(end - start)))
if r == 0:
self.optimize_result = self.success_string
self.execute(plan)
self.plan_rm(name)
else:
self.optimize_result = detail
self.optimizing = False
self.log.debug('Sleeping for %d', sleep_interval)
self.event.wait(sleep_interval)
self.event.clear()
Expand All @@ -639,7 +675,6 @@ def plan_create(self, name, osdmap, pools):
self.get("pg_dump"),
'plan %s initial' % name),
pools)
self.plans[name] = plan
return plan

def plan_rm(self, name):
Expand Down
2 changes: 2 additions & 0 deletions src/test/cli-integration/balancer/misplaced.t
Expand Up @@ -10,6 +10,8 @@
$ ceph config set osd.* target_max_misplaced_ratio .07
$ ceph balancer eval
current cluster score [0-9]*\.?[0-9]+.* (re)
# Turn off active balancer to use manual commands
$ ceph balancer off
$ ceph balancer optimize test_plan balancer_opt
$ ceph balancer ls
[
Expand Down

0 comments on commit 5def1df

Please sign in to comment.