Mongomirror
^^^^^^^^^^^

``mongomirror`` is a tool that lets you migrate data from a MongoDB replica set into
MongoDB Atlas without having to shut down your cluster. It continuously tails
the replica set oplog to listen for changes and replays them on the target
cluster in Atlas. ``mongomirror`` will continue to run until you shut it down, when
you're ready to switch your application over to Atlas.

Installing ``mongomirror``
==========================

You can get the latest version of ``mongomirror`` from the `releases page`_ on
this project's Github.

.. _releases page: https://github.com/10gen/mongomirror/releases

Basic Usage
===========

Before you begin, make sure that the destination to which ``mongomirror`` will
be copying data is *empty*. Otherwise, you must use the ``--drop`` option when
running ``mongomirror``, which will drop all non-system collections on the
destination.

``mongomirror`` needs to know about your source MongoDB cluster and your Atlas
cluster. Note that the source MongoDB cluster *must* be a replica set. If you're
migrating from a standalone MongoDB deployment, see the section `migrating from
a standalone MongoDB deployment`_. ``mongomirror`` **does not** support migrating
from sharded clusters at this time. To specify the source cluster, you'll need
the replica set name and the host and port of at least one replica set
member. You will also need to provide the username and password of an admin user
in Atlas::

  mongomirror --host replica-set-name/mongodb-source-cluster:27017 \
              --destination atlas-replica-set-name/atlas-cluster-host:27017 \
              --destinationUsername atlasUser \
              --destinationPassword atlasPassword

Above, we're importing data from the replica set ``replica-set-name`` and
specifying one member located at ``mongodb-source-cluster:27017``. The
destination in Atlas is a replica set with the name ``atlas-replica-set-name``,
which includes the host ``atlas-cluster-host:27017``. We will log in to the
atlas cluster as the user ``atlasUser`` with the password ``atlasPassword``.

Note: the examples in this document provide only a single hostname for each
replica set for brevity. However, providing multiple hostnames is also
acceptable::

  --host replica-set-name/host1,host2,... \
  --destination atlas-replica-set-name/atlashost1,atlashost2,...

Limitations
===========

``mongomirror`` has a number of limitations:
- Does not copy any users or roles from the source. These will need to be
  recreated on the destination.
- Does not support changing featureCompatibilityVersion during migration.
- Does not support the renameCollection command during mongomirror's initial sync.
  ``mongomirror`` will error if the source cluster performs a renameCollection
  command while the initial sync stage is in progress. Applications that rename
  collections directly or indirectly (eg. with the $out aggregation operator)
  must be disabled before running mongomirror.
- Mongomirror removes the "background" flag from all indexes it creates.
  Background indexes created on the source cluster will be created as
  foreground indexes on the destination cluster.

Authentication and Authorization
================================

Permissions in Atlas
--------------------

In order to use ``mongomirror``, make sure that you are authenticating as a user
with the ``atlasAdmin`` role (i.e. has the "Atlas admin" privilege under "User
Privileges").

Permissions on the Source Replica Set
-------------------------------------

If your source replica set requires authentication, make sure that ``mongomirror``
can authenticate as a user that has permission to read any collection, including
the oplog and the "config" database.  Even without the ``--replicateConfigDB`` option,
reading the "config" database is required.  The `backup`_ role works for this::

  > use admin
  > db.createUser({user: "mongomirror", pwd: "tropmisalta", roles: ["backup"]})

.. _backup: https://docs.mongodb.com/manual/reference/built-in-roles/#backup

Authenticating to the Source Cluster
------------------------------------

``mongomirror`` supports authentication when reading from the source cluster via the
``--username`` and ``--password`` options. For example, if you had a user with
the name ``mango`` and the password ``tr0picalFru1t``::

  mongomirror --username mango \
              --password tr0picalFru1t \
              --host replica-set-name/local-mongodb-deployment:27017 \
              --destination atlas-replica-set-name/atlas-host-name:27017 \
              --destinationUser atlasUser \
              --destinationPassword atlasPassword

By default, ``mongomirror`` will use the `SCRAM-SHA-1`_ authentication mechanism, but
there are other ways to authenticate as well.

.. _SCRAM-SHA-1: https://docs.mongodb.com/manual/core/security-scram-sha-1

X509 Client Authentication
..........................

You can also authenticate to the source cluster using the `MONGODB-X509`_
authentication mechanism::

  mongomirror --username "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry"
              --sslPEMKeyFile <path-to-my-client-certificate.pem> \
              --sslCAFile <path-to-my-certificate-authority-certificate.pem> \
              --authenticationDatabase '$external' \
              --authenticationMechanism MONGODB-X509 \
              --host replica-set-name/local-mongodb-deployment:27017 \
              --destination atlas-replica-set-name/atlas-host-name:27017 \
              --destinationUser atlasUser \
              --destinationPassword atlasPassword

Above, we provide the *subject name* of the client certificate (the one passed
to ``--sslPEMKeyFile``) to ``--username``. See the `tutorial`_ for authenticating
a client with an x509 certificate for more details.

.. _MONGODB-X509: https://docs.mongodb.com/manual/tutorial/configure-x509-client-authentication/
.. _tutorial: https://docs.mongodb.com/manual/tutorial/configure-x509-client-authentication/

Kerberos/GSSAPI Authentication
..............................

Authenticating with `Kerberos/GSSAPI`_ is also supported::

  mongomirror --username 'KERBEROS@PRINCIPAL.COM' \
              --authenticationMechanism GSSAPI \
              --authenticationDatabase '$external' \
              --host replica-set-name/local-mongodb-deployment:27017 \
              --destination atlas-replica-set-name/atlas-host-name:27017 \
              --destinationUser atlasUser \
              --destinationPassword atlasPassword

There are also a couple additional options that can be given for Kerberos/GSSAPI
authentication:

``--gssapiServiceName``
.......................

Specify the name of the service using GSSAPI/Kerberos. Only required if the
service does not use the default name of ``mongodb``.

``--gssapiHostName``
....................

Specify the hostname of a service using GSSAPI/Kerberos. Only required if the
hostname of a machine does not match the hostname resolved by DNS.

.. _Kerberos/GSSAPI: https://docs.mongodb.com/manual/core/kerberos/

Replicating the "config" Database
=================================

Pass the ``--replicateConfigDB`` option to enable replication of the "config"
database. By default ``mongomirror`` does not replicate the "config" database.
Note that writing to the "config" database requires extra permissions on the
destination cluster. The following roles are required:

  {"db": "config", "role": "dbAdmin"}
  {"db": "config", "role": "readWrite"}

Buffering the oplog
===================

By default mongomirror streams oplog entries from the source and applies them
to the destination. When the source oplog is not large enough to contain
the entire initial sync oplog window, mongomirror may fail with the following
error::

  Checkpoint not available in oplog! expected: 6522497714079399948; got: 6522938622537105416

To avoid this error, either `increase the size of the source oplog`_
or pass the ``--oplogPath=<directory-path>`` option to enable buffering the
initial sync oplog window to disk. When enabled mongomirror streams the oplog
entries to the given directory in a single file: "<oplogPath>/oplog-mongomirror.bson.sz"
The file is a BSON document stream compressed using Snappy's framing format.

There must be enough disk space to contain all the source oplog entries that
occur during mongomirror's initial sync. For example, if the source oplog is
10 GB and covers 24 hours of changes and mongomirror's initial sync is
estimated to take 48 hours, then there must be at least 20 GB of free disk
space in the given directory.

Mongomirror will replay the oplog entries from disk to avoid falling off the
oplog. After the entire oplog file is replayed to the destination, the file is
removed and mongomirror starts directly tailing the source oplog without
buffering.

.. _increase the size of the source oplog: https://docs.mongodb.com/manual/tutorial/change-oplog-size/index.html

Connecting over SSL
===================

``mongomirror`` will automatically connect to Atlas over SSL and use the correct
settings. In addition, you can configure ``mongomirror`` to connect to the source
cluster over SSL using the following options:

``--ssl``
---------

This option enables connecting to the source cluster over SSL.

``--sslPEMKeyFile <pem file>``
------------------------------

Specifies the .pem file that contains both the TLS/SSL certificate and
key. Specify the file name of the .pem file using relative or absolute
paths. You should use this option if the source cluster requires clients to
present a certificate.

``--sslCAFile <certificate authority certificate>``
---------------------------------------------------

Specifies the .pem file that contains the root certificate chain from the
Certificate Authority. Specify the file name of the .pem file using relative or
absolute paths. This option is useful when using certificates signed by a
Certificate Authority that isn't available on your operating system.

``--sslCRLFile <certificate revocation list>``
----------------------------------------------

Specifies the .pem file that contains the Certificate Revocation List. Specify
the file name of the .pem file using relative or absolute paths.

``--sslAllowInvalidHostnames``
------------------------------

Disables the validation of the hostnames in TLS/SSL certificates. Allows
``mongomirror`` to connect to MongoDB instances even if the hostname in their
certificates do not match the specified hostname.

``--sslAllowInvalidCertificates``
---------------------------------

Bypasses the validation checks for server certificates and allows the use of
invalid certificates. When using the ``allowInvalidCertificates`` setting,
MongoDB logs as a warning the use of the invalid certificate.

Migrating from a Standalone MongoDB Deployment
==============================================

If your source is a standalone MongoDB deployment, then you'll need to restart
your MongoDB deployment as a replica set before running ``mongomirror``. `This
tutorial`_ will run you through the steps.

.. _this tutorial: https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/

Measuring Progress
==================

``mongomirror`` logs its progress to standard output of the
terminal. Additionally, it can be configured to run an HTTP server at a
specified port by running it with the flag ``--httpStatusPort``.

Reading Progress over HTTP
--------------------------

To start ``mongomirror`` with support for reading progress over HTTP, run it
with the ``--httpStatusPort`` option::

  mongomirror --httpStatusPort 8080 ... <other options>

The above will cause ``mongomirror`` to start an HTTP server on port 8080. Note
that ``mongomirror`` does not exit when it encounters an error when
``--httpStatusPort`` is provided, staying alive so that the HTTP service
continues to be available.

There is only a single endpoint for the HTTP, which is the root path. Continuing
the above example, all requests for progress on mongomirror should be routed to
``http://localhost:8080``. Only the HTTP ``GET`` method is supported for
obtaining progress information. Sending a request using the HTTP ``DELETE``
method will cause ``mongomirror`` to stop.

The response from ``mongomirror`` always takes the following form::

  {
    "stage": <stage name>,
    "phase": <phase name>,
    "details": <details>,
    "errorMessage": <error message>
  }

* ``stage``: The name of the stage:

  + ``initializing``: ``mongomirror`` is initializing. No copying is being done
    yet.
  + ``initial sync``: ``mongomirror`` is copying over documents and indexes that
    already exist on the source deployment.
  + ``oplog sync``: ``mongomirror`` is tailing and applying entries from the
    oplog.

* ``phase`` (not always present): The name of the phase. This provides more
  specific details about what part of the stage is in progress.

* ``details`` (not always present): A document providing a detailed description
  of the progress of the current phase. This document may include information
  about how many bytes have been copied so far from each collection, or the
  timestamp of the oplog record that was most recently processed compared to the
  newest one available on the source.

* ``errorMessage`` (not always present): A string that describes what went
  wrong. Note that ``mongomirror`` does not exit when it encounters an error
  when ``--httpStatusPort`` is provided, staying alive so that the HTTP service
  continues to be available.

Examples
........

* This is an example response during initial sync::

    {
        "details": {
            "zoo.animals": {
                "complete": false,
                "copiedBytes": 46362399,
                "totalBytes": 66881409
            },
            "park.events": {
                "complete": false,
                "copiedBytes": 29347,
                "totalBytes": 29347
            },
            "park.dailyReport": {
                "complete": true,
                "copiedBytes": 297234,
                "totalBytes": 297111
            },
            "sensors.temperatureLogs": {
                "complete": false,
                "copiedBytes": 0,
                "totalBytes": 23947377
            }
        },
        "phase": "copying initial data",
        "stage": "initial sync"
    }

  Each key in the ``details`` document is the name of a MongoDB collection that
  is being copied. Within each of these documents, we have the following fields:

  + ``complete`` (boolean): Whether all work copying documents from collection
    is done.
  + ``copiedBytes`` (number): The number of bytes copied so far. Note that this
    is a different measurement of progress from what's in the logs, which
    reports the current/total number of *documents* copied.
  + ``totalBytes`` (number): The total size (in bytes) of the collection.

* Another example of a response during initial sync, during the phase ``applying
  oplog entries``::

    {
        "details": {
            "currentTimestamp": 6375221159490749088,
            "latestTimestamp": 6375221176670620325
        },
        "phase": "applying oplog entries",
        "stage": "initial sync"
    }

  ``details.currentTimestamp`` shows the BSON timestamp value of the oplog entry
  that was most recently processed by
  ``mongomirror``. ``details.latestTimestamp`` provides the BSON timestamp value
  of the latest oplog entry available after the initial data was copied during
  initial sync. ``mongomirror`` only refreshes its view of these data once every
  10 seconds (it does not refresh on each request), so be aware that
  ``mongomirror`` may be slightly further ahead of these times.

* A third example of a response during initial sync, during the phase ``copying
  indexes``::

    {
        "details": {
            "zoo.animals": {
                "complete": false,
                "createIndexes": 3
            },
            "park.events": {
                "complete": false,
                "createIndexes": 2
            },
            "sensors.temperatureLogs": {
                "complete": true,
                "createIndexes": 1
            }
        },
        "phase": "copying indexes",
        "stage": "initial sync"
    }

  Each key in the ``details`` document is the name of a MongoDB collection that
  is being copied. Within each of these documents, we have the following fields:

  + ``complete`` (boolean): Whether all work copying indexes on this collection
    is done.
  + ``createIndexes`` (number): The number of indexes that have been or will be
    created.

* This is an example response during oplog tailing::

    {
        "details": {
            "currentTimestamp": 6375221159490749088,
            "latestTimestamp": 6375221176670620325
        },
        "phase": "applying oplog entries",
        "stage": "oplog sync"
    }

  ``details.currentTimestamp`` shows the BSON timestamp value of the oplog entry
  that was most recently processed by
  ``mongomirror``. ``details.latestTimestamp`` provides the BSON timestamp value
  of the newest oplog entry available on the source deployment. ``mongomirror``
  only refreshes its view of these data once every 10 seconds (it does not
  refresh on each request), so be aware that ``mongomirror`` may be slightly
  further ahead of these times.

* This is an example response after an unrecoverable error::

    {
        "errorMessage": "error creating collection zoo.animals: Collection
    already exists. Please ensure the destination is empty or run mongomirror
    with --drop.",
        "phase": "copying initial data",
        "stage": "initial sync"
    }

  Above, we see that the error message is reported in the ``errorMessage``
  field, and that the ``phase`` and ``stage`` details are still available, so
  that we know when the error occurred in the process.

Reading Progress in the Log
---------------------------

``mongomirror`` logs its progress for synchronizing initial data and tailing the
oplog to standard output in the terminal. When copying initial data,
``mongomirror`` will show progress copying each collection in the form of a
progress bar (similar to `mongodump
<https://docs.mongodb.com/manual/reference/program/mongodump>`_ and
`mongorestore
<https://docs.mongodb.com/manual/reference/program/mongorestore>`_)::

  2016-12-16T17:54:53.638-0800    [#.......................]  park.events              2179/34184    (6.4%)
  2016-12-16T17:54:53.638-0800    [#############...........]  zoo.animals              29000/49778  (58.3%)
  2016-12-16T17:54:53.638-0800    [######..................]  park.dailyReport         13000/49926  (26.0%)
  2016-12-16T17:54:53.638-0800    [........................]  sensors.temperatureLogs  1000/119226   (0.8%)

While tailing the oplog, ``mongomirror`` measures its progress in terms of how
far behind the last processed oplog entry is from the most recent one available
on the source, in seconds. This is called the *lag time*. For example::

  2016-12-16T17:56:17.027-0800    Current lag from source: 6s

This means that the last oplog entry ``mongomirror`` processed was 6 seconds
behind the most recent one available. Note that the amount of time it takes
``mongomirror`` to catch up completely may be greater or lesser than 6 seconds,
depending on how many entries arrive per second.

When ``mongomirror`` reports a lag time of *0 seconds*, this means that
``mongomirror`` is processing entries that arrived less than one second before
the latest oplog entry.

If there were no incoming oplog entries the entire time ``mongomirror`` was
running, ``mongomirror`` will log the following message::

  2017-02-01T11:28:35.503-0800    Waiting for new oplog entries to apply.
