Skip to content

Commit d6bb830

Browse files
author
Shunichi Shinohara
committed
Automate user/bucket creation
1 parent cca7d45 commit d6bb830

2 files changed

Lines changed: 126 additions & 13 deletions

File tree

examples/cs.config.sample

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,24 @@
1313

1414
{driver, basho_bench_driver_cs}.
1515

16-
%% Replace this with a user you have created.
17-
%% Instructions to create a user are here:
18-
%% https://github.com/basho/riak_cs/wiki/Creating-a-User
16+
%% Two ways of user configuration
17+
%% 1. Set cs_access_key and cs_secret_key for existing user.
18+
%% Replace this with a user you have created.
19+
%% Instructions to create a user are here:
20+
%% https://github.com/basho/riak_cs/wiki/Creating-a-User
1921
{cs_access_key, "ZG7SS3ZPECF-8LZOEBMA"}.
2022
{cs_secret_key, "21HoIRdeO617nJrIbam9mKH2MBxmcsMEwESvmQ=="}.
21-
{cs_bucket, "test"}. % create this with s3cmd before running basho_bench!
23+
24+
%% 2. Let the driver create or retrieve user
25+
%% In this case, you should
26+
%% - setup riak-cs with {admin_auth_enabled, false} and
27+
%% - comment out cs_access_key and cs_secret_key above
28+
%% cs_display_name is used to identify user.
29+
%% {cs_display_name, "test-user"}.
30+
31+
%% CS Bucket, it will be created if needed
32+
{cs_bucket, "test-bucket"}.
33+
2234
{cs_disconnect_frequency, 5}. % # ops before disconnecting HTTP socket
2335
{cs_raw_ip, "s3.amazonaws.com"}. % DO NOT CHANGE
2436
{cs_raw_port, 80}. % DO NOT CHANGE
@@ -46,3 +58,4 @@
4658
%% bad idea: {operations, [{insert, 1}, {get, 1}]}.
4759
{operations, [{insert, 1}]}.
4860
%{operations, [{get, 1}]}.
61+
%{operations, [{delete, 1}]}.

src/basho_bench_driver_cs.erl

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,15 @@ new(ID) ->
120120
lager:log(info, self(), "ID ~p Proxy host ~p TCP port ~p\n",
121121
[ID, ProxyH, ProxyP]),
122122

123-
{ok, #state{client_id=ID, hosts=Hosts,
124-
bucket = basho_bench_config:get(cs_bucket, "test"),
125-
report_fun = ReportFun,
126-
http_proxy_host = ProxyH, http_proxy_port = ProxyP}}.
123+
State = #state{client_id=ID, hosts=Hosts,
124+
bucket = basho_bench_config:get(cs_bucket, "test"),
125+
report_fun = ReportFun,
126+
http_proxy_host = ProxyH, http_proxy_port = ProxyP},
127+
case ID of
128+
1 -> ok = setup_user_and_bucket(State);
129+
_ -> ok
130+
end,
131+
{ok, State}.
127132

128133
%% This module does some crazy stuff, but it's there for a reason.
129134
%% The reason is that basho_bench is expecting the run() function to
@@ -278,10 +283,12 @@ insert(KeyGen, ValueGen, {Host, Port}, Bucket, State) ->
278283
do_put({Host, Port}, Url, [{"content-length", integer_to_list(CL)}], ValueT,
279284
State).
280285

286+
url(Host, Port, Bucket, undefined) ->
287+
UnparsedUrl = lists:concat(["http://", Host, ":", Port, "/", Bucket]),
288+
ibrowse_lib:parse_url(UnparsedUrl);
281289
url(Host, Port, Bucket, Key) ->
282290
UnparsedUrl = lists:concat(["http://", Host, ":", Port, "/", Bucket, "/", Key]),
283-
Url = ibrowse_lib:parse_url(UnparsedUrl),
284-
Url.
291+
ibrowse_lib:parse_url(UnparsedUrl).
285292

286293
-spec next_host(term()) -> {term(), term()}.
287294
%% TODO:
@@ -494,7 +501,9 @@ uppercase_verb(put) ->
494501
uppercase_verb(get) ->
495502
'GET';
496503
uppercase_verb(delete) ->
497-
'DELETE'.
504+
'DELETE';
505+
uppercase_verb(post) ->
506+
'POST'.
498507

499508
to_list(A) when is_atom(A) ->
500509
atom_to_list(A);
@@ -512,9 +521,100 @@ initiate_request(Host, Url, Headers0, Method, Body, Options) ->
512521
Uri = element(7, Url),
513522
Sig = stanchion_auth:request_signature(
514523
uppercase_verb(Method), Headers, Uri,
515-
basho_bench_config:get(cs_secret_key)),
516-
AuthStr = ["AWS ", basho_bench_config:get(cs_access_key), ":", Sig],
524+
basho_bench_config:get(cs_secret_key, "undefined")),
525+
AuthStr = ["AWS ", basho_bench_config:get(cs_access_key, "undefined"), ":", Sig],
517526
HeadersWithAuth = [{'Authorization', AuthStr}|Headers],
518527
Timeout = basho_bench_config:get(cs_request_timeout, 5000),
519528
ibrowse_http_client:send_req(Pid, Url, HeadersWithAuth, Method,
520529
Body, Options, Timeout).
530+
531+
%% Setup user, not related to load operations
532+
533+
setup_user_and_bucket(State) ->
534+
case basho_bench_config:get(cs_access_key, undefined) of
535+
undefined ->
536+
DisplayName = basho_bench_config:get(cs_display_name, "test-user"),
537+
ok = maybe_create_user(DisplayName, State),
538+
{ok, {_DisplayName, KeyId, KeySecret}} = fetch_user_info(DisplayName, State),
539+
lager:info("Target User: ~p", [{DisplayName, KeyId, KeySecret}]),
540+
ok = basho_bench_config:set(cs_access_key, KeyId),
541+
ok = basho_bench_config:set(cs_secret_key, KeySecret);
542+
_ ->
543+
ok
544+
end,
545+
ok = maybe_create_bucket(State#state.bucket, State).
546+
547+
maybe_create_user(DisplayName, #state{hosts=Hosts} = State) ->
548+
{Host, Port} = hd(Hosts),
549+
Json = io_lib:format("{\"email\": \"~s@example.com\", \"name\": \"~s\"}",
550+
[DisplayName, DisplayName]),
551+
Url = url(Host, Port, "riak-cs", "user"),
552+
Headers = [{'Content-Type', 'application/json'}],
553+
case send_request({Host, Port}, Url, Headers, post, Json, proxy_opts(State)) of
554+
{ok, "201", _Header, Body} ->
555+
lager:debug("User created: ~p~n", [Body]),
556+
ok;
557+
{ok, "409", _Header, Body} ->
558+
lager:debug("User already exists: ~p~n", [Body]),
559+
ok;
560+
{ok, Code, Header, Body} ->
561+
{error, {user_creation, Code, Header, Body}};
562+
{error, Reason} ->
563+
{error, {user_creation, Reason}}
564+
end.
565+
566+
fetch_user_info(DisplayName, State) ->
567+
case list_users(State) of
568+
{ok, UserList} ->
569+
{ok, lists:keyfind(DisplayName, 1, UserList)};
570+
{error, Reason} ->
571+
{error, Reason}
572+
end.
573+
574+
list_users(#state{hosts=Hosts} = State) ->
575+
{Host, Port} = hd(Hosts),
576+
Url = url(Host, Port, "riak-cs", "users"),
577+
case send_request({Host, Port}, Url, [{'Accept', 'application/json'}], get,
578+
[], proxy_opts(State)) of
579+
{ok, "200", _Headers, Body} ->
580+
{ok, parse_user_info(Body)};
581+
{error, Reason} ->
582+
{error, {list_users, Reason}}
583+
end.
584+
585+
parse_user_info(Output) ->
586+
[Boundary | Tokens] = string:tokens(binary_to_list(Output), "\r\n"),
587+
parse_user_info(Tokens, Boundary, []).
588+
589+
parse_user_info([_LastToken], _, Users) ->
590+
ordsets:from_list(Users);
591+
parse_user_info(["Content-Type: application/json", RawJson | RestTokens],
592+
Boundary, Users) ->
593+
UpdUsers = parse_user_records(RawJson, json) ++ Users,
594+
parse_user_info(RestTokens, Boundary, UpdUsers);
595+
parse_user_info([_ | RestTokens], Boundary, Users) ->
596+
parse_user_info(RestTokens, Boundary, Users).
597+
598+
parse_user_records(Output, json) ->
599+
JsonData = mochijson2:decode(Output),
600+
[begin
601+
KeyId = binary_to_list(proplists:get_value(<<"key_id">>, UserJson)),
602+
KeySecret = binary_to_list(proplists:get_value(<<"key_secret">>, UserJson)),
603+
Name = binary_to_list(proplists:get_value(<<"name">>, UserJson)),
604+
{Name, KeyId, KeySecret}
605+
end || {struct, UserJson} <- JsonData].
606+
607+
maybe_create_bucket(Bucket, #state{hosts=Hosts} = State) ->
608+
{Host, Port} = hd(Hosts),
609+
Url = url(Host, Port, Bucket, undefined),
610+
case send_request({Host, Port}, Url, [], put, [], proxy_opts(State)) of
611+
{ok, "200", _Headers, _Body} ->
612+
lager:debug("Bucket created (maybe): ~p~n", [Bucket]),
613+
ok;
614+
{ok, Code, Header, Body} ->
615+
lager:error("Create bucket: ~p~n", [{Code, Header, Body}]),
616+
{error, {bucket_creation, Code, Header, Body}};
617+
{error, Reason} ->
618+
lager:error("Create bucket: ~p~n", [Reason]),
619+
{error, {bucket_creation, Reason}}
620+
end.

0 commit comments

Comments
 (0)