Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Camel OpenStack Component

DZone's Guide to

Camel OpenStack Component

In this post, we look at how to integrate two interesting technologies: Apache Camel and the OpenStack cloud platform. Let's get to it!

· Integration Zone ·
Free Resource

The State of API Integration 2018: Get Cloud Elements’ report for the most comprehensive breakdown of the API integration industry’s past, present, and future.

1.0 Overview

Integration. We need to integrate applications through different APIs and protocols. It does not seem to be a difficult thing but modern technologies are based on different programming languages, use different protocols for communication, and have a lot of other differences. The consequence is that these systems don’t have a common language for communication. This is the main purpose of integration frameworks which are designed to solve these problems. One of this frameworks is Apache Camel.

The second aspect of modern deployment is cloud computing. One of the cloud computing platforms is OpenStack. This system provides us with an Infrastructure as a Service (IaaS) cloud. 

The main purpose of the Camel OpenStack component is to provide integration of Apache Camel with OpenStack system.

2.0 Apache Camel

Apache Camel is a Java-based, open source integration framework which supports most of the Enterprise Integration Patterns (EIP).

The configuration of Camel is really easy. You just specify the “path” where you want to send your data. This path is called the route. You can use a bunch of languages such as XML, Scala DSL, Java DSL etc.

For more information about Camel see:

3.0 Camel OpenStack Component

Camel OpenStack is built on the top of the OpenStack4j library and provides the basic functionality of the OpenStack system for Camel users.

This component is divided into six subcomponents. Each subcomponent focuses on one OpenStack component:

OpenStack Cinder

openstack-cinder

Component to maintain OpenStack Cinder.

OpenStack Glance

openstack-glance

Component to maintain OpenStack Glance.

OpenStack Keystone

openstack-keystone

Component to maintain OpenStack Keystone.

OpenStack Neutron

openstack-neutron

Component to maintain OpenStack Neutron.

OpenStack Nova

openstack-nova

Component to maintain OpenStack Nova.

OpenStack Swift

openstack-swift

Component to maintain OpenStack Swift.

4.0 Usage

Our use case will be very simple. We will create two new OpenStack slaves and perform some command on them using a camel-ssh component. Let’s start.

First of all, we need to create new Maven project. We can use the prepared maven-archetype for our camel-java project to simplify this step.Image title

Open your IDE and import it as a Maven project.

Add camel-ssh and camel-openstack dependencies to the pom.xml file.

Image title

Now, create your OpenStack nodes configuration. We will load it from the files located in src/data folder. Next, remove all existing files from this directory and create two new files:

node1.xml

<?xml version="1.0" encoding="UTF-8"?>
<node>
  <name>node1</name>
  <flavorId>SUBSTITUTE WITH FLAVOR ID</flavorId>
  <imageId>SUBSTITUTE WITH IMAGE ID</imageId>
</node>

node2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<node>
  <name>node2</name>
  <flavorId>SUBSTITUTE WITH FLAVOR ID</flavorId>
  <imageId>SUBSTITUTE WITH IMAGE ID</imageId>
</node>

Note: do not forget to substitute imageId and flaworId values

Open the MyRouteBuilder class and insert following code:

package org.apache.camel.openstack;

import org.apache.camel.builder.RouteBuilder;

/**
 * A Camel Java DSL Router
 */
public class MyRouteBuilder extends RouteBuilder {

public static final String OPENSTACK_ENDPOINT = "http://openstack-host:5000/v3";
public static final String OPENSTACK_PASSWORD = "nomoresecret";
public static final String OPENSTACK_USER = "admin";
public static final String OPENSTACK_PROJECT_ID = "projectId";

/**
 * Let's configure the Camel routing rules using Java code...
 */
public void configure() {

// this route gets configuration from file resources
// see files in src/data
from("file:src/data")

// set required headers
.setHeader("operation", constant("create"))
.setHeader("name", xpath("/node/name/text()"))
.setHeader("FlavorId", xpath("/node/flavorId/text()"))
.setHeader("ImageId", xpath("/node/imageId/text()"))

// create servers
.to("openstack-nova://" + OPENSTACK_ENDPOINT + "?password=" + OPENSTACK_PASSWORD + "&username="
+ OPENSTACK_USER + "&project=" + OPENSTACK_PROJECT_ID + "&subsystem=servers");

}
}

