diff options
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | src/setup.erl | 60 | ||||
-rw-r--r-- | src/setup_httpd.erl | 41 | ||||
-rwxr-xr-x | test/t-single-node.sh | 46 |
4 files changed, 143 insertions, 21 deletions
@@ -2,21 +2,26 @@ This module implements /_cluster_setup and manages the setting up, duh, of a Cou ### Testing -``` +```bash git clone https://git-wip-us.apache.org/repos/asf/couchdb.git cd couchdb git checkout setup ./configure make +dev/run --no-join -n 2 --admin a:b +``` -# in dev/run comment out the line `connect_nodes("127.0.0.1", 15984)` +Then, in a new terminal: -dev/run --admin a:b + $ src/setup/test/t.sh -# in a new terminal -src/setup/test/t.sh +Before running each test, kill the `dev/run` script, then reset the +CouchDB instances with: -``` + $ rm -rf dev/lib/ dev/logs/ + $ dev/run --no-join -n 2 --admin a:b + +before running the next shell script. The Plan: diff --git a/src/setup.erl b/src/setup.erl index dd7410aa1..7aeac3ec5 100644 --- a/src/setup.erl +++ b/src/setup.erl @@ -14,6 +14,7 @@ -export([enable_cluster/1, finish_cluster/1, add_node/1, receive_cookie/1]). -export([is_cluster_enabled/0, has_cluster_system_dbs/1, cluster_system_dbs/0]). +-export([enable_single_node/1, is_single_node_enabled/1]). -include_lib("../couch/include/couch_db.hrl"). @@ -49,6 +50,15 @@ is_cluster_enabled() -> {_,_} -> ok end. +is_single_node_enabled(Dbs) -> + % admins != empty AND dbs exist + Admins = config:get("admins"), + HasDbs = has_cluster_system_dbs(Dbs), + case {Admins, HasDbs} of + {[], _} -> no; + {_, no} -> no; + {_,_} -> ok + end. cluster_system_dbs() -> ["_users", "_replicator", "_global_changes"]. @@ -129,18 +139,27 @@ enable_cluster_int(Options, no) -> Pw -> Pw end }, + ok = require_admins(CurrentAdmins, NewCredentials), % if bind_address == 127.0.0.1 and no bind_address in req -> error CurrentBindAddress = config:get("chttpd","bind_address"), NewBindAddress = proplists:get_value(bind_address, Options), - ok = require_admins(CurrentAdmins, NewCredentials), ok = require_bind_address(CurrentBindAddress, NewBindAddress), + NodeCount = couch_util:get_value(node_count, Options), + ok = require_node_count(NodeCount), + + Port = proplists:get_value(port, Options), + + setup_node(NewCredentials, NewBindAddress, NodeCount, Port), + couch_log:notice("Enable Cluster: ~p~n", [Options]). + +setup_node(NewCredentials, NewBindAddress, NodeCount, Port) -> case NewCredentials of {undefined, undefined} -> ok; {Username, Password} -> - set_admin(Username, Password) + config:set("admins", binary_to_list(Username), binary_to_list(Password)) end, case NewBindAddress of @@ -150,11 +169,8 @@ enable_cluster_int(Options, no) -> config:set("chttpd", "bind_address", binary_to_list(NewBindAddress)) end, - NodeCount = couch_util:get_value(node_count, Options), - ok = require_node_count(NodeCount), config:set_integer("cluster", "n", NodeCount), - Port = proplists:get_value(port, Options), case Port of undefined -> ok; @@ -162,11 +178,7 @@ enable_cluster_int(Options, no) -> config:set("chttpd", "port", binary_to_list(Port)); Port when is_integer(Port) -> config:set_integer("chttpd", "port", Port) - end, - couch_log:notice("Enable Cluster: ~p~n", [Options]). - -set_admin(Username, Password) -> - config:set("admins", binary_to_list(Username), binary_to_list(Password)). + end. finish_cluster(Options) -> @@ -184,6 +196,34 @@ finish_cluster_int(Dbs, no) -> lists:foreach(fun fabric:create_db/1, Dbs). +enable_single_node(Options) -> + % if no admin in config and no admin in req -> error + CurrentAdmins = config:get("admins"), + NewCredentials = { + proplists:get_value(username, Options), + case proplists:get_value(password_hash, Options) of + undefined -> proplists:get_value(password, Options); + Pw -> Pw + end + }, + ok = require_admins(CurrentAdmins, NewCredentials), + + % skip bind_address validation, anything is fine + NewBindAddress = proplists:get_value(bind_address, Options), + + Port = proplists:get_value(port, Options), + + setup_node(NewCredentials, NewBindAddress, 1, Port), + Dbs = proplists:get_value(ensure_dbs_exist, Options), + case Dbs of + undefined -> + finish_cluster_int(cluster_system_dbs(), has_cluster_system_dbs(cluster_system_dbs())); + Dbs -> + finish_cluster_int(Dbs, has_cluster_system_dbs(Dbs)) + end, + couch_log:notice("Enable Single Node: ~p~n", [Options]). + + add_node(Options) -> add_node_int(Options, is_cluster_enabled()). diff --git a/src/setup_httpd.erl b/src/setup_httpd.erl index 59ed5c7cd..a5a8157c8 100644 --- a/src/setup_httpd.erl +++ b/src/setup_httpd.erl @@ -30,16 +30,27 @@ handle_setup_req(#httpd{method='POST'}=Req) -> handle_setup_req(#httpd{method='GET'}=Req) -> ok = chttpd:verify_is_server_admin(Req), Dbs = chttpd:qs_json_value(Req, "ensure_dbs_exist", setup:cluster_system_dbs()), - case setup:is_cluster_enabled() of + couch_log:notice("Dbs: ~p~n", [Dbs]), + case erlang:list_to_integer(config:get("cluster", "n", undefined)) of + 1 -> + case setup:is_single_node_enabled(Dbs) of + no -> + chttpd:send_json(Req, 200, {[{state, single_node_disabled}]}); + ok -> + chttpd:send_json(Req, 200, {[{state, single_node_enabled}]}) + end; + _ -> + case setup:is_cluster_enabled() of no -> chttpd:send_json(Req, 200, {[{state, cluster_disabled}]}); ok -> case setup:has_cluster_system_dbs(Dbs) of - no -> - chttpd:send_json(Req, 200, {[{state, cluster_enabled}]}); - ok -> - chttpd:send_json(Req, 200, {[{state, cluster_finished}]}) + no -> + chttpd:send_json(Req, 200, {[{state, cluster_enabled}]}); + ok -> + chttpd:send_json(Req, 200, {[{state, cluster_finished}]}) end + end end; handle_setup_req(#httpd{}=Req) -> chttpd:send_method_not_allowed(Req, "GET,POST"). @@ -87,6 +98,26 @@ handle_action("finish_cluster", Setup) -> ok end; +handle_action("enable_single_node", Setup) -> + couch_log:notice("enable_single_node: ~p~n", [Setup]), + + Options = get_options([ + {ensure_dbs_exist, <<"ensure_dbs_exist">>}, + {username, <<"username">>}, + {password, <<"password">>}, + {password_hash, <<"password_hash">>}, + {bind_address, <<"bind_address">>}, + {port, <<"port">>} + ], Setup), + case setup:enable_single_node(Options) of + {error, cluster_finished} -> + {error, <<"Cluster is already finished">>}; + Else -> + couch_log:notice("Else: ~p~n", [Else]), + ok + end; + + handle_action("add_node", Setup) -> couch_log:notice("add_node: ~p~n", [Setup]), diff --git a/test/t-single-node.sh b/test/t-single-node.sh new file mode 100755 index 000000000..d49043773 --- /dev/null +++ b/test/t-single-node.sh @@ -0,0 +1,46 @@ +#!/bin/sh -ex +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +HEADERS="-HContent-Type:application/json" +# show cluster state: +curl a:b@127.0.0.1:15986/_nodes/_all_docs +curl a:b@127.0.0.1:15984/_cluster_setup + +# Enable Cluster on single node +curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"enable_single_node","username":"foo","password":"baz","bind_address":"127.0.0.1"}' $HEADERS + +# Show cluster state: +curl a:b@127.0.0.1:15986/_nodes/_all_docs +curl a:b@127.0.0.1:15984/_all_dbs +curl a:b@127.0.0.1:15984/_cluster_setup + +# Delete a database +curl -X DELETE a:b@127.0.0.1:15984/_global_changes + +# Should show single_node_disabled +curl a:b@127.0.0.1:15984/_cluster_setup + +# Change the check +curl -g 'a:b@127.0.0.1:15984/_cluster_setup?ensure_dbs_exist=["_replicator","_users"]' + +# delete all the things +curl -X DELETE a:b@127.0.0.1:15984/_replicator +curl -X DELETE a:b@127.0.0.1:15984/_users + +# setup only creating _users +curl -g a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"enable_single_node","username":"foo","password":"baz","bind_address":"127.0.0.1","ensure_dbs_exist":["_users"]}' $HEADERS + +# check it +curl -g 'a:b@127.0.0.1:15984/_cluster_setup?ensure_dbs_exist=["_users"]' + +echo "YAY ALL GOOD" |