Skip to content

Commit 6191e91

Browse files
phlogistonjohnmergify[bot]
authored andcommitted
commands: prepare ctdb commands for using cluster meta objects
This change prepares the ctdb related commands in sambacc for using different paths or, eventually, different uris for the cluster metadata state data. Currently, this must still be a file but the file can be specified by path `/foo/bar/baz` or uri style `file:///foo/bar/baz`. The CLI now constructs a ClusterMeta object and passes it to the library functions rather than passing a path. Signed-off-by: John Mulligan <[email protected]>
1 parent 600e3bf commit 6191e91

File tree

1 file changed

+81
-22
lines changed

1 file changed

+81
-22
lines changed

sambacc/commands/ctdb.py

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import typing
2424

2525
from sambacc import ctdb
26+
from sambacc import jfile
27+
from sambacc.simple_waiter import Waiter
2628

2729
from .cli import best_waiter, commands, Context, Fail
2830

@@ -86,6 +88,13 @@ def _ctdb_general_node_args(parser: argparse.ArgumentParser) -> None:
8688
"--persistent-path",
8789
help="Path to a persistent path for storing nodes file",
8890
)
91+
parser.add_argument(
92+
"--metadata-source",
93+
help=(
94+
"Specify location of cluster metadata state-tracking object."
95+
" This can be a file path or a URI-style identifier."
96+
),
97+
)
8998

9099

91100
def _ctdb_set_node_args(parser: argparse.ArgumentParser) -> None:
@@ -101,8 +110,11 @@ class NodeParams:
101110
node_number: typing.Optional[int] = None
102111
hostname: typing.Optional[str] = None
103112
persistent_path: str = ""
104-
nodes_json: str = ""
113+
_nodes_json: str = ""
114+
_cluster_meta_uri: str = ""
105115
_ip_addr: typing.Optional[str] = None
116+
_cluster_meta_obj: typing.Optional[ctdb.ClusterMeta] = None
117+
_waiter_obj: typing.Optional[Waiter] = None
106118

107119
def __init__(self, ctx: Context):
108120
self._ctx = ctx
@@ -112,7 +124,12 @@ def __init__(self, ctx: Context):
112124
self.persistent_path = ctx.cli.persistent_path
113125
if self.persistent_path is None:
114126
self.persistent_path = ccfg["nodes_path"]
115-
self.nodes_json = ccfg["nodes_json"]
127+
# nodes_json will now only be in the ctdb config section if it has been
128+
# specified by the user.
129+
self._nodes_json = ccfg.get("nodes_json") or ""
130+
# cluster_meta_uri can be a uri-ish string or path. It will be set with
131+
# a default value by the config even if there's no user supplied value.
132+
self._cluster_meta_uri = ccfg.get("cluster_meta_uri") or ""
116133

117134
self.hostname = ctx.cli.hostname
118135
if ctx.cli.node_number is not None:
@@ -145,7 +162,7 @@ def node_ip_addr(self) -> str:
145162
return self._ip_addr
146163

147164
@property
148-
def identity(self):
165+
def identity(self) -> str:
149166
# this could be extended to use something like /etc/machine-id
150167
# or whatever in the future.
151168
if self.hostname:
@@ -156,6 +173,49 @@ def identity(self):
156173
# the dashes make this an invalid dns name
157174
return "-unknown-"
158175

