Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Create a bucket props validation module and register it #256

Merged
merged 2 commits into from

2 participants

@russelldb
Owner

Update HTTP/PB interfaces to return errors for invalid bucket props

@rustyio rustyio commented on the diff
src/riak_kv_app.erl
@@ -79,6 +79,9 @@ start(_Type, _StartArgs) ->
%% the app is missing or packaging is broken.
catch cluster_info:register_app(riak_kv_cinfo),
+ %% Register the bucket validation fun
+ riak_core:register([{bucket_validator, riak_kv_bucket}]),
@rustyio
rustyio added a note

When merging, this should be combined with the call to riak_core:register/N that happens after we start the supervisor. This was a recent change, for background, see #261 and basho/riak_core#121.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rustyio

Assuming that validating non-bool settings (such as integers / modfuns / etc.) is out of scope, then this looks good.

+1 merge.

Tested with:

import riak
client = riak.RiakClient()
bucket = client.bucket('bucket')
bucket.set_allow_multiples("foo")
import riak
client = riak.RiakClient(port=8087, transport_class=riak.RiakPbcTransport)
bucket = client.bucket('bucket')
bucket.set_allow_multiples("foo")
curl -X PUT \
  -H "Content-Type: application/json" -d '{"props":{"allow_mult":true}}' \
  localhost:8098/riak/mybucket
curl localhost:8098/riak/mybucket

curl -X PUT \
  -H "Content-Type: application/json" -d '{"props":{"allow_mult":5}}' \
  localhost:8098/riak/mybucket
curl localhost:8098/riak/mybucket

curl -X PUT \
  -H "Content-Type: application/json" -d '{"props":{"allow_mult":-5}}' \
  localhost:8098/riak/mybucket
curl localhost:8098/riak/mybucket

curl -X PUT \
  -H "Content-Type: application/json" -d '{"props":{"allow_mult":"foo"}}' \
  localhost:8098/riak/mybucket
curl localhost:8098/riak/mybucket
# Result: {"allow_mult":"not_boolean"}
@russelldb russelldb merged commit b447e30 into master
@seancribbs seancribbs deleted the rdb_bz1278 branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 7, 2011
  1. @russelldb

    Create a bucket props validation module and register it

    russelldb authored
    Update HTTP/PB interfaces to return errors for invalid bucket props
Commits on Dec 16, 2011
  1. @russelldb
This page is out of date. Refresh to see the latest.
View
3  src/riak_kv_app.erl
@@ -79,6 +79,9 @@ start(_Type, _StartArgs) ->
%% the app is missing or packaging is broken.
catch cluster_info:register_app(riak_kv_cinfo),
+ %% Register the bucket validation fun
+ riak_core:register([{bucket_validator, riak_kv_bucket}]),
@rustyio
rustyio added a note

