Custom plugins for Db2 Mirror using IBM Administration Runtime Expert for i
Custom plugin is an interface of IBM® Administration Runtime Expert for i (ARE). It’s flexible because you can customize a plugin to your specifications. This makes it suitable for handling Db2® Mirror pre-clone and post-clone configuration requirements.
The Db2 Mirror clone or reclone process results in some configuration information copied from the setup source node that is not correct for the setup copy node. Configuration files need to be updated to contain the values required on the setup copy node. These configuration files can include system defined entities like TCP/IP host table entries, RDB entries, and job scheduler entries. User created entities could also be affected, such as web servers or other applications where the host name or other node-centric details may be stored in an application configuration file. ARE provides an automated ability to handle these setup copy node updates. There is a Db2 Mirror custom plugin for ARE that you can update and build. It is called during the clone process.
You will need to install the 5733ARE product on one partition, preferably on the managing node for Db2 Mirror. The ARE GUI interface is used to build your Db2 Mirror customized plugins into an ARE template. The ARE template is what is run as part of the clone process.
The plugins will be called by Db2 Mirror during the cloning process, both pre-clone and post-clone. This will happen whether you are running the clone through the GUI or using the db2mtool commands. If you write the plugins and build the template, the plugins will be called automatically.
You can access the customized Db2 Mirror template from the ARE ftp server: ftp://public.dhe.ibm.com/systems/i/are.
Writing a Db2 Mirror custom plugin
For background and more details on writing ARE custom plugins, refer to public.dhe.ibm.com/systems/i/are/systems_i_are_writing_custom_plugins.pdf.
For a Db2 Mirror custom plugin, you need to extend the Java™ class com.ibm.are.plugin.MirrorPlugin.
The MirrorPlugin class contains the AS400 object of the setup source node and setup copy node. During pre-clone, you could perform some clean up jobs on the setup source node or backups of the system configuration on the setup copy node. At post-clone time, you could restore the configuration settings that are needed for the setup copy node. The usage scenario determines which partition the plugin will be running on.
Required parameters
- custStage supports values for four stages:
- PRE_CLONE
- before the clone of SYSBAS
- POST_CLONE
- after the clone of SYSBAS
- PRE_IASP_CLONE
- before the clone of an IASP
- POST_IASP_CLONE
- after the clone of an IASP
- custRmtSys supports values for two nodes:
- SOURCE
- setup source node
- COPY
- setup copy node
public MirrorCustomPlugin() {
this.custStage = MirrorPlugin.POST_CLONE;
this.custRmtSys = MirrorPlugin.COPY;
}
@Override
public String getCommonName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return null;
}
@Override
protected Version initPluginVersion() {
// TODO Auto-generated method stub
return null;
}
@Override
ResultInfo CustomProcess() {
// TODO Auto-generated method stub
return null;
}
AS400 localSystem = IBMi.getAS400();
Adding a plugin to the Db2 Mirror template
An ARE template is required to deploy the custom plugin. The template operations require using the ARE console that is in product 5733ARE. You can access the ARE console using http://hostname:12401/are. Sign in with your IBM i user profile and password.
Create a template named plugin4mirror as shown here.

Open the Advanced section and click on the Custom Plugins option. Then click Build template as shown below to prepare your Db2 Mirror plug in.

