Merge pull request #671 from rabbitmq/rabbitmq-management-665
Allow loading definitions from file or directory
This commit is contained in:
		
						commit
						b2bf952704
					
				| 
						 | 
				
			
			@ -4,11 +4,11 @@
 | 
			
		|||
%% See http://www.rabbitmq.com/management.html for details
 | 
			
		||||
%% ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 % {rabbitmq_management,
 | 
			
		||||
  % [%% Pre-Load schema definitions from the following JSON file. See
 | 
			
		||||
%% Load definitions from a JSON file or directory of files. See
 | 
			
		||||
%% http://www.rabbitmq.com/management.html#load-definitions
 | 
			
		||||
%%
 | 
			
		||||
%% {load_definitions, "/path/to/schema.json"},
 | 
			
		||||
%% {load_definitions, "/path/to/schemas"},
 | 
			
		||||
{mapping, "management.load_definitions", "rabbitmq_management.load_definitions",
 | 
			
		||||
    [{datatype, string},
 | 
			
		||||
     {validators, ["file_accessible"]}]}.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,14 @@
 | 
			
		|||
%% The Original Code is RabbitMQ Management Plugin.
 | 
			
		||||
%%
 | 
			
		||||
%% The Initial Developer of the Original Code is GoPivotal, Inc.
 | 
			
		||||
%% Copyright (c) 2007-2018 Pivotal Software, Inc.  All rights reserved.
 | 
			
		||||
%% Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved.
 | 
			
		||||
%%
 | 
			
		||||
 | 
			
		||||
-module(rabbit_mgmt_load_definitions).
 | 
			
		||||
 | 
			
		||||
-include_lib("rabbit_common/include/rabbit.hrl").
 | 
			
		||||
 | 
			
		||||
-export([maybe_load_definitions/0]).
 | 
			
		||||
-export([maybe_load_definitions/0, maybe_load_definitions_from/2]).
 | 
			
		||||
 | 
			
		||||
%% We want to A) make sure we apply definitions before being open for
 | 
			
		||||
%% business (hence why we don't do this in the mgmt app startup) and
 | 
			
		||||
| 
						 | 
				
			
			@ -34,15 +34,42 @@
 | 
			
		|||
                    {enables,     empty_db_check}]}).
 | 
			
		||||
 | 
			
		||||
maybe_load_definitions() ->
 | 
			
		||||
    {ok, File} = application:get_env(rabbitmq_management, load_definitions),
 | 
			
		||||
    case File of
 | 
			
		||||
        none -> ok;
 | 
			
		||||
        _    -> case file:read_file(File) of
 | 
			
		||||
                    {ok, Body} -> rabbit_log:info(
 | 
			
		||||
                                    "Applying definitions from: ~s", [File]),
 | 
			
		||||
                                  load_definitions(Body);
 | 
			
		||||
                    {error, E} -> {error, {could_not_read_defs, {File, E}}}
 | 
			
		||||
                end
 | 
			
		||||
    case application:get_env(rabbitmq_management, load_definitions) of
 | 
			
		||||
        {ok, none} ->
 | 
			
		||||
            ok;
 | 
			
		||||
        {ok, FileOrDir} ->
 | 
			
		||||
            IsDir = filelib:is_dir(FileOrDir),
 | 
			
		||||
            maybe_load_definitions_from(IsDir, FileOrDir)
 | 
			
		||||
    end.
 | 
			
		||||
 | 
			
		||||
maybe_load_definitions_from(true, Dir) ->
 | 
			
		||||
    rabbit_log:info("Applying definitions from directory ~s", [Dir]),
 | 
			
		||||
    load_definitions_from_files(file:list_dir(Dir), Dir);
 | 
			
		||||
maybe_load_definitions_from(false, File) ->
 | 
			
		||||
    load_definitions_from_file(File).
 | 
			
		||||
 | 
			
		||||
load_definitions_from_files({ok, Filenames0}, Dir) ->
 | 
			
		||||
    Filenames1 = lists:sort(Filenames0),
 | 
			
		||||
    Filenames2 = [filename:join(Dir, F) || F <- Filenames1],
 | 
			
		||||
    load_definitions_from_filenames(Filenames2);
 | 
			
		||||
load_definitions_from_files({error, E}, Dir) ->
 | 
			
		||||
    rabbit_log:error("Could not read definitions from directory ~s, Error: ~p", [Dir, E]),
 | 
			
		||||
    {error, {could_not_read_defs, E}}.
 | 
			
		||||
 | 
			
		||||
load_definitions_from_filenames([]) ->
 | 
			
		||||
    ok;
 | 
			
		||||
load_definitions_from_filenames([File|Rest]) ->
 | 
			
		||||
    load_definitions_from_file(File),
 | 
			
		||||
    load_definitions_from_filenames(Rest).
 | 
			
		||||
 | 
			
		||||
load_definitions_from_file(File) ->
 | 
			
		||||
    case file:read_file(File) of
 | 
			
		||||
        {ok, Body} ->
 | 
			
		||||
            rabbit_log:info("Applying definitions from ~s", [File]),
 | 
			
		||||
            load_definitions(Body);
 | 
			
		||||
        {error, E} ->
 | 
			
		||||
            rabbit_log:error("Could not read definitions from ~s, Error: ~p", [File, E]),
 | 
			
		||||
            {error, {could_not_read_defs, {File, E}}}
 | 
			
		||||
    end.
 | 
			
		||||
 | 
			
		||||
load_definitions(Body) ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,7 +166,7 @@ accept(Body, ReqData, Context = #context{user = #user{username = Username}}) ->
 | 
			
		|||
    end.
 | 
			
		||||
 | 
			
		||||
apply_defs(Body, ActingUser, SuccessFun, ErrorFun) ->
 | 
			
		||||
    rabbit_log:info("Asked to import definitions. Acting user: ~p", [ActingUser]),
 | 
			
		||||
    rabbit_log:info("Asked to import definitions. Acting user: ~s", [rabbit_data_coercion:to_binary(ActingUser)]),
 | 
			
		||||
    case rabbit_mgmt_util:decode([], Body) of
 | 
			
		||||
        {error, E} ->
 | 
			
		||||
            ErrorFun(E);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,8 @@ groups() ->
 | 
			
		|||
                               import_case5,
 | 
			
		||||
                               import_case6,
 | 
			
		||||
                               import_case7,
 | 
			
		||||
                               import_case8
 | 
			
		||||
                               import_case8,
 | 
			
		||||
                               import_case9
 | 
			
		||||
                              ]}
 | 
			
		||||
    ].
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,16 +81,18 @@ end_per_testcase(Testcase, Config) ->
 | 
			
		|||
%% Tests
 | 
			
		||||
%%
 | 
			
		||||
 | 
			
		||||
import_case1(Config) -> import_case(Config, "case1").
 | 
			
		||||
import_case2(Config) -> import_case(Config, "case2").
 | 
			
		||||
import_case3(Config) -> import_case(Config, "case3").
 | 
			
		||||
import_case4(Config) -> import_case(Config, "case4").
 | 
			
		||||
import_case6(Config) -> import_case(Config, "case6").
 | 
			
		||||
import_case7(Config) -> import_case(Config, "case7").
 | 
			
		||||
import_case8(Config) -> import_case(Config, "case8").
 | 
			
		||||
import_case1(Config) -> import_file_case(Config, "case1").
 | 
			
		||||
import_case2(Config) -> import_file_case(Config, "case2").
 | 
			
		||||
import_case3(Config) -> import_file_case(Config, "case3").
 | 
			
		||||
import_case4(Config) -> import_file_case(Config, "case4").
 | 
			
		||||
import_case6(Config) -> import_file_case(Config, "case6").
 | 
			
		||||
import_case7(Config) -> import_file_case(Config, "case7").
 | 
			
		||||
import_case8(Config) -> import_file_case(Config, "case8").
 | 
			
		||||
 | 
			
		||||
import_case9(Config) -> import_from_directory_case(Config, "case9").
 | 
			
		||||
 | 
			
		||||
import_case5(Config) ->
 | 
			
		||||
    import_case(Config, "case5"),
 | 
			
		||||
    import_file_case(Config, "case5"),
 | 
			
		||||
    ?assertEqual(rabbit_ct_broker_helpers:rpc(Config, 0,
 | 
			
		||||
                                              rabbit_runtime_parameters, value_global,
 | 
			
		||||
                                              [mqtt_port_to_vhost_mapping]),
 | 
			
		||||
| 
						 | 
				
			
			@ -97,15 +100,25 @@ import_case5(Config) ->
 | 
			
		|||
                 [{<<"1883">>,<<"/">>},
 | 
			
		||||
                  {<<"1884">>,<<"vhost2">>}]).
 | 
			
		||||
 | 
			
		||||
import_case(Config, CaseName) ->
 | 
			
		||||
import_file_case(Config, CaseName) ->
 | 
			
		||||
    CasePath = filename:join(?config(data_dir, Config), CaseName ++ ".json"),
 | 
			
		||||
    rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, run_import_case, [CasePath]),
 | 
			
		||||
    ok.
 | 
			
		||||
 | 
			
		||||
import_from_directory_case(Config, CaseName) ->
 | 
			
		||||
    CasePath = filename:join(?config(data_dir, Config), CaseName),
 | 
			
		||||
    ?assert(filelib:is_dir(CasePath)),
 | 
			
		||||
    rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, run_directory_import_case, [CasePath]),
 | 
			
		||||
    ok.
 | 
			
		||||
 | 
			
		||||
run_directory_import_case(Path) ->
 | 
			
		||||
    ct:pal("Will load definitions from files under ~p~n", [Path]),
 | 
			
		||||
    rabbit_mgmt_load_definitions:maybe_load_definitions_from(true, Path).
 | 
			
		||||
 | 
			
		||||
run_import_case(Path) ->
 | 
			
		||||
    {ok, Body} = file:read_file(Path),
 | 
			
		||||
    ct:pal("Successfully loaded a definition to import from ~p~n", [Path]),
 | 
			
		||||
    rabbit_mgmt_wm_definitions:apply_defs(Body, ?INTERNAL_USER,
 | 
			
		||||
                                          fun ()  -> ct:pal("Import case ~p succeeded~n",  [Path]) end,
 | 
			
		||||
                                          fun (E) -> ct:pal("Import case ~p failed: ~p~n", [Path, E]),
 | 
			
		||||
                                                     ct:fail({failure, Path, E}) end).
 | 
			
		||||
   {ok, Body} = file:read_file(Path),
 | 
			
		||||
   ct:pal("Successfully loaded a definition to import from ~p~n", [Path]),
 | 
			
		||||
   rabbit_mgmt_wm_definitions:apply_defs(Body, ?INTERNAL_USER,
 | 
			
		||||
                                         fun ()  -> ct:pal("Import case ~p succeeded~n",  [Path]) end,
 | 
			
		||||
                                         fun (E) -> ct:pal("Import case ~p failed: ~p~n", [Path, E]),
 | 
			
		||||
                                                    ct:fail({failure, Path, E}) end).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								deps/rabbitmq_management/test/definitions_import_SUITE_data/case9/case9a.json
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										1
									
								
								deps/rabbitmq_management/test/definitions_import_SUITE_data/case9/case9a.json
								
								
								
									vendored
								
								
									Normal file
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								deps/rabbitmq_management/test/definitions_import_SUITE_data/case9/case9b.json
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										1
									
								
								deps/rabbitmq_management/test/definitions_import_SUITE_data/case9/case9b.json
								
								
								
									vendored
								
								
									Normal file
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
		Reference in New Issue