When merging, this should be combined with the call to riak_core:register/N that happens after we start the supervisor. This was a recent change, for background, see #261 and basho/riak_core#121.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
%% Spin up supervisor
case riak_kv_sup:start_link() of
{ok, Pid} ->
View
104 src/riak_kv_bucket.erl
@@ -0,0 +1,104 @@
+%% -------------------------------------------------------------------
+%%
+%% riak_kv_bucket: bucket validation functions
+%%
+%% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved.
+%%
+%% This file is provided to you 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.
+%%
+%% -------------------------------------------------------------------
+%% @doc KV Bucket validation functions
+
+-module(riak_kv_bucket).
+
+-export([validate/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-type prop() :: {PropName::atom(), PropValue::any()}.
+-type error() :: {PropName::atom(), ErrorReason::atom()}.
+-type props() :: [prop()].
+-type errors() :: [error()].
+
+-spec validate(props()) -> {props(), errors()}.
+validate(BucketProps) when is_list(BucketProps) ->
+ lager:debug("Was called ~p~n", [BucketProps]),
+ validate(BucketProps, [], []).
+
+-spec validate(InProps::props(), ValidProps::props(), Errors::errors()) ->
+ {props(), errors()}.
+validate([], ValidProps, Errors) ->
+ {ValidProps, Errors};
+validate([{BoolProp, MaybeBool}|T], ValidProps, Errors) when is_atom(BoolProp), BoolProp =:= allow_mult
+ orelse BoolProp =:= basic_quorum
+ orelse BoolProp =:= last_write_wins
+ orelse BoolProp =:= notfound_ok ->
+ case coerce_bool(MaybeBool) of
+ error ->
+ validate(T, ValidProps, [{BoolProp, not_boolean}|Errors]);
+ Bool ->
+ validate(T, [{BoolProp, Bool}|ValidProps], Errors)
+ end;
+validate([Prop|T], ValidProps, Errors) ->
+ validate(T, [Prop|ValidProps], Errors).
+
+-spec coerce_bool(any()) -> boolean() | error.
+coerce_bool(true) ->
+ true;
+coerce_bool(false) ->
+ false;
+coerce_bool(MaybeBool) when is_atom(MaybeBool) ->
+ coerce_bool(atom_to_list(MaybeBool));
+coerce_bool(MaybeBool) when is_binary(MaybeBool) ->
+ coerce_bool(binary_to_list(MaybeBool));
+coerce_bool(Int) when is_integer(Int), Int =< 0 ->
+ false;
+coerce_bool(Int) when is_integer(Int) , Int > 0 ->
+ true;
+coerce_bool(MaybeBool) when is_list(MaybeBool) ->
+ Lower = string:to_lower(MaybeBool),
+ Atom = (catch list_to_existing_atom(Lower)),
+ case Atom of
+ true -> true;
+ false -> false;
+ _ -> error
+ end;
+coerce_bool(_) ->
+ error.
+
+%%
+%% EUNIT tests...
+%%
+
+-ifdef (TEST).
+
+coerce_bool_test_ () ->
+ [?_assertEqual(false, coerce_bool(false)),
+ ?_assertEqual(true, coerce_bool(true)),
+ ?_assertEqual(true, coerce_bool("True")),
+ ?_assertEqual(false, coerce_bool("fAlSE")),
+ ?_assertEqual(false, coerce_bool(<<"FAlse">>)),
+ ?_assertEqual(true, coerce_bool(<<"trUe">>)),
+ ?_assertEqual(true, coerce_bool(1)),
+ ?_assertEqual(true, coerce_bool(234567)),
+ ?_assertEqual(false, coerce_bool(0)),
+ ?_assertEqual(false, coerce_bool(-1234)),
+ ?_assertEqual(false, coerce_bool('FALSE')),
+ ?_assertEqual(true, coerce_bool('TrUe')),
+ ?_assertEqual(error, coerce_bool("Purple")),
+ ?_assertEqual(error, coerce_bool(<<"frangipan">>)),
+ ?_assertEqual(error, coerce_bool(erlang:make_ref()))
+ ].
+-endif.
View
8 src/riak_kv_pb_socket.erl
@@ -441,8 +441,12 @@ process_message(#rpbgetbucketreq{bucket=B},
process_message(#rpbsetbucketreq{bucket=B, props = PbProps},
#state{client=C} = State) ->
Props = riakc_pb:erlify_rpbbucketprops(PbProps),
- ok = C:set_bucket(B, Props),
- send_msg(rpbsetbucketresp, State);
+ case C:set_bucket(B, Props) of
+ ok ->
+ send_msg(rpbsetbucketresp, State);
+ {error, Details} ->
+ send_error("Invalid bucket properties: ~p", [Details], State)
+ end;
%% TODO: refactor, cleanup
%% Start map/reduce job - results will be processed in handle_info
View
12 src/riak_kv_wm_props.erl
@@ -195,8 +195,14 @@ get_bucket_props_json(Client, Bucket) ->
%% bucket-level PUT request.
accept_bucket_body(RD, Ctx=#ctx{bucket=B, client=C, bucketprops=Props}) ->
ErlProps = lists:map(fun erlify_bucket_prop/1, Props),
- C:set_bucket(B, ErlProps),
- {true, RD, Ctx}.
+ case C:set_bucket(B, ErlProps) of
+ ok ->
+ {true, RD, Ctx};
+ {error, Details} ->
+ JSON = mochijson2:encode(Details),
+ RD2 = wrq:append_to_resp_body(JSON, RD),
+ {{halt, 400}, RD2, Ctx}
+ end.
%% @spec jsonify_bucket_prop({Property::atom(), erlpropvalue()}) ->
%% {Property::binary(), jsonpropvalue()}
@@ -297,7 +303,5 @@ erlify_bucket_prop({?JSON_CHASH, {struct, Props}}) ->
list_to_existing_atom(
binary_to_list(
proplists:get_value(?JSON_FUN, Props)))}};
-erlify_bucket_prop({?JSON_ALLOW_MULT, Value}) ->
- {allow_mult, riak_kv_wm_utils:any_to_bool(Value)};
erlify_bucket_prop({Prop, Value}) ->
{list_to_existing_atom(binary_to_list(Prop)), Value}.
Something went wrong with that request. Please try again.