Commit 77715d06 authored by Ondřej Kuzník's avatar Ondřej Kuzník
Browse files

Add synccheck

parent 386fe12f
Pipeline #3461 passed with stage
in 42 seconds
......@@ -18,7 +18,10 @@ setup(
packages=find_packages(exclude=('tests', 'docs')),
python_requires=">= 3.7", # Modern asyncio
entry_points={
'console_scripts': ['syncmonitor = syncmonitor.ui:main'],
'console_scripts': [
'syncmonitor = syncmonitor.ui:main',
'synccheck = syncmonitor.check:main',
],
},
install_requires=[
'ldap0 >= 1.1.0',
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This work is part of OpenLDAP Software <http://www.openldap.org/>.
#
# Copyright 2020-2021 The OpenLDAP Foundation.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted only as authorized by the OpenLDAP
# Public License.
#
# A copy of this license is available in the file LICENSE in the
# top-level directory of the distribution or, alternatively, at
# <http://www.OpenLDAP.org/license.html>.
#
# ACKNOWLEDGEMENTS:
# This work was initially developed by Ondřej Kuzník
# for inclusion in OpenLDAP Software.
"""
OpenLDAP multiprovider replication monitor
"""
import argparse
import asyncio
import logging
import sys
from .environment import SyncreplEnvironment, ReplicaState
logger = logging.getLogger(__name__)
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--config', type=argparse.FileType('r'),
help='Authentication and connection config')
parser.add_argument('-b', '--base', required=True, help='Search base')
parser.add_argument('-p', '--persist', action='store_const',
const='refreshAndPersist', default='refreshOnly',
help='Use refresh and persist mode')
parser.add_argument('-c', '--cookie', action='store', help='Initial cookie')
parser.add_argument('-v', '--verbose', action='store_true',
help="Set log level to 'debug'")
parser.add_argument('-t', '--timeout', type=int, default=30,
help="How long to wait for servers to sync")
parser.add_argument('args', nargs='+', help='URLs for servers to contact')
async def run(args=None):
logging.basicConfig()
options = parser.parse_args(args)
if options.config:
import yaml
options.config = yaml.full_load(options.config.read())
level = None
if options.verbose:
level = logging.DEBUG
if sys.stderr.isatty():
try:
import coloredlogs
coloredlogs.install(level=level)
except ImportError:
pass
environment = SyncreplEnvironment(options.args, options.base,
cookie=options.cookie,
config=options.config)
await environment.set_up()
logger.error("started")
finished = asyncio.Event()
def state_changed(new_state):
if all(p.state == ReplicaState.UPTODATE
for uri, p in environment.providers.items()):
finished.set()
for uri, provider in environment.providers.items():
provider.state_changed.connect(state_changed)
done, pending = await asyncio.wait([finished.wait()], timeout=30)
if pending:
for task in pending:
task.cancel()
raise SystemExit("Timed out waiting for systems to resync")
for uri, p in environment.providers.items():
print("%s cookie %s" % (p, p.cookie), file=sys.stderr)
environment.stop()
logger.info("Finished sync")
def main(args=None):
asyncio.run(run(args))
......@@ -94,6 +94,8 @@ class Provider:
if self.scope == ldap0.SCOPE_BASE and not searchbase:
self.scope = ldap0.SCOPE_SUBTREE
self.up_to_date = asyncio.Event()
self.behind = Watchdog(30)
self.behind.triggered.connect(self._no_progress)
......@@ -186,11 +188,16 @@ class Provider:
if old_state != self.state:
self.state_changed(self.state)
if self.state == ReplicaState.UPTODATE:
self.up_to_date.set()
else:
self.up_to_date.clear()
async def search_finished(self):
try:
result = await self.search
self.state = ReplicaState.CONNECTING
self.up_to_date.clear()
if self.mode == 'refreshOnly':
await asyncio.sleep(1)
except ldap0.LDAPError as e:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment