Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BF08A1891B for ; Mon, 16 Nov 2015 12:16:16 +0000 (UTC) Received: (qmail 44325 invoked by uid 500); 16 Nov 2015 12:16:16 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 44280 invoked by uid 500); 16 Nov 2015 12:16:16 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 44271 invoked by uid 99); 16 Nov 2015 12:16:16 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 16 Nov 2015 12:16:16 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7D845E009E; Mon, 16 Nov 2015 12:16:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: garren@apache.org To: commits@couchdb.apache.org Message-Id: <785205a1986642438d6f4069f38b34fe@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: couchdb-nmo git commit: Replication Date: Mon, 16 Nov 2015 12:16:16 +0000 (UTC) Repository: couchdb-nmo Updated Branches: refs/heads/master f29ee61d7 -> 532cd6eb1 Replication This adds `replicate-from` and `replicate-to`. Replication to and from a cluster to another CouchDB instance. Project: http://git-wip-us.apache.org/repos/asf/couchdb-nmo/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-nmo/commit/532cd6eb Tree: http://git-wip-us.apache.org/repos/asf/couchdb-nmo/tree/532cd6eb Diff: http://git-wip-us.apache.org/repos/asf/couchdb-nmo/diff/532cd6eb Branch: refs/heads/master Commit: 532cd6eb11f41f1e9ff6adb8d10ea1d7df2efe65 Parents: f29ee61 Author: Garren Smith Authored: Mon Oct 26 16:03:43 2015 +0200 Committer: Garren Smith Committed: Mon Nov 16 14:14:44 2015 +0200 ---------------------------------------------------------------------- doc/api/nmo-replicate-from.md | 11 +++++ doc/api/replicate-to.md | 11 +++++ doc/cli/nmo-replicate-from.md | 24 ++++++++++ doc/cli/nmo-replicate-to.md | 24 ++++++++++ src/nmo.js | 4 +- src/replicate-from.js | 49 ++++++++++++++++++++ src/replicate-to.js | 49 ++++++++++++++++++++ src/replicate.js | 21 +++++++++ test/replicate-from.js | 91 ++++++++++++++++++++++++++++++++++++++ test/replicate-to.js | 91 ++++++++++++++++++++++++++++++++++++++ test/replicate.js | 74 +++++++++++++++++++++++++++++++ 11 files changed, 448 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/doc/api/nmo-replicate-from.md ---------------------------------------------------------------------- diff --git a/doc/api/nmo-replicate-from.md b/doc/api/nmo-replicate-from.md new file mode 100644 index 0000000..126e28a --- /dev/null +++ b/doc/api/nmo-replicate-from.md @@ -0,0 +1,11 @@ +nmo-replicatefrom(3) -- replicate-from +============================== + +## SYNOPSIS + + nmo.commands.replicatefrom([ || ], database, url) + + +## DESCRIPTION + +Replicate the database from the supplied cluster or cluster url to the given url. http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/doc/api/replicate-to.md ---------------------------------------------------------------------- diff --git a/doc/api/replicate-to.md b/doc/api/replicate-to.md new file mode 100644 index 0000000..41b3dee --- /dev/null +++ b/doc/api/replicate-to.md @@ -0,0 +1,11 @@ +nmo-replicateto(3) -- replicate-to +============================== + +## SYNOPSIS + + nmo.commands.replicateto([ || ], database, url) + + +## DESCRIPTION + +Replicate the database at `url` to the supplied cluster or cluster url and database. http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/doc/cli/nmo-replicate-from.md ---------------------------------------------------------------------- diff --git a/doc/cli/nmo-replicate-from.md b/doc/cli/nmo-replicate-from.md new file mode 100644 index 0000000..57fd903 --- /dev/null +++ b/doc/cli/nmo-replicate-from.md @@ -0,0 +1,24 @@ +nmo-replicate-from(1) -- replicate a database from the cluster to another CouchDB database url +=========================================== + +## SYNOPSIS + + nmo replicate-from [--continuous] [--create-target] [--json] + nmo replicate-from [--continuous] [--create-target] [--json] + + +## DESCRIPTION + +Replicate a database from the `cluster` to the supplied CouchDB instance url and database. Or it will replicate from a CouchDB url and database to the supplied CouchDB instance url and database. + + +Example: + +This will replicate the database `hello-database` from the cluster `mycluster` to the supplied url + nmo replicate-from mycluster hello-database http://192.0.0.1/hello-database-replicated + +This will replicate the database `hello-database` from the cluster `mycluster` to the supplied url and create the target and make it a continuous replication + nmo replicate-from mycluster hello-database http://192.0.0.1/hello-database-replicated --create-target --continuous + +This will replicate the database `hello-database` from the url `http://my-couchdb-cluster.com` to the supplied url + nmo replicate-from http://my-couchdb-cluster.com hello-database http://192.0.0.1/hello-database-replicated http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/doc/cli/nmo-replicate-to.md ---------------------------------------------------------------------- diff --git a/doc/cli/nmo-replicate-to.md b/doc/cli/nmo-replicate-to.md new file mode 100644 index 0000000..9549eb3 --- /dev/null +++ b/doc/cli/nmo-replicate-to.md @@ -0,0 +1,24 @@ +nmo-replicate-to(1) -- replicate a database to the cluster from another CouchDB database url +=========================================== + +## SYNOPSIS + + nmo replicate-to [--continuous] [--create-target] [--json] + nmo replicate-to [--continuous] [--create-target] [--json] + + +## DESCRIPTION + +Replicate a database to the `cluster` from the supplied CouchDB instance url and database. Or it will replicate from a CouchDB url and database to the supplied CouchDB instance url and database. + + +Example: + +This will replicate the database `hello-database` from the url to database `hlloe-database-replicated` in cluster `mycluster`. + nmo replicate-to mycluster hello-database-replicated http://192.0.0.1/hello-database + +This will replicate the database `hello-database` to the cluster `mycluster` and create the database and make it a continuous replication + nmo replicate-to mycluster hello-database-replicated http://192.0.0.1/hello-database --create-target --continuous + +This will replicate the database `hello-database` to the url `http://my-couchdb-cluster.com` from the supplied url + nmo replicate-to http://my-couchdb-cluster hello-database-replicated http://192.0.0.1/hello-database http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/src/nmo.js ---------------------------------------------------------------------- diff --git a/src/nmo.js b/src/nmo.js index 6b76095..978f236 100644 --- a/src/nmo.js +++ b/src/nmo.js @@ -15,7 +15,9 @@ const commands = [ 'import-csv', 'couch-config', 'activetasks', - 'savetofile' + 'savetofile', + 'replicate-from', + 'replicate-to' ]; const nmo = { http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/src/replicate-from.js ---------------------------------------------------------------------- diff --git a/src/replicate-from.js b/src/replicate-from.js new file mode 100644 index 0000000..704176c --- /dev/null +++ b/src/replicate-from.js @@ -0,0 +1,49 @@ +import nmo from './nmo.js'; +import Promise from 'bluebird'; +import { getUrlFromCluster } from './utils'; +import {replicate, createReplicatorDoc } from './replicate'; + + +export function cli (cluster, dbname, url) { + return new Promise((resolve, reject) => { + if (!cluster || !dbname || !url) { + const msg = [ + 'Usage:', + '', + 'nmo replicate-from [--continuous] [--create-target] [--json]', + 'nmo replicate-from [--continuous] [--create-target] [--json]', + ].join('\n'); + + const err = new Error(msg); + err.type = 'EUSAGE'; + return reject(err); + } + + replicateFrom(cluster, dbname, url) + .then(resp => { + console.log('Replication started.'); + resolve(resp); + }) + .catch(err => { + err.type = 'EUSAGE'; + reject(err); + }); + }); +} + +export default function replicateFrom(cluster, dbname, url) { + return new Promise((resolve, reject) => { + const clusterUrl = getUrlFromCluster(cluster); + const replicatorUrl = clusterUrl + '/_replicator'; + const dbUrl = clusterUrl + '/' + dbname; + + const replicator = createReplicatorDoc(dbUrl, url, { + continuous: !!nmo.config.get('continuous'), + create_target: !!nmo.config.get('create-target') + }); + + replicate(replicatorUrl, replicator) + .then(resolve) + .catch(reject); + }); +} http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/src/replicate-to.js ---------------------------------------------------------------------- diff --git a/src/replicate-to.js b/src/replicate-to.js new file mode 100644 index 0000000..5cc567c --- /dev/null +++ b/src/replicate-to.js @@ -0,0 +1,49 @@ +import nmo from './nmo.js'; +import Promise from 'bluebird'; +import { getUrlFromCluster } from './utils'; +import {replicate, createReplicatorDoc } from './replicate'; + + +export function cli (cluster, dbname, url) { + return new Promise((resolve, reject) => { + if (!cluster || !dbname || !url) { + const msg = [ + 'Usage:', + '', + 'nmo replicate-to [--continuous] [--create-target] [--json]', + 'nmo replicate-to [--continuous] [--create-target] [--json]', + ].join('\n'); + + const err = new Error(msg); + err.type = 'EUSAGE'; + return reject(err); + } + + replicateto(cluster, dbname, url) + .then(resp => { + console.log('Replication started.'); + resolve(resp); + }) + .catch(err => { + err.type = 'EUSAGE'; + reject(err); + }); + }); +} + +export default function replicateto(cluster, dbname, url) { + return new Promise((resolve, reject) => { + const clusterUrl = getUrlFromCluster(cluster); + const replicatorUrl = clusterUrl + '/_replicator'; + const dbUrl = clusterUrl + '/' + dbname; + + const replicator = createReplicatorDoc(url, dbUrl, { + continuous: !!nmo.config.get('continuous'), + 'create_target': !!nmo.config.get('create-target') + }); + + replicate(replicatorUrl, replicator) + .then(resolve) + .catch(reject); + }); +} http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/src/replicate.js ---------------------------------------------------------------------- diff --git a/src/replicate.js b/src/replicate.js new file mode 100644 index 0000000..b89c8d3 --- /dev/null +++ b/src/replicate.js @@ -0,0 +1,21 @@ +import { sendJsonToNode } from './utils'; + + +export function createReplicatorDoc (source, target, options) { + return { + source: { + url: source + }, + + target: { + url: target + }, + + continuous: options.continuous, + 'create_target': options.create_target + }; +} + +export function replicate (replicatorUrl, doc) { + return sendJsonToNode(replicatorUrl, doc); +} http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/test/replicate-from.js ---------------------------------------------------------------------- diff --git a/test/replicate-from.js b/test/replicate-from.js new file mode 100644 index 0000000..9504bb8 --- /dev/null +++ b/test/replicate-from.js @@ -0,0 +1,91 @@ +import assert from 'assert'; +import Lab from 'lab'; + +import { cli } from '../src/replicate-from.js'; + +import * as common from './common.js'; +import nmo from '../src/nmo.js'; + +import nock from 'nock'; + +export let lab = Lab.script(); +const oldConsole = console.log; +const nmoconf = {nmoconf: __dirname + '/fixtures/randomini'}; + +common.createConfigFile(); + +lab.experiment('replicate-from', () => { + + lab.experiment('cli', () => { + lab.beforeEach((done) => { + nmo + .load(nmoconf) + .then(() => done()) + .catch(() => done()); + + }); + + lab.afterEach((done) => { + console.log = oldConsole; + done(); + }); + + lab.test('returns error on no value provided', done => { + cli() + .catch((err) => { + assert.ok(err instanceof Error); + done(); + }); + }); + + lab.test('replicates db given cluster details', done => { + const doc = { + 'source':{ + 'url':'http://127.0.0.1/mydb' + }, + 'target':{ + 'url':'https://target-repl.com/new-db' + }, + 'continuous':false, + 'create_target':false + }; + + nock('http://127.0.0.1') + .post('/_replicator', doc) + .reply(200, {ok: true, id: '123', rev: '123'}); + + cli('clusterone', 'mydb', 'https://target-repl.com/new-db') + .then(resp => { + assert.ok(resp.ok); + done(); + }); + }); + + lab.test('replicates db given cluster details with continuous and create_target', done => { + nmo + .load({nmoconf: __dirname + '/fixtures/randomini', 'create-target': true, continuous: true}) + .then(() => { + const doc = { + 'source':{ + 'url':'http://127.0.0.1/mydb' + }, + 'target':{ + 'url':'https://target-repl.com/new-db' + }, + 'continuous':true, + 'create_target':true + }; + + nock('http://127.0.0.1') + .post('/_replicator', doc) + .reply(200, {ok: true, id: '123', rev: '123'}); + + cli('clusterone', 'mydb', 'https://target-repl.com/new-db') + .then(resp => { + assert.ok(resp.ok); + done(); + }); + }); + }); + }); +}); http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/test/replicate-to.js ---------------------------------------------------------------------- diff --git a/test/replicate-to.js b/test/replicate-to.js new file mode 100644 index 0000000..7872580 --- /dev/null +++ b/test/replicate-to.js @@ -0,0 +1,91 @@ +import assert from 'assert'; +import Lab from 'lab'; + +import { cli } from '../src/replicate-to.js'; + +import * as common from './common.js'; +import nmo from '../src/nmo.js'; + +import nock from 'nock'; + +export let lab = Lab.script(); +const oldConsole = console.log; +const nmoconf = {nmoconf: __dirname + '/fixtures/randomini'}; + +common.createConfigFile(); + +lab.experiment('replicate-to', () => { + + lab.experiment('cli', () => { + lab.beforeEach((done) => { + nmo + .load(nmoconf) + .then(() => done()) + .catch(() => done()); + + }); + + lab.afterEach((done) => { + console.log = oldConsole; + done(); + }); + + lab.test('returns error on no value provided', done => { + cli() + .catch((err) => { + assert.ok(err instanceof Error); + done(); + }); + }); + + lab.test('replicates db given cluster details', done => { + const doc = { + 'target':{ + 'url':'http://127.0.0.1/mydb' + }, + 'source':{ + 'url':'https://target-repl.com/new-db' + }, + 'continuous':false, + 'create_target':false + }; + + nock('http://127.0.0.1') + .post('/_replicator', doc) + .reply(200, {ok: true, id: '123', rev: '123'}); + + cli('clusterone', 'mydb', 'https://target-repl.com/new-db') + .then(resp => { + assert.ok(resp.ok); + done(); + }); + }); + + lab.test('replicates db given cluster details with continuous and create_target', done => { + nmo + .load({nmoconf: __dirname + '/fixtures/randomini', 'create-target': true, continuous: true}) + .then(() => { + const doc = { + 'target':{ + 'url':'http://127.0.0.1/mydb' + }, + 'source':{ + 'url':'https://target-repl.com/new-db' + }, + 'continuous':true, + 'create_target':true + }; + + nock('http://127.0.0.1') + .post('/_replicator', doc) + .reply(200, {ok: true, id: '123', rev: '123'}); + + cli('clusterone', 'mydb', 'https://target-repl.com/new-db') + .then(resp => { + assert.ok(resp.ok); + done(); + }); + }); + }); + }); +}); http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/532cd6eb/test/replicate.js ---------------------------------------------------------------------- diff --git a/test/replicate.js b/test/replicate.js new file mode 100644 index 0000000..013c124 --- /dev/null +++ b/test/replicate.js @@ -0,0 +1,74 @@ +import assert from 'assert'; +import Lab from 'lab'; +import nock from 'nock'; + +import {createReplicatorDoc, replicate} from '../src/replicate.js'; +export let lab = Lab.script(); + + +lab.experiment('replicate', () => { + + lab.experiment('createReplicatorDoc', () => { + lab.test('creates correctly defined doc', (done) => { + var doc = createReplicatorDoc('source-url', 'target-url', {continuous: true, 'create_target': true}); + + assert.deepEqual({ + source: { + url: 'source-url' + }, + + target: { + url: 'target-url' + }, + continuous: true, + 'create_target': true + }, doc); + + done(); + }); + }); + + lab.experiment('replicate', () => { + + lab.it('returns json response', done => { + var data = {ok: true}; + var payload = { + source: { + url: 'source-url' + }, + + target: { + url: 'target-url' + }, + continuous: true, + 'create_target': true + }; + + nock('http://127.0.0.1') + .post('/_replicator') + .reply(200, data); + + replicate('http://127.0.0.1/_replicator', payload) + .then(resp => { + assert.deepEqual(resp, data); + done(); + }); + + + }); + + lab.it('returns error on failed replication', done => { + nock('http://127.0.0.1') + .post('/_replicator') + .reply(500, {reason: 'ERROR'}); + + replicate('http://127.0.0.1/_replicator', {}) + .catch(err => { + assert.deepEqual(err.type, 'EUSAGE'); + done(); + }); + + }); + + }); +});