diff options
Diffstat (limited to 'src/setup')
-rw-r--r-- | src/setup/.gitignore | 4 | ||||
-rw-r--r-- | src/setup/LICENSE | 203 | ||||
-rw-r--r-- | src/setup/README.md | 210 | ||||
-rw-r--r-- | src/setup/src/setup.app.src | 27 | ||||
-rw-r--r-- | src/setup/src/setup.erl | 386 | ||||
-rw-r--r-- | src/setup/src/setup_app.erl | 28 | ||||
-rw-r--r-- | src/setup/src/setup_epi.erl | 49 | ||||
-rw-r--r-- | src/setup/src/setup_httpd.erl | 180 | ||||
-rw-r--r-- | src/setup/src/setup_httpd_handlers.erl | 32 | ||||
-rw-r--r-- | src/setup/src/setup_sup.erl | 44 | ||||
-rwxr-xr-x | src/setup/test/t-frontend-setup.sh | 71 | ||||
-rwxr-xr-x | src/setup/test/t-single-node-auto-setup.sh | 24 | ||||
-rwxr-xr-x | src/setup/test/t-single-node.sh | 46 | ||||
-rwxr-xr-x | src/setup/test/t.sh | 63 |
14 files changed, 0 insertions, 1367 deletions
diff --git a/src/setup/.gitignore b/src/setup/.gitignore deleted file mode 100644 index f84f14c93..000000000 --- a/src/setup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -ebin -.rebar -*~ -*.swp diff --git a/src/setup/LICENSE b/src/setup/LICENSE deleted file mode 100644 index 94ad231b8..000000000 --- a/src/setup/LICENSE +++ /dev/null @@ -1,203 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff --git a/src/setup/README.md b/src/setup/README.md deleted file mode 100644 index 8a76d9dc5..000000000 --- a/src/setup/README.md +++ /dev/null @@ -1,210 +0,0 @@ -This module implements /_cluster_setup and manages the setting up, duh, of a CouchDB cluster. - -### 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 -``` - -Then, 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: - -N. End User Action -- What happens behind the scenes. - - -1. Launch CouchDB with `$ couchdb`, or init.d, or any other way, exactly -like it is done in 1.x.x. -- CouchDB launches and listens on 127.0.0.1:5984 - -From here on, there are two paths, one is via Fauxton (a) the other is -using a HTTP endpoint (b). Fauxton just uses the HTTP endpoint in (b). -(b) can be used to set up a cluster programmatically. - -When using (b) you POST HTTP requests with a JSON request body (the request content type has to be set to application/json). - -If you have already setup a server admin account, you might need to pass the credentials to the HTTP calls using HTTP basic authentication. -Alternativaly, if you use the cURL command you can can add username and password inline, like so: - -``` -curl -X PUT "http://admin:password@127.0.0.1:5984/mydb" -``` - -2.a. Go to Fauxton. There is a “Cluster Setup” tab in the sidebar. Go -to the tab and get presented with a form that asks you to enter an admin -username, admin password and optionally a bind_address and port to bind -to publicly. Submit the form with the [Enable Cluster] button. - -If this is a single node install that already has an admin set up, there -is no need to ask for admin credentials here. If the bind_address is != -127.0.0.1, we can skip this entirely and Fauxton can show the add_node -UI right away. - -- POST a JSON entity to /_cluster_setup, the entity looks like: -``` -{ - "action":"enable_cluster", - "username":"username", - "password":"password", - "bind_address":"0.0.0.0", - "port": 5984 -} -``` - -This sets up the admin user on the current node and binds to 0.0.0.0:5984 -or the specified ip:port. Logs admin user into Fauxton automatically. - -2.b. POST to /_cluster_setup as shown above. - -Repeat on all nodes. -- keep the same username/password everywhere. - - -3. Pick any one node, for simplicity use the first one, to be the -“setup coordination node”. -- this is a “master” node that manages the setup and requires all - other nodes to be able to see it and vice versa. Setup won’t work - with unavailable nodes (duh). The notion of “master” will be gone - once the setup is finished. At that point, the system has no - master node. Ignore I ever said “master”. - -a. Go to Fauxton / Cluster Setup, once we have enabled the cluster, the -UI shows an “Add Node” interface with the fields admin, and node: -- POST a JSON entity to /_cluster_setup, the entity looks like: -``` -{ - "action":"add_node", - "username":"username", - "password":"password", - "host":"192.168.1.100", - ["port": 5984], - "name": "node1" // as in “node1@hostname”, same as in vm.args -} -``` - -In the example above, this adds the node with IP address 192.168.1.100 to the cluster. - -b. as in a, but without the Fauxton bits, just POST to /_cluster_setup -- this request will do this: - - on the “setup coordination node”: - - check if we have an Erlang Cookie Secret. If not, generate - a UUID and set the erlang cookie to to that UUID. - - store the cookie in config.ini, re-set_cookie() on startup. - - make a POST request to the node specified in the body above - using the admin credentials in the body above: - POST to http://username:password@node_b:5984/_cluster_setup with: -``` - { - "action": "receive_cookie", - "cookie": "<secretcookie>", - } -``` - - - when the request to node B returns, we know the Erlang-level - inter-cluster communication is enabled and we can start adding - the node on the CouchDB level. To do that, the “setup - coordination node” does this to it’s own HTTP endpoint: - PUT /nodes/node_b:5984 or the same thing with internal APIs. - -- Repeat for all nodes. -- Fauxton keeps a list of all set up nodes for users to see. - - -4.a. When all nodes are added, click the [Finish Cluster Setup] button -in Fauxton. -- this does POST /_cluster_setup -``` - { - "action": "finish_cluster" - } -``` - -b. Same as in a. - -- this manages the final setup bits, like creating the _users, - _replicator and _metadata, _db_updates endpoints and - whatever else is needed. // TBD: collect what else is needed. - -## Single node auto setup - -Option `single_node` set to `true` in `[couchdb]` configuration executes single node configuration on startup so the node is ready for use immediately. - -### Testing single_node auto setup - -Pass `--config-overrides single_node=true` and `-n 1` to `dev/run` - - - $ dev/run --no-join -n 1 --admin a:b --config-overrides single_node=true - - -Then, in a new terminal: - - $ src/setup/test/t-single_node.sh - -The script should show that single node is enabled. - -## The Setup Endpoint - -This is not a REST-y endpoint, it is a simple state machine operated -by HTTP POST with JSON bodies that have an `action` field. - -### State 1: No Cluster Enabled - -This is right after starting a node for the first time, and any time -before the cluster is enabled as outlined above. - -``` -GET /_cluster_setup -{"state": "cluster_disabled"} - -POST /_cluster_setup {"action":"enable_cluster"...} -> Transition to State 2 -POST /_cluster_setup {"action":"enable_cluster"...} with empty admin user/pass or invalid host/post or host/port not available -> Error -POST /_cluster_setup {"action":"anything_but_enable_cluster"...} -> Error -``` - -### State 2: Cluster enabled, admin user set, waiting for nodes to be added. - -``` -GET /_cluster_setup -{"state":"cluster_enabled","nodes":[]} - -POST /_cluster_setup {"action":"enable_cluster"...} -> Error -POST /_cluster_setup {"action":"add_node"...} -> Stay in State 2, but return "nodes":["node B"}] on GET -POST /_cluster_setup {"action":"add_node"...} -> if target node not available, Error -POST /_cluster_setup {"action":"finish_cluster"} with no nodes set up -> Error -POST /_cluster_setup {"action":"finish_cluster"} -> Transition to State 3 -POST /_cluster_setup {"action":"delete_node"...} -> Stay in State 2, but delete node from /nodes, reflect the change in GET /_cluster_setup -POST /_cluster_setup {"action":"delete_node","node":"unknown"} -> Error Unknown Node -``` - -### State 3: Cluster set up, all nodes operational - -``` -GET /_cluster_setup -{"state":"cluster_finished","nodes":["node a", "node b", ...]} - -POST /_cluster_setup {"action":"enable_cluster"...} -> Error -POST /_cluster_setup {"action":"finish_cluster"...} -> Stay in State 3, do nothing -POST /_cluster_setup {"action":"add_node"...} -> Error -POST /_cluster_setup?i_know_what_i_am_doing=true {"action":"add_node"...} -> Add node, stay in State 3. -POST /_cluster_setup {"action":"delete_node"...} -> Stay in State 3, but delete node from /nodes, reflect the change in GET /_cluster_setup -POST /_cluster_setup {"action":"delete_node","node":"unknown"} -> Error Unknown Node -``` - -// TBD: we need to persist the setup state somewhere. diff --git a/src/setup/src/setup.app.src b/src/setup/src/setup.app.src deleted file mode 100644 index ae685c971..000000000 --- a/src/setup/src/setup.app.src +++ /dev/null @@ -1,27 +0,0 @@ -% 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. - -{application, setup, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib, - couch_epi, - chttpd, - couch_log - ]}, - {mod, { setup_app, []}}, - {env, []} - ]}. diff --git a/src/setup/src/setup.erl b/src/setup/src/setup.erl deleted file mode 100644 index 5129765da..000000000 --- a/src/setup/src/setup.erl +++ /dev/null @@ -1,386 +0,0 @@ -% 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. - --module(setup). - --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"). - - -require_admins(undefined, {undefined, undefined}) -> - % no admin in CouchDB, no admin in request - throw({error, "Cluster setup requires admin account to be configured"}); -require_admins(_,_) -> - ok. - -require_node_count(undefined) -> - throw({error, "Cluster setup requires node_count to be configured"}); -require_node_count(_) -> - ok. - -error_local_bind_address() -> - throw({error, "Cluster setup requires a remote bind_address (not 127.0.0.1 nor ::1)"}). - -error_invalid_bind_address(InvalidBindAddress) -> - throw({error, io:format("Setup requires a valid IP bind_address. " ++ - "~p is invalid.", [InvalidBindAddress])}). - -require_remote_bind_address(OldBindAddress, NewBindAddress) -> - case {OldBindAddress, NewBindAddress} of - {"127.0.0.1", undefined} -> error_local_bind_address(); - {_, <<"127.0.0.1">>} -> error_local_bind_address(); - {"::1", undefined} -> error_local_bind_address(); - {_, <<"::1">>} -> error_local_bind_address(); - {_, undefined} -> ok; - {_, PresentNewBindAddress} -> require_valid_bind_address(PresentNewBindAddress) - end. - -require_valid_bind_address(BindAddress) -> - ListBindAddress = binary_to_list(BindAddress), - case inet_parse:address(ListBindAddress) of - {ok, _} -> ok; - {error, _} -> error_invalid_bind_address(ListBindAddress) - end. - -is_cluster_enabled() -> - % bind_address != 127.0.0.1 AND admins != empty - BindAddress = config:get("chttpd", "bind_address"), - Admins = config:get("admins"), - case {BindAddress, Admins} of - {"127.0.0.1", _} -> false; - {_,[]} -> false; - {_,_} -> true - 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 - {[], _} -> false; - {_, false} -> false; - {_,_} -> true - end. - -cluster_system_dbs() -> - ["_users", "_replicator"]. - - -has_cluster_system_dbs([]) -> - true; -has_cluster_system_dbs([Db|Dbs]) -> - case catch fabric:get_db_info(Db) of - {ok, _} -> has_cluster_system_dbs(Dbs); - _ -> false - end. - -enable_cluster(Options) -> - - case couch_util:get_value(remote_node, Options, undefined) of - undefined -> - enable_cluster_int(Options, is_cluster_enabled()); - _ -> - enable_cluster_http(Options) - end. - -get_remote_request_options(Options) -> - case couch_util:get_value(remote_current_user, Options, undefined) of - undefined -> - []; - _ -> - [ - {basic_auth, { - binary_to_list(couch_util:get_value(remote_current_user, Options)), - binary_to_list(couch_util:get_value(remote_current_password, Options)) - }} - ] - end. - -enable_cluster_http(Options) -> - % POST to nodeB/_setup - RequestOptions = get_remote_request_options(Options), - AdminUsername = couch_util:get_value(username, Options), - AdminPasswordHash = config:get("admins", binary_to_list(AdminUsername)), - - Body = ?JSON_ENCODE({[ - {<<"action">>, <<"enable_cluster">>}, - {<<"username">>, AdminUsername}, - {<<"password_hash">>, ?l2b(AdminPasswordHash)}, - {<<"bind_address">>, couch_util:get_value(bind_address, Options)}, - {<<"port">>, couch_util:get_value(port, Options)}, - {<<"node_count">>, couch_util:get_value(node_count, Options)} - ]}), - - Headers = [ - {"Content-Type","application/json"} - ], - - RemoteNode = couch_util:get_value(remote_node, Options), - Port = get_port(couch_util:get_value(port, Options, 5984)), - - Url = binary_to_list(<<"http://", RemoteNode/binary, ":", Port/binary, "/_cluster_setup">>), - - case ibrowse:send_req(Url, Headers, post, Body, RequestOptions) of - {ok, "201", _, _} -> - ok; - Else -> - {error, Else} - end. - -enable_cluster_int(_Options, true) -> - {error, cluster_enabled}; -enable_cluster_int(Options, false) -> - - % 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), - % 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_remote_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:debug("Enable Cluster: ~p~n", [Options]). - -set_admin(Username, Password) -> - config:set("admins", binary_to_list(Username), binary_to_list(Password), #{sensitive => true}). - -setup_node(NewCredentials, NewBindAddress, NodeCount, Port) -> - case NewCredentials of - {undefined, undefined} -> - ok; - {Username, Password} -> - set_admin(Username, Password) - end, - - ok = require_valid_bind_address(NewBindAddress), - case NewBindAddress of - undefined -> - config:set("chttpd", "bind_address", "0.0.0.0"); - NewBindAddress -> - config:set("chttpd", "bind_address", binary_to_list(NewBindAddress)) - end, - - % for single node setups, set n=1, for larger setups, don’t - % exceed n=3 as a default - config:set_integer("cluster", "n", min(NodeCount, 3)), - - case Port of - undefined -> - ok; - Port when is_binary(Port) -> - config:set("chttpd", "port", binary_to_list(Port)); - Port when is_integer(Port) -> - config:set_integer("chttpd", "port", Port) - end. - - -finish_cluster(Options) -> - % ensure that uuid is set - couch_server:get_uuid(), - - ok = wait_connected(), - ok = sync_admins(), - ok = sync_uuid(), - ok = sync_auth_secret(), - Dbs = proplists:get_value(ensure_dbs_exist, Options, cluster_system_dbs()), - finish_cluster_int(Dbs, has_cluster_system_dbs(Dbs)). - - -wait_connected() -> - Nodes = other_nodes(), - Result = test_util:wait(fun() -> - case disconnected(Nodes) of - [] -> ok; - _ -> wait - end - end), - case Result of - timeout -> - Reason = "Cluster setup timed out waiting for nodes to connect", - throw({setup_error, Reason}); - ok -> - ok - end. - - -other_nodes() -> - mem3:nodes() -- [node()]. - - -disconnected(Nodes) -> - lists:filter(fun(Node) -> - case net_adm:ping(Node) of - pong -> false; - pang -> true - end - end, Nodes). - - -sync_admins() -> - ok = lists:foreach(fun({User, Pass}) -> - sync_admin(User, Pass) - end, config:get("admins")). - - -sync_admin(User, Pass) -> - sync_config("admins", User, Pass). - - -sync_uuid() -> - Uuid = config:get("couchdb", "uuid"), - sync_config("couchdb", "uuid", Uuid). - -sync_auth_secret() -> - Secret = config:get("couch_httpd_auth", "secret"), - sync_config("couch_httpd_auth", "secret", Secret). - - -sync_config(Section, Key, Value) -> - {Results, Errors} = rpc:multicall(other_nodes(), config, set, - [Section, Key, Value]), - case validate_multicall(Results, Errors) of - ok -> - ok; - error -> - couch_log:error("~p sync_admin results ~p errors ~p", - [?MODULE, Results, Errors]), - Reason = "Cluster setup unable to sync admin passwords", - throw({setup_error, Reason}) - end. - - -validate_multicall(Results, Errors) -> - AllOk = lists:all(fun - (ok) -> true; - (_) -> false - end, Results), - case AllOk andalso Errors == [] of - true -> - ok; - false -> - error - end. - - -finish_cluster_int(_Dbs, true) -> - {error, cluster_finished}; -finish_cluster_int(Dbs, false) -> - 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, cluster_system_dbs()), - finish_cluster_int(Dbs, has_cluster_system_dbs(Dbs)), - couch_log:debug("Enable Single Node: ~p~n", [Options]). - - -add_node(Options) -> - add_node_int(Options, is_cluster_enabled()). - -add_node_int(_Options, false) -> - {error, cluster_not_enabled}; -add_node_int(Options, true) -> - couch_log:debug("add node_int: ~p~n", [Options]), - ErlangCookie = erlang:get_cookie(), - - % POST to nodeB/_setup - RequestOptions = [ - {basic_auth, { - binary_to_list(proplists:get_value(username, Options)), - binary_to_list(proplists:get_value(password, Options)) - }} - ], - - Body = ?JSON_ENCODE({[ - {<<"action">>, <<"receive_cookie">>}, - {<<"cookie">>, atom_to_binary(ErlangCookie, utf8)} - ]}), - - Headers = [ - {"Content-Type","application/json"} - ], - - Host = proplists:get_value(host, Options), - Port = get_port(proplists:get_value(port, Options, 5984)), - Name = proplists:get_value(name, Options, get_default_name(Port)), - - Url = binary_to_list(<<"http://", Host/binary, ":", Port/binary, "/_cluster_setup">>), - - case ibrowse:send_req(Url, Headers, post, Body, RequestOptions) of - {ok, "201", _, _} -> - % when done, PUT :5986/nodes/nodeB - create_node_doc(Host, Name); - Else -> - Else - end. - -get_port(Port) when is_integer(Port) -> - list_to_binary(integer_to_list(Port)); -get_port(Port) when is_list(Port) -> - list_to_binary(Port); -get_port(Port) when is_binary(Port) -> - Port. - -create_node_doc(Host, Name) -> - {ok, Db} = couch_db:open_int(<<"_nodes">>, []), - Doc = {[{<<"_id">>, <<Name/binary, "@", Host/binary>>}]}, - Options = [], - CouchDoc = couch_doc:from_json_obj(Doc), - - couch_db:update_doc(Db, CouchDoc, Options). - -get_default_name(Port) -> - case Port of - % shortcut for easier development - <<"15984">> -> - <<"node1">>; - <<"25984">> -> - <<"node2">>; - <<"35984">> -> - <<"node3">>; - % by default, all nodes have the user `couchdb` - _ -> - <<"couchdb">> - end. - -receive_cookie(Options) -> - Cookie = proplists:get_value(cookie, Options), - erlang:set_cookie(node(), binary_to_atom(Cookie, latin1)). diff --git a/src/setup/src/setup_app.erl b/src/setup/src/setup_app.erl deleted file mode 100644 index 330450131..000000000 --- a/src/setup/src/setup_app.erl +++ /dev/null @@ -1,28 +0,0 @@ -% 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. - --module(setup_app). - --behaviour(application). - -%% Application callbacks --export([start/2, stop/1]). - -%% =================================================================== -%% Application callbacks -%% =================================================================== - -start(_StartType, _StartArgs) -> - setup_sup:start_link(). - -stop(_State) -> - ok. diff --git a/src/setup/src/setup_epi.erl b/src/setup/src/setup_epi.erl deleted file mode 100644 index c3f2636f0..000000000 --- a/src/setup/src/setup_epi.erl +++ /dev/null @@ -1,49 +0,0 @@ -% 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. - - --module(setup_epi). - --behaviour(couch_epi_plugin). - --export([ - app/0, - providers/0, - services/0, - data_subscriptions/0, - data_providers/0, - processes/0, - notify/3 -]). - -app() -> - setup. - -providers() -> - [ - {chttpd_handlers, setup_httpd_handlers} - ]. - -services() -> - []. - -data_subscriptions() -> - []. - -data_providers() -> - []. - -processes() -> - []. - -notify(_Key, _Old, _New) -> - ok. diff --git a/src/setup/src/setup_httpd.erl b/src/setup/src/setup_httpd.erl deleted file mode 100644 index 48b1b2a5a..000000000 --- a/src/setup/src/setup_httpd.erl +++ /dev/null @@ -1,180 +0,0 @@ -% 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. - --module(setup_httpd). --include_lib("couch/include/couch_db.hrl"). - --export([handle_setup_req/1]). - -handle_setup_req(#httpd{method='POST'}=Req) -> - ok = chttpd:verify_is_server_admin(Req), - couch_httpd:validate_ctype(Req, "application/json"), - Setup = get_body(Req), - couch_log:notice("Setup: ~p~n", [remove_sensitive(Setup)]), - Action = binary_to_list(couch_util:get_value(<<"action">>, Setup, <<"missing">>)), - case handle_action(Action, Setup) of - ok -> - chttpd:send_json(Req, 201, {[{ok, true}]}); - {error, Message} -> - couch_httpd:send_error(Req, 400, <<"bad_request">>, Message) - end; -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()), - couch_log:notice("Dbs: ~p~n", [Dbs]), - SingleNodeConfig = config:get_boolean("couchdb", "single_node", false), - case SingleNodeConfig of - true -> - chttpd:send_json(Req, 200, {[{state, single_node_enabled}]}); - _ -> - case config:get("cluster", "n", undefined) of - "1" -> - case setup:is_single_node_enabled(Dbs) of - false -> - chttpd:send_json(Req, 200, {[{state, single_node_disabled}]}); - true -> - chttpd:send_json(Req, 200, {[{state, single_node_enabled}]}) - end; - _ -> - case setup:is_cluster_enabled() of - false -> - chttpd:send_json(Req, 200, {[{state, cluster_disabled}]}); - true -> - case setup:has_cluster_system_dbs(Dbs) of - false -> - chttpd:send_json(Req, 200, {[{state, cluster_enabled}]}); - true -> - chttpd:send_json(Req, 200, {[{state, cluster_finished}]}) - end - end - end - end; -handle_setup_req(#httpd{}=Req) -> - chttpd:send_method_not_allowed(Req, "GET,POST"). - - -get_options(Options, Setup) -> - ExtractValues = fun({Tag, Option}, OptionsAcc) -> - case couch_util:get_value(Option, Setup) of - undefined -> OptionsAcc; - Value -> [{Tag, Value} | OptionsAcc] - end - end, - lists:foldl(ExtractValues, [], Options). - -handle_action("enable_cluster", Setup) -> - Options = get_options([ - {username, <<"username">>}, - {password, <<"password">>}, - {password_hash, <<"password_hash">>}, - {bind_address, <<"bind_address">>}, - {port, <<"port">>}, - {remote_node, <<"remote_node">>}, - {remote_current_user, <<"remote_current_user">>}, - {remote_current_password, <<"remote_current_password">>}, - {node_count, <<"node_count">>} - ], Setup), - case setup:enable_cluster(Options) of - {error, cluster_enabled} -> - {error, <<"Cluster is already enabled">>}; - _ -> ok - end; - - -handle_action("finish_cluster", Setup) -> - couch_log:notice("finish_cluster: ~p~n", [remove_sensitive(Setup)]), - - Options = get_options([ - {ensure_dbs_exist, <<"ensure_dbs_exist">>} - ], Setup), - case setup:finish_cluster(Options) of - {error, cluster_finished} -> - {error, <<"Cluster is already finished">>}; - Else -> - couch_log:notice("finish_cluster: ~p~n", [Else]), - ok - end; - -handle_action("enable_single_node", Setup) -> - couch_log:notice("enable_single_node: ~p~n", [remove_sensitive(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", [remove_sensitive(Setup)]), - - Options = get_options([ - {username, <<"username">>}, - {password, <<"password">>}, - {host, <<"host">>}, - {port, <<"port">>}, - {name, <<"name">>} - ], Setup), - case setup:add_node(Options) of - {error, cluster_not_enabled} -> - {error, <<"Cluster is not enabled.">>}; - {error, {conn_failed, {error, econnrefused}}} -> - {error, <<"Add node failed. Invalid Host and/or Port.">>}; - {error, wrong_credentials} -> - {error, <<"Add node failed. Invalid admin credentials,">>}; - {error, Message} -> - {error, Message}; - _ -> ok - end; - -handle_action("remove_node", Setup) -> - couch_log:notice("remove_node: ~p~n", [remove_sensitive(Setup)]); - -handle_action("receive_cookie", Setup) -> - couch_log:notice("receive_cookie: ~p~n", [remove_sensitive(Setup)]), - Options = get_options([ - {cookie, <<"cookie">>} - ], Setup), - case setup:receive_cookie(Options) of - {error, Error} -> - {error, Error}; - _ -> ok - end; - -handle_action(_, _) -> - couch_log:notice("invalid_action: ~n", []), - {error, <<"Invalid Action'">>}. - - -get_body(Req) -> - case catch couch_httpd:json_body_obj(Req) of - {Body} -> - Body; - Else -> - couch_log:notice("Body Fail: ~p~n", [Else]), - couch_httpd:send_error(Req, 400, <<"bad_request">>, <<"Missing JSON body'">>) - end. - -remove_sensitive(KVList0) -> - KVList1 = lists:keyreplace(<<"username">>, 1, KVList0, {<<"username">>, <<"****">>}), - KVList2 = lists:keyreplace(<<"password">>, 1, KVList1, {<<"password">>, <<"****">>}), - KVList2.
\ No newline at end of file diff --git a/src/setup/src/setup_httpd_handlers.erl b/src/setup/src/setup_httpd_handlers.erl deleted file mode 100644 index e26fbc3c4..000000000 --- a/src/setup/src/setup_httpd_handlers.erl +++ /dev/null @@ -1,32 +0,0 @@ -% 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. - --module(setup_httpd_handlers). - --export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]). - -url_handler(<<"_cluster_setup">>) -> fun setup_httpd:handle_setup_req/1; -url_handler(_) -> no_match. - -db_handler(_) -> no_match. - -design_handler(_) -> no_match. - - -handler_info('GET', [<<"_cluster_setup">>], _) -> - {'cluster_setup.read', #{}}; - -handler_info('POST', [<<"_cluster_setup">>], _) -> - {'cluster_setup.write', #{}}; - -handler_info(_, _, _) -> - no_match.
\ No newline at end of file diff --git a/src/setup/src/setup_sup.erl b/src/setup/src/setup_sup.erl deleted file mode 100644 index 4670a0a59..000000000 --- a/src/setup/src/setup_sup.erl +++ /dev/null @@ -1,44 +0,0 @@ -% 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. - --module(setup_sup). - --behaviour(supervisor). - -%% API --export([start_link/0]). - -%% Supervisor callbacks --export([init/1]). - -%% Helper macro for declaring children of supervisor --define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). - -%% =================================================================== -%% API functions -%% =================================================================== - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -%% =================================================================== -%% Supervisor callbacks -%% =================================================================== - -init([]) -> - case config:get_boolean("couchdb", "single_node", false) of - true -> - setup:finish_cluster([]); - false -> - ok - end, - {ok, {{one_for_one, 5, 10}, couch_epi:register_service(setup_epi, [])}}. diff --git a/src/setup/test/t-frontend-setup.sh b/src/setup/test/t-frontend-setup.sh deleted file mode 100755 index e025cfba2..000000000 --- a/src/setup/test/t-frontend-setup.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/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. - -echo "To test, comment out the fake_uuid line in dev/run" - -HEADERS="-HContent-Type:application/json" -# show cluster state: -curl a:b@127.0.0.1:15986/_nodes/_all_docs - -# Enable Cluster on node A -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"enable_cluster","username":"foo","password":"baz","bind_address":"0.0.0.0","node_count":2}' $HEADERS - -# Enable Cluster on node B -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"enable_cluster","remote_node":"127.0.0.1","port":"25984","remote_current_user":"a","remote_current_password":"b","username":"foo","password":"baz","bind_address":"0.0.0.0","node_count":2}' $HEADERS - -# Add node B on node A -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"add_node","username":"foo","password":"baz","host":"127.0.0.1","port":25984,"name":"node2"}' $HEADERS - -# Show cluster state: -curl a:b@127.0.0.1:15986/_nodes/_all_docs - -# Show db doesn’t exist on node A -curl a:b@127.0.0.1:15984/foo - -# Show db doesn’t exist on node B -curl a:b@127.0.0.1:25984/foo - -# Create database (on node A) -curl -X PUT a:b@127.0.0.1:15984/foo - -# Show db does exist on node A -curl a:b@127.0.0.1:15984/foo - -# Show db does exist on node B -curl a:b@127.0.0.1:25984/foo - -# Finish cluster -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"finish_cluster"}' $HEADERS - -# Show system dbs exist on node A -curl a:b@127.0.0.1:15984/_users -curl a:b@127.0.0.1:15984/_replicator -curl a:b@127.0.0.1:15984/_global_changes - -# Show system dbs exist on node B -curl a:b@127.0.0.1:25984/_users -curl a:b@127.0.0.1:25984/_replicator -curl a:b@127.0.0.1:25984/_global_changes - -# Number of nodes is set to 2 -curl a:b@127.0.0.1:25984/_node/node2@127.0.0.1/_config/cluster/n - -# uuid and auth secret are the same -curl a:b@127.0.0.1:15984/_node/node1@127.0.0.1/_config/couchdb/uuid -curl a:b@127.0.0.1:15984/_node/node2@127.0.0.1/_config/couchdb/uuid - -curl a:b@127.0.0.1:15984/_node/node1@127.0.0.1/_config/couch_httpd_auth/secret -curl a:b@127.0.0.1:15984/_node/node2@127.0.0.1/_config/couch_httpd_auth/secret - - -echo "YAY ALL GOOD" diff --git a/src/setup/test/t-single-node-auto-setup.sh b/src/setup/test/t-single-node-auto-setup.sh deleted file mode 100755 index 0276990f5..000000000 --- a/src/setup/test/t-single-node-auto-setup.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/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/_all_dbs -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"]' - -echo "YAY ALL GOOD" diff --git a/src/setup/test/t-single-node.sh b/src/setup/test/t-single-node.sh deleted file mode 100755 index d49043773..000000000 --- a/src/setup/test/t-single-node.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/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" diff --git a/src/setup/test/t.sh b/src/setup/test/t.sh deleted file mode 100755 index 6bd74cdd7..000000000 --- a/src/setup/test/t.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/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 - -# Enable Cluster on node A -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"enable_cluster","username":"foo","password":"baz","bind_address":"0.0.0.0","node_count":2}' $HEADERS - -# Enable Cluster on node B -curl a:b@127.0.0.1:25984/_cluster_setup -d '{"action":"enable_cluster","username":"foo","password":"baz","bind_address":"0.0.0.0","node_count":2}' $HEADERS - -# Add node B on node A -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"add_node","username":"foo","password":"baz","host":"127.0.0.1","port":25984,"name":"node2"}' $HEADERS - -# Show cluster state: -curl a:b@127.0.0.1:15986/_nodes/_all_docs - -# Show db doesn’t exist on node A -curl a:b@127.0.0.1:15984/foo - -# Show db doesn’t exist on node B -curl a:b@127.0.0.1:25984/foo - -# Create database (on node A) -curl -X PUT a:b@127.0.0.1:15984/foo - -# Show db does exist on node A -curl a:b@127.0.0.1:15984/foo - -# Show db does exist on node B -curl a:b@127.0.0.1:25984/foo - -# Finish cluster -curl a:b@127.0.0.1:15984/_cluster_setup -d '{"action":"finish_cluster"}' $HEADERS - -# Show system dbs exist on node A -curl a:b@127.0.0.1:15984/_users -curl a:b@127.0.0.1:15984/_replicator -curl a:b@127.0.0.1:15984/_metadata -curl a:b@127.0.0.1:15984/_global_changes - -# Show system dbs exist on node B -curl a:b@127.0.0.1:25984/_users -curl a:b@127.0.0.1:25984/_replicator -curl a:b@127.0.0.1:25984/_metadata -curl a:b@127.0.0.1:25984/_global_changes - -# Number of nodes is set to 2 -curl a:b@127.0.0.1:25984/_node/node2@127.0.0.1/_config/cluster/n - -echo "YAY ALL GOOD" |