|
39 | 39 | GetACL, |
40 | 40 | SetACL, |
41 | 41 | GetData, |
| 42 | + Reconfig, |
42 | 43 | SetData, |
43 | 44 | Sync, |
44 | 45 | Transaction |
@@ -1326,6 +1327,98 @@ def _delete_recursive(self, path): |
1326 | 1327 | except NoNodeError: # pragma: nocover |
1327 | 1328 | pass |
1328 | 1329 |
|
| 1330 | + def reconfig(self, joining, leaving, new_members, from_config=-1): |
| 1331 | + """Reconfig a cluster. |
| 1332 | +
|
| 1333 | + This call will succeed if the cluster was reconfigured accordingly. |
| 1334 | +
|
| 1335 | + :param joining: a comma separated list of servers being added |
| 1336 | + (see example for format) (incremental reconfiguration) |
| 1337 | + :param leaving: a comma separated list of servers being removed |
| 1338 | + (see example for format) (incremental reconfiguration) |
| 1339 | + :param new_members: a comma separated list of new membership |
| 1340 | + (non-incremental reconfiguration) |
| 1341 | + :param from_config: version of the current configuration (optional - |
| 1342 | + causes reconfiguration to throw an exception if |
| 1343 | + configuration is no longer current) |
| 1344 | + :type from_config: int |
| 1345 | + :returns: |
| 1346 | + Tuple (value, :class:`~kazoo.protocol.states.ZnodeStat`) of |
| 1347 | + node. |
| 1348 | + :rtype: tuple |
| 1349 | +
|
| 1350 | + Basic Example: |
| 1351 | +
|
| 1352 | + .. code-block:: python |
| 1353 | +
|
| 1354 | + zk = KazooClient() |
| 1355 | + zk.start() |
| 1356 | +
|
| 1357 | + # first add an observer (incremental reconfiguration) |
| 1358 | + joining = 'server.100=10.0.0.10:2889:3888:observer;0.0.0.0:2181' |
| 1359 | + data, _ = zk.reconfig( |
| 1360 | + joining=joining, leaving=None, new_members=None) |
| 1361 | +
|
| 1362 | + # wait and then remove it (just by using its id) (incremental) |
| 1363 | + data, _ = zk.reconfig(joining=None, leaving='100', new_members=None) |
| 1364 | +
|
| 1365 | + # now do a full change of the cluster (non-incremental) |
| 1366 | + new = [ |
| 1367 | + 'server.100=10.0.0.10:2889:3888:observer;0.0.0.0:2181', |
| 1368 | + 'server.100=10.0.0.11:2889:3888:observer;0.0.0.0:2181', |
| 1369 | + 'server.100=10.0.0.12:2889:3888:observer;0.0.0.0:2181', |
| 1370 | + ] |
| 1371 | + data, _ = zk.reconfig( |
| 1372 | + joining=None, leaving=None, new_members=','.join(new)) |
| 1373 | +
|
| 1374 | + zk.stop() |
| 1375 | +
|
| 1376 | + :raises: |
| 1377 | + :exc:`~kazoo.exceptions.UnimplementedError` if not supported. |
| 1378 | +
|
| 1379 | + :exc:`~kazoo.exceptions.NewConfigNoQuorumError` if no quorum of new |
| 1380 | + config is connected and up-to-date with the leader of last |
| 1381 | + commmitted config - try invoking reconfiguration after new servers |
| 1382 | + are connected and synced. |
| 1383 | +
|
| 1384 | + :exc:`~kazoo.exceptions.ReconfigInProcessError` if another |
| 1385 | + reconfiguration is in progress. |
| 1386 | +
|
| 1387 | + :exc:`~kazoo.exceptions.BadVersionError` if version doesn't |
| 1388 | + match. |
| 1389 | +
|
| 1390 | + :exc:`~kazoo.exceptions.BadArgumentsError` if any of the given |
| 1391 | + lists of servers has a bad format. |
| 1392 | +
|
| 1393 | + :exc:`~kazoo.exceptions.ZookeeperError` if the server |
| 1394 | + returns a non-zero error code. |
| 1395 | +
|
| 1396 | + """ |
| 1397 | + result = self.reconfig_async(joining, leaving, new_members, from_config) |
| 1398 | + return result.get() |
| 1399 | + |
| 1400 | + def reconfig_async(self, joining, leaving, new_members, from_config): |
| 1401 | + """Asynchronously reconfig a cluster. Takes the same arguments as |
| 1402 | + :meth:`reconfig`. |
| 1403 | +
|
| 1404 | + :rtype: :class:`~kazoo.interfaces.IAsyncResult` |
| 1405 | +
|
| 1406 | + """ |
| 1407 | + if joining and not isinstance(joining, basestring): |
| 1408 | + raise TypeError("joining must be a string") |
| 1409 | + if leaving and not isinstance(leaving, basestring): |
| 1410 | + raise TypeError("leaving must be a string") |
| 1411 | + if new_members and not isinstance(new_members, basestring): |
| 1412 | + raise TypeError("new_members must be a string") |
| 1413 | + if not isinstance(from_config, int): |
| 1414 | + raise TypeError("from_config must be an int") |
| 1415 | + |
| 1416 | + async_result = self.handler.async_result() |
| 1417 | + reconfig = Reconfig(joining, leaving, new_members, from_config) |
| 1418 | + self._call(reconfig, async_result) |
| 1419 | + |
| 1420 | + return async_result |
| 1421 | + |
1329 | 1422 |
|
1330 | 1423 | class TransactionRequest(object): |
1331 | 1424 | """A Zookeeper Transaction Request |
|
0 commit comments