From e3610fa481b5c506ca0b69f49a6f350fce8b3399 Mon Sep 17 00:00:00 2001 From: Jan Lehnardt Date: Sun, 11 Oct 2009 05:49:19 +0000 Subject: add create_target:true option to _replicate that creates the target database git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@824029 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_httpd.erl | 4 +++- src/couchdb/couch_rep.erl | 47 +++++++++++++++++++++++++++++------------ src/couchdb/couch_rep_httpc.erl | 16 +++++++++++++- 3 files changed, 51 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl index b4e8793b..70b31d16 100644 --- a/src/couchdb/couch_httpd.erl +++ b/src/couchdb/couch_httpd.erl @@ -362,7 +362,9 @@ etag_respond(Req, CurrentEtag, RespFun) -> RespFun() end. -verify_is_server_admin(#httpd{user_ctx=#user_ctx{roles=Roles}}) -> +verify_is_server_admin(#httpd{user_ctx=UserCtx}) -> + verify_is_server_admin(UserCtx); +verify_is_server_admin(#user_ctx{roles=Roles}) -> case lists:member(<<"_admin">>, Roles) of true -> ok; false -> throw({unauthorized, <<"You are not a server admin.">>}) diff --git a/src/couchdb/couch_rep.erl b/src/couchdb/couch_rep.erl index 14ecdf53..1a894523 100644 --- a/src/couchdb/couch_rep.erl +++ b/src/couchdb/couch_rep.erl @@ -28,6 +28,7 @@ source, target, continuous, + create_target, init_args, checkpoint_scheduled = nil, @@ -102,9 +103,10 @@ do_init([RepId, {PostProps}, UserCtx] = InitArgs) -> TargetProps = proplists:get_value(<<"target">>, PostProps), Continuous = proplists:get_value(<<"continuous">>, PostProps, false), + CreateTarget = proplists:get_value(<<"create_target">>, PostProps, false), Source = open_db(SourceProps, UserCtx), - Target = open_db(TargetProps, UserCtx), + Target = open_db(TargetProps, UserCtx, CreateTarget), SourceLog = open_replication_log(Source, RepId), TargetLog = open_replication_log(Target, RepId), @@ -143,6 +145,7 @@ do_init([RepId, {PostProps}, UserCtx] = InitArgs) -> source = Source, target = Target, continuous = Continuous, + create_target = CreateTarget, init_args = InitArgs, stats = Stats, checkpoint_scheduled = nil, @@ -375,6 +378,17 @@ has_session_id(SessionId, [{Props} | Rest]) -> has_session_id(SessionId, Rest) end. +maybe_append_options(Options, Props) -> + lists:foldl(fun(Option, Acc) -> + Acc ++ + case proplists:get_value(Option, Props, false) of + true -> + "+" ++ ?b2l(Option); + false -> + "" + end + end, [], Options). + make_replication_id({Props}, UserCtx) -> %% funky algorithm to preserve backwards compatibility {ok, HostName} = inet:gethostname(), @@ -382,12 +396,8 @@ make_replication_id({Props}, UserCtx) -> Src = get_rep_endpoint(UserCtx, proplists:get_value(<<"source">>, Props)), Tgt = get_rep_endpoint(UserCtx, proplists:get_value(<<"target">>, Props)), Base = couch_util:to_hex(erlang:md5(term_to_binary([HostName, Src, Tgt]))), - Extension = case proplists:get_value(<<"continuous">>, Props, false) of - true -> - "+continuous"; - false -> - "" - end, + Extension = maybe_append_options( + [<<"continuous">>, <<"create_target">>], Props), {Base, Extension}. maybe_add_trailing_slash(Url) -> @@ -432,7 +442,10 @@ open_replication_log(Db, RepId) -> #doc{id=DocId} end. -open_db({Props}, _UserCtx) -> +open_db(Props, UserCtx) -> + open_db(Props, UserCtx, false). + +open_db({Props}, _UserCtx, CreateTarget) -> Url = maybe_add_trailing_slash(proplists:get_value(<<"url">>, Props)), {AuthProps} = proplists:get_value(<<"auth">>, Props, {[]}), {BinHeaders} = proplists:get_value(<<"headers">>, Props, {[]}), @@ -443,12 +456,18 @@ open_db({Props}, _UserCtx) -> auth = AuthProps, headers = lists:ukeymerge(1, Headers, DefaultHeaders) }, - couch_rep_httpc:db_exists(Db); -open_db(<<"http://",_/binary>>=Url, _) -> - open_db({[{<<"url">>,Url}]}, []); -open_db(<<"https://",_/binary>>=Url, _) -> - open_db({[{<<"url">>,Url}]}, []); -open_db(<>, UserCtx) -> + couch_rep_httpc:db_exists(Db, CreateTarget); +open_db(<<"http://",_/binary>>=Url, _, CreateTarget) -> + open_db({[{<<"url">>,Url}]}, [], CreateTarget); +open_db(<<"https://",_/binary>>=Url, _, CreateTarget) -> + open_db({[{<<"url">>,Url}]}, [], CreateTarget); +open_db(<>, UserCtx, CreateTarget) -> + ok = couch_httpd:verify_is_server_admin(UserCtx), + case CreateTarget of + true -> couch_server:create(DbName, [{user_ctx, UserCtx}]); + false -> ok + end, + case couch_db:open(DbName, [{user_ctx, UserCtx}]) of {ok, Db} -> couch_db:monitor(Db), diff --git a/src/couchdb/couch_rep_httpc.erl b/src/couchdb/couch_rep_httpc.erl index b714be6b..ba863746 100644 --- a/src/couchdb/couch_rep_httpc.erl +++ b/src/couchdb/couch_rep_httpc.erl @@ -14,7 +14,7 @@ -include("couch_db.hrl"). -include("../ibrowse/ibrowse.hrl"). --export([db_exists/1, full_url/1, request/1, spawn_worker_process/1, +-export([db_exists/1, db_exists/2, full_url/1, request/1, spawn_worker_process/1, spawn_link_worker_process/1]). request(Req) when is_record(Req, http_db) -> @@ -59,7 +59,16 @@ do_request(Req) -> db_exists(Req) -> db_exists(Req, Req#http_db.url). +db_exists(Req, true) -> + db_exists(Req, Req#http_db.url, true); + +db_exists(Req, false) -> + db_exists(Req, Req#http_db.url, false); + db_exists(Req, CanonicalUrl) -> + db_exists(Req, CanonicalUrl, false). + +db_exists(Req, CanonicalUrl, CreateDB) -> #http_db{ auth = Auth, headers = Headers0, @@ -71,6 +80,11 @@ db_exists(Req, CanonicalUrl) -> {OAuthProps} -> [oauth_header(Url, [], head, OAuthProps) | Headers0] end, + case CreateDB of + true -> + catch ibrowse:send_req(Url, Headers, put); + _Else -> ok + end, case catch ibrowse:send_req(Url, Headers, head) of {ok, "200", _, _} -> Req#http_db{url = CanonicalUrl}; -- cgit v1.2.3