Skip to content

Commit 94001b8

Browse files
committed
MB-70082 Add support for KV rate limiting to cluster-init
Change-Id: I9db2ddca2a82dc3fdaffe4e6355e5ce75f19e898 Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/242093 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Matt Hall <matt.hall@couchbase.com>
1 parent f95aba0 commit 94001b8

5 files changed

Lines changed: 97 additions & 0 deletions

File tree

cbmgr.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,15 @@ def __init__(self):
11091109
help="Set the IP family for the cluster")
11101110
group.add_argument("--node-to-node-encryption", dest="encryption", metavar="<on|off>", default="off",
11111111
choices=["on", "off"], help="Enable node to node encryption")
1112+
group.add_argument("--node-capacity", dest="node_capacity", metavar="<units>", type=(int),
1113+
help="The number of units (bytes) per second. This is a global counter that any "
1114+
"bucket can consume from")
1115+
group.add_argument("--throttle-enabled", dest="throttle_enabled", metavar="<1|0>", choices=["0", "1"],
1116+
help="Enable/Disable throttling feature")
1117+
group.add_argument("--read-unit-size", dest="read_unit_size", metavar="<bytes>", type=(int),
1118+
help="Size of read that will consume 1 unit")
1119+
group.add_argument("--write-unit-size", dest="write_unit_size", metavar="<bytes>", type=(int),
1120+
help="Size of write that will consume 1 unit")
11121121

11131122
@rest_initialiser(enterprise_check=False, enterprise_analytics_check=False)
11141123
def execute(self, opts):
@@ -1182,6 +1191,13 @@ def execute(self, opts):
11821191
send_stats=opts.notifications == "1")
11831192
_exit_if_errors(errors)
11841193

1194+
# Set global throttling settings if any were provided
1195+
if (opts.node_capacity is not None or opts.throttle_enabled is not None or opts.read_unit_size is not None or
1196+
opts.write_unit_size is not None):
1197+
_, errors = self.rest.set_global_memcached_settings(
1198+
opts.node_capacity, opts.throttle_enabled, opts.read_unit_size, opts.write_unit_size)
1199+
_exit_if_errors(errors)
1200+
11851201
_success("Cluster initialized")
11861202

11871203
def setup_ip_family_and_encryption(self, opts):