176+
@property
177+
def cluster_meta_uri(self) -> str:
178+
"""Return a cluster meta uri value."""
179+
values = (
180+
# cli takes highest precedence
181+
self._ctx.cli.metadata_source,
182+
# _nodes_json should only be set if user set it using the old key
183+
self._nodes_json,
184+
# default or customized value on current key
185+
self._cluster_meta_uri,
186+
)
187+
for uri in values:
188+
if uri:
189+
return uri
190+
raise ValueError("failed to determine cluster_meta_uri")
191+
192+
def _cluster_meta_init(self) -> None:
193+
uri = self.cluster_meta_uri
194+
# it'd be nice to re-use the opener infrastructure here but openers
195+
# don't do file modes the way we need for JSON state file or do
196+
# writable file types in the url_opener (urllib wrapper). For now, just
197+
# manually handle the string.
198+
if uri.startswith("file:"):
199+
path = uri.split(":", 1)[-1]
200+
else:
201+
path = uri
202+
if path.startswith("/"):
203+
path = "/" + path.rstrip("/") # ensure one leading /
204+
self._cluster_meta_obj = jfile.ClusterMetaJSONFile(path)
205+
self._waiter_obj = best_waiter(path)
206+
207+
def cluster_meta(self) -> ctdb.ClusterMeta:
208+
if self._cluster_meta_obj is None:
209+
self._cluster_meta_init()
210+
assert self._cluster_meta_obj is not None
211+
return self._cluster_meta_obj
212+
213+
def cluster_meta_waiter(self) -> Waiter:
214+
if self._waiter_obj is None:
215+
self._cluster_meta_init()
216+
assert self._waiter_obj is not None
217+
return self._waiter_obj
218+
159219

160220
@commands.command(name="ctdb-migrate", arg_func=_ctdb_migrate_args)
161221
def ctdb_migrate(ctx: Context) -> None:
@@ -180,21 +240,21 @@ def ctdb_set_node(ctx: Context) -> None:
180240
expected_pnn = np.node_number
181241

182242
try:
183-
ctdb.refresh_node_in_statefile(
184-
np.identity,
185-
np.node_ip_addr,
186-
int(expected_pnn or 0),
187-
path=np.nodes_json,
243+
ctdb.refresh_node_in_cluster_meta(
244+
cmeta=np.cluster_meta(),
245+
identity=np.identity,
246+
node=np.node_ip_addr,
247+
pnn=int(expected_pnn or 0),
188248
)
189249
return
190250
except ctdb.NodeNotPresent:
191251
pass
192252

193-
ctdb.add_node_to_statefile(
194-
np.identity,
195-
np.node_ip_addr,
196-
int(expected_pnn or 0),
197-
path=np.nodes_json,
253+
ctdb.add_node_to_cluster_meta(
254+
cmeta=np.cluster_meta(),
255+
identity=np.identity,
256+
node=np.node_ip_addr,
257+
pnn=int(expected_pnn or 0),
198258
in_nodes=(expected_pnn == 0),
199259
)
200260
if expected_pnn == 0:
@@ -214,14 +274,14 @@ def ctdb_manage_nodes(ctx: Context) -> None:
214274
_ctdb_ok()
215275
np = NodeParams(ctx)
216276
expected_pnn = np.node_number or 0
217-
waiter = best_waiter(np.nodes_json)
277+
waiter = np.cluster_meta_waiter()
218278

219279
errors = 0
220280
while True:
221281
try:
222-
ctdb.manage_nodes(
223-
expected_pnn,
224-
nodes_json=np.nodes_json,
282+
ctdb.monitor_cluster_meta_updates(
283+
cmeta=np.cluster_meta(),
284+
pnn=expected_pnn,
225285
real_path=np.persistent_path,
226286
pause_func=waiter.wait,
227287
)
@@ -246,13 +306,12 @@ def ctdb_must_have_node(ctx: Context) -> None:
246306
_ctdb_ok()
247307
np = NodeParams(ctx)
248308
expected_pnn = np.node_number or 0
249-
waiter = best_waiter(np.nodes_json)
309+
waiter = np.cluster_meta_waiter()
250310

251311
while True:
252-
if ctdb.pnn_in_nodes(
253-
expected_pnn,
254-
nodes_json=np.nodes_json,
255-
real_path=np.persistent_path,
312+
if ctdb.pnn_in_cluster_meta(
313+
cmeta=np.cluster_meta(),
314+
pnn=expected_pnn,
256315
):
257316
return
258317
_logger.info("node not yet ready")

0 commit comments

Comments
 (0)