Github user gilv commented on a diff in the pull request:
https://github.com/apache/couchdb-fabric/pull/33#discussion_r49943389
--- Diff: src/fabric_swift_driver.erl ---
@@ -0,0 +1,269 @@
+% 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(fabric_swift_driver).
+
+-export([put_object/5, delete_object/2, get_object/2, head_object/2]).
+-export([store_id/0, create_container/1, delete_container/1 ]).
+%% ====================================================================
+%% OpenStack Swift implementation
+%% ====================================================================
+
+store_id() ->
+ "swift".
+
+put_object(Container, ObjName, ContextType, CustomHeaders, Data) ->
+ couch_log:debug("Swift: PUT ~p/~s object ~n", [Container, ObjName]),
+ case authenticate() of
+ {ok, {Url, Storage_Token}} ->
+ ObjNameEncoded = couch_util:url_encode(ObjName),
+ Headers = CustomHeaders ++ [{"X-Auth-Token", Storage_Token},
+ {"Content-Type",
+
unicode:characters_to_list(ContextType)}],
+ Method = put,
+ couch_log:debug("Swift: PUT : ~p ~p ~p ~p~n",
+ [Url,ContextType, ObjNameEncoded, Container]),
+ NewUrl = Url ++ "/" ++ unicode:characters_to_list(Container)
++ "/" ++ unicode:characters_to_list(ObjNameEncoded),
+ couch_log:debug("Swift: PUT url: ~p~n",[NewUrl]),
+ R = ibrowse:send_req(NewUrl, Headers, Method, Data),
+ case R of
+ {ok, ReturnCode, _, _} ->
+ {ok, {ReturnCode, NewUrl}};
+ Error ->
+ couch_log:debug("PUT object failed ~p ~n",
[element(2, Error)]),
+ {error, "PUT object failed"}
+ end;
+ {not_authenticated, _} ->
+ {error, "Not authenticated"}
+ end.
+
+delete_object(Container, ObjName) ->
+ %TO-DO: should be called during database compaction.
+ couch_log:debug("Swift: Delete ~p/~p ~n", [Container, ObjName]),
+ case authenticate() of
+ {ok, {Url, Storage_Token}} ->
+ Header = [{"X-Auth-Token", Storage_Token}],
+ ObjNameEncoded = couch_util:url_encode(ObjName),
+ Method = delete,
+ NewUrl = Url ++ "/" ++ unicode:characters_to_list(Container)
++ "/"
+ ++ unicode:characters_to_list(ObjNameEncoded),
+ couch_log:debug("Swift: url ~p~n", [NewUrl]),
+ R = ibrowse:send_req(NewUrl, Header, Method),
+ case R of
+ {ok, ReturnCode, _, _} ->
+ couch_log:debug("Swift: Delete ~p. Return code ~p ~n",
+ [NewUrl, ReturnCode]),
+ {ok, ReturnCode};
+ Error ->
+ couch_log:debug("Swift: Delete ~p failed. ~n",
[NewUrl]),
+ couch_log:debug("Swift: ~p ~n", [element(2, Error)]),
+ {error, "Delete object failed"}
+ end;
+ {not_authenticated, _} ->
+ {error, "Not authenticated"}
+ end.
+
+get_object(Container, ObjName) ->
+ couch_log:debug("Swift: get object ~p/~p ~n", [Container, ObjName]),
+ case authenticate() of
+ {ok, {Url, Storage_Token}} ->
+ Header = [{"X-Auth-Token", Storage_Token}],
+ ObjNameEncoded = couch_util:url_encode(ObjName),
+ Method = get,
+ NewUrl = Url ++ "/" ++ unicode:characters_to_list(Container)
++ "/"
+ ++ unicode:characters_to_list(ObjNameEncoded),
+ couch_log:debug("Swift: url ~p~n", [NewUrl]),
+ R = ibrowse:send_req(NewUrl, Header, Method),
+ case R of
+ {ok, ReturnCode, _, Body} ->
+ couch_log:debug("Swift: GET ~p with return code ~p
~n", [NewUrl, ReturnCode]),
+ Body;
+ Error ->
+ couch_log:debug("Swift: GET ~p failed. ~n", [NewUrl]),
+ couch_log:debug("Swift: ~p ~n", [element(2, Error)]),
+ {error, "Get object failed"}
+ end;
+ {not_authenticated, _} ->
+ {error, "Not authenticated"}
+ end.
+
+head_object(Container, ObjName) ->
+ couch_log:debug("Swift: head object ~p/~p ~n", [Container, ObjName]),
+ case authenticate() of
+ {ok, {Url, Storage_Token}} ->
+ Header = [{"X-Auth-Token", Storage_Token}],
+ Method = head,
+ ObjNameEncoded = couch_util:url_encode(ObjName),
+ NewUrl = Url ++ "/" ++ unicode:characters_to_list(Container)
+ ++ "/" ++ unicode:characters_to_list(ObjNameEncoded),
+ couch_log:debug("Swift: url ~p~n", [NewUrl]),
+ R = ibrowse:send_req(NewUrl, Header, Method),
+ case R of
+ {ok, ReturnCode, Head, _} ->
+ couch_log:debug("Swift: ~p~p~n", [ReturnCode, Head]),
+ ObjectSize = lists:filter(fun ({"Content-Length", _})
-> true; (_) -> false end, Head),
+ EtagHeader = lists:filter(fun ({"Etag", _}) -> true ;
(_) -> false end, Head),
+ Etag = element(2, lists:nth(1, EtagHeader)),
+ {ObjectSizeNumeric, _} = string:to_integer(element(2,
lists:nth(1, ObjectSize))),
+ couch_log:debug("Swift: Object size is: ~p and Etag:
~p~n",
+ [ObjectSizeNumeric, Etag]),
+ EtagDecode = hex_to_bin(Etag),
+ EtagMD5 = base64:encode(EtagDecode),
+ couch_log:debug("Etag in base64 ~p~n", [EtagMD5]),
+ {ok, {ObjectSizeNumeric, EtagMD5}};
+ Error ->
+ couch_log:debug("Swift: Head ~p failed ~n", [NewUrl]),
+ couch_log:debug("Swift: ~p ~n", [element(2, Error)]),
+ {error,"HEAD object failed"}
+ end;
+ {not_authenticated, _} ->
+ {error, "Not authenticated"}
+ end.
+
+create_container(DbName) ->
+ couch_log:debug("Swift : create container ~p~n", [DbName]),
+ case authenticate() of
+ {ok, {Url, Storage_Token}} ->
+ Header = [{"X-Auth-Token",Storage_Token}],
+ Method = put,
+ Container = DbName,
+ NewUrl = Url ++ "/" ++ unicode:characters_to_list(Container)
++"/",
+ couch_log:debug("Swift: url ~p ~n",[NewUrl]),
+ R = ibrowse:send_req(NewUrl, Header, Method),
+ case R of
+ {ok, ReturnCode, _, _} ->
+ couch_log:debug("Swift: container ~p created with code
: ~p~n",[Container, ReturnCode]),
+ {ok,{ReturnCode,Container}};
+ Error ->
+ couch_log:debug("Swift: container ~p creation failed :
~p~n",[Container, element(2,Error)]),
+ {error, "Failed to create container"}
+ end;
+ {not_authenticated,_} ->
+ {error, "Failed to create container. Not authenticated"}
+ end.
+
+delete_container(Container) ->
+ case authenticate() of
+ {ok,{Url,Storage_Token}} ->
+ Header = [{"X-Auth-Token",Storage_Token}],
+ Method = delete,
+ NewUrl = Url ++ "/" ++ Container ++"/",
+ R = ibrowse:send_req(NewUrl, Header, Method),
+ case R of
+ {ok, ReturnCode, _, _} ->
+ {ok,{ReturnCode,Container}};
+ Error ->
+ {error,{element(2,Error),Container}}
+ end;
+ {not_authenticated, _} ->
+ {error, "Not authenticated"};
+ {not_supported, Error} ->
+ {error,{element(2,Error),""}}
+ end.
+
+%% ====================================================================
+%% Internal functions
+%% ====================================================================
+
+hex_to_bin(Str) -> << << (erlang:list_to_integer([H], 16)):4 >> || H <-
Str >>.
+
+authenticate() ->
+ couch_log:debug("Going to authenticate in Swift",[]),
+ case config:get("swift", "auth_model", "tempauth") of
+ "tempauth" ->
+ swift_v1_auth();
+ "keystone" ->
+ keystone_auth();
+ Error ->
+ couch_log:debug("Authentication method is not supported: ~p",
element(2,Error)),
+ {not_authenticated, ""}
+ end.
+
+keystone_auth() ->
+ Method = post,
+ URL = config:get("swift", "auth_url"),
+ Header = [{"Content-Type", "application/json"}],
+ Tenant = config:get("swift", "account_tenant"),
+ User = config:get("swift", "username"),
+ Psw = config:get("swift", "password"),
+ Body = "{\"auth\": {\"tenantName\": \"" ++ Tenant
+ ++ "\", \"passwordCredentials\": {\"username\": \""
+ ++ User ++ "\", \"password\": \"" ++ Psw ++ "\"}}}",
--- End diff --
@kxepal It actually depends on the Keystone. I couldn't understand
completely if Keystone permits such passwords or they should be encoded. My
guess Keystone does not permits such passwords , so password will be ascii. Do
you think i should add some encoding here? I can document your comment in the
code, so we can handle it at later stage.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---