web stats
Programatically Backup to Standby Server - Mirth Community

Go Back   Mirth Community > Mirth Connect > Support

Reply
 
Thread Tools Display Modes
  #1  
Old 02-21-2018, 08:23 AM
ccitrano@tangible.com ccitrano@tangible.com is offline
OBX.3 Kenobi
 
Join Date: Apr 2008
Posts: 122
ccitrano@tangible.com
Default Programatically Backup to Standby Server

Hello,

What is the best way to programatically (once a day or twice a day) export everything about a Mirth setup (channels, code templates, settings) and import them into another Mirth server.

I don't want a clone, i.e. same Server Name, but rather just a standby server in another location that I can bring online in a pinch.

The goal would be to work on the Primary Server and have everything automatically moved to the other server.

If you can make recommendations on the best simplest strategy, I can take it from there.

Cheers.
Chuck.
__________________
Chuck Citrano
ccitrano at tangible.com
[url][/http://www.tangible.comurl]
Reply With Quote
  #2  
Old 02-21-2018, 10:54 PM
odo odo is offline
OBX.3 Kenobi
 
Join Date: Feb 2017
Location: Luxembourg
Posts: 137
odo is on a distinguished road
Default

This shouldn't be a big deal. Create a channel or code template with the following code:
  1. Build a client instance for the production server
  2. Build a client instance for the backup server
  3. Obtain the configuration from the production server (use function getServerConfiguration())
  4. Send the production configuration to the backup server (use function setServerConfiguration())

Here is a code template that should accomplish this task. It is however quickly assembled and not tested. Thus it might contain bugs (let me know if so):
Code:
/**
	Synchronizes the configuration of a mirth instance to another mirth instance (e.g. production to backup system)

	@param {String} usernameProduction - The username that the channel should use to connect to the production server
	@param {String} passwordProduction - The password that the channel should use to connect to the production server
	@param {String} serverProducution - The ip or name of the production server 
	@param {String} usernameBackup - The username that the channel should use to connect to the backup server
	@param {String} passwordBackup - The password that the channel should use to connect to the backup server
	@param {String} serverBackup - The ip or name of the backup server 
	@param {boolean} deploy - Deploy the synchronized configuration on the backup system (<b>true</b>) or not (<b>false</b>). <i>(Default value is <b>true</b>)</i>
*/
function synchronizeConfiguration(usernameProduction, passwordProduction, serverProducution, usernameBackup, passwordBackup, serverBackup, deploy) {

	logger.info('Initializing synchronization ' + serverProducution + ' ==> ' + serverBackup);
	
	// default behavior is to deploy the updated configuration on the backup server
	deploy = (deploy !== undefined) ? deploy : true;
	
	// create a client instance and initialize it with the production server
	var clientProduction = new com.mirth.connect.client.core.Client('https://' + serverProducution + ':8443');
	// create a client instance and initialize it with the backup server
	var clientBackup = new com.mirth.connect.client.core.Client('https://' + serverBackup + ':8443');

	// log on to the production server
	try{
		var loginStatus = clientProduction.login(usernameProduction, passwordProduction);
	}catch(ex){
		throw 'Unable to log-on the server "' + serverProducution + '" with credentials ' + usernameProduction + '/' + passwordProduction + ' (incompatible mirth version?): ' + ex.message;
	}
	
	// check if login was successful
	if (loginStatus.getStatus() != com.mirth.connect.model.LoginStatus.Status.SUCCESS) {
		logger.error('Unable to log-on the server "' + serverProducution + '" with credentials ' + usernameProduction + '/' + passwordProduction + '(status ' + loginStatus.getStatus() + ')');
		return;
	}
	// log on to the production server
	try{
		var loginStatus = clientProduction.login(usernameBackup, passwordBackup);
	}catch(ex){
		throw 'Unable to log-on the server "' + serverBackup + '" with credentials ' + usernameBackup + '/' + passwordBackup + ' (incompatible mirth version?): ' + ex.message;
	}
	
	// check if login was successful
	if (loginStatus.getStatus() != com.mirth.connect.model.LoginStatus.Status.SUCCESS) {
		logger.error('Unable to log-on the server "' + serverBackup + '" with credentials ' + usernameBackup + '/' + passwordBackup + '(status ' + loginStatus.getStatus() + ')');
		return;
	}
	
	try {
		// get the server configuration
		var configuration = clientProduction.getServerConfiguration();
		// and set it to the backup server
		clientBackup.setServerConfiguration(configuration, deploy);
	} finally{
		// assure that the connections are closed
		try{clientProduction.close();}catch(e){}
		try{clientBackup.close();}catch(e){}
	}
}
Reply With Quote
  #3  
Old 02-22-2018, 03:48 AM
AlexNeiva AlexNeiva is offline
Mirth Guru
 
Join Date: Oct 2013
Location: Portugal
Posts: 277
AlexNeiva is on a distinguished road
Default

Hello,

the approach that @odo publish is very good.
Normally i backup automatically using a windows task.
I just use a .bat file to do it.

Just create a folder, and put the 2 attachments:
  • script_bk.txt (Note: this file has to be in Mirth Connect installation folder)
  • BAT_auto_backup_BAT.txt (Note: is a .bat file, i just put .txt to be able to upload, just change the extension)
and then create a windows task to run the .bar file each time you want.
This is just for backup only... to set up the other server probably need to import manually. Is just a simple and automatic way to backup Mirth without using code inside Mirth.
Attached Files
File Type: txt script_bk.txt (44 Bytes, 6 views)
File Type: txt BAT_auto_backup_BAT.txt (219 Bytes, 7 views)

Last edited by AlexNeiva; 02-22-2018 at 05:17 AM.
Reply With Quote
  #4  
Old 02-22-2018, 06:01 AM
ccitrano@tangible.com ccitrano@tangible.com is offline
OBX.3 Kenobi
 
Join Date: Apr 2008
Posts: 122
ccitrano@tangible.com
Default

Odo,

Thanks a lot. This was what I was looking for. I had to clean up a few things in your code and here is what I currently have.

The one additional step that I'd like to implement is "undeploying" a specific channel after the config is copied and deploy = true.

I have the channel that initiates the backup on my Prod server, and when I send the config to the backup I want everything deployed except for the BackupSync Channel.

Is there anything I can do with the clientBackup object to accomplish this??

Thanks.
Chuck.



Code:
/**
	Synchronizes the configuration of a mirth instance to another mirth instance (e.g. production to backup system)

	@param {String} usernameProduction - The username that the channel should use to connect to the production server
	@param {String} passwordProduction - The password that the channel should use to connect to the production server
	@param {String} serverProduction - The ip or name of the production server 
	@param {String} usernameBackup - The username that the channel should use to connect to the backup server
	@param {String} passwordBackup - The password that the channel should use to connect to the backup server
	@param {String} serverBackup - The ip or name of the backup server 
	@param {boolean} deploy - Deploy the synchronized configuration on the backup system (<b>true</b>) or not (<b>false</b>). <i>(Default value is <b>true</b>)</i>
*/
function synchronizeConfiguration(usernameProduction, passwordProduction, serverProduction, usernameBackup, passwordBackup, serverBackup, deploy) {

	logger.info('Initializing synchronization ' + serverProduction + ' ==> ' + serverBackup);
	
	// default behavior is to deploy the updated configuration on the backup server
	deploy = (deploy !== undefined) ? deploy : true;
	
	// create a client instance and initialize it with the production server
	var clientProduction = new com.mirth.connect.client.core.Client('https://' + serverProduction + ':8443');
	// create a client instance and initialize it with the backup server
	var clientBackup = new com.mirth.connect.client.core.Client('https://' + serverBackup + ':8443');

	// log on to the production server
	try{
		var loginStatus = clientProduction.login(usernameProduction, passwordProduction);
	}catch(ex){
		throw 'Unable to log-on the server "' + serverProducution + '" with credentials ' + usernameProduction + '/' + passwordProduction + ' (incompatible mirth version?): ' + ex.message;
	}
	
	// check if login was successful
	if (loginStatus.getStatus() != com.mirth.connect.model.LoginStatus.Status.SUCCESS) {
		logger.error('Unable to log-on the server "' + serverProducution + '" with credentials ' + usernameProduction + '/' + passwordProduction + '(status ' + loginStatus.getStatus() + ')');
		return;
	}
	// log on to the backup server
	try{
		var loginStatus = clientBackup.login(usernameBackup, passwordBackup);
	}catch(ex){
		throw 'Unable to log-on the server "' + serverBackup + '" with credentials ' + usernameBackup + '/' + passwordBackup + ' (incompatible mirth version?): ' + ex.message;
	}
	
	// check if login was successful
	if (loginStatus.getStatus() != com.mirth.connect.model.LoginStatus.Status.SUCCESS) {
		logger.error('Unable to log-on the server "' + serverBackup + '" with credentials ' + usernameBackup + '/' + passwordBackup + '(status ' + loginStatus.getStatus() + ')');
		return;
	}
	
	try {
		// get the server configuration
		var configuration = clientProduction.getServerConfiguration();
		// and set it to the backup server
		clientBackup.setServerConfiguration(configuration, deploy);
	} finally{
		// assure that the connections are closed
		try{clientProduction.close();}catch(e){}
		try{clientBackup.close();}catch(e){}
	}
}
__________________
Chuck Citrano
ccitrano at tangible.com
[url][/http://www.tangible.comurl]
Reply With Quote
  #5  
Old 02-22-2018, 10:04 PM
odo odo is offline
OBX.3 Kenobi
 
Join Date: Feb 2017
Location: Luxembourg
Posts: 137
odo is on a distinguished road
Default

Quote:
Originally Posted by ccitrano@tangible.com View Post
I have the channel that initiates the backup on my Prod server, and when I send the config to the backup I want everything deployed except for the BackupSync Channel.
Code:
clientBackup.undeployChannel(<channelId>);
Alternatively, you could configure the initial state of the channel to 'Stopped':


Or you stop, respectively undeploy, the channel in the deploy script when it is deployed on the backup-server (check server name or IP)
Attached Images
File Type: jpg InitialStateConfigurtation.jpg (35.2 KB, 27 views)
Reply With Quote
  #6  
Old 02-23-2018, 04:33 AM
ccitrano@tangible.com ccitrano@tangible.com is offline
OBX.3 Kenobi
 
Join Date: Apr 2008
Posts: 122
ccitrano@tangible.com
Default

Odo,

Thanks. I was able to use the undeploy along with setenable to deactivate the channel on the standby server.

At first glance, I'm really happy with this solution and it is helping me bring my backup datacenter to life with ready to go Mirth servers.

I'm going to continue to tweak and learn. The things I need to confirm are:
1. If I'm using a SQL Database as the the datastore, will the the connectionstring info get overwritten? I'm hoping no, as I'm testing with derby right now and the setconfiguration doesn't seem to hit that part. I'm digging through some documentation that Nick R pointed me to and trying to digest the scope of some calls.

2. I have ConfigurationMap variables that I'd like to update as well. These typically will have global information that is datacenter specific. So in a sense, I need to update them, and then stop and start the service.

I'm sure there will be other tweaks, but I think this is a great basis for where I'm going.

Cheers.
Chuck.
__________________
Chuck Citrano
ccitrano at tangible.com
[url][/http://www.tangible.comurl]
Reply With Quote
  #7  
Old 02-23-2018, 08:25 AM
ccitrano@tangible.com ccitrano@tangible.com is offline
OBX.3 Kenobi
 
Join Date: Apr 2008
Posts: 122
ccitrano@tangible.com
Default

All,

ConfigurationMap does not move across using setServerConfiguration(), which probably makes sense.

Tags and Data Pruning settings did move across.

It looks like Users do not move across although the documentation says it should. My testing shows that it didn't. But the setServerConfiguration() does not look like it updates/adds users.

* Returns a ServerConfiguration object which contains all of the channels, users, alerts and
* properties stored on the Mirth Connect server.
*
* @see ConfigurationServletInterface#getServerConfigurati on
*/
public ServerConfiguration getServerConfiguration() throws ClientException {
return getServlet(ConfigurationServletInterface.class).ge tServerConfiguration(null, false);
__________________
Chuck Citrano
ccitrano at tangible.com
[url][/http://www.tangible.comurl]
Reply With Quote
  #8  
Old 02-25-2018, 10:09 PM
odo odo is offline
OBX.3 Kenobi
 
Join Date: Feb 2017
Location: Luxembourg
Posts: 137
odo is on a distinguished road
Default

Quote:
Originally Posted by ccitrano@tangible.com View Post
1. If I'm using a SQL Database as the the datastore, will the the connectionstring info get overwritten?
No. The connection string is configured in an external configuration file (./conf/mirth.properties)

Quote:
Originally Posted by ccitrano@tangible.com View Post
2. I have ConfigurationMap variables that I'd like to update as well. These typically will have global information that is datacenter specific. So in a sense, I need to update them, and then stop and start the service.
The configuration map is not contained in the server configuration. You should be able to transfer the configuration with:

Code:
// fetch the configuration map of the production system
var configurationMap = clientProduction.getConfigurationMap();
// transfer the configuration map to the backup system
// (You are free to manipulate the map content at will before you transfer it)
clientBackup.setConfguruationMap(configurationMap);
Btw. there is no need to restart the service. If you transfer the configuration map before you deploy the channels, everything should be fine.
Quote:
Originally Posted by ccitrano@tangible.com View Post
It looks like Users do not move across although the documentation says it should.
That is true. You can accomplish this via:
  1. production: getAllUsers()
  2. backup: getAllUsers()
  3. backup: removeUser(<userId>) for all backup users
  4. backup: updateUser(<User>) for all production users
Btw. there is a bug in updateUser(Integer userId, User user). The first argument is never used.

Last edited by odo; 02-26-2018 at 12:31 AM.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -8. The time now is 03:46 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Mirth Corporation