cluster_manager.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,26 @@ def cluster_init(self, services=None, username=None, password=None, port=None,
15331533

15341534
return self._post_form_encoded(url, params)
15351535

1536+
def set_global_memcached_settings(
1537+
self,
1538+
node_capacity=None,
1539+
throttle_enabled=None,
1540+
read_unit_size=None,
1541+
write_unit_size=None):
1542+
url = f'{self.hostname}/pools/default/settings/memcached/global'
1543+
params = {}
1544+
1545+
if node_capacity is not None:
1546+
params["nodeCapacity"] = node_capacity
1547+
if throttle_enabled is not None:
1548+
params["throttleEnabled"] = "true" if throttle_enabled == "1" else "false"
1549+
if read_unit_size is not None:
1550+
params["readUnitSize"] = read_unit_size
1551+
if write_unit_size is not None:
1552+
params["writeUnitSize"] = write_unit_size
1553+
1554+
return self._post_form_encoded(url, params)
1555+
15361556
def node_info(self):
15371557
url = f'{self.hostname}/nodes/self'
15381558
return self._get(url)

docs/modules/cli/pages/cbcli/couchbase-cli-cluster-init.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ _couchbase-cli cluster-init_ [--cluster <url>] [--cluster-username <username>] [
2222
[--index-storage-setting <setting>] [--services <services>]
2323
[--update-notifications <1|0>]
2424
[--ip-family <ipv4|ipv6|ipv4-only|ipv6-only>] [--node-to-node-encryption <on|off>]
25+
[--node-capacity <capacity>] [--throttle-enabled <1|0>]
26+
[--read-unit-size <size>] [--write-unit-size <size>]
2527

2628
== DESCRIPTION
2729

@@ -149,6 +151,21 @@ which will determine how the global secondary indexes (GSI) are stored.
149151
'off'. When set to 'on' all communications between nodes will be over a
150152
encrypted connection.
151153

154+
--node-capacity::
155+
The number of units (bytes) per second. This is a global counter that any
156+
bucket can consume from. This sets the total amount of resources available on
157+
the node.
158+
159+
--throttle-enabled::
160+
Enable or disable the throttling feature. Accepted values are "1" to enable
161+
and "0" to disable.
162+
163+
--read-unit-size::
164+
The size in bytes of read that will consume 1 unit.
165+
166+
--write-unit-size::
167+
The size in bytes of write that will consume 1 unit.
168+
152169
include::{partialsdir}/cbcli/part-host-formats.adoc[]
153170

154171
include::{partialsdir}/cbcli/part-certificate-authentication.adoc[]

test/mock_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ def export_eventing_functions(rest_params=None, server_args=None, path="", endpo
570570
(r'/settings/retryRebalance$', {'GET': get_by_path, 'POST': do_nothing}),
571571
(r'/settings/replications/(\d|\w)+$', {'POST': do_nothing, 'GET': get_by_path}),
572572
(r'/settings/analytics', {'POST': do_nothing, 'GET': get_by_path}),
573+
(r'/pools/default/settings/memcached/global$', {'POST': do_nothing}),
573574
(r'/nodes/self/controller/settings$', {'POST': do_nothing}),
574575
(r'/nodes/self$', {'GET': get_node_info}),
575576
(r'/nodeInit', {'POST': do_nothing}),

test/test_cli.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,49 @@ def test_error_manager_only_service_enterprise_analytics(self):
409409
['--services', 'manager-only'], self.server_args)
410410
self.assertIn('--services cannot be specified on Enterprise Analytics', self.str_output)
411411

412+
def test_init_cluster_with_throttle_settings(self):
413+
self.server_args['init'] = False
414+
full_options = cluster_connect_args[:2] + self.command_args + [
415+
'--cluster-ramsize', '512', '--services', 'data',
416+
'--node-capacity', '10000', '--throttle-enabled', '1',
417+
'--read-unit-size', '1024', '--write-unit-size', '2048'
418+
]
419+
420+
self.no_error_run(self.command + full_options, self.server_args)
421+
self.assertIn('SUCCESS', self.str_output)
422+
expected_params = ['memoryQuota=512', 'username=Administrator', 'password=asdasd', 'port=6789',
423+
'nodeCapacity=10000', 'throttleEnabled=true', 'readUnitSize=1024', 'writeUnitSize=2048']
424+
self.rest_parameter_match(expected_params, False)
425+
self.assertIn('POST:/pools/default/settings/memcached/global', self.server.trace)
426+
427+
def test_init_cluster_with_throttle_disabled(self):
428+
self.server_args['init'] = False
429+
full_options = cluster_connect_args[:2] + self.command_args + [
430+
'--cluster-ramsize', '512', '--services', 'data',
431+
'--node-capacity', '10000', '--throttle-enabled', '0'
432+
]
433+
434+
self.no_error_run(self.command + full_options, self.server_args)
435+
self.assertIn('SUCCESS', self.str_output)
436+
expected_params = ['memoryQuota=512', 'username=Administrator', 'password=asdasd', 'port=6789',
437+
'nodeCapacity=10000', 'throttleEnabled=false']
438+
self.rest_parameter_match(expected_params, False)
439+
self.assertIn('POST:/pools/default/settings/memcached/global', self.server.trace)
440+
441+
def test_init_cluster_with_only_node_capacity(self):
442+
self.server_args['init'] = False
443+
full_options = cluster_connect_args[:2] + self.command_args + [
444+
'--cluster-ramsize', '512', '--services', 'data',
445+
'--node-capacity', '50000'
446+
]
447+
448+
self.no_error_run(self.command + full_options, self.server_args)
449+
self.assertIn('SUCCESS', self.str_output)
450+
expected_params = ['memoryQuota=512', 'username=Administrator', 'password=asdasd', 'port=6789',
451+
'nodeCapacity=50000']
452+
self.rest_parameter_match(expected_params, False)
453+
self.assertIn('POST:/pools/default/settings/memcached/global', self.server.trace)
454+
412455

413456
class TestBucketCompact(CommandTest):
414457
def setUp(self):

0 commit comments

Comments
 (0)