couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject [couchdb] branch master updated: Make peruser database prefix configurable
Date Tue, 23 Jan 2018 11:38:34 GMT
This is an automated email from the ASF dual-hosted git repository.

jan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/master by this push:
     new d16f2db  Make peruser database prefix configurable
d16f2db is described below

commit d16f2db901c9b3b24c7189acfec35ec42895bd25
Author: jiangphcn <jiangph@cn.ibm.com>
AuthorDate: Fri Dec 15 15:07:04 2017 +0800

    Make peruser database prefix configurable
    
    Fixes #876
---
 rel/overlay/etc/default.ini                   |  4 ++
 src/couch_peruser/src/couch_peruser.erl       | 52 ++++++++++++--------
 src/couch_peruser/test/couch_peruser_test.erl | 68 +++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 19 deletions(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index c473495..7e429f6 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -91,6 +91,10 @@ delete_dbs = false
 ; Set a default q value for peruser-created databases that is different from
 ; cluster / q
 ;q = 1
+; prefix for user databases. If you change this after user dbs have been
+; created, the existing databases won’t get deleted if the associated user
+; gets deleted because of the then prefix mismatch.
+database_prefix = userdb-
 
 [httpd]
 port = {{backend_port}}
diff --git a/src/couch_peruser/src/couch_peruser.erl b/src/couch_peruser/src/couch_peruser.erl
index bbf4012..886fb4f 100644
--- a/src/couch_peruser/src/couch_peruser.erl
+++ b/src/couch_peruser/src/couch_peruser.erl
@@ -35,7 +35,8 @@
     delete_dbs :: boolean(),
     changes_pid :: pid(),
     changes_ref :: reference(),
-    q_for_peruser_db :: integer()
+    q_for_peruser_db :: integer(),
+    peruser_dbname_prefix :: binary()
 }).
 
 -record(state, {
@@ -45,10 +46,11 @@
     states :: list(),
     mem3_cluster_pid :: pid(),
     cluster_stable :: boolean(),
-    q_for_peruser_db :: integer()
+    q_for_peruser_db :: integer(),
+    peruser_dbname_prefix :: binary()
 }).
 
--define(USERDB_PREFIX, "userdb-").
+-define(DEFAULT_USERDB_PREFIX, "userdb-").
 -define(RELISTEN_DELAY, 5000).
 -define(DEFAULT_QUIET_PERIOD, 60). % seconds
 -define(DEFAULT_START_PERIOD, 5). % seconds
@@ -73,6 +75,14 @@ init_state() ->
                          "couch_httpd_auth", "authentication_db", "_users")),
         DeleteDbs = config:get_boolean("couch_peruser", "delete_dbs", false),
         Q = config:get_integer("couch_peruser", "q", 1),
+        Prefix = config:get("couch_peruser", "database_prefix", ?DEFAULT_USERDB_PREFIX),
+        case couch_db:validate_dbname(Prefix) of
+            ok -> ok;
+            Error ->
+                couch_log:error("couch_peruser can't proceed as illegal database prefix ~p.
+                    Error: ~p", [Prefix, Error]),
+                throw(Error)
+        end,
 
 
         % set up cluster-stable listener
@@ -90,7 +100,8 @@ init_state() ->
             delete_dbs = DeleteDbs,
             mem3_cluster_pid = Mem3Cluster,
             cluster_stable = false,
-            q_for_peruser_db = Q
+            q_for_peruser_db = Q,
+            peruser_dbname_prefix = ?l2b(Prefix)
         }
     end.
 
@@ -100,7 +111,8 @@ start_listening(#state{states=ChangesStates}=State)
     when length(ChangesStates) > 0 ->
     % couch_log:debug("peruser: start_listening() already run on node ~p in pid ~p", [node(),
self()]),
     State;
-start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs, q_for_peruser_db = Q} = State)
->
+start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs,
+    q_for_peruser_db = Q, peruser_dbname_prefix = Prefix} = State) ->
     % couch_log:debug("peruser: start_listening() on node ~p", [node()]),
     try
         States = lists:map(fun (A) ->
@@ -108,7 +120,8 @@ start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs, q_for_peruser_db
=
                 parent = State#state.parent,
                 db_name = A#shard.name,
                 delete_dbs = DeleteDbs,
-                q_for_peruser_db = Q
+                q_for_peruser_db = Q,
+                peruser_dbname_prefix = Prefix
             },
             {Pid, Ref} = spawn_opt(
                 ?MODULE, init_changes_handler, [S], [link, monitor]),
