Migrating an App Builder or REST API application

Author: Dave Cassel  |  Category: Software Development

In MarkLogic 6, Application Builder has gotten an overhaul. I really like the result — you can now get some interesting charts and maps set up just by clicking through the wizard, and the source code it deploys is easier to work with. There is one aspect that’s a bit tricky, however — migrating the application from one server to another.

I do this a lot. I build an app on my laptop, then deploy it to one or more servers for others to review and use. The first couple times I tried it, the application failed when it made calls back to the server to get search results. The reason turned out to be the way that I had migrated the options for the REST app server.

REST Application Server Configuration

When you use App Builder to create an application, it builds a modules database for the code. Taking a look, we’ll see three things in the root directory: index.html, an /application/ directory, and a directory with a large number for a name.

The large number is the id of the HTTP application server that App Builder created. Inside that directory, you’ll find XML documents containing options that control the REST api search (like /5453550488621052036/rest-api/options/default.xml). The tricky part is that the app server’s id will be different on the server that you’re migrating to.

Migration Procedure

Here’s the procedure that I’ve used successfully.

  1. Export the content database configuration from the original server
  2. Import that configuration on the new server
  3. Copy the content to the new server
  4. Create a REST API app server on the new server, using the content database
  5. Replace the code and REST API config with your code and config from the original server
For the examples below, assume that server1 is the original server and server2 is the new server.

Export the configuration

  • Point your browser to http://server1:8002, the Configuration Manager.
  • Click the Export link
  • Check the box for just your content database (the modules database and your HTTP app server will be created in step 4)
  • Name the package (near the bottom)
  • Click the Download Package button (near the top)

Import the configuration

  • Point your browser to http://server2:8002, the Configuration Manager
  • Click the Import Link
  • Select the package XML file you downloaded in step 1 and click the Upload button
  • The Configuration Manager will read the package and determine what changes need to be made. Click the Apply button to have it create your content database.

Copy the content

Use mlcp to copy the content from the original server to the new one. In this example I’m using the admin user, with password “admin” on both hosts (bad, bad). server1 has an XDBC app server on port 8006 pointing to the old content database, and server2 has an XDBC app server on port 8008 pointing to the new content database. You will probably need to create the XDBC app server on server2.

$ bin/mlcp.sh COPY -input_username admin -input_password admin -input_host server1 \
  -input_port 8006 -output_username admin -output_password admin -output_host server2 \
  -output_port 8008

Create a REST app server

In order to make sure the app server gets initialized correctly, we’ll tell MarkLogic to create a REST API app server. These are basically HTTP app servers with some configuration differences here and there. We can use either of two methods:

  • Use the REST API itself: POST to http://server2:8002/v1/rest-apis
  • Use the App Services GUI: point your browser to http://server2:8000, click on Information Studio, select your content database in the Database drop down, and click the Configure button. On the Database Settings page that comes up, scroll down and you’ll see a button to create a new REST API Instance.

Replace the code and config

Having completed the previous step, you have an HTTP app server set up with the REST API. The process also creates a modules database for the app server. The next step is to copy over the source code and the REST API configuration, both of which will be in a modules database on server1. (Of course, you also have them in git or something, right?)

We can use mlcp again to copy the modules database contents. To do so, you can either set up new XDBC app servers pointing to the modules databases, or you can change the ones you used in step 3 to point to the modules databases instead of the content. If you take the latter approach, then the command is the same as above:

$ bin/mlcp.sh COPY -input_username admin -input_password admin -input_host server1 \
  -input_port 8006 -output_username admin -output_password admin -output_host server2 \
  -output_port 8008

You could also use XQSync, in which case you can use the connection string to specify the target database (mlcp doesn’t allow that option currently).

Moving the REST API Options

Here’s an important step, and an easy one to miss: you need to change the URIs of the REST API options documents, or the new app server won’t see them. Your old app server had the options under its app server id; now you need to move it under the new app server’s id. Start by finding the app server ids.

In Query Console (http://server2:8000/qconsole), set the Content Source to your modules database and run this:

cts:uri-match("*rest-api*")

You’ll see a bunch of URIs that start with /<appserver id>/rest-api/…. Actually, you’ll see two app server IDs represented, the old (here because you copied code and options into this modules database) and the new (here because creating a REST API app server creates a rest-api/options/all.xml). Find the old app server’s id, copy it into the script below as the $old-id. Also change $new-appserver-name to the name of the app server you created in step 4, above. Set the Content Source to your modules database and run this:

import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
let $old-id := "5453550488621052036"
let $new-appserver-name := "test2"
let $config := admin:get-configuration()
let $new-id :=
  xs:string(admin:appserver-get-id(
    $config, 
    admin:group-get-id($config, "Default"),
   $new-appserver-name))
for $uri in cts:uri-match("/" || $old-id || "*.xml")
return (
  xdmp:document-insert(
    fn:replace($uri, $old-id, $new-id),
    fn:doc($uri),
    xdmp:document-get-permissions($uri),
    xdmp:document-get-collections($uri),
    xdmp:document-get-quality($uri)),
  xdmp:document-delete($uri)
)

This will move your options XML files under the new appserver id. You can verify that it worked by running the

cts:uri-match("*rest-api*")

command in Query Console again. You should see all the XML files under the new app server’s id.

Long Term

I’ve talked to some people in Engineering about how to make this easier. Paxton & I are also looking at using Roxy to simplify the process. In the meantime, following this procedure will get you there.

Tags: , , ,

Leave a Reply