Substitute OPENSTACK_ENDPOINT, PASSWORD, USER, and PROJECT_ID with the correct values.

That's it. You can run the code and Camel will create two new slaves in your OpenStack deployment.

But you can't connect to your slaves unless you provide them with public "floating IP addresses." So how can you do this in Camel? Let's create a processor which can do this for us.

package org.apache.camel.openstack;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;

import org.openstack4j.api.OSClient;
import org.openstack4j.api.client.IOSClientBuilder;
import org.openstack4j.model.common.Identifier;
import org.openstack4j.model.compute.FloatingIP;
import org.openstack4j.model.compute.Server;
import org.openstack4j.openstack.OSFactory;

/**
 * Processor which add floating IP to servers
 */
public class FloatingIpProcessor implements Processor {

@Override
public void process(Exchange e) throws Exception {
final OSClient os = createClient();

// first we need to associate new floating IP from pool
FloatingIP ip = createClient().compute().floatingIps().allocateIP("public");
Server s = e.getIn().getBody(Server.class);

// wait until server is Active
while (!Server.Status.ACTIVE.equals(s.getStatus())) {
Thread.sleep(500);
s = os.compute().servers().get(s.getId());
}

// associate floating IP with the server
os.compute().floatingIps().addFloatingIP(s, ip.getFloatingIpAddress());

// set headers
e.getIn().setHeader("server_ip", ip.getFloatingIpAddress());
e.getIn().setHeader("server_name", s.getName());
}

private OSClient createClient() {
IOSClientBuilder.V3 builder = OSFactory.builderV3().endpoint(MyRouteBuilder.OPENSTACK_ENDPOINT);

builder.credentials(MyRouteBuilder.OPENSTACK_USER, MyRouteBuilder.OPENSTACK_PASSWORD,
Identifier.byId("default"));

builder.scopeToProject(Identifier.byId(MyRouteBuilder.OPENSTACK_PROJECT_ID));

return builder.authenticate();
}
}

And modify our RouteBuilder as follows:

package org.apache.camel.openstack;

import org.apache.camel.builder.RouteBuilder;

/**
 * A Camel Java DSL Router
 */
public class MyRouteBuilder extends RouteBuilder {

public static final String OPENSTACK_ENDPOINT = "http://openstack-host:5000/v3";
public static final String OPENSTACK_PASSWORD = "nomoresecret";
public static final String OPENSTACK_USER = "admin";
public static final String OPENSTACK_PROJECT_ID = "projectId";

/**
 * Let's configure the Camel routing rules using Java code...
 */
public void configure() {

// this route gets configuration from file resources
// see files in src/data
from("file:src/data")

// set required headers
.setHeader("operation", constant("create"))
.setHeader("name", xpath("/node/name/text()"))
.setHeader("FlavorId", xpath("/node/flavorId/text()"))
.setHeader("ImageId", xpath("/node/imageId/text()"))

// create servers
.to("openstack-nova://" + OPENSTACK_ENDPOINT + "?password=" + OPENSTACK_PASSWORD + "&username="
+ OPENSTACK_USER + "&project=" + OPENSTACK_PROJECT_ID + "&subsystem=servers")
          // associate floating IP with servers
// using wireTap -> asynchronous execution
.wireTap("direct:floatingIp");

      // associate floating IP with node
      // see FloatingIpProcessor
      from("direct:floatingIp")
.process(new FloatingIpProcessor())
// wait unless IP address is properly assotiated with node
.delayer(3000)
.log("Floating IP ${header.server_ip} was assotiated with ${header.server_name}");

}
}

The last step is to execute an SSH command on each node using camel-ssh.

package org.apache.camel.openstack;

import org.apache.camel.builder.RouteBuilder;

/**
 * A Camel Java DSL Router
 */
