|
|
15f218 |
From cf1c95354a9db8b81712d7b98d0cc55e777e0516 Mon Sep 17 00:00:00 2001
|
|
|
15f218 |
From: Ondrej Mular <omular@redhat.com>
|
|
|
15f218 |
Date: Thu, 4 Aug 2016 00:59:11 +0200
|
|
|
15f218 |
Subject: [PATCH] web UI: add support for unmanaged resources
|
|
|
15f218 |
|
|
|
15f218 |
---
|
|
|
15f218 |
pcsd/cluster_entity.rb | 13 ++++++++--
|
|
|
15f218 |
pcsd/pcs.rb | 1 +
|
|
|
15f218 |
pcsd/public/js/nodes-ember.js | 22 +++++++++++++----
|
|
|
15f218 |
pcsd/public/js/pcsd.js | 52 ++++++++++++++++++++++++++++++++++++++++
|
|
|
15f218 |
pcsd/remote.rb | 55 +++++++++++++++++++++++++++++++++++++++----
|
|
|
15f218 |
pcsd/views/main.erb | 26 ++++++++++++++++++++
|
|
|
15f218 |
6 files changed, 158 insertions(+), 11 deletions(-)
|
|
|
15f218 |
|
|
|
15f218 |
diff --git a/pcsd/cluster_entity.rb b/pcsd/cluster_entity.rb
|
|
|
15f218 |
index fa56fe2..7216626 100644
|
|
|
15f218 |
--- a/pcsd/cluster_entity.rb
|
|
|
15f218 |
+++ b/pcsd/cluster_entity.rb
|
|
|
15f218 |
@@ -332,7 +332,11 @@ module ClusterEntity
|
|
|
15f218 |
:unknown => {
|
|
|
15f218 |
:val => 6,
|
|
|
15f218 |
:str => 'unknown'
|
|
|
15f218 |
- }
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ :unmanaged => {
|
|
|
15f218 |
+ :val => 7,
|
|
|
15f218 |
+ :str => 'unmanaged'
|
|
|
15f218 |
+ },
|
|
|
15f218 |
}
|
|
|
15f218 |
|
|
|
15f218 |
def initialize(status=:unknown)
|
|
|
15f218 |
@@ -532,8 +536,11 @@ module ClusterEntity
|
|
|
15f218 |
def get_status
|
|
|
15f218 |
running = 0
|
|
|
15f218 |
failed = 0
|
|
|
15f218 |
+ unmanaged = 0
|
|
|
15f218 |
@crm_status.each do |s|
|
|
|
15f218 |
- if s.active
|
|
|
15f218 |
+ if !s.managed
|
|
|
15f218 |
+ unmanaged += 1
|
|
|
15f218 |
+ elsif s.active
|
|
|
15f218 |
running += 1
|
|
|
15f218 |
elsif s.failed
|
|
|
15f218 |
failed += 1
|
|
|
15f218 |
@@ -542,6 +549,8 @@ module ClusterEntity
|
|
|
15f218 |
|
|
|
15f218 |
if disabled?
|
|
|
15f218 |
status = ClusterEntity::ResourceStatus.new(:disabled)
|
|
|
15f218 |
+ elsif unmanaged >0
|
|
|
15f218 |
+ status = ClusterEntity::ResourceStatus.new(:unmanaged)
|
|
|
15f218 |
elsif running > 0
|
|
|
15f218 |
status = ClusterEntity::ResourceStatus.new(:running)
|
|
|
15f218 |
elsif failed > 0 or @error_list.length > 0
|
|
|
15f218 |
diff --git a/pcsd/pcs.rb b/pcsd/pcs.rb
|
|
|
15f218 |
index 1eb9e9e..553a20c 100644
|
|
|
15f218 |
--- a/pcsd/pcs.rb
|
|
|
15f218 |
+++ b/pcsd/pcs.rb
|
|
|
15f218 |
@@ -1703,6 +1703,7 @@ def get_node_status(auth_user, cib_dom)
|
|
|
15f218 |
'sbd',
|
|
|
15f218 |
'ticket_constraints',
|
|
|
15f218 |
'moving_resource_in_group',
|
|
|
15f218 |
+ 'unmanaged_resource',
|
|
|
15f218 |
]
|
|
|
15f218 |
}
|
|
|
15f218 |
|
|
|
15f218 |
diff --git a/pcsd/public/js/nodes-ember.js b/pcsd/public/js/nodes-ember.js
|
|
|
15f218 |
index 3d4fe79..c51a341 100644
|
|
|
15f218 |
--- a/pcsd/public/js/nodes-ember.js
|
|
|
15f218 |
+++ b/pcsd/public/js/nodes-ember.js
|
|
|
15f218 |
@@ -57,6 +57,9 @@ Pcs = Ember.Application.createWithMixins({
|
|
|
15f218 |
this.get("available_features").indexOf("moving_resource_in_group") != -1
|
|
|
15f218 |
);
|
|
|
15f218 |
}.property("available_features"),
|
|
|
15f218 |
+ is_supported_unmanaged_resource: function() {
|
|
|
15f218 |
+ return (this.get("available_features").indexOf("unmanaged_resource") != -1);
|
|
|
15f218 |
+ }.property("available_features"),
|
|
|
15f218 |
is_sbd_running: false,
|
|
|
15f218 |
is_sbd_enabled: false,
|
|
|
15f218 |
is_sbd_enabled_or_running: function() {
|
|
|
15f218 |
@@ -869,9 +872,17 @@ Pcs.ResourceObj = Ember.Object.extend({
|
|
|
15f218 |
return '' + this.get('status') + '';
|
|
|
15f218 |
}.property("status_style", "disabled"),
|
|
|
15f218 |
status_class: function() {
|
|
|
15f218 |
- var show = ((Pcs.clusterController.get("show_all_resources"))? "" : "hidden ");
|
|
|
15f218 |
- return ((this.get("status_val") == get_status_value("ok") || this.status == "disabled") ? show + "default-hidden" : "");
|
|
|
15f218 |
- }.property("status_val"),
|
|
|
15f218 |
+ if (
|
|
|
15f218 |
+ this.get("status_val") == get_status_value("ok") ||
|
|
|
15f218 |
+ ["disabled", "unmanaged"].indexOf(this.get("status")) != -1
|
|
|
15f218 |
+ ) {
|
|
|
15f218 |
+ return (
|
|
|
15f218 |
+ Pcs.clusterController.get("show_all_resources") ? "" : "hidden "
|
|
|
15f218 |
+ ) + "default-hidden";
|
|
|
15f218 |
+ } else {
|
|
|
15f218 |
+ return "";
|
|
|
15f218 |
+ }
|
|
|
15f218 |
+ }.property("status_val", "status"),
|
|
|
15f218 |
status_class_fence: function() {
|
|
|
15f218 |
var show = ((Pcs.clusterController.get("show_all_fence"))? "" : "hidden ");
|
|
|
15f218 |
return ((this.get("status_val") == get_status_value("ok")) ? show + "default-hidden" : "");
|
|
|
15f218 |
@@ -1681,8 +1692,9 @@ Pcs.Cluster = Ember.Object.extend({
|
|
|
15f218 |
var num = 0;
|
|
|
15f218 |
$.each(this.get(type), function(key, value) {
|
|
|
15f218 |
if (value.get("status_val") < get_status_value("ok") &&
|
|
|
15f218 |
- value.status != "disabled" && value.status != "standby" &&
|
|
|
15f218 |
- value.status != "maintenance"
|
|
|
15f218 |
+ [
|
|
|
15f218 |
+ "unmanaged", "disabled", "standby", "maintenance"
|
|
|
15f218 |
+ ].indexOf(value.status) == -1
|
|
|
15f218 |
) {
|
|
|
15f218 |
num++;
|
|
|
15f218 |
}
|
|
|
15f218 |
diff --git a/pcsd/public/js/pcsd.js b/pcsd/public/js/pcsd.js
|
|
|
15f218 |
index 82187ef..56219d4 100644
|
|
|
15f218 |
--- a/pcsd/public/js/pcsd.js
|
|
|
15f218 |
+++ b/pcsd/public/js/pcsd.js
|
|
|
15f218 |
@@ -1333,6 +1333,9 @@ function remove_resource(ids, force) {
|
|
|
15f218 |
message += "\n\n" + xhr.responseText.replace(
|
|
|
15f218 |
"--force", "'Enforce removal'"
|
|
|
15f218 |
);
|
|
|
15f218 |
+ alert(message);
|
|
|
15f218 |
+ $("#verify_remove_submit_btn").button("option", "disabled", false);
|
|
|
15f218 |
+ return;
|
|
|
15f218 |
}
|
|
|
15f218 |
}
|
|
|
15f218 |
alert(message);
|
|
|
15f218 |
@@ -1957,6 +1960,7 @@ function get_status_value(status) {
|
|
|
15f218 |
maintenance: 2,
|
|
|
15f218 |
"partially running": 2,
|
|
|
15f218 |
disabled: 3,
|
|
|
15f218 |
+ unmanaged: 3,
|
|
|
15f218 |
unknown: 4,
|
|
|
15f218 |
ok: 5,
|
|
|
15f218 |
running: 5,
|
|
|
15f218 |
@@ -2987,3 +2991,51 @@ function sbd_status_dialog() {
|
|
|
15f218 |
buttons: buttonsOpts
|
|
|
15f218 |
});
|
|
|
15f218 |
}
|
|
|
15f218 |
+
|
|
|
15f218 |
+function unmanage_resource(resource_id) {
|
|
|
15f218 |
+ if (!resource_id) {
|
|
|
15f218 |
+ return;
|
|
|
15f218 |
+ }
|
|
|
15f218 |
+ fade_in_out("#resource_unmanage_link");
|
|
|
15f218 |
+ ajax_wrapper({
|
|
|
15f218 |
+ type: 'POST',
|
|
|
15f218 |
+ url: get_cluster_remote_url() + "unmanage_resource",
|
|
|
15f218 |
+ data: {
|
|
|
15f218 |
+ resource_list_json: JSON.stringify([resource_id]),
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ timeout: pcs_timeout,
|
|
|
15f218 |
+ complete: function() {
|
|
|
15f218 |
+ Pcs.update();
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ error: function (xhr, status, error) {
|
|
|
15f218 |
+ alert(
|
|
|
15f218 |
+ `Unable to unmanage '${resource_id}': ` +
|
|
|
15f218 |
+ ajax_simple_error(xhr, status, error)
|
|
|
15f218 |
+ );
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ });
|
|
|
15f218 |
+}
|
|
|
15f218 |
+
|
|
|
15f218 |
+function manage_resource(resource_id) {
|
|
|
15f218 |
+ if (!resource_id) {
|
|
|
15f218 |
+ return;
|
|
|
15f218 |
+ }
|
|
|
15f218 |
+ fade_in_out("#resource_manage_link");
|
|
|
15f218 |
+ ajax_wrapper({
|
|
|
15f218 |
+ type: 'POST',
|
|
|
15f218 |
+ url: get_cluster_remote_url() + "manage_resource",
|
|
|
15f218 |
+ data: {
|
|
|
15f218 |
+ resource_list_json: JSON.stringify([resource_id]),
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ timeout: pcs_timeout,
|
|
|
15f218 |
+ complete: function() {
|
|
|
15f218 |
+ Pcs.update();
|
|
|
15f218 |
+ },
|
|
|
15f218 |
+ error: function (xhr, status, error) {
|
|
|
15f218 |
+ alert(
|
|
|
15f218 |
+ `Unable to manage '${resource_id}': ` +
|
|
|
15f218 |
+ ajax_simple_error(xhr, status, error)
|
|
|
15f218 |
+ );
|
|
|
15f218 |
+ }
|
|
|
15f218 |
+ });
|
|
|
15f218 |
+}
|
|
|
15f218 |
diff --git a/pcsd/remote.rb b/pcsd/remote.rb
|
|
|
15f218 |
index 4844adf..ebf425c 100644
|
|
|
15f218 |
--- a/pcsd/remote.rb
|
|
|
15f218 |
+++ b/pcsd/remote.rb
|
|
|
15f218 |
@@ -116,7 +116,9 @@ def remote(params, request, auth_user)
|
|
|
15f218 |
:set_resource_utilization => method(:set_resource_utilization),
|
|
|
15f218 |
:set_node_utilization => method(:set_node_utilization),
|
|
|
15f218 |
:get_resource_agent_metadata => method(:get_resource_agent_metadata),
|
|
|
15f218 |
- :get_fence_agent_metadata => method(:get_fence_agent_metadata)
|
|
|
15f218 |
+ :get_fence_agent_metadata => method(:get_fence_agent_metadata),
|
|
|
15f218 |
+ :manage_resource => method(:manage_resource),
|
|
|
15f218 |
+ :unmanage_resource => method(:unmanage_resource),
|
|
|
15f218 |
}
|
|
|
15f218 |
|
|
|
15f218 |
command = params[:command].to_sym
|
|
|
15f218 |
@@ -1575,10 +1577,10 @@ def remove_resource(params, request, auth_user)
|
|
|
15f218 |
end
|
|
|
15f218 |
cmd = [PCS, '-f', tmp_file.path, 'resource', 'disable']
|
|
|
15f218 |
resource_list.each { |resource|
|
|
|
15f218 |
- _, err, retval = run_cmd(user, *(cmd + [resource]))
|
|
|
15f218 |
+ out, err, retval = run_cmd(user, *(cmd + [resource]))
|
|
|
15f218 |
if retval != 0
|
|
|
15f218 |
unless (
|
|
|
15f218 |
- err.join('').index('unable to find a resource') != -1 and
|
|
|
15f218 |
+ (out + err).join('').include?(' does not exist.') and
|
|
|
15f218 |
no_error_if_not_exists
|
|
|
15f218 |
)
|
|
|
15f218 |
errors += "Unable to stop resource '#{resource}': #{err.join('')}"
|
|
|
15f218 |
@@ -1613,7 +1615,10 @@ def remove_resource(params, request, auth_user)
|
|
|
15f218 |
end
|
|
|
15f218 |
out, err, retval = run_cmd(auth_user, *cmd)
|
|
|
15f218 |
if retval != 0
|
|
|
15f218 |
- unless out.index(' does not exist.') != -1 and no_error_if_not_exists
|
|
|
15f218 |
+ unless (
|
|
|
15f218 |
+ (out + err).join('').include?(' does not exist.') and
|
|
|
15f218 |
+ no_error_if_not_exists
|
|
|
15f218 |
+ )
|
|
|
15f218 |
errors += err.join(' ').strip + "\n"
|
|
|
15f218 |
end
|
|
|
15f218 |
end
|
|
|
15f218 |
@@ -2630,3 +2635,45 @@ def qdevice_client_start(param, request, auth_user)
|
|
|
15f218 |
return [400, msg]
|
|
|
15f218 |
end
|
|
|
15f218 |
end
|
|
|
15f218 |
+
|
|
|
15f218 |
+def manage_resource(param, request, auth_user)
|
|
|
15f218 |
+ unless allowed_for_local_cluster(auth_user, Permissions::WRITE)
|
|
|
15f218 |
+ return 403, 'Permission denied'
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ unless param[:resource_list_json]
|
|
|
15f218 |
+ return [400, "Required parameter 'resource_list_json' is missing."]
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ begin
|
|
|
15f218 |
+ resource_list = JSON.parse(param[:resource_list_json])
|
|
|
15f218 |
+ _, err, retval = run_cmd(
|
|
|
15f218 |
+ auth_user, PCS, 'resource', 'manage', *resource_list
|
|
|
15f218 |
+ )
|
|
|
15f218 |
+ if retval != 0
|
|
|
15f218 |
+ return [400, err.join('')]
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ return [200, '']
|
|
|
15f218 |
+ rescue JSON::ParserError
|
|
|
15f218 |
+ return [400, 'Invalid input data format']
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+end
|
|
|
15f218 |
+
|
|
|
15f218 |
+def unmanage_resource(param, request, auth_user)
|
|
|
15f218 |
+ unless allowed_for_local_cluster(auth_user, Permissions::WRITE)
|
|
|
15f218 |
+ return 403, 'Permission denied'
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ unless param[:resource_list_json]
|
|
|
15f218 |
+ return [400, "Required parameter 'resource_list_json' is missing."]
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ begin
|
|
|
15f218 |
+ resource_list = JSON.parse(param[:resource_list_json])
|
|
|
15f218 |
+ _, err, retval = run_cmd(
|
|
|
15f218 |
+ auth_user, PCS, 'resource', 'unmanage', *resource_list
|
|
|
15f218 |
+ )
|
|
|
15f218 |
+ if retval != 0
|
|
|
15f218 |
+ return [400, err.join('')]
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+ return [200, '']
|
|
|
15f218 |
+ rescue JSON::ParserError
|
|
|
15f218 |
+ return [400, 'Invalid input data format']
|
|
|
15f218 |
+ end
|
|
|
15f218 |
+end
|
|
|
15f218 |
diff --git a/pcsd/views/main.erb b/pcsd/views/main.erb
|
|
|
15f218 |
index 1b21f92..64fe560 100644
|
|
|
15f218 |
--- a/pcsd/views/main.erb
|
|
|
15f218 |
+++ b/pcsd/views/main.erb
|
|
|
15f218 |
@@ -160,6 +160,7 @@
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
+
|
|
|
15f218 |
{{#if resource.stonith}}
|
|
|
15f218 |
|
|
|
15f218 |
Remove
|
|
|
15f218 |
@@ -174,7 +175,32 @@
|
|
|
15f218 |
Cleanup
|
|
|
15f218 |
|
|
|
15f218 |
Remove
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+ {{#if Pcs.is_supported_unmanaged_resource}}
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+ id="resource_manage_link"
|
|
|
15f218 |
+ class="link"
|
|
|
15f218 |
+ onclick="manage_resource(curResource());"
|
|
|
15f218 |
+ >
|
|
|
15f218 |
+ Manage
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+ id="resource_unmanage_link"
|
|
|
15f218 |
+ class="link"
|
|
|
15f218 |
+ onclick="unmanage_resource(curResource());"
|
|
|
15f218 |
+ >
|
|
|
15f218 |
+ Unmanage
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+ {{/if}}
|
|
|
15f218 |
{{/if}}
|
|
|
15f218 |
+
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
Move
|
|
|
15f218 |
--
|
|
|
15f218 |
1.8.3.1
|
|
|
15f218 |
|