summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@apache.org>2019-04-23 18:36:35 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2019-04-23 19:31:20 -0400
commit3a54280670704c96f8628eb7cfe926f6f2e414e0 (patch)
tree07c637db7777526ff35b37123be4ec1a5890078d
parentb1f65df8b1b0b425563e9b33c84bb8228de21578 (diff)
downloadcouchdb-3a54280670704c96f8628eb7cfe926f6f2e414e0.tar.gz
Allow restricting resharding parameters
To avoid inadvertently splitting all the shards in all the ranges due to user error, introduce an option enforce the presence of node and range job creation parameters.
-rw-r--r--src/mem3/src/mem3_reshard_api.erl22
-rw-r--r--src/mem3/test/mem3_reshard_api_test.erl29
2 files changed, 51 insertions, 0 deletions
diff --git a/src/mem3/src/mem3_reshard_api.erl b/src/mem3/src/mem3_reshard_api.erl
index f39df4cbb..0d3377db7 100644
--- a/src/mem3/src/mem3_reshard_api.erl
+++ b/src/mem3/src/mem3_reshard_api.erl
@@ -166,13 +166,17 @@ get_reason(StateProps) when is_list(StateProps) ->
pick_shards(undefined, undefined, Db, undefined) when is_binary(Db) ->
+ check_node_required(),
+ check_range_required(),
mem3:shards(Db);
pick_shards(Node, undefined, Db, undefined) when is_atom(Node),
is_binary(Db) ->
+ check_range_required(),
[S || S <- mem3:shards(Db), mem3:node(S) == Node];
pick_shards(undefined, undefined, Db, [_B, _E] = Range) when is_binary(Db) ->
+ check_node_required(),
[S || S <- mem3:shards(Db), mem3:range(S) == Range];
pick_shards(Node, undefined, Db, [_B, _E] = Range) when is_atom(Node),
@@ -180,6 +184,7 @@ pick_shards(Node, undefined, Db, [_B, _E] = Range) when is_atom(Node),
[S || S <- mem3:shards(Db), mem3:node(S) == Node, mem3:range(S) == Range];
pick_shards(undefined, Shard, undefined, undefined) when is_binary(Shard) ->
+ check_node_required(),
Db = mem3:dbname(Shard),
[S || S <- mem3:shards(Db), mem3:name(S) == Shard];
@@ -193,3 +198,20 @@ pick_shards(_, undefined, undefined, _) ->
pick_shards(_, Db, Shard, _) when is_binary(Db), is_binary(Shard) ->
throw({bad_request, <<"`db` and `shard` are mutually exclusive">>}).
+
+
+check_node_required() ->
+ case config:get_boolean("reshard", "require_node_param", false) of
+ true ->
+ throw({bad_request, <<"`node` prameter is required">>});
+ false ->
+ ok
+ end.
+
+check_range_required() ->
+ case config:get_boolean("reshard", "require_range_param", false) of
+ true ->
+ throw({bad_request, <<"`range` prameter is required">>});
+ false ->
+ ok
+ end.
diff --git a/src/mem3/test/mem3_reshard_api_test.erl b/src/mem3/test/mem3_reshard_api_test.erl
index c8be28591..982fed173 100644
--- a/src/mem3/test/mem3_reshard_api_test.erl
+++ b/src/mem3/test/mem3_reshard_api_test.erl
@@ -49,6 +49,8 @@ teardown({Url, {Db1, Db2, Db3}}) ->
delete_db(Url, Db2),
delete_db(Url, Db3),
ok = config:delete("reshard", "max_jobs", _Persist=false),
+ ok = config:delete("reshard", "require_node_param", _Persist=false),
+ ok = config:delete("reshard", "require_range_param", _Persist=false),
ok = config:delete("admins", ?USER, _Persist=false),
meck:unload().
@@ -99,6 +101,7 @@ mem3_reshard_api_test_() ->
fun recover_in_topoff3/1,
fun recover_in_source_delete/1,
fun check_max_jobs/1,
+ fun check_node_and_range_required_params/1,
fun cleanup_completed_jobs/1
]
}
@@ -678,6 +681,32 @@ check_max_jobs({Top, {Db1, Db2, _}}) ->
end).
+check_node_and_range_required_params({Top, {Db1, _, _}}) ->
+ ?_test(begin
+ Jobs = Top ++ ?JOBS,
+
+ Node = atom_to_binary(node(), utf8),
+ Range = <<"00000000-ffffffff">>,
+
+ config:set("reshard", "require_node_param", "true", _Persist=false),
+ {C1, R1} = req(post, Jobs, #{type => split, db => Db1}),
+ NodeRequiredErr = <<"`node` prameter is required">>,
+ ?assertEqual({400, #{<<"error">> => <<"bad_request">>,
+ <<"reason">> => NodeRequiredErr}}, {C1, R1}),
+
+ config:set("reshard", "require_range_param", "true", _Persist=false),
+ {C2, R2} = req(post, Jobs, #{type => split, db => Db1, node => Node}),
+ RangeRequiredErr = <<"`range` prameter is required">>,
+ ?assertEqual({400, #{<<"error">> => <<"bad_request">>,
+ <<"reason">> => RangeRequiredErr}}, {C2, R2}),
+
+ Body = #{type => split, db => Db1, range => Range, node => Node},
+ {C3, R3} = req(post, Jobs, Body),
+ ?assertMatch({201, [#{?OK := true}]}, {C3, R3}),
+ wait_to_complete_then_cleanup(Top, R3)
+ end).
+
+
cleanup_completed_jobs({Top, {Db1, _, _}}) ->
?_test(begin
Body = #{type => split, db => Db1},