1__all__ = ["Replication"]
2
3from typing import Optional, Sequence
4
5from arango.api import ApiGroup
6from arango.exceptions import (
7    ReplicationApplierConfigError,
8    ReplicationApplierConfigSetError,
9    ReplicationApplierStartError,
10    ReplicationApplierStateError,
11    ReplicationApplierStopError,
12    ReplicationClusterInventoryError,
13    ReplicationDumpBatchCreateError,
14    ReplicationDumpBatchDeleteError,
15    ReplicationDumpBatchExtendError,
16    ReplicationDumpError,
17    ReplicationInventoryError,
18    ReplicationLoggerFirstTickError,
19    ReplicationLoggerStateError,
20    ReplicationMakeSlaveError,
21    ReplicationServerIDError,
22    ReplicationSyncError,
23)
24from arango.formatter import (
25    format_replication_applier_config,
26    format_replication_applier_state,
27    format_replication_header,
28    format_replication_inventory,
29    format_replication_logger_state,
30    format_replication_sync,
31)
32from arango.request import Request
33from arango.response import Response
34from arango.result import Result
35from arango.typings import Json, Params
36
37
38class Replication(ApiGroup):
39    def inventory(
40        self,
41        batch_id: str,
42        include_system: Optional[bool] = None,
43        all_databases: Optional[bool] = None,
44    ) -> Result[Json]:
45        """Return an overview of collections and indexes.
46
47        :param batch_id: Batch ID.
48        :type batch_id: str
49        :param include_system: Include system collections in the result.
50            Default value is True.
51        :type include_system: bool | None
52        :param all_databases: Include all databases. Only works on "_system"
53            database. Default value is False.
54        :type all_databases: bool | None
55        :return: Overview of collections and indexes.
56        :rtype: dict
57        :raise arango.exceptions.ReplicationInventoryError: If retrieval fails.
58        """
59        params: Params = {"batchId": batch_id}
60        if include_system is not None:
61            params["includeSystem"] = include_system
62        if all_databases is not None:
63            params["global"] = all_databases
64
65        request = Request(
66            method="get", endpoint="/_api/replication/inventory", params=params
67        )
68
69        def response_handler(resp: Response) -> Json:
70            if resp.is_success:
71                return format_replication_inventory(resp.body)
72            raise ReplicationInventoryError(resp, request)
73
74        return self._execute(request, response_handler)
75
76    def create_dump_batch(self, ttl: Optional[int] = None) -> Result[Json]:
77        """Create a new dump batch.
78
79        :param ttl: Time-to-live for the new batch in seconds.
80        :type ttl: int | None
81        :return: ID of the batch.
82        :rtype: dict
83        :raise arango.exceptions.ReplicationDumpBatchCreateError: If create fails.
84        """
85        request = Request(
86            method="post", endpoint="/_api/replication/batch", data={"ttl": ttl}
87        )
88
89        def response_handler(resp: Response) -> Json:
90            if resp.is_success:
91                return {"id": resp.body["id"], "last_tick": resp.body["lastTick"]}
92            raise ReplicationDumpBatchCreateError(resp, request)
93
94        return self._execute(request, response_handler)
95
96    def delete_dump_batch(self, batch_id: str) -> Result[bool]:
97        """Delete a dump batch.
98
99        :param batch_id: Dump batch ID.
100        :type batch_id: str
101        :return: True if deletion was successful.
102        :rtype: bool
103        :raise arango.exceptions.ReplicationDumpBatchDeleteError: If delete fails.
104        """
105        request = Request(
106            method="delete",
107            endpoint=f"/_api/replication/batch/{batch_id}",
108            deserialize=False,
109        )
110
111        def response_handler(resp: Response) -> bool:
112            if resp.is_success:
113                return True
114            raise ReplicationDumpBatchDeleteError(resp, request)
115
116        return self._execute(request, response_handler)
117
118    def extend_dump_batch(self, batch_id: str, ttl: int) -> Result[bool]:
119        """Extend a dump batch.
120
121        :param batch_id: Dump batch ID.
122        :type batch_id: str
123        :param ttl: Time-to-live for the new batch in seconds.
124        :type ttl: int
125        :return: True if operation was successful.
126        :rtype: bool
127        :raise arango.exceptions.ReplicationDumpBatchExtendError: If dump fails.
128        """
129        request = Request(
130            method="put",
131            endpoint=f"/_api/replication/batch/{batch_id}",
132            data={"ttl": ttl},
133            deserialize=False,
134        )
135
136        def response_handler(resp: Response) -> bool:
137            if resp.is_success:
138                return True
139            raise ReplicationDumpBatchExtendError(resp, request)
140
141        return self._execute(request, response_handler)
142
143    def dump(
144        self,
145        collection: str,
146        batch_id: Optional[str] = None,
147        chunk_size: Optional[int] = None,
148        deserialize: bool = False,
149    ) -> Result[Json]:
150        """Return the events data of one collection.
151
152        :param collection: Name or ID of the collection to dump.
153        :type collection: str
154        :param batch_id: Batch ID.
155        :type batch_id: str | None
156        :param chunk_size: Size of the result in bytes. This value is honored
157            approximately only.
158        :type chunk_size: int | None
159        :param deserialize: Deserialize the response content. Default is False.
160        :type deserialize: bool
161        :return: Collection events data.
162        :rtype: str | [dict]
163        :raise arango.exceptions.ReplicationDumpError: If retrieval fails.
164        """
165        params: Params = {"collection": collection}
166
167        if chunk_size is not None:
168            params["chunkSize"] = chunk_size
169        if batch_id is not None:
170            params["batchId"] = batch_id
171
172        request = Request(
173            method="get",
174            endpoint="/_api/replication/dump",
175            params=params,
176            deserialize=False,
177        )
178
179        def response_handler(resp: Response) -> Json:
180            if resp.is_success:
181                result = format_replication_header(resp.headers)
182                result["content"] = [
183                    [
184                        self._conn.deserialize(line)
185                        for line in resp.body.split("\n")
186                        if line
187                    ]
188                    if deserialize
189                    else resp.body
190                ]
191                return result
192
193            raise ReplicationDumpError(resp, request)
194
195        return self._execute(request, response_handler)
196
197    def synchronize(
198        self,
199        endpoint: str,
200        database: Optional[str] = None,
201        username: Optional[str] = None,
202        password: Optional[str] = None,
203        include_system: Optional[bool] = None,
204        incremental: Optional[bool] = None,
205        restrict_type: Optional[str] = None,
206        restrict_collections: Optional[Sequence[str]] = None,
207        initial_sync_wait_time: Optional[int] = None,
208    ) -> Result[Json]:  # pragma: no cover
209        """Synchronize data from a remote endpoint.
210
211        :param endpoint: Master endpoint (e.g. "tcp://192.168.173.13:8529").
212        :type endpoint: str
213        :param database: Database name.
214        :type database: str | None
215        :param username: Username.
216        :type username: str | None
217        :param password: Password.
218        :type password: str | None
219        :param include_system: Whether to include system collection operations.
220        :type include_system: bool | None
221        :param incremental: If set to True, then an incremental synchronization
222            method is used for synchronizing data in collections. This
223            method is useful when collections already exist locally, and only
224            the remaining differences need to be transferred from the remote
225            endpoint. In this case, the incremental synchronization can be
226            faster than a full synchronization. Default value is False, meaning
227            complete data is transferred.
228        :type incremental: bool | None
229        :param restrict_type: Optional string value for collection filtering.
230            Allowed values are "include" or "exclude".
231        :type restrict_type: str | None
232        :param restrict_collections: Optional list of collections for use with
233            argument **restrict_type**. If **restrict_type** set to "include",
234            only the specified collections are synchronised. Otherwise, all but
235            the specified ones are synchronized.
236        :type restrict_collections: [str] | None
237        :param initial_sync_wait_time: Maximum wait time in seconds that the
238            initial synchronization will wait for a response from master when
239            fetching collection data. This can be used to control after what
240            time the initial synchronization will give up waiting for response
241            and fail. Value is ignored if set to 0.
242        :type initial_sync_wait_time: int | None
243        :return: Collections transferred and last log tick.
244        :rtype: dict
245        :raise arango.exceptions.ReplicationSyncError: If sync fails.
246        """
247        data: Json = {"endpoint": endpoint}
248
249        if database is not None:
250            data["database"] = database
251        if username is not None:
252            data["username"] = username
253        if password is not None:
254            data["password"] = password
255        if include_system is not None:
256            data["includeSystem"] = include_system
257        if incremental is not None:
258            data["incremental"] = incremental
259        if restrict_type is not None:
260            data["restrictType"] = restrict_type
261        if restrict_collections is not None:
262            data["restrictCollections"] = restrict_collections
263        if initial_sync_wait_time is not None:
264            data["initialSyncMaxWaitTime"] = initial_sync_wait_time
265
266        request = Request(method="put", endpoint="/_api/replication/sync", data=data)
267
268        def response_handler(resp: Response) -> Json:
269            if resp.is_success:
270                return format_replication_sync(resp.body)
271            raise ReplicationSyncError(resp, request)
272
273        return self._execute(request, response_handler)
274
275    def cluster_inventory(self, include_system: Optional[bool] = None) -> Result[Json]:
276        """Return an overview of collections and indexes in a cluster.
277
278        :param include_system: Include system collections in the result.
279            Default value is True.
280        :type include_system: bool
281        :return: Overview of collections and indexes on the cluster.
282        :rtype: dict
283        :raise arango.exceptions.ReplicationClusterInventoryError: If retrieval fails.
284        """
285        params: Params = {}
286        if include_system is not None:
287            params["includeSystem"] = include_system
288
289        request = Request(
290            method="get", endpoint="/_api/replication/clusterInventory", params=params
291        )
292
293        def response_handler(resp: Response) -> Json:
294            if resp.is_success:  # pragma: no cover
295                return format_replication_inventory(resp.body)
296            raise ReplicationClusterInventoryError(resp, request)
297
298        return self._execute(request, response_handler)
299
300    def logger_state(self) -> Result[Json]:
301        """Return the state of the replication logger.
302
303        :return: Logger state.
304        :rtype: dict
305        :raise arango.exceptions.ReplicationLoggerStateError: If retrieval fails.
306        """
307        request = Request(
308            method="get",
309            endpoint="/_api/replication/logger-state",
310        )
311
312        def response_handler(resp: Response) -> Json:
313            if resp.is_success:
314                return format_replication_logger_state(resp.body)
315            raise ReplicationLoggerStateError(resp, request)
316
317        return self._execute(request, response_handler)
318
319    def logger_first_tick(self) -> Result[str]:
320        """Return the first available tick value from the server.
321
322        :return: First tick value.
323        :rtype: str
324        :raise arango.exceptions.ReplicationLoggerFirstTickError: If retrieval fails.
325        """
326        request = Request(
327            method="get",
328            endpoint="/_api/replication/logger-first-tick",
329        )
330
331        def response_handler(resp: Response) -> str:
332            if resp.is_success:
333                return str(resp.body["firstTick"])
334            raise ReplicationLoggerFirstTickError(resp, request)
335
336        return self._execute(request, response_handler)
337
338    def applier_config(self) -> Result[Json]:
339        """Return the configuration of the replication applier.
340
341        :return: Configuration of the replication applier.
342        :rtype: dict
343        :raise arango.exceptions.ReplicationApplierConfigError: If retrieval fails.
344        """
345        request = Request(
346            method="get",
347            endpoint="/_api/replication/applier-config",
348        )
349
350        def response_handler(resp: Response) -> Json:
351            if resp.is_success:
352                return format_replication_applier_config(resp.body)
353            raise ReplicationApplierConfigError(resp, request)
354
355        return self._execute(request, response_handler)
356
357    def set_applier_config(
358        self,
359        endpoint: str,
360        database: Optional[str] = None,
361        username: Optional[str] = None,
362        password: Optional[str] = None,
363        max_connect_retries: Optional[int] = None,
364        connect_timeout: Optional[int] = None,
365        request_timeout: Optional[int] = None,
366        chunk_size: Optional[int] = None,
367        auto_start: Optional[bool] = None,
368        adaptive_polling: Optional[bool] = None,
369        include_system: Optional[bool] = None,
370        auto_resync: Optional[bool] = None,
371        auto_resync_retries: Optional[int] = None,
372        initial_sync_max_wait_time: Optional[int] = None,
373        connection_retry_wait_time: Optional[int] = None,
374        idle_min_wait_time: Optional[int] = None,
375        idle_max_wait_time: Optional[int] = None,
376        require_from_present: Optional[bool] = None,
377        verbose: Optional[bool] = None,
378        restrict_type: Optional[str] = None,
379        restrict_collections: Optional[Sequence[str]] = None,
380    ) -> Result[Json]:
381        """Set configuration values of the replication applier.
382
383        :param endpoint: Server endpoint (e.g. "tcp://192.168.173.13:8529").
384        :type endpoint: str
385        :param database: Database name.
386        :type database: str | None
387        :param username: Username.
388        :type username: str | None
389        :param password: Password.
390        :type password: str | None
391        :param max_connect_retries: Maximum number of connection attempts the
392            applier makes in a row before stopping itself.
393        :type max_connect_retries: int | None
394        :param connect_timeout: Timeout in seconds when attempting to connect
395            to the endpoint. This value is used for each connection attempt.
396        :type connect_timeout: int | None
397        :param request_timeout: Timeout in seconds for individual requests to
398            the endpoint.
399        :type request_timeout: int | None
400        :param chunk_size: Requested maximum size in bytes for log transfer
401            packets when the endpoint is contacted.
402        :type chunk_size: int | None
403        :param auto_start: Whether to auto-start the replication applier on
404            (next and following) server starts.
405        :type auto_start: bool | None
406        :param adaptive_polling: If set to True, replication applier sleeps
407            for an increasingly long period in case the logger server at the
408            endpoint has no replication events to apply. Using adaptive polling
409            reduces the amount of work done by both the applier and the logger
410            server when there are infrequent changes. The downside is that it
411            might take longer for the replication applier to detect new events.
412        :type adaptive_polling: bool | None
413        :param include_system: Whether system collection operations are
414            applied.
415        :type include_system: bool | None
416        :param auto_resync: Whether the slave should perform a full automatic
417            resynchronization with the master in case the master cannot serve
418            log data requested by the slave, or when the replication is started
419            and no tick value can be found.
420        :type auto_resync: bool | None
421        :param auto_resync_retries: Max number of resynchronization retries.
422            Setting this to 0 disables it.
423        :type auto_resync_retries: int | None
424        :param initial_sync_max_wait_time: Max wait time in seconds the initial
425            synchronization waits for master on collection data. This value
426            is relevant even for continuous replication when **auto_resync** is
427            set to True because this may re-start the initial synchronization
428            when master cannot provide log data slave requires. This value is
429            ignored if set to 0.
430        :type initial_sync_max_wait_time: int | None
431        :param connection_retry_wait_time: Time in seconds the applier idles
432            before trying to connect to master in case of connection problems.
433            This value is ignored if set to 0.
434        :type connection_retry_wait_time: int | None
435        :param idle_min_wait_time: Minimum wait time in seconds the applier
436            idles before fetching more log data from the master in case the
437            master has already sent all its log data. This wait time can be
438            used to control the frequency with which the replication applier
439            sends HTTP log fetch requests to the master in case there is no
440            write activity on the master. This value is ignored if set to 0.
441        :type idle_min_wait_time: int | None
442        :param idle_max_wait_time: Maximum wait time in seconds the applier
443            idles before fetching more log data from the master in case the
444            master has already sent all its log data. This wait time can be
445            used to control the maximum frequency with which the replication
446            applier sends HTTP log fetch requests to the master in case there
447            is no write activity on the master. Applies only when argument
448            **adaptive_polling** is set to True. This value is ignored if set
449            to 0.
450        :type idle_max_wait_time: int | None
451        :param require_from_present: If set to True, replication applier checks
452            at start whether the start tick from which it starts or resumes
453            replication is still present on the master. If not, then there
454            would be data loss. If set to True, the replication applier aborts
455            with an appropriate error message. If set to False, the applier
456            still starts and ignores the data loss.
457        :type require_from_present: bool | None
458        :param verbose: If set to True, a log line is emitted for all
459            operations performed by the replication applier. This should be
460            used for debugging replication problems only.
461        :type verbose: bool | None
462        :param restrict_type: Optional string value for collection filtering.
463            Allowed values are "include" or "exclude".
464        :type restrict_type: str | None
465        :param restrict_collections: Optional list of collections for use with
466            argument **restrict_type**. If **restrict_type** set to "include",
467            only the specified collections are included. Otherwise, only the
468            specified collections are excluded.
469        :type restrict_collections: [str] | None
470        :return: Updated configuration.
471        :rtype: dict
472        :raise arango.exceptions.ReplicationApplierConfigSetError: If update fails.
473        """
474        data: Json = {"endpoint": endpoint}
475
476        if database is not None:
477            data["database"] = database
478        if username is not None:
479            data["username"] = username
480        if password is not None:
481            data["password"] = password
482        if max_connect_retries is not None:
483            data["maxConnectRetries"] = max_connect_retries
484        if connect_timeout is not None:
485            data["connectTimeout"] = connect_timeout
486        if request_timeout is not None:
487            data["requestTimeout"] = request_timeout
488        if chunk_size is not None:
489            data["chunkSize"] = chunk_size
490        if auto_start is not None:
491            data["autoStart"] = auto_start
492        if adaptive_polling is not None:
493            data["adaptivePolling"] = adaptive_polling
494        if include_system is not None:
495            data["includeSystem"] = include_system
496        if auto_resync is not None:
497            data["autoResync"] = auto_resync
498        if auto_resync_retries is not None:
499            data["autoResyncRetries"] = auto_resync_retries
500        if initial_sync_max_wait_time is not None:
501            data["initialSyncMaxWaitTime"] = initial_sync_max_wait_time
502        if connection_retry_wait_time is not None:
503            data["connectionRetryWaitTime"] = connection_retry_wait_time
504        if idle_min_wait_time is not None:
505            data["idleMinWaitTime"] = idle_min_wait_time
506        if idle_max_wait_time is not None:
507            data["idleMaxWaitTime"] = idle_max_wait_time
508        if require_from_present is not None:
509            data["requireFromPresent"] = require_from_present
510        if verbose is not None:
511            data["verbose"] = verbose
512        if restrict_type is not None:
513            data["restrictType"] = restrict_type
514        if restrict_collections is not None:
515            data["restrictCollections"] = restrict_collections
516
517        request = Request(
518            method="put", endpoint="/_api/replication/applier-config", data=data
519        )
520
521        def response_handler(resp: Response) -> Json:
522            if resp.is_success:
523                return format_replication_applier_config(resp.body)
524            raise ReplicationApplierConfigSetError(resp, request)
525
526        return self._execute(request, response_handler)
527
528    def applier_state(self) -> Result[Json]:
529        """Return the state of the replication applier
530
531        :return: Applier state and details.
532        :rtype: dict
533        :raise arango.exceptions.ReplicationApplierStateError: If retrieval fails.
534        """
535        request = Request(
536            method="get",
537            endpoint="/_api/replication/applier-state",
538        )
539
540        def response_handler(resp: Response) -> Json:
541            if resp.is_success:
542                return format_replication_applier_state(resp.body)
543            raise ReplicationApplierStateError(resp, request)
544
545        return self._execute(request, response_handler)
546
547    def start_applier(self, last_tick: Optional[str] = None) -> Result[Json]:
548        """Start the replication applier.
549
550        :param last_tick: The remote last log tick value from which to start
551            applying replication. If not specified, the last saved tick from
552            the previous applier run is used. If there is no previous applier
553            state saved, the applier starts at the beginning of the logger
554            server's log.
555        :type last_tick: str
556        :return: Applier state and details.
557        :rtype: dict
558        :raise arango.exceptions.ReplicationApplierStartError: If operation fails.
559        """
560        request = Request(
561            method="put",
562            endpoint="/_api/replication/applier-start",
563            params={} if last_tick is None else {"from": last_tick},
564        )
565
566        def response_handler(resp: Response) -> Json:
567            if resp.is_success:
568                return format_replication_applier_state(resp.body)
569            raise ReplicationApplierStartError(resp, request)
570
571        return self._execute(request, response_handler)
572
573    def stop_applier(self) -> Result[Json]:
574        """Stop the replication applier.
575
576        :return: Applier state and details.
577        :rtype: dict
578        :raise arango.exceptions.ReplicationApplierStopError: If operation fails.
579        """
580        request = Request(
581            method="put",
582            endpoint="/_api/replication/applier-stop",
583        )
584
585        def response_handler(resp: Response) -> Json:
586            if resp.is_success:
587                return format_replication_applier_state(resp.body)
588            raise ReplicationApplierStopError(resp, request)
589
590        return self._execute(request, response_handler)
591
592    def make_slave(
593        self,
594        endpoint: str,
595        database: Optional[str] = None,
596        username: Optional[str] = None,
597        password: Optional[str] = None,
598        restrict_type: Optional[str] = None,
599        restrict_collections: Optional[Sequence[str]] = None,
600        include_system: Optional[bool] = None,
601        max_connect_retries: Optional[int] = None,
602        connect_timeout: Optional[int] = None,
603        request_timeout: Optional[int] = None,
604        chunk_size: Optional[int] = None,
605        adaptive_polling: Optional[bool] = None,
606        auto_resync: Optional[bool] = None,
607        auto_resync_retries: Optional[int] = None,
608        initial_sync_max_wait_time: Optional[int] = None,
609        connection_retry_wait_time: Optional[int] = None,
610        idle_min_wait_time: Optional[int] = None,
611        idle_max_wait_time: Optional[int] = None,
612        require_from_present: Optional[bool] = None,
613        verbose: Optional[bool] = None,
614    ) -> Result[Json]:  # pragma: no cover
615        """Change the server role to slave.
616
617        :param endpoint: Master endpoint (e.g. "tcp://192.168.173.13:8529").
618        :type endpoint: str
619        :param database: Database name.
620        :type database: str | None
621        :param username: Username.
622        :type username: str | None
623        :param password: Password.
624        :type password: str | None
625        :param restrict_type: Optional string value for collection filtering.
626            Allowed values are "include" or "exclude".
627        :type restrict_type: str | None
628        :param restrict_collections: Optional list of collections for use with
629            argument **restrict_type**. If **restrict_type** set to "include",
630            only the specified collections are included. Otherwise, only the
631            specified collections are excluded.
632        :type restrict_collections: [str] | None
633        :param include_system: Whether system collection operations are
634            applied.
635        :type include_system: bool | None
636        :param max_connect_retries: Maximum number of connection attempts the
637            applier makes in a row before stopping itself.
638        :type max_connect_retries: int | None
639        :param connect_timeout: Timeout in seconds when attempting to connect
640            to the endpoint. This value is used for each connection attempt.
641        :type connect_timeout: int | None
642        :param request_timeout: Timeout in seconds for individual requests to
643            the endpoint.
644        :type request_timeout: int | None
645        :param chunk_size: Requested maximum size in bytes for log transfer
646            packets when the endpoint is contacted.
647        :type chunk_size: int | None
648        :param adaptive_polling: If set to True, replication applier sleeps
649            for an increasingly long period in case the logger server at the
650            endpoint has no replication events to apply. Using adaptive polling
651            reduces the amount of work done by both the applier and the logger
652            server when there are infrequent changes. The downside is that it
653            might take longer for the replication applier to detect new events.
654        :type adaptive_polling: bool | None
655        :param auto_resync: Whether the slave should perform a full automatic
656            resynchronization with the master in case the master cannot serve
657            log data requested by the slave, or when the replication is started
658            and no tick value can be found.
659        :type auto_resync: bool | None
660        :param auto_resync_retries: Max number of resynchronization retries.
661            Setting this to 0 disables it.
662        :type auto_resync_retries: int | None
663        :param initial_sync_max_wait_time: Max wait time in seconds the initial
664            synchronization waits for master on collection data. This value
665            is relevant even for continuous replication when **auto_resync** is
666            set to True because this may restart the initial synchronization
667            when master cannot provide log data slave requires. This value is
668            ignored if set to 0.
669        :type initial_sync_max_wait_time: int | None
670        :param connection_retry_wait_time: Time in seconds the applier idles
671            before trying to connect to master in case of connection problems.
672            This value is ignored if set to 0.
673        :type connection_retry_wait_time: int | None
674        :param idle_min_wait_time: Minimum wait time in seconds the applier
675            idles before fetching more log data from the master in case the
676            master has already sent all its log data. This wait time can be
677            used to control the frequency with which the replication applier
678            sends HTTP log fetch requests to the master in case there is no
679            write activity on the master. This value is ignored if set to 0.
680        :type idle_min_wait_time: int | None
681        :param idle_max_wait_time: Maximum wait time in seconds the applier
682            idles before fetching more log data from the master in case the
683            master has already sent all its log data. This wait time can be
684            used to control the maximum frequency with which the replication
685            applier sends HTTP log fetch requests to the master in case there
686            is no write activity on the master. Applies only when argument
687            **adaptive_polling** is set to True. This value is ignored if set
688            to 0.
689        :type idle_max_wait_time: int | None
690        :param require_from_present: If set to True, replication applier checks
691            at start whether the start tick from which it starts or resumes
692            replication is still present on the master. If not, then there
693            would be data loss. If set to True, the replication applier aborts
694            with an appropriate error message. If set to False, the applier
695            still starts and ignores the data loss.
696        :type require_from_present: bool | None
697        :param verbose: If set to True, a log line is emitted for all
698            operations performed by the replication applier. This should be
699            used for debugging replication problems only.
700        :type verbose: bool | None
701        :return: Replication details.
702        :rtype: dict
703        :raise arango.exceptions.ReplicationApplierStopError: If operation fails.
704        """
705        data: Json = {"endpoint": endpoint}
706
707        if database is not None:
708            data["database"] = database
709        if username is not None:
710            data["username"] = username
711        if password is not None:
712            data["password"] = password
713        if restrict_type is not None:
714            data["restrictType"] = restrict_type
715        if restrict_collections is not None:
716            data["restrictCollections"] = restrict_collections
717        if include_system is not None:
718            data["includeSystem"] = include_system
719        if max_connect_retries is not None:
720            data["maxConnectRetries"] = max_connect_retries
721        if connect_timeout is not None:
722            data["connectTimeout"] = connect_timeout
723        if request_timeout is not None:
724            data["requestTimeout"] = request_timeout
725        if chunk_size is not None:
726            data["chunkSize"] = chunk_size
727        if adaptive_polling is not None:
728            data["adaptivePolling"] = adaptive_polling
729        if auto_resync is not None:
730            data["autoResync"] = auto_resync
731        if auto_resync_retries is not None:
732            data["autoResyncRetries"] = auto_resync_retries
733        if initial_sync_max_wait_time is not None:
734            data["initialSyncMaxWaitTime"] = initial_sync_max_wait_time
735        if connection_retry_wait_time is not None:
736            data["connectionRetryWaitTime"] = connection_retry_wait_time
737        if idle_min_wait_time is not None:
738            data["idleMinWaitTime"] = idle_min_wait_time
739        if idle_max_wait_time is not None:
740            data["idleMaxWaitTime"] = idle_max_wait_time
741        if require_from_present is not None:
742            data["requireFromPresent"] = require_from_present
743        if verbose is not None:
744            data["verbose"] = verbose
745
746        request = Request(
747            method="put", endpoint="/_api/replication/make-slave", data=data
748        )
749
750        def response_handler(resp: Response) -> Json:
751            if resp.is_success:
752                return format_replication_applier_state(resp.body)
753            raise ReplicationMakeSlaveError(resp, request)
754
755        return self._execute(request, response_handler)
756
757    def server_id(self) -> Result[str]:
758        """Return this server's ID.
759
760        :return: Server ID.
761        :rtype: str
762        :raise arango.exceptions.ReplicationServerIDError: If retrieval fails.
763        """
764        request = Request(
765            method="get",
766            endpoint="/_api/replication/server-id",
767        )
768
769        def response_handler(resp: Response) -> str:
770            if resp.is_success:
771                return str(resp.body["serverId"])
772            raise ReplicationServerIDError(resp, request)
773
774        return self._execute(request, response_handler)
775