API to restart a crashed vhost.
Administrator should be able to restart vhosts if they believe it can be recovered. Added buttons to vhost status tables and the new HTTP API endpoint: /vhosts/:vhost/start/:node Part of rabbitmq/rabbitmq-server#1321 [#149484305]
This commit is contained in:
		
							parent
							
								
									179e99bd93
								
							
						
					
					
						commit
						7f54319279
					
				|  | @ -235,6 +235,7 @@ table.two-col-layout > tbody > tr > td { width: 50%; vertical-align: top; } | ||||||
| 
 | 
 | ||||||
| input[type=submit], button { padding: 8px; border-radius: 5px; -moz-border-radius: 5px; color: black !important; text-decoration: none; cursor: pointer; font-weight: normal; } | input[type=submit], button { padding: 8px; border-radius: 5px; -moz-border-radius: 5px; color: black !important; text-decoration: none; cursor: pointer; font-weight: normal; } | ||||||
| table.list input[type=submit], table.list button { padding: 4px; } | table.list input[type=submit], table.list button { padding: 4px; } | ||||||
|  | table.mini input[type=submit], table.mini button { padding: 4px; } | ||||||
| 
 | 
 | ||||||
| input[type=submit], button { | input[type=submit], button { | ||||||
|     background: #ddf; |     background: #ddf; | ||||||
|  |  | ||||||
|  | @ -282,6 +282,9 @@ dispatcher_add(function(sammy) { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |     sammy.post('#/restart_vhost', function(){ | ||||||
|  |         if(sync_post(this, '/vhosts/:vhost/start/:node')) update(); | ||||||
|  |     }) | ||||||
|     sammy.del('#/limits', function() { |     sammy.del('#/limits', function() { | ||||||
|         if (sync_delete(this, '/vhost-limits/:vhost/:name')) update(); |         if (sync_delete(this, '/vhost-limits/:vhost/:name')) update(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -27,7 +27,15 @@ | ||||||
|         <% for (var node in vhost.cluster_state) { %> |         <% for (var node in vhost.cluster_state) { %> | ||||||
|             <tr> |             <tr> | ||||||
|             <th><%= fmt_escape_html(node) %> :</th> |             <th><%= fmt_escape_html(node) %> :</th> | ||||||
|             <td><%= vhost.cluster_state[node] %></td> |             <td><%= vhost.cluster_state[node] %> | ||||||
|  |             <% if (vhost.cluster_state[node] == "stopped"){ %> | ||||||
|  |                 <form action="#/restart_vhost" method="post"> | ||||||
|  |                     <input type="hidden" name="node" value="<%= node %>"/> | ||||||
|  |                     <input type="hidden" name="vhost" value="<%= vhost.name %>"/> | ||||||
|  |                     <input type="submit" value="Restart"/> | ||||||
|  |                 </form> | ||||||
|  |             <% } %> | ||||||
|  |             </td> | ||||||
|             </tr> |             </tr> | ||||||
|         <% } %> |         <% } %> | ||||||
|         </table> |         </table> | ||||||
|  |  | ||||||
|  | @ -69,7 +69,16 @@ | ||||||
|             %> |             %> | ||||||
|             <tr> |             <tr> | ||||||
|             <td><%= node %></td> |             <td><%= node %></td> | ||||||
|             <td><%= state %></td> |             <td> | ||||||
|  |             <%= state %> | ||||||
|  |             <% if (state == "stopped"){ %> | ||||||
|  |                 <form action="#/restart_vhost" method="post" class="confirm"> | ||||||
|  |                     <input type="hidden" name="node" value="<%= node %>"/> | ||||||
|  |                     <input type="hidden" name="vhost" value="<%= vhost.name %>"/> | ||||||
|  |                     <input type="submit" value="Restart"/> | ||||||
|  |                 </form> | ||||||
|  |             <% } %> | ||||||
|  |             </td> | ||||||
|             </tr> |             </tr> | ||||||
|             <% |             <% | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -117,6 +117,7 @@ dispatcher() -> | ||||||
|      {"/bindings/:vhost/e/:source/:dtype/:destination/:props", rabbit_mgmt_wm_binding, []}, |      {"/bindings/:vhost/e/:source/:dtype/:destination/:props", rabbit_mgmt_wm_binding, []}, | ||||||
|      {"/vhosts",                                               rabbit_mgmt_wm_vhosts, []}, |      {"/vhosts",                                               rabbit_mgmt_wm_vhosts, []}, | ||||||
|      {"/vhosts/:vhost",                                        rabbit_mgmt_wm_vhost, []}, |      {"/vhosts/:vhost",                                        rabbit_mgmt_wm_vhost, []}, | ||||||
|  |      {"/vhosts/:vhost/start/:node",                            rabbit_mgmt_wm_vhost_restart, []}, | ||||||
|      {"/vhosts/:vhost/permissions",                            rabbit_mgmt_wm_permissions_vhost, []}, |      {"/vhosts/:vhost/permissions",                            rabbit_mgmt_wm_permissions_vhost, []}, | ||||||
|      {"/vhosts/:vhost/topic-permissions",                      rabbit_mgmt_wm_topic_permissions_vhost, []}, |      {"/vhosts/:vhost/topic-permissions",                      rabbit_mgmt_wm_topic_permissions_vhost, []}, | ||||||
|      %% /connections/:connection is already taken, we cannot use our standard scheme here |      %% /connections/:connection is already taken, we cannot use our standard scheme here | ||||||
|  |  | ||||||
|  | @ -0,0 +1,67 @@ | ||||||
|  | %%   The contents of this file are subject to the Mozilla Public License | ||||||
|  | %%   Version 1.1 (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.mozilla.org/MPL/ | ||||||
|  | %% | ||||||
|  | %%   Software distributed under the License is distributed on an "AS IS" | ||||||
|  | %%   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | ||||||
|  | %%   License for the specific language governing rights and limitations | ||||||
|  | %%   under the License. | ||||||
|  | %% | ||||||
|  | %%   The Original Code is RabbitMQ Management Plugin. | ||||||
|  | %% | ||||||
|  | %%   The Initial Developer of the Original Code is GoPivotal, Inc. | ||||||
|  | %%   Copyright (c) 2011-2012 GoPivotal, Inc.  All rights reserved. | ||||||
|  | %% | ||||||
|  | 
 | ||||||
|  | -module(rabbit_mgmt_wm_vhost_restart). | ||||||
|  | 
 | ||||||
|  | -export([init/3, rest_init/2, resource_exists/2, is_authorized/2, | ||||||
|  |          allowed_methods/2, content_types_accepted/2, accept_content/2]). | ||||||
|  | -export([variances/2]). | ||||||
|  | 
 | ||||||
|  | -include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). | ||||||
|  | -include_lib("amqp_client/include/amqp_client.hrl"). | ||||||
|  | 
 | ||||||
|  | %%-------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | init(_, _, _) -> {upgrade, protocol, cowboy_rest}. | ||||||
|  | 
 | ||||||
|  | rest_init(Req, _Config) -> | ||||||
|  |     {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. | ||||||
|  | 
 | ||||||
|  | variances(Req, Context) -> | ||||||
|  |     {[<<"accept-encoding">>, <<"origin">>], Req, Context}. | ||||||
|  | 
 | ||||||
|  | allowed_methods(ReqData, Context) -> | ||||||
|  |     {[<<"POST">>, <<"OPTIONS">>], ReqData, Context}. | ||||||
|  | 
 | ||||||
|  | resource_exists(ReqData, Context) -> | ||||||
|  |     VHost = id(ReqData), | ||||||
|  |     {rabbit_vhost:exists(VHost), ReqData, Context}. | ||||||
|  | 
 | ||||||
|  | content_types_accepted(ReqData, Context) -> | ||||||
|  |    {[{'*', accept_content}], ReqData, Context}. | ||||||
|  | 
 | ||||||
|  | accept_content(ReqData, Context) -> | ||||||
|  |     VHost = id(ReqData), | ||||||
|  |     NodeB = rabbit_mgmt_util:id(node, ReqData), | ||||||
|  |     Node  = binary_to_atom(NodeB, utf8), | ||||||
|  |     case rabbit_vhost_sup_sup:start_vhost(VHost, Node) of | ||||||
|  |         {ok, _} -> | ||||||
|  |             {true, ReqData, Context}; | ||||||
|  |         {error, {already_started, _}} -> | ||||||
|  |             {true, ReqData, Context}; | ||||||
|  |         {error, Err} -> | ||||||
|  |             Message = io_lib:format("Request to node ~s failed with ~p", | ||||||
|  |                                     [Node, Err]), | ||||||
|  |             rabbit_mgmt_util:bad_request(list_to_binary(Message), ReqData, Context) | ||||||
|  |     end. | ||||||
|  | 
 | ||||||
|  | is_authorized(ReqData, Context) -> | ||||||
|  |     rabbit_mgmt_util:is_authorized_admin(ReqData, Context). | ||||||
|  | 
 | ||||||
|  | %%-------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | id(ReqData) -> | ||||||
|  |     rabbit_mgmt_util:id(vhost, ReqData). | ||||||
|  | @ -334,6 +334,19 @@ vhosts_test(Config) -> | ||||||
|     %% Check individually |     %% Check individually | ||||||
|     assert_item(#{name => <<"/">>}, http_get(Config, "/vhosts/%2f", ?OK)), |     assert_item(#{name => <<"/">>}, http_get(Config, "/vhosts/%2f", ?OK)), | ||||||
|     assert_item(#{name => <<"myvhost">>},http_get(Config, "/vhosts/myvhost")), |     assert_item(#{name => <<"myvhost">>},http_get(Config, "/vhosts/myvhost")), | ||||||
|  | 
 | ||||||
|  |     %% Crash it | ||||||
|  |     rabbit_ct_broker_helpers:force_vhost_failure(Config, <<"myvhost">>), | ||||||
|  |     [NodeData] = http_get(Config, "/nodes"), | ||||||
|  |     Node = binary_to_atom(maps:get(name, NodeData), utf8), | ||||||
|  |     assert_item(#{name => <<"myvhost">>, cluster_state => #{Node => <<"stopped">>}}, | ||||||
|  |                 http_get(Config, "/vhosts/myvhost")), | ||||||
|  | 
 | ||||||
|  |     %% Restart it | ||||||
|  |     http_post(Config, "/vhosts/myvhost/start/" ++ atom_to_list(Node), [], {group, '2xx'}), | ||||||
|  |     assert_item(#{name => <<"myvhost">>, cluster_state => #{Node => <<"running">>}}, | ||||||
|  |                 http_get(Config, "/vhosts/myvhost")), | ||||||
|  | 
 | ||||||
|     %% Delete it |     %% Delete it | ||||||
|     http_delete(Config, "/vhosts/myvhost", {group, '2xx'}), |     http_delete(Config, "/vhosts/myvhost", {group, '2xx'}), | ||||||
|     %% It's not there |     %% It's not there | ||||||
|  | @ -344,17 +357,15 @@ vhosts_test(Config) -> | ||||||
| 
 | 
 | ||||||
| vhosts_trace_test(Config) -> | vhosts_trace_test(Config) -> | ||||||
|     http_put(Config, "/vhosts/myvhost", none, {group, '2xx'}), |     http_put(Config, "/vhosts/myvhost", none, {group, '2xx'}), | ||||||
|     ?assertMatch(#{name := <<"myvhost">>, tracing := false,  cluster_state := _}, |     Disabled = #{name => <<"myvhost">>, tracing => false}, | ||||||
|                  http_get(Config, "/vhosts/myvhost")), |     Enabled  = #{name => <<"myvhost">>, tracing => true}, | ||||||
|  |     assert_item(Disabled, http_get(Config, "/vhosts/myvhost")), | ||||||
|     http_put(Config, "/vhosts/myvhost", [{tracing, true}], {group, '2xx'}), |     http_put(Config, "/vhosts/myvhost", [{tracing, true}], {group, '2xx'}), | ||||||
|     ?assertMatch(#{name := <<"myvhost">>, tracing := true, cluster_state := _}, |     assert_item(Enabled, http_get(Config, "/vhosts/myvhost")), | ||||||
|                  http_get(Config, "/vhosts/myvhost")), |  | ||||||
|     http_put(Config, "/vhosts/myvhost", [{tracing, true}], {group, '2xx'}), |     http_put(Config, "/vhosts/myvhost", [{tracing, true}], {group, '2xx'}), | ||||||
|     ?assertMatch(#{name := <<"myvhost">>, tracing := true}, |     assert_item(Enabled, http_get(Config, "/vhosts/myvhost")), | ||||||
|                  http_get(Config, "/vhosts/myvhost")), |  | ||||||
|     http_put(Config, "/vhosts/myvhost", [{tracing, false}], {group, '2xx'}), |     http_put(Config, "/vhosts/myvhost", [{tracing, false}], {group, '2xx'}), | ||||||
|     ?assertMatch(#{name := <<"myvhost">>, tracing := false}, |     assert_item(Disabled, http_get(Config, "/vhosts/myvhost")), | ||||||
|                  http_get(Config, "/vhosts/myvhost")), |  | ||||||
|     http_delete(Config, "/vhosts/myvhost", {group, '2xx'}), |     http_delete(Config, "/vhosts/myvhost", {group, '2xx'}), | ||||||
| 
 | 
 | ||||||
|     passed. |     passed. | ||||||
|  | @ -809,9 +820,9 @@ queues_test(Config) -> | ||||||
| 
 | 
 | ||||||
|     rabbit_ct_broker_helpers:force_vhost_failure(Config, <<"downvhost">>), |     rabbit_ct_broker_helpers:force_vhost_failure(Config, <<"downvhost">>), | ||||||
|     %% The vhost is down |     %% The vhost is down | ||||||
|     #{name := <<"downvhost">>, tracing := false, cluster_state := DownClusterState} = |     Node = rabbit_ct_broker_helpers:get_node_config(Config, 0, nodename), | ||||||
|         http_get(Config, "/vhosts/downvhost"), |     DownVHost = #{name => <<"downvhost">>, tracing => false, cluster_state => #{Node => <<"stopped">>}}, | ||||||
|     ?assertEqual([<<"stopped">>], lists:usort(maps:values(DownClusterState))), |     assert_item(DownVHost, http_get(Config, "/vhosts/downvhost")), | ||||||
| 
 | 
 | ||||||
|     DownQueues = http_get(Config, "/queues/downvhost"), |     DownQueues = http_get(Config, "/queues/downvhost"), | ||||||
|     DownQueue  = http_get(Config, "/queues/downvhost/foo"), |     DownQueue  = http_get(Config, "/queues/downvhost/foo"), | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue