|
|
3604df |
From 7fa90a37f083181eac97c646714ca46b6a3fd679 Mon Sep 17 00:00:00 2001
|
|
|
3604df |
From: Aravinda VK <avishwan@redhat.com>
|
|
|
3604df |
Date: Thu, 17 Nov 2016 15:42:24 +0530
|
|
|
3604df |
Subject: [PATCH 217/227] eventsapi: JSON output and different error codes
|
|
|
3604df |
|
|
|
3604df |
JSON outputs are added to all commands, use `--json` to
|
|
|
3604df |
get JSON output.
|
|
|
3604df |
|
|
|
3604df |
Following error codes are added to differenciate between errors.
|
|
|
3604df |
Any other Unknown errors will have return code 1
|
|
|
3604df |
|
|
|
3604df |
ERROR_SAME_CONFIG = 2
|
|
|
3604df |
ERROR_ALL_NODES_STATUS_NOT_OK = 3
|
|
|
3604df |
ERROR_PARTIAL_SUCCESS = 4
|
|
|
3604df |
ERROR_WEBHOOK_ALREADY_EXISTS = 5
|
|
|
3604df |
ERROR_WEBHOOK_NOT_EXISTS = 6
|
|
|
3604df |
ERROR_INVALID_CONFIG = 7
|
|
|
3604df |
ERROR_WEBHOOK_SYNC_FAILED = 8
|
|
|
3604df |
ERROR_CONFIG_SYNC_FAILED = 9
|
|
|
3604df |
|
|
|
3604df |
Also hidden `node-` commands in the help message.
|
|
|
3604df |
|
|
|
3604df |
> Reviewed-on: http://review.gluster.org/15867
|
|
|
3604df |
> Smoke: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> Reviewed-by: Prashanth Pai <ppai@redhat.com>
|
|
|
3604df |
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
|
|
|
3604df |
BUG: 1395603
|
|
|
3604df |
Change-Id: I962b5435c8a448b4573059da0eae42f3f93cc97e
|
|
|
3604df |
Signed-off-by: Aravinda VK <avishwan@redhat.com>
|
|
|
3604df |
Reviewed-on: https://code.engineering.redhat.com/gerrit/91988
|
|
|
3604df |
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
|
|
|
3604df |
---
|
|
|
3604df |
events/src/eventsapiconf.py.in | 10 ++
|
|
|
3604df |
events/src/peer_eventsapi.py | 309 ++++++++++++++++++++++++++++++-----------
|
|
|
3604df |
extras/cliutils/__init__.py | 6 +-
|
|
|
3604df |
extras/cliutils/cliutils.py | 21 ++-
|
|
|
3604df |
4 files changed, 259 insertions(+), 87 deletions(-)
|
|
|
3604df |
|
|
|
3604df |
diff --git a/events/src/eventsapiconf.py.in b/events/src/eventsapiconf.py.in
|
|
|
3604df |
index ecccd3d..0159241 100644
|
|
|
3604df |
--- a/events/src/eventsapiconf.py.in
|
|
|
3604df |
+++ b/events/src/eventsapiconf.py.in
|
|
|
3604df |
@@ -24,3 +24,13 @@ RESTART_CONFIGS = ["port"]
|
|
|
3604df |
EVENTS_ENABLED = @EVENTS_ENABLED@
|
|
|
3604df |
UUID_FILE = "@GLUSTERD_WORKDIR@/glusterd.info"
|
|
|
3604df |
PID_FILE = "@localstatedir@/run/glustereventsd.pid"
|
|
|
3604df |
+
|
|
|
3604df |
+# Errors
|
|
|
3604df |
+ERROR_SAME_CONFIG = 2
|
|
|
3604df |
+ERROR_ALL_NODES_STATUS_NOT_OK = 3
|
|
|
3604df |
+ERROR_PARTIAL_SUCCESS = 4
|
|
|
3604df |
+ERROR_WEBHOOK_ALREADY_EXISTS = 5
|
|
|
3604df |
+ERROR_WEBHOOK_NOT_EXISTS = 6
|
|
|
3604df |
+ERROR_INVALID_CONFIG = 7
|
|
|
3604df |
+ERROR_WEBHOOK_SYNC_FAILED = 8
|
|
|
3604df |
+ERROR_CONFIG_SYNC_FAILED = 9
|
|
|
3604df |
diff --git a/events/src/peer_eventsapi.py b/events/src/peer_eventsapi.py
|
|
|
3604df |
index 7f80f79..6cba277 100644
|
|
|
3604df |
--- a/events/src/peer_eventsapi.py
|
|
|
3604df |
+++ b/events/src/peer_eventsapi.py
|
|
|
3604df |
@@ -17,13 +17,15 @@ from errno import EEXIST
|
|
|
3604df |
import fcntl
|
|
|
3604df |
from errno import EACCES, EAGAIN
|
|
|
3604df |
import signal
|
|
|
3604df |
+import sys
|
|
|
3604df |
|
|
|
3604df |
import requests
|
|
|
3604df |
from prettytable import PrettyTable
|
|
|
3604df |
|
|
|
3604df |
-from gluster.cliutils import (Cmd, execute, node_output_ok, node_output_notok,
|
|
|
3604df |
+from gluster.cliutils import (Cmd, node_output_ok, node_output_notok,
|
|
|
3604df |
sync_file_to_peers, GlusterCmdException,
|
|
|
3604df |
- output_error, execute_in_peers, runcli)
|
|
|
3604df |
+ output_error, execute_in_peers, runcli,
|
|
|
3604df |
+ set_common_args_func)
|
|
|
3604df |
from events.utils import LockedOpen
|
|
|
3604df |
|
|
|
3604df |
from events.eventsapiconf import (WEBHOOKS_FILE_TO_SYNC,
|
|
|
3604df |
@@ -36,7 +38,26 @@ from events.eventsapiconf import (WEBHOOKS_FILE_TO_SYNC,
|
|
|
3604df |
BOOL_CONFIGS,
|
|
|
3604df |
INT_CONFIGS,
|
|
|
3604df |
PID_FILE,
|
|
|
3604df |
- RESTART_CONFIGS)
|
|
|
3604df |
+ RESTART_CONFIGS,
|
|
|
3604df |
+ ERROR_INVALID_CONFIG,
|
|
|
3604df |
+ ERROR_WEBHOOK_NOT_EXISTS,
|
|
|
3604df |
+ ERROR_CONFIG_SYNC_FAILED,
|
|
|
3604df |
+ ERROR_WEBHOOK_ALREADY_EXISTS,
|
|
|
3604df |
+ ERROR_PARTIAL_SUCCESS,
|
|
|
3604df |
+ ERROR_ALL_NODES_STATUS_NOT_OK,
|
|
|
3604df |
+ ERROR_SAME_CONFIG,
|
|
|
3604df |
+ ERROR_WEBHOOK_SYNC_FAILED)
|
|
|
3604df |
+
|
|
|
3604df |
+
|
|
|
3604df |
+def handle_output_error(err, errcode=1, json_output=False):
|
|
|
3604df |
+ if json_output:
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": "",
|
|
|
3604df |
+ "error": err
|
|
|
3604df |
+ }))
|
|
|
3604df |
+ sys.exit(errcode)
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ output_error(err, errcode)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def file_content_overwrite(fname, data):
|
|
|
3604df |
@@ -46,15 +67,27 @@ def file_content_overwrite(fname, data):
|
|
|
3604df |
os.rename(fname + ".tmp", fname)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def create_custom_config_file_if_not_exists():
|
|
|
3604df |
- mkdirp(os.path.dirname(CUSTOM_CONFIG_FILE))
|
|
|
3604df |
+def create_custom_config_file_if_not_exists(args):
|
|
|
3604df |
+ try:
|
|
|
3604df |
+ config_dir = os.path.dirname(CUSTOM_CONFIG_FILE)
|
|
|
3604df |
+ mkdirp(config_dir)
|
|
|
3604df |
+ except OSError as e:
|
|
|
3604df |
+ handle_output_error("Failed to create dir %s: %s" % (config_dir, e),
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
+
|
|
|
3604df |
if not os.path.exists(CUSTOM_CONFIG_FILE):
|
|
|
3604df |
with open(CUSTOM_CONFIG_FILE, "w") as f:
|
|
|
3604df |
f.write("{}")
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def create_webhooks_file_if_not_exists():
|
|
|
3604df |
- mkdirp(os.path.dirname(WEBHOOKS_FILE))
|
|
|
3604df |
+def create_webhooks_file_if_not_exists(args):
|
|
|
3604df |
+ try:
|
|
|
3604df |
+ webhooks_dir = os.path.dirname(WEBHOOKS_FILE)
|
|
|
3604df |
+ mkdirp(webhooks_dir)
|
|
|
3604df |
+ except OSError as e:
|
|
|
3604df |
+ handle_output_error("Failed to create dir %s: %s" % (webhooks_dir, e),
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
+
|
|
|
3604df |
if not os.path.exists(WEBHOOKS_FILE):
|
|
|
3604df |
with open(WEBHOOKS_FILE, "w") as f:
|
|
|
3604df |
f.write("{}")
|
|
|
3604df |
@@ -75,11 +108,9 @@ def mkdirp(path, exit_on_err=False, logger=None):
|
|
|
3604df |
"""
|
|
|
3604df |
try:
|
|
|
3604df |
os.makedirs(path)
|
|
|
3604df |
- except (OSError, IOError) as e:
|
|
|
3604df |
- if e.errno == EEXIST and os.path.isdir(path):
|
|
|
3604df |
- pass
|
|
|
3604df |
- else:
|
|
|
3604df |
- output_error("Fail to create dir %s: %s" % (path, e))
|
|
|
3604df |
+ except OSError as e:
|
|
|
3604df |
+ if e.errno != EEXIST or not os.path.isdir(path):
|
|
|
3604df |
+ raise
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def is_active():
|
|
|
3604df |
@@ -111,33 +142,77 @@ def reload_service():
|
|
|
3604df |
return (0, "", "")
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def sync_to_peers():
|
|
|
3604df |
+def rows_to_json(json_out, column_name, rows):
|
|
|
3604df |
+ num_ok_rows = 0
|
|
|
3604df |
+ for row in rows:
|
|
|
3604df |
+ num_ok_rows += 1 if row.ok else 0
|
|
|
3604df |
+ json_out.append({
|
|
|
3604df |
+ "node": row.hostname,
|
|
|
3604df |
+ "node_status": "UP" if row.node_up else "DOWN",
|
|
|
3604df |
+ column_name: "OK" if row.ok else "NOT OK",
|
|
|
3604df |
+ "error": row.error
|
|
|
3604df |
+ })
|
|
|
3604df |
+ return num_ok_rows
|
|
|
3604df |
+
|
|
|
3604df |
+
|
|
|
3604df |
+def rows_to_table(table, rows):
|
|
|
3604df |
+ num_ok_rows = 0
|
|
|
3604df |
+ for row in rows:
|
|
|
3604df |
+ num_ok_rows += 1 if row.ok else 0
|
|
|
3604df |
+ table.add_row([row.hostname,
|
|
|
3604df |
+ "UP" if row.node_up else "DOWN",
|
|
|
3604df |
+ "OK" if row.ok else "NOT OK: {1}".format(
|
|
|
3604df |
+ row.error)])
|
|
|
3604df |
+ return num_ok_rows
|
|
|
3604df |
+
|
|
|
3604df |
+
|
|
|
3604df |
+def sync_to_peers(args):
|
|
|
3604df |
if os.path.exists(WEBHOOKS_FILE):
|
|
|
3604df |
try:
|
|
|
3604df |
sync_file_to_peers(WEBHOOKS_FILE_TO_SYNC)
|
|
|
3604df |
except GlusterCmdException as e:
|
|
|
3604df |
- output_error("Failed to sync Webhooks file: [Error: {0}]"
|
|
|
3604df |
- "{1}".format(e[0], e[2]))
|
|
|
3604df |
+ handle_output_error("Failed to sync Webhooks file: [Error: {0}]"
|
|
|
3604df |
+ "{1}".format(e[0], e[2]),
|
|
|
3604df |
+ errcode=ERROR_WEBHOOK_SYNC_FAILED,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
if os.path.exists(CUSTOM_CONFIG_FILE):
|
|
|
3604df |
try:
|
|
|
3604df |
sync_file_to_peers(CUSTOM_CONFIG_FILE_TO_SYNC)
|
|
|
3604df |
except GlusterCmdException as e:
|
|
|
3604df |
- output_error("Failed to sync Config file: [Error: {0}]"
|
|
|
3604df |
- "{1}".format(e[0], e[2]))
|
|
|
3604df |
+ handle_output_error("Failed to sync Config file: [Error: {0}]"
|
|
|
3604df |
+ "{1}".format(e[0], e[2]),
|
|
|
3604df |
+ errcode=ERROR_CONFIG_SYNC_FAILED,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
out = execute_in_peers("node-reload")
|
|
|
3604df |
- table = PrettyTable(["NODE", "NODE STATUS", "SYNC STATUS"])
|
|
|
3604df |
- table.align["NODE STATUS"] = "r"
|
|
|
3604df |
- table.align["SYNC STATUS"] = "r"
|
|
|
3604df |
+ if not args.json:
|
|
|
3604df |
+ table = PrettyTable(["NODE", "NODE STATUS", "SYNC STATUS"])
|
|
|
3604df |
+ table.align["NODE STATUS"] = "r"
|
|
|
3604df |
+ table.align["SYNC STATUS"] = "r"
|
|
|
3604df |
|
|
|
3604df |
- for p in out:
|
|
|
3604df |
- table.add_row([p.hostname,
|
|
|
3604df |
- "UP" if p.node_up else "DOWN",
|
|
|
3604df |
- "OK" if p.ok else "NOT OK: {0}".format(
|
|
|
3604df |
- p.error)])
|
|
|
3604df |
+ json_out = []
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ num_ok_rows = rows_to_json(json_out, "sync_status", out)
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ num_ok_rows = rows_to_table(table, out)
|
|
|
3604df |
+
|
|
|
3604df |
+ ret = 0
|
|
|
3604df |
+ if num_ok_rows == 0:
|
|
|
3604df |
+ ret = ERROR_ALL_NODES_STATUS_NOT_OK
|
|
|
3604df |
+ elif num_ok_rows != len(out):
|
|
|
3604df |
+ ret = ERROR_PARTIAL_SUCCESS
|
|
|
3604df |
+
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": json_out,
|
|
|
3604df |
+ "error": ""
|
|
|
3604df |
+ }))
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ print (table)
|
|
|
3604df |
|
|
|
3604df |
- print (table)
|
|
|
3604df |
+ # If sync status is not ok for any node set error code as partial success
|
|
|
3604df |
+ sys.exit(ret)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def node_output_handle(resp):
|
|
|
3604df |
@@ -148,29 +223,24 @@ def node_output_handle(resp):
|
|
|
3604df |
node_output_notok(err)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def action_handle(action):
|
|
|
3604df |
+def action_handle(action, json_output=False):
|
|
|
3604df |
out = execute_in_peers("node-" + action)
|
|
|
3604df |
column_name = action.upper()
|
|
|
3604df |
if action == "status":
|
|
|
3604df |
column_name = EVENTSD.upper()
|
|
|
3604df |
|
|
|
3604df |
- table = PrettyTable(["NODE", "NODE STATUS", column_name + " STATUS"])
|
|
|
3604df |
- table.align["NODE STATUS"] = "r"
|
|
|
3604df |
- table.align[column_name + " STATUS"] = "r"
|
|
|
3604df |
-
|
|
|
3604df |
- for p in out:
|
|
|
3604df |
- status_col_val = "OK" if p.ok else "NOT OK: {0}".format(
|
|
|
3604df |
- p.error)
|
|
|
3604df |
- if action == "status":
|
|
|
3604df |
- status_col_val = "DOWN"
|
|
|
3604df |
- if p.ok:
|
|
|
3604df |
- status_col_val = p.output
|
|
|
3604df |
+ if not json_output:
|
|
|
3604df |
+ table = PrettyTable(["NODE", "NODE STATUS", column_name + " STATUS"])
|
|
|
3604df |
+ table.align["NODE STATUS"] = "r"
|
|
|
3604df |
+ table.align[column_name + " STATUS"] = "r"
|
|
|
3604df |
|
|
|
3604df |
- table.add_row([p.hostname,
|
|
|
3604df |
- "UP" if p.node_up else "DOWN",
|
|
|
3604df |
- status_col_val])
|
|
|
3604df |
+ json_out = []
|
|
|
3604df |
+ if json_output:
|
|
|
3604df |
+ rows_to_json(json_out, column_name.lower() + "_status", out)
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ rows_to_table(table, out)
|
|
|
3604df |
|
|
|
3604df |
- print (table)
|
|
|
3604df |
+ return json_out if json_output else table
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class NodeReload(Cmd):
|
|
|
3604df |
@@ -184,7 +254,14 @@ class ReloadCmd(Cmd):
|
|
|
3604df |
name = "reload"
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- action_handle("reload")
|
|
|
3604df |
+ out = action_handle("reload", args.json)
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": out,
|
|
|
3604df |
+ "error": ""
|
|
|
3604df |
+ }))
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ print (out)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class NodeStatus(Cmd):
|
|
|
3604df |
@@ -202,12 +279,25 @@ class StatusCmd(Cmd):
|
|
|
3604df |
if os.path.exists(WEBHOOKS_FILE):
|
|
|
3604df |
webhooks = json.load(open(WEBHOOKS_FILE))
|
|
|
3604df |
|
|
|
3604df |
- print ("Webhooks: " + ("" if webhooks else "None"))
|
|
|
3604df |
- for w in webhooks:
|
|
|
3604df |
- print (w)
|
|
|
3604df |
-
|
|
|
3604df |
- print ()
|
|
|
3604df |
- action_handle("status")
|
|
|
3604df |
+ json_out = {"webhooks": [], "data": []}
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ json_out["webhooks"] = webhooks.keys()
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ print ("Webhooks: " + ("" if webhooks else "None"))
|
|
|
3604df |
+ for w in webhooks:
|
|
|
3604df |
+ print (w)
|
|
|
3604df |
+
|
|
|
3604df |
+ print ()
|
|
|
3604df |
+
|
|
|
3604df |
+ out = action_handle("status", args.json)
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ json_out["data"] = out
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": json_out,
|
|
|
3604df |
+ "error": ""
|
|
|
3604df |
+ }))
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ print (out)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class WebhookAddCmd(Cmd):
|
|
|
3604df |
@@ -219,17 +309,19 @@ class WebhookAddCmd(Cmd):
|
|
|
3604df |
default="")
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- create_webhooks_file_if_not_exists()
|
|
|
3604df |
+ create_webhooks_file_if_not_exists(args)
|
|
|
3604df |
|
|
|
3604df |
with LockedOpen(WEBHOOKS_FILE, 'r+'):
|
|
|
3604df |
data = json.load(open(WEBHOOKS_FILE))
|
|
|
3604df |
if data.get(args.url, None) is not None:
|
|
|
3604df |
- output_error("Webhook already exists")
|
|
|
3604df |
+ handle_output_error("Webhook already exists",
|
|
|
3604df |
+ errcode=ERROR_WEBHOOK_ALREADY_EXISTS,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
data[args.url] = args.bearer_token
|
|
|
3604df |
file_content_overwrite(WEBHOOKS_FILE, data)
|
|
|
3604df |
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class WebhookModCmd(Cmd):
|
|
|
3604df |
@@ -241,17 +333,19 @@ class WebhookModCmd(Cmd):
|
|
|
3604df |
default="")
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- create_webhooks_file_if_not_exists()
|
|
|
3604df |
+ create_webhooks_file_if_not_exists(args)
|
|
|
3604df |
|
|
|
3604df |
with LockedOpen(WEBHOOKS_FILE, 'r+'):
|
|
|
3604df |
data = json.load(open(WEBHOOKS_FILE))
|
|
|
3604df |
if data.get(args.url, None) is None:
|
|
|
3604df |
- output_error("Webhook does not exists")
|
|
|
3604df |
+ handle_output_error("Webhook does not exists",
|
|
|
3604df |
+ errcode=ERROR_WEBHOOK_NOT_EXISTS,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
data[args.url] = args.bearer_token
|
|
|
3604df |
file_content_overwrite(WEBHOOKS_FILE, data)
|
|
|
3604df |
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class WebhookDelCmd(Cmd):
|
|
|
3604df |
@@ -261,17 +355,19 @@ class WebhookDelCmd(Cmd):
|
|
|
3604df |
parser.add_argument("url", help="URL of Webhook")
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- create_webhooks_file_if_not_exists()
|
|
|
3604df |
+ create_webhooks_file_if_not_exists(args)
|
|
|
3604df |
|
|
|
3604df |
with LockedOpen(WEBHOOKS_FILE, 'r+'):
|
|
|
3604df |
data = json.load(open(WEBHOOKS_FILE))
|
|
|
3604df |
if data.get(args.url, None) is None:
|
|
|
3604df |
- output_error("Webhook does not exists")
|
|
|
3604df |
+ handle_output_error("Webhook does not exists",
|
|
|
3604df |
+ errcode=ERROR_WEBHOOK_NOT_EXISTS,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
del data[args.url]
|
|
|
3604df |
file_content_overwrite(WEBHOOKS_FILE, data)
|
|
|
3604df |
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class NodeWebhookTestCmd(Cmd):
|
|
|
3604df |
@@ -314,17 +410,33 @@ class WebhookTestCmd(Cmd):
|
|
|
3604df |
|
|
|
3604df |
out = execute_in_peers("node-webhook-test", [url, bearer_token])
|
|
|
3604df |
|
|
|
3604df |
- table = PrettyTable(["NODE", "NODE STATUS", "WEBHOOK STATUS"])
|
|
|
3604df |
- table.align["NODE STATUS"] = "r"
|
|
|
3604df |
- table.align["WEBHOOK STATUS"] = "r"
|
|
|
3604df |
+ if not args.json:
|
|
|
3604df |
+ table = PrettyTable(["NODE", "NODE STATUS", "WEBHOOK STATUS"])
|
|
|
3604df |
+ table.align["NODE STATUS"] = "r"
|
|
|
3604df |
+ table.align["WEBHOOK STATUS"] = "r"
|
|
|
3604df |
|
|
|
3604df |
- for p in out:
|
|
|
3604df |
- table.add_row([p.hostname,
|
|
|
3604df |
- "UP" if p.node_up else "DOWN",
|
|
|
3604df |
- "OK" if p.ok else "NOT OK: {0}".format(
|
|
|
3604df |
- p.error)])
|
|
|
3604df |
+ num_ok_rows = 0
|
|
|
3604df |
+ json_out = []
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ num_ok_rows = rows_to_json(json_out, "webhook_status", out)
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ num_ok_rows = rows_to_table(table, out)
|
|
|
3604df |
+
|
|
|
3604df |
+ ret = 0
|
|
|
3604df |
+ if num_ok_rows == 0:
|
|
|
3604df |
+ ret = ERROR_ALL_NODES_STATUS_NOT_OK
|
|
|
3604df |
+ elif num_ok_rows != len(out):
|
|
|
3604df |
+ ret = ERROR_PARTIAL_SUCCESS
|
|
|
3604df |
+
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": json_out,
|
|
|
3604df |
+ "error": ""
|
|
|
3604df |
+ }))
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ print (table)
|
|
|
3604df |
|
|
|
3604df |
- print (table)
|
|
|
3604df |
+ sys.exit(ret)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class ConfigGetCmd(Cmd):
|
|
|
3604df |
@@ -339,16 +451,30 @@ class ConfigGetCmd(Cmd):
|
|
|
3604df |
data.update(json.load(open(CUSTOM_CONFIG_FILE)))
|
|
|
3604df |
|
|
|
3604df |
if args.name is not None and args.name not in CONFIG_KEYS:
|
|
|
3604df |
- output_error("Invalid Config item")
|
|
|
3604df |
+ handle_output_error("Invalid Config item",
|
|
|
3604df |
+ errcode=ERROR_INVALID_CONFIG,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
+
|
|
|
3604df |
+ if args.json:
|
|
|
3604df |
+ json_out = {}
|
|
|
3604df |
+ if args.name is None:
|
|
|
3604df |
+ json_out = data
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ json_out[args.name] = data[args.name]
|
|
|
3604df |
|
|
|
3604df |
- table = PrettyTable(["NAME", "VALUE"])
|
|
|
3604df |
- if args.name is None:
|
|
|
3604df |
- for k, v in data.items():
|
|
|
3604df |
- table.add_row([k, v])
|
|
|
3604df |
+ print (json.dumps({
|
|
|
3604df |
+ "output": json_out,
|
|
|
3604df |
+ "error": ""
|
|
|
3604df |
+ }))
|
|
|
3604df |
else:
|
|
|
3604df |
- table.add_row([args.name, data[args.name]])
|
|
|
3604df |
+ table = PrettyTable(["NAME", "VALUE"])
|
|
|
3604df |
+ if args.name is None:
|
|
|
3604df |
+ for k, v in data.items():
|
|
|
3604df |
+ table.add_row([k, v])
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ table.add_row([args.name, data[args.name]])
|
|
|
3604df |
|
|
|
3604df |
- print (table)
|
|
|
3604df |
+ print (table)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def read_file_content_json(fname):
|
|
|
3604df |
@@ -370,9 +496,11 @@ class ConfigSetCmd(Cmd):
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
if args.name not in CONFIG_KEYS:
|
|
|
3604df |
- output_error("Invalid Config item")
|
|
|
3604df |
+ handle_output_error("Invalid Config item",
|
|
|
3604df |
+ errcode=ERROR_INVALID_CONFIG,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
- create_custom_config_file_if_not_exists()
|
|
|
3604df |
+ create_custom_config_file_if_not_exists(args)
|
|
|
3604df |
|
|
|
3604df |
with LockedOpen(CUSTOM_CONFIG_FILE, 'r+'):
|
|
|
3604df |
data = json.load(open(DEFAULT_CONFIG_FILE))
|
|
|
3604df |
@@ -382,7 +510,9 @@ class ConfigSetCmd(Cmd):
|
|
|
3604df |
|
|
|
3604df |
# Do Nothing if same as previous value
|
|
|
3604df |
if data[args.name] == args.value:
|
|
|
3604df |
- return
|
|
|
3604df |
+ handle_output_error("Config value not changed. Same config",
|
|
|
3604df |
+ errcode=ERROR_SAME_CONFIG,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
# TODO: Validate Value
|
|
|
3604df |
new_data = read_file_content_json(CUSTOM_CONFIG_FILE)
|
|
|
3604df |
@@ -402,10 +532,11 @@ class ConfigSetCmd(Cmd):
|
|
|
3604df |
if args.name in RESTART_CONFIGS:
|
|
|
3604df |
restart = True
|
|
|
3604df |
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
if restart:
|
|
|
3604df |
print ("\nRestart glustereventsd in all nodes")
|
|
|
3604df |
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
+
|
|
|
3604df |
|
|
|
3604df |
class ConfigResetCmd(Cmd):
|
|
|
3604df |
name = "config-reset"
|
|
|
3604df |
@@ -414,7 +545,7 @@ class ConfigResetCmd(Cmd):
|
|
|
3604df |
parser.add_argument("name", help="Config Name or all")
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- create_custom_config_file_if_not_exists()
|
|
|
3604df |
+ create_custom_config_file_if_not_exists(args)
|
|
|
3604df |
|
|
|
3604df |
with LockedOpen(CUSTOM_CONFIG_FILE, 'r+'):
|
|
|
3604df |
changed_keys = []
|
|
|
3604df |
@@ -422,8 +553,14 @@ class ConfigResetCmd(Cmd):
|
|
|
3604df |
if os.path.exists(CUSTOM_CONFIG_FILE):
|
|
|
3604df |
data = read_file_content_json(CUSTOM_CONFIG_FILE)
|
|
|
3604df |
|
|
|
3604df |
- if not data:
|
|
|
3604df |
- return
|
|
|
3604df |
+ # If No data available in custom config or, the specific config
|
|
|
3604df |
+ # item is not available in custom config
|
|
|
3604df |
+ if not data or \
|
|
|
3604df |
+ (args.name != "all" and data.get(args.name, None) is None):
|
|
|
3604df |
+ handle_output_error("Config value not reset. Already "
|
|
|
3604df |
+ "set to default value",
|
|
|
3604df |
+ errcode=ERROR_SAME_CONFIG,
|
|
|
3604df |
+ json_output=args.json)
|
|
|
3604df |
|
|
|
3604df |
if args.name.lower() == "all":
|
|
|
3604df |
for k, v in data.items():
|
|
|
3604df |
@@ -443,17 +580,23 @@ class ConfigResetCmd(Cmd):
|
|
|
3604df |
restart = True
|
|
|
3604df |
break
|
|
|
3604df |
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
if restart:
|
|
|
3604df |
print ("\nRestart glustereventsd in all nodes")
|
|
|
3604df |
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
+
|
|
|
3604df |
|
|
|
3604df |
class SyncCmd(Cmd):
|
|
|
3604df |
name = "sync"
|
|
|
3604df |
|
|
|
3604df |
def run(self, args):
|
|
|
3604df |
- sync_to_peers()
|
|
|
3604df |
+ sync_to_peers(args)
|
|
|
3604df |
+
|
|
|
3604df |
+
|
|
|
3604df |
+def common_args(parser):
|
|
|
3604df |
+ parser.add_argument("--json", help="JSON Output", action="store_true")
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
if __name__ == "__main__":
|
|
|
3604df |
+ set_common_args_func(common_args)
|
|
|
3604df |
runcli()
|
|
|
3604df |
diff --git a/extras/cliutils/__init__.py b/extras/cliutils/__init__.py
|
|
|
3604df |
index 4bb8395..9c93098 100644
|
|
|
3604df |
--- a/extras/cliutils/__init__.py
|
|
|
3604df |
+++ b/extras/cliutils/__init__.py
|
|
|
3604df |
@@ -11,7 +11,8 @@ from cliutils import (runcli,
|
|
|
3604df |
yesno,
|
|
|
3604df |
get_node_uuid,
|
|
|
3604df |
Cmd,
|
|
|
3604df |
- GlusterCmdException)
|
|
|
3604df |
+ GlusterCmdException,
|
|
|
3604df |
+ set_common_args_func)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
# This will be useful when `from cliutils import *`
|
|
|
3604df |
@@ -26,4 +27,5 @@ __all__ = ["runcli",
|
|
|
3604df |
"yesno",
|
|
|
3604df |
"get_node_uuid",
|
|
|
3604df |
"Cmd",
|
|
|
3604df |
- "GlusterCmdException"]
|
|
|
3604df |
+ "GlusterCmdException",
|
|
|
3604df |
+ "set_common_args_func"]
|
|
|
3604df |
diff --git a/extras/cliutils/cliutils.py b/extras/cliutils/cliutils.py
|
|
|
3604df |
index 4e035d7..d805ac6 100644
|
|
|
3604df |
--- a/extras/cliutils/cliutils.py
|
|
|
3604df |
+++ b/extras/cliutils/cliutils.py
|
|
|
3604df |
@@ -16,6 +16,7 @@ subparsers = parser.add_subparsers(dest="mode")
|
|
|
3604df |
subcommands = {}
|
|
|
3604df |
cache_data = {}
|
|
|
3604df |
ParseError = etree.ParseError if hasattr(etree, 'ParseError') else SyntaxError
|
|
|
3604df |
+_common_args_func = lambda p: True
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class GlusterCmdException(Exception):
|
|
|
3604df |
@@ -50,9 +51,9 @@ def oknotok(flag):
|
|
|
3604df |
return "OK" if flag else "NOT OK"
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def output_error(message):
|
|
|
3604df |
+def output_error(message, errcode=1):
|
|
|
3604df |
print (message, file=sys.stderr)
|
|
|
3604df |
- sys.exit(1)
|
|
|
3604df |
+ sys.exit(errcode)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def node_output_ok(message=""):
|
|
|
3604df |
@@ -186,6 +187,7 @@ def runcli():
|
|
|
3604df |
# a subcommand as specified in the Class name. Call the args
|
|
|
3604df |
# method by passing subcommand parser, Derived class can add
|
|
|
3604df |
# arguments to the subcommand parser.
|
|
|
3604df |
+ metavar_data = []
|
|
|
3604df |
for c in Cmd.__subclasses__():
|
|
|
3604df |
cls = c()
|
|
|
3604df |
if getattr(cls, "name", "") == "":
|
|
|
3604df |
@@ -193,14 +195,24 @@ def runcli():
|
|
|
3604df |
"to \"{0}\"".format(
|
|
|
3604df |
cls.__class__.__name__))
|
|
|
3604df |
|
|
|
3604df |
+ # Do not show in help message if subcommand starts with node-
|
|
|
3604df |
+ if not cls.name.startswith("node-"):
|
|
|
3604df |
+ metavar_data.append(cls.name)
|
|
|
3604df |
+
|
|
|
3604df |
p = subparsers.add_parser(cls.name)
|
|
|
3604df |
args_func = getattr(cls, "args", None)
|
|
|
3604df |
if args_func is not None:
|
|
|
3604df |
args_func(p)
|
|
|
3604df |
|
|
|
3604df |
+ # Apply common args if any
|
|
|
3604df |
+ _common_args_func(p)
|
|
|
3604df |
+
|
|
|
3604df |
# A dict to save subcommands, key is name of the subcommand
|
|
|
3604df |
subcommands[cls.name] = cls
|
|
|
3604df |
|
|
|
3604df |
+ # Hide node commands in Help message
|
|
|
3604df |
+ subparsers.metavar = "{" + ",".join(metavar_data) + "}"
|
|
|
3604df |
+
|
|
|
3604df |
# Get all parsed arguments
|
|
|
3604df |
args = parser.parse_args()
|
|
|
3604df |
|
|
|
3604df |
@@ -210,3 +222,8 @@ def runcli():
|
|
|
3604df |
# Run
|
|
|
3604df |
if cls is not None:
|
|
|
3604df |
cls.run(args)
|
|
|
3604df |
+
|
|
|
3604df |
+
|
|
|
3604df |
+def set_common_args_func(func):
|
|
|
3604df |
+ global _common_args_func
|
|
|
3604df |
+ _common_args_func = func
|
|
|
3604df |
--
|
|
|
3604df |
2.9.3
|
|
|
3604df |
|