@@ -144,7 +157,8 @@ init_changes_handler(#changes_state{db_name=DbName} = ChangesState) ->
 changes_handler(
     {change, {Doc}, _Prepend},
     _ResType,
-    ChangesState=#changes_state{db_name=DbName, q_for_peruser_db = Q}) ->
+    ChangesState=#changes_state{db_name=DbName, q_for_peruser_db = Q,
+        peruser_dbname_prefix = Prefix}) ->
     % couch_log:debug("peruser: changes_handler() on DbName/Doc ~p/~p", [DbName, Doc]),
 
     case couch_util:get_value(<<"id">>, Doc) of
@@ -153,16 +167,16 @@ changes_handler(
         true ->
             case couch_util:get_value(<<"deleted">>, Doc, false) of
             false ->
-                UserDb = ensure_user_db(User, Q),
+                UserDb = ensure_user_db(Prefix, User, Q),
                 ok = ensure_security(User, UserDb, fun add_user/3),
                 ChangesState;
             true ->
                 case ChangesState#changes_state.delete_dbs of
                 true ->
-                    _UserDb = delete_user_db(User),
+                    _UserDb = delete_user_db(Prefix, User),
                     ChangesState;
                 false ->
-                    UserDb = user_db_name(User),
+                    UserDb = user_db_name(Prefix, User),
                     ok = ensure_security(User, UserDb, fun remove_user/3),
                     ChangesState
                 end
@@ -207,9 +221,9 @@ should_handle_doc_int(ShardName, DocId) ->
         false
   end.
 
--spec delete_user_db(User :: binary()) -> binary().
-delete_user_db(User) ->
-    UserDb = user_db_name(User),
+-spec delete_user_db(Prefix:: binary(), User :: binary()) -> binary().
+delete_user_db(Prefix, User) ->
+    UserDb = user_db_name(Prefix, User),
     try
         case fabric:delete_db(UserDb, [?ADMIN_CTX]) of
         ok -> ok;
@@ -220,9 +234,9 @@ delete_user_db(User) ->
     end,
     UserDb.
 
--spec ensure_user_db(User :: binary(), Q :: integer()) -> binary().
-ensure_user_db(User, Q) ->
-    UserDb = user_db_name(User),
+-spec ensure_user_db(Prefix:: binary(), User :: binary(), Q :: integer()) -> binary().
+ensure_user_db(Prefix, User, Q) ->
+    UserDb = user_db_name(Prefix, User),
     try
         {ok, _DbInfo} = fabric:get_db_info(UserDb)
     catch error:database_does_not_exist ->
@@ -300,11 +314,11 @@ ensure_security(User, UserDb, TransformFun) ->
         end
     end.
 
--spec user_db_name(User :: binary()) -> binary().
-user_db_name(User) ->
+-spec user_db_name(Prefix :: binary(), User :: binary()) -> binary().
+user_db_name(Prefix, User) ->
     HexUser = list_to_binary(
         [string:to_lower(integer_to_list(X, 16)) || <<X>> <= User]),
-    <<?USERDB_PREFIX,HexUser/binary>>.
+    <<Prefix/binary,HexUser/binary>>.
 
 -spec exit_changes(State :: #state{}) -> ok.
 exit_changes(State) ->
diff --git a/src/couch_peruser/test/couch_peruser_test.erl b/src/couch_peruser/test/couch_peruser_test.erl
index 1ce1964..f6ef88f 100644
--- a/src/couch_peruser/test/couch_peruser_test.erl
+++ b/src/couch_peruser/test/couch_peruser_test.erl
@@ -156,6 +156,20 @@ should_create_user_db_with_default(TestAuthDb) ->
         ?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
     ].
 
+should_create_user_db_with_custom_prefix(TestAuthDb) ->
+    set_config("couch_peruser", "database_prefix", "newuserdb-"),
+    create_user(TestAuthDb, "fooo"),
+    wait_for_db_create(<<"newuserdb-666f6f6f">>),
+    delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+    ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_user_db_with_custom_special_prefix(TestAuthDb) ->
+    set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    create_user(TestAuthDb, "fooo"),
+    wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+    delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
 should_create_anon_user_db_with_default(TestAuthDb) ->
     create_anon_user(TestAuthDb, "fooo"),
     wait_for_db_create(<<"userdb-666f6f6f">>),
@@ -166,6 +180,20 @@ should_create_anon_user_db_with_default(TestAuthDb) ->
         ?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
     ].
 
