Dispatch parameterized daemon actions
This commit is contained in:
+25
-4
@@ -81,7 +81,13 @@ class Plugin:
|
|||||||
+ ", ".join(missing)
|
+ ", ".join(missing)
|
||||||
)
|
)
|
||||||
|
|
||||||
def execute(self, action, config, runtime_state):
|
def execute(
|
||||||
|
self,
|
||||||
|
action,
|
||||||
|
config,
|
||||||
|
runtime_state,
|
||||||
|
request_parameters=None,
|
||||||
|
):
|
||||||
if action not in self.actions:
|
if action not in self.actions:
|
||||||
raise RegistryError(
|
raise RegistryError(
|
||||||
f"plugin {self.name} does not support action {action}"
|
f"plugin {self.name} does not support action {action}"
|
||||||
@@ -98,9 +104,18 @@ class Plugin:
|
|||||||
# Backward-compatible generic state injection. Existing one-argument
|
# Backward-compatible generic state injection. Existing one-argument
|
||||||
# plugins continue to receive only config; state-aware plugins can
|
# plugins continue to receive only config; state-aware plugins can
|
||||||
# declare a second positional parameter named runtime_state.
|
# declare a second positional parameter named runtime_state.
|
||||||
parameters = list(inspect.signature(handler).parameters.values())
|
handler_parameters = list(
|
||||||
|
inspect.signature(handler).parameters.values()
|
||||||
|
)
|
||||||
|
|
||||||
if len(parameters) >= 2:
|
if len(handler_parameters) >= 3:
|
||||||
|
return handler(
|
||||||
|
config,
|
||||||
|
runtime_state,
|
||||||
|
request_parameters or {},
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(handler_parameters) >= 2:
|
||||||
return handler(config, runtime_state)
|
return handler(config, runtime_state)
|
||||||
|
|
||||||
return handler(config)
|
return handler(config)
|
||||||
@@ -178,7 +193,12 @@ class Registry:
|
|||||||
in self.resources.items()
|
in self.resources.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self, resource_id, action):
|
def execute(
|
||||||
|
self,
|
||||||
|
resource_id,
|
||||||
|
action,
|
||||||
|
request_parameters=None,
|
||||||
|
):
|
||||||
resource = self.resources.get(resource_id)
|
resource = self.resources.get(resource_id)
|
||||||
|
|
||||||
if resource is None:
|
if resource is None:
|
||||||
@@ -190,6 +210,7 @@ class Registry:
|
|||||||
action,
|
action,
|
||||||
resource.config,
|
resource.config,
|
||||||
resource.runtime_state,
|
resource.runtime_state,
|
||||||
|
request_parameters,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -209,6 +209,20 @@ def handle_request(
|
|||||||
"resources": registry.list_resources(),
|
"resources": registry.list_resources(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
request_parameters = req.get(
|
||||||
|
"parameters",
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
|
||||||
|
if not isinstance(request_parameters, dict):
|
||||||
|
return protocol_response({
|
||||||
|
"ok": False,
|
||||||
|
"error_code": "invalid_request",
|
||||||
|
"error": "parameters must be a JSON object",
|
||||||
|
"resource": req.get("resource"),
|
||||||
|
"action": action,
|
||||||
|
})
|
||||||
|
|
||||||
resource = req.get("resource")
|
resource = req.get("resource")
|
||||||
|
|
||||||
if not resource:
|
if not resource:
|
||||||
@@ -259,6 +273,15 @@ def handle_request(
|
|||||||
"action": action,
|
"action": action,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if request_parameters:
|
||||||
|
return protocol_response(
|
||||||
|
registry.execute(
|
||||||
|
resource,
|
||||||
|
action,
|
||||||
|
request_parameters,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return protocol_response(
|
return protocol_response(
|
||||||
registry.execute(
|
registry.execute(
|
||||||
resource,
|
resource,
|
||||||
|
|||||||
Executable
+110
@@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, "daemon")
|
||||||
|
|
||||||
|
import server
|
||||||
|
|
||||||
|
|
||||||
|
class FakeRegistry:
|
||||||
|
def __init__(self):
|
||||||
|
self.resources = {"postgresql-ha": object()}
|
||||||
|
self.executions = []
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
self,
|
||||||
|
resource,
|
||||||
|
action,
|
||||||
|
request_parameters=None,
|
||||||
|
):
|
||||||
|
self.executions.append(
|
||||||
|
(resource, action, request_parameters)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"resource": resource,
|
||||||
|
"plugin": "fake",
|
||||||
|
"action": action,
|
||||||
|
"result": {
|
||||||
|
"parameters": request_parameters or {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def require(condition, message):
|
||||||
|
if not condition:
|
||||||
|
raise SystemExit("FAIL: " + message)
|
||||||
|
|
||||||
|
|
||||||
|
print("===== PARAMETERIZED ACTIONS =====")
|
||||||
|
|
||||||
|
registry = FakeRegistry()
|
||||||
|
server.registry = registry
|
||||||
|
server.pacemaker_resource_id = "postgresql-ha"
|
||||||
|
server.pacemaker_peer_uid = 65534
|
||||||
|
server.pacemaker_peer_gid = 65534
|
||||||
|
server.pacemaker_node_name = "david-prodesk"
|
||||||
|
|
||||||
|
peer = {
|
||||||
|
"pid": 1,
|
||||||
|
"uid": 65534,
|
||||||
|
"gid": 65534,
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters = {
|
||||||
|
"type": "pre",
|
||||||
|
"operation": "demote",
|
||||||
|
"promote_uname": "david-eve",
|
||||||
|
"demote_uname": "david-prodesk",
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle_request(
|
||||||
|
{
|
||||||
|
"protocol_version": 1,
|
||||||
|
"resource": "postgresql-ha",
|
||||||
|
"action": "notify",
|
||||||
|
"parameters": parameters,
|
||||||
|
},
|
||||||
|
peer,
|
||||||
|
)
|
||||||
|
|
||||||
|
require(response["ok"] is True, "parameterized action was rejected")
|
||||||
|
require(
|
||||||
|
response["result"]["parameters"] == parameters,
|
||||||
|
"action parameters were not preserved",
|
||||||
|
)
|
||||||
|
require(
|
||||||
|
registry.executions
|
||||||
|
== [("postgresql-ha", "notify", parameters)],
|
||||||
|
"parameterized action was not dispatched exactly once",
|
||||||
|
)
|
||||||
|
print("parameterized_action dispatched")
|
||||||
|
|
||||||
|
response = server.handle_request(
|
||||||
|
{
|
||||||
|
"protocol_version": 1,
|
||||||
|
"resource": "postgresql-ha",
|
||||||
|
"action": "notify",
|
||||||
|
"parameters": [],
|
||||||
|
},
|
||||||
|
peer,
|
||||||
|
)
|
||||||
|
|
||||||
|
require(
|
||||||
|
response["ok"] is False,
|
||||||
|
"non-object parameters were accepted",
|
||||||
|
)
|
||||||
|
require(
|
||||||
|
response["error_code"] == "invalid_request",
|
||||||
|
"invalid parameters had the wrong classification",
|
||||||
|
)
|
||||||
|
require(
|
||||||
|
len(registry.executions) == 1,
|
||||||
|
"invalid parameters reached the registry",
|
||||||
|
)
|
||||||
|
print("invalid_parameters rejected")
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("PARAMETERIZED_ACTION_TEST_PASS=1")
|
||||||
Reference in New Issue
Block a user