23
23
import typing
24
24
25
25
from sambacc import ctdb
26
+ from sambacc import jfile
27
+ from sambacc .simple_waiter import Waiter
26
28
27
29
from .cli import best_waiter , commands , Context , Fail
28
30
@@ -86,6 +88,13 @@ def _ctdb_general_node_args(parser: argparse.ArgumentParser) -> None:
86
88
"--persistent-path" ,
87
89
help = "Path to a persistent path for storing nodes file" ,
88
90
)
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
+ )
89
98
90
99
91
100
def _ctdb_set_node_args (parser : argparse .ArgumentParser ) -> None :
@@ -101,8 +110,11 @@ class NodeParams:
101
110
node_number : typing .Optional [int ] = None
102
111
hostname : typing .Optional [str ] = None
103
112
persistent_path : str = ""
104
- nodes_json : str = ""
113
+ _nodes_json : str = ""
114
+ _cluster_meta_uri : str = ""
105
115
_ip_addr : typing .Optional [str ] = None
116
+ _cluster_meta_obj : typing .Optional [ctdb .ClusterMeta ] = None
117
+ _waiter_obj : typing .Optional [Waiter ] = None
106
118
107
119
def __init__ (self , ctx : Context ):
108
120
self ._ctx = ctx
@@ -112,7 +124,12 @@ def __init__(self, ctx: Context):
112
124
self .persistent_path = ctx .cli .persistent_path
113
125
if self .persistent_path is None :
114
126
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 ""
116
133
117
134
self .hostname = ctx .cli .hostname
118
135
if ctx .cli .node_number is not None :
@@ -145,7 +162,7 @@ def node_ip_addr(self) -> str:
145
162
return self ._ip_addr
146
163
147
164
@property
148
- def identity (self ):
165
+ def identity (self ) -> str :
149
166
# this could be extended to use something like /etc/machine-id
150
167
# or whatever in the future.
151
168
if self .hostname :
@@ -156,6 +173,49 @@ def identity(self):
156
173
# the dashes make this an invalid dns name
157
174
return "-unknown-"
158
175
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
+
159
219
160
220
@commands .command (name = "ctdb-migrate" , arg_func = _ctdb_migrate_args )
161
221
def ctdb_migrate (ctx : Context ) -> None :
@@ -180,21 +240,21 @@ def ctdb_set_node(ctx: Context) -> None:
180
240
expected_pnn = np .node_number
181
241
182
242
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 ) ,
188
248
)
189
249
return
190
250
except ctdb .NodeNotPresent :
191
251
pass
192
252
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 ) ,
198
258
in_nodes = (expected_pnn == 0 ),
199
259
)
200
260
if expected_pnn == 0 :
@@ -214,14 +274,14 @@ def ctdb_manage_nodes(ctx: Context) -> None:
214
274
_ctdb_ok ()
215
275
np = NodeParams (ctx )
216
276
expected_pnn = np .node_number or 0
217
- waiter = best_waiter ( np .nodes_json )
277
+ waiter = np .cluster_meta_waiter ( )
218
278
219
279
errors = 0
220
280
while True :
221
281
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 ,
225
285
real_path = np .persistent_path ,
226
286
pause_func = waiter .wait ,
227
287
)
@@ -246,13 +306,12 @@ def ctdb_must_have_node(ctx: Context) -> None:
246
306
_ctdb_ok ()
247
307
np = NodeParams (ctx )
248
308
expected_pnn = np .node_number or 0
249
- waiter = best_waiter ( np .nodes_json )
309
+ waiter = np .cluster_meta_waiter ( )
250
310
251
311
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 ,
256
315
):
257
316
return
258
317
_logger .info ("node not yet ready" )
0 commit comments