public class MyRouteBuilder extends RouteBuilder {

public static final String OPENSTACK_ENDPOINT = "http://172.24.1.69:5000/v3";
public static final String OPENSTACK_PASSWORD = "nomoresecret";
public static final String OPENSTACK_USER = "admin";
public static final String OPENSTACK_PROJECT_ID = "d387038c917d4e21bd83be4bb3e7a9eb";

public static final String SSH_USER = "cirros";
public static final String SSH_PASSWORD = "cubswin:)";
/**
 * Let's configure the Camel routing rules using Java code...
 */
public void configure() {

// this route gets configuration from file resources
// see files in src/data
from("file:src/data")

// set required headers
.setHeader("operation", constant("create"))
.setHeader("name", xpath("/node/name/text()"))
.setHeader("FlavorId", xpath("/node/flavorId/text()"))
.setHeader("ImageId", xpath("/node/imageId/text()"))

// create servers
.to("openstack-nova://" + OPENSTACK_ENDPOINT + "?password=" + OPENSTACK_PASSWORD + "&username="
+ OPENSTACK_USER + "&project=" + OPENSTACK_PROJECT_ID + "&subsystem=servers")

// associate floating IP with servers
// using wireTap -> asynchronous execution
.wireTap("direct:floatingIp");

// associate floating IP with node
// see FloatingIpProcessor
from("direct:floatingIp")
.process(new FloatingIpProcessor())
// wait unless IP address is properly assotiated with node
.delayer(3000)
.log("Floating IP ${header.server_ip} was assotiated with ${header.server_name}")
.to("direct:ssh");

// execute ssh command
from("direct:ssh")
.setBody(constant("echo $SSH_CONNECTION"))
.toD("ssh:" + SSH_USER + ":" + SSH_PASSWORD + "@${headers.server_ip}?")
.log("SSH connection info: ${body}");
}
}

Run the application using the following command:

$ mvn exec:java 

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building A Camel Route 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ openstack-ssh ---
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Apache Camel 2.20.1 (CamelContext: camel-1) is starting
[camel.openstack.MainApp.main()] ManagedManagementStrategy      INFO  JMX is enabled
[camel.openstack.MainApp.main()] DefaultTypeConverter           INFO  Type converters loaded (core: 192, classpath: 0)
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Route: route1 started and consuming from: file://src/data
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Route: route2 started and consuming from: direct://floatingIp
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Route: route3 started and consuming from: direct://ssh
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Total 3 routes, of which 3 are started
[camel.openstack.MainApp.main()] DefaultCamelContext            INFO  Apache Camel 2.20.1 (CamelContext: camel-1) started in 0.797 seconds
[1) thread #2 - file://src/data] XPathBuilder                   INFO  Created default XPathFactory com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl@53acf835
[ (camel-1) thread #3 - WireTap] route2                         INFO  Floating IP 172.24.4.17 was assotiated with node2
[ (camel-1) thread #4 - WireTap] route2                         INFO  Floating IP 172.24.4.9 was assotiated with node1
[ (camel-1) thread #3 - WireTap] astleSecurityProviderRegistrar INFO  getOrCreateProvider(BC) created instance of org.bouncycastle.jce.provider.BouncyCastleProvider
[hClient[63ff359]-nio2-thread-2] AcceptAllServerKeyVerifier     WARN  Server at /172.24.4.9:22 presented unverified RSA key: SHA256:zA3T46EqLnrO3S7hZubAKSbRJBTV5NqixkOmQD/hzbI
[Client[510f1319]-nio2-thread-2] AcceptAllServerKeyVerifier     WARN  Server at /172.24.4.17:22 presented unverified RSA key: SHA256:VFbH1deVTtqBCGtSpKltdn3DkHvMbRpjVJBXyvvNlZY
[ (camel-1) thread #3 - WireTap] route3                         INFO  SSH connection info: 172.24.4.1 46134 10.0.0.9 22

[ (camel-1) thread #4 - WireTap] route3                         INFO  SSH connection info: 172.24.4.1 51646 10.0.0.6 22

As you can see from last two lines there were two nodes created (one with IP 10.0.0.9 and the second with IP 10.0.0.6) and they are available for further computation.

Full code is available here.

See also:

Your API is not enough. Learn why (and how) leading SaaS providers are turning their products into platforms with API integration in the ebook, Build Platforms, Not Products from Cloud Elements.

Topics:
integration ,camel ,openstack ,cloud integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}