+should_create_anon_user_db_with_custom_prefix(TestAuthDb) ->
+    set_config("couch_peruser", "database_prefix", "newuserdb-"),
+    create_anon_user(TestAuthDb, "fooo"),
+    wait_for_db_create(<<"newuserdb-666f6f6f">>),
+    delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+    ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_anon_user_db_with_custom_special_prefix(TestAuthDb) ->
+    set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    create_anon_user(TestAuthDb, "fooo"),
+    wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+    delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
 should_create_user_db_with_q4(TestAuthDb) ->
     set_config("couch_peruser", "q", "4"),
     create_user(TestAuthDb, "foo"),
@@ -214,6 +242,40 @@ should_delete_user_db(TestAuthDb) ->
     AfterDelete = lists:member(UserDbName, all_dbs()),
     [?_assert(AfterCreate), ?_assertNot(AfterDelete)].
 
+should_delete_user_db_with_custom_prefix(TestAuthDb) ->
+    User = "bar",
+    UserDbName = <<"newuserdb-626172">>,
+    set_config("couch_peruser", "delete_dbs", "true"),
+    set_config("couch_peruser", "database_prefix", "newuserdb-"),
+    create_user(TestAuthDb, User),
+    wait_for_db_create(UserDbName),
+    AfterCreate = lists:member(UserDbName, all_dbs()),
+    delete_user(TestAuthDb, User),
+    wait_for_db_delete(UserDbName),
+    delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+    AfterDelete = lists:member(UserDbName, all_dbs()),
+    [
+        ?_assert(AfterCreate),
+        ?_assertNot(AfterDelete)
+    ].
+
+should_delete_user_db_with_custom_special_prefix(TestAuthDb) ->
+    User = "bar",
+    UserDbName = <<"userdb_$()+--/626172">>,
+    set_config("couch_peruser", "delete_dbs", "true"),
+    set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    create_user(TestAuthDb, User),
+    wait_for_db_create(UserDbName),
+    AfterCreate = lists:member(UserDbName, all_dbs()),
+    delete_user(TestAuthDb, User),
+    wait_for_db_delete(UserDbName),
+    delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+    AfterDelete = lists:member(UserDbName, all_dbs()),
+    [
+        ?_assert(AfterCreate),
+        ?_assertNot(AfterDelete)
+    ].
+
 should_reflect_config_changes(TestAuthDb) ->
     User = "baz",
     UserDbName = <<"userdb-62617a">>,
@@ -445,11 +507,17 @@ couch_peruser_test_() ->
                 fun setup/0, fun teardown/1,
                 [
                     fun should_create_anon_user_db_with_default/1,
+                    fun should_create_anon_user_db_with_custom_prefix/1,
+                    fun should_create_anon_user_db_with_custom_special_prefix/1,
                     fun should_create_user_db_with_default/1,
+                    fun should_create_user_db_with_custom_prefix/1,
+                    fun should_create_user_db_with_custom_special_prefix/1,
                     fun should_create_user_db_with_q4/1,
                     fun should_create_anon_user_db_with_q4/1,
                     fun should_not_delete_user_db/1,
                     fun should_delete_user_db/1,
+                    fun should_delete_user_db_with_custom_prefix/1,
+                    fun should_delete_user_db_with_custom_special_prefix/1,
                     fun should_reflect_config_changes/1,
                     fun should_add_user_to_db_admins/1,
                     fun should_add_user_to_db_members/1,

-- 
To stop receiving notification emails like this one, please contact
jan@apache.org.

Mime
View raw message