Compare commits

..

4 Commits

Author SHA1 Message Date
Joshua Boniface 9f47da6777 Fix triplicate API calls on GET commands 2024-08-19 17:33:21 -04:00
Joshua Boniface 0cf229273a Add API endpoint for current primary node
This was never exposed before, so expose it for use in other functions
being built.
2024-08-19 17:15:52 -04:00
Joshua Boniface 212ecaab68 Fix Swagger doc issues 2024-08-19 16:56:18 -04:00
Joshua Boniface f1b4593367 Store current stats with snapshots
Allows getting info like size, etc. for the snapshot.
2024-08-19 14:07:27 -04:00
3 changed files with 99 additions and 43 deletions

View File

@ -597,7 +597,7 @@ class API_Status(Resource):
Set the cluster maintenance mode Set the cluster maintenance mode
--- ---
tags: tags:
- node - root
parameters: parameters:
- in: query - in: query
name: state name: state
@ -622,6 +622,45 @@ class API_Status(Resource):
api.add_resource(API_Status, "/status") api.add_resource(API_Status, "/status")
# /status/primary_node
class API_Status_Primary(Resource):
def get(self):
"""
Return the name of the current primary node.
---
tags:
- root
responses:
200:
description: OK
schema:
type: object
properties:
primary_node:
type: string
description: The name of the current primary node
204:
description: No content
schema:
type: object
properties:
primary_node:
type: string
description: An empty response; there is not currently a primary node, try again later
"""
primary_node = get_primary_node()
if primary_node is None:
retdata = None
retcode = 204
else:
retdata = {"primary_node": primary_node}
retcode = 200
return retdata, retcode
api.add_resource(API_Status_Primary, "/status/primary_node")
# /metrics # /metrics
class API_Metrics(Resource): class API_Metrics(Resource):
def get(self): def get(self):
@ -838,25 +877,8 @@ class API_Faults(Resource):
--- ---
tags: tags:
- faults - faults
parameters: definitions:
- in: query - schema:
name: sort_key
type: string
required: false
description: The fault object key to sort results by
enum:
- first_reported
- last_reported
- acknowledged_at
- status
- health_delta
- message
responses:
200:
description: OK
schema:
type: array
items:
type: object type: object
id: fault id: fault
properties: properties:
@ -888,6 +910,26 @@ class API_Faults(Resource):
type: string type: string
description: The textual description of the fault description: The textual description of the fault
example: "Node hv1 was at 40% (psur@-10%, psql@-50%) <= 50% health" example: "Node hv1 was at 40% (psur@-10%, psql@-50%) <= 50% health"
parameters:
- in: query
name: sort_key
type: string
required: false
description: The fault object key to sort results by
enum:
- first_reported
- last_reported
- acknowledged_at
- status
- health_delta
- message
responses:
200:
description: OK
schema:
type: array
items:
$ref: '#/definitions/fault'
""" """
return api_helper.fault_list(sort_key=reqargs.get("sort_key", "last_reported")) return api_helper.fault_list(sort_key=reqargs.get("sort_key", "last_reported"))
@ -948,8 +990,6 @@ class API_Faults_Element(Resource):
schema: schema:
type: array type: array
items: items:
type: object
id: fault
$ref: '#/definitions/fault' $ref: '#/definitions/fault'
""" """
return api_helper.fault_list(limit=fault_id) return api_helper.fault_list(limit=fault_id)
@ -1625,7 +1665,7 @@ class API_VM_Root(Resource):
descrpition: Unix timestamp of the snapshot descrpition: Unix timestamp of the snapshot
age: age:
type: string type: string
description: Human-readable age of the snapshot in the largest viable unit: seconds, minutes, hours, days description: Human-readable age of the snapshot in the largest viable unit (seconds, minutes, hours, days)
rbd_snapshots: rbd_snapshots:
type: array type: array
items: items:

View File

@ -158,9 +158,10 @@ def call_api(
if response.status_code in retry_on_code: if response.status_code in retry_on_code:
failed = True failed = True
continue continue
break
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
failed = True failed = True
pass continue
if failed: if failed:
error = f"Code {response.status_code}" if response else "Timeout" error = f"Code {response.status_code}" if response else "Timeout"
raise requests.exceptions.ConnectionError( raise requests.exceptions.ConnectionError(

View File

@ -1015,23 +1015,27 @@ def add_snapshot(zkhandler, pool, volume, name, zk_only=False):
), ),
) )
# 2. Add the snapshot to Zookeeper # 2. Get snapshot stats
retcode, stdout, stderr = common.run_os_command(
"rbd info --format json {}/{}@{}".format(pool, volume, name)
)
snapstats = stdout
# 3. Add the snapshot to Zookeeper
zkhandler.write( zkhandler.write(
[ [
(("snapshot", f"{pool}/{volume}/{name}"), ""), (("snapshot", f"{pool}/{volume}/{name}"), ""),
(("snapshot.stats", f"{pool}/{volume}/{name}"), "{}"), (("snapshot.stats", f"{pool}/{volume}/{name}"), snapstats),
] ]
) )
# 3. Update the count of snapshots on this volume # 4. Update the count of snapshots on this volume
volume_stats_raw = zkhandler.read(("volume.stats", f"{pool}/{volume}")) volume_stats_raw = zkhandler.read(("volume.stats", f"{pool}/{volume}"))
volume_stats = dict(json.loads(volume_stats_raw)) volume_stats = dict(json.loads(volume_stats_raw))
# Format the size to something nicer
volume_stats["snapshot_count"] = volume_stats["snapshot_count"] + 1 volume_stats["snapshot_count"] = volume_stats["snapshot_count"] + 1
volume_stats_raw = json.dumps(volume_stats)
zkhandler.write( zkhandler.write(
[ [
(("volume.stats", f"{pool}/{volume}"), volume_stats_raw), (("volume.stats", f"{pool}/{volume}"), json.dumps(volume_stats)),
] ]
) )
@ -1174,6 +1178,11 @@ def get_list_snapshot(zkhandler, target_pool, target_volume, limit=None, is_fuzz
continue continue
if target_volume and volume_name != target_volume: if target_volume and volume_name != target_volume:
continue continue
snapshot_stats = json.loads(
zkhandler.read(
("snapshot.stats", f"{pool_name}/{volume_name}/{snapshot_name}")
)
)
if limit: if limit:
try: try:
if re.fullmatch(limit, snapshot_name): if re.fullmatch(limit, snapshot_name):
@ -1182,13 +1191,19 @@ def get_list_snapshot(zkhandler, target_pool, target_volume, limit=None, is_fuzz
"pool": pool_name, "pool": pool_name,
"volume": volume_name, "volume": volume_name,
"snapshot": snapshot_name, "snapshot": snapshot_name,
"stats": snapshot_stats,
} }
) )
except Exception as e: except Exception as e:
return False, "Regex Error: {}".format(e) return False, "Regex Error: {}".format(e)
else: else:
snapshot_list.append( snapshot_list.append(
{"pool": pool_name, "volume": volume_name, "snapshot": snapshot_name} {
"pool": pool_name,
"volume": volume_name,
"snapshot": snapshot_name,
"stats": snapshot_stats,
}
) )
return True, sorted(snapshot_list, key=lambda x: str(x["snapshot"])) return True, sorted(snapshot_list, key=lambda x: str(x["snapshot"]))