After the template is built successfully, you will need to export the template and upload the jar file to the managing node that will be running the Db2 Mirror tools. Upload the file to the directory /QIBM/ProdData/QDB2MIR/MRDB/TOOLS/plugin4mirror.jar.
Note: The directory and jar file name must be exactly as shown, so that the plugin will be recognized and processed by the Db2 Mirror configuration tools.
For information on templates, refer to https://www-01.ibm.com/support/docview.wss?uid=isg3T1027249.
Db2 Mirror template
For Db2 Mirror tools to make use of your plugin, it needs to be added to the Db2 Mirror ARE template, called plugin4mirror. There is only one template for Db2 Mirror. Many custom plugins can be added to that template. Each component or LPP requiring a custom plugin must be added to the same Db2 Mirror deployment template.
Example: A full Db2 Mirror custom plugin
- Save the host table entries from the setup copy node before cloning is performed
- Restore the host table entries to the setup copy node after the clone is finished
Back up the host table entries pre-clone:
package com.ibm.are.mirror;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.ibm.are.common.Version;
import com.ibm.are.platform.impl.IBMi;
import com.ibm.are.plugin.MirrorPlugin;
import com.ibm.are.plugin.ResultInfo;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.IFSFile;
import com.ibm.as400.access.IFSFileInputStream;
import com.ibm.as400.access.IFSFileOutputStream;
public class HostTablePre extends MirrorPlugin {
private static final String HOST_TABLE_FILE_NAME = "/QIBM/USERDATA/OS400/TCPIP/QTOCHOSTS";
private static final String ARE_TEMP_DIR = "/QIBM/PRODDATA/ARE/TEMP";
private static final String ARE_TEMP_HOST_TABLE_FILE = "/QIBM/PRODDATA/ARE/TEMP/QTOCHOSTS";
public HostTablePre() {
//specify the plugin is to run before the clone on the setup copy node
this.custRmtSys = MirrorPlugin.COPY;
this.custStage = MirrorPlugin.PRE_CLONE;
}
@Override
public String getCommonName() {
return "HostTablePre";
}
@Override
public String getDescription() {
return "Pre process for Host Table Entry";
}
@Override
protected Version initPluginVersion() {
return new Version(1, 0, 0);
}
@Override
protected ResultInfo CustomProcess() {
AS400 localAS400 = IBMi.getAS400();
AS400 remoteAS400 = this.cpySysObj;
boolean retVal = false;
try {
retVal = preClone(localAS400, remoteAS400);
} catch(Exception e) {
e.printStackTrace();
reportError("Exception: " + e.getMessage());//method reportError could log the error message
}
return new ResultInfo(retVal);
}
private boolean preClone(AS400 localSystem, AS400 targetSystem) throws Exception {
IFSFile areTempDir = new IFSFile(localSystem, ARE_TEMP_DIR);
if(!areTempDir.exists()) {//if /QIBM/PRODDATR/ARE/TEMP not exists, create the directory
areTempDir.mkdirs();
}
IFSFile tempHostTable = new IFSFile(localSystem, ARE_TEMP_HOST_TABLE_FILE);
if(tempHostTable.exists()) {//if /QIBM/PRODDATR/ARE/TEMP/QTOCHOSTS exists, delete the file
tempHostTable.delete();
}
tempHostTable.createNewFile();//create a new QTOCHOSTS file
IFSFileInputStream inStream = new IFSFileInputStream(
new IFSFile(targetSystem, HOST_TABLE_FILE_NAME));
IFSFileOutputStream outStream = new IFSFileOutputStream(
new IFSFile(localSystem, ARE_TEMP_HOST_TABLE_FILE));
streamXfer(inStream, outStream);
inStream.close();
outStream.close();
return true;
}
private static void streamXfer(final InputStream in, final OutputStream out) throws IOException {
final BufferedInputStream b_in = new BufferedInputStream(in);
final BufferedOutputStream b_out = new BufferedOutputStream(out);
final byte [] buf = new byte[8 * 1024];
int bytesRead = 0;
while (-1 != (bytesRead = b_in.read(buf))) {
b_out.write(buf, 0, bytesRead);
}
b_out.flush();
}
}
Restore the host table entries post-clone
package com.ibm.are.mirror;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import com.ibm.are.common.Version;
import com.ibm.are.plugin.MirrorPlugin;
import com.ibm.are.plugin.ResultInfo;
import com.ibm.as400.access.AS400Message;
import com.ibm.as400.access.CommandCall;
public class HostTablePost extends MirrorPlugin {
private static final String ARE_TEMP_HOST_TABLE_FILE = "/QIBM/PRODDATA/ARE/TEMP/QTOCHOSTS";
public HostTablePost() {
//specify the plugin is to run after the clone on the setup copy node
this.custStage = MirrorPlugin.POST_CLONE;
}
@Override
public String getCommonName() {
return "HostTablePost";
}
@Override
public String getDescription() {
return "Post process for Host Table Entry";
}
@Override
protected Version initPluginVersion() {
return new Version(1, 0, 0);
}
@Override
protected ResultInfo CustomProcess() {
boolean retVal = true;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(new File(ARE_TEMP_HOST_TABLE_FILE))));
String line = null;
while((line=reader.readLine()) != null) {
if(!line.contains("::1") && !line.contains("127.0.0.1")) {
retVal &= addTCPHostEntry(line);
}
}
reader.close();
} catch(Exception e) {
e.printStackTrace();
reportError("Exception: " + e.getMessage());//method reportError could log the error message
}
return new ResultInfo(retVal);
}
private boolean addTCPHostEntry(String line) throws Exception {
//example: 123.123.123.123 HOSTNAME1 HOSTNAME2 HOSTNAME3 # DESCRIPTION
boolean retVal = true;
String[] para = line.split(" ");
if(para.length > 2) { //at least there are two strings, IP and hostname
String IP = para[0];
String description = null;
String hostname = " ";
if(line.contains("#")) {
description = line.substring(line.indexOf("#")+2);
}
for(int i=1; i<para.length; i++) {
if(para[i].equals("#")) {
break;
}
hostname += "(" + para[i] + ") ";
}
String command = "ADDTCPHTE INTNETADR('" + IP + "') HOSTNAME(" + hostname.trim() + ")";
if(description != null) {
command += " TEXT('" + description + "')";
}
reporter.reportInfo("Adding host entry: " + command);
CommandCall cmdCall = new CommandCall(this.cpySysObj, command);
if(!cmdCall.run()) {
AS400Message[] list = cmdCall.getMessageList();
for(AS400Message msg : list) {
if(!msg.getID().equalsIgnoreCase("TCP1904")) {//ip already exists
reporter.reportError(msg.toString());
retVal = false;
}
}
}
}
return retVal;
}
}