In a cloud orchestration environment, developers commonly use OpenStack to manage the infrastructure and applications. The OpenStack project is a global collaboration of developers and cloud computing technologists producing the open standard cloud computing platform for both public and private clouds. OpenStack provides a cloud operating system where administrators can manage compute, storage, and network resources in a datacenter through a dashboard and users can provision resources through a web interface.

The OpenStack technology consists of a series of interrelated programs delivering various components for a cloud infrastructure solution. One such program is Heat Orchestration Templates (HOT), which implements an orchestration engine to automate provisioning and deployment of the full stack of VMs. HOT templates are defined in YAML.

A YAML HOT template is used to define, create, and configure a stack or collection of resources and define relationships between them. Resources are objects in OpenStack and can include compute resources, network configuration, security groups, scaling rules, and custom resources.

Usage scenario

Consider a scenario where YAML HOT templates are used for PaaS (Platform as a Service) to securely auto-provision and manage complex middleware stacks across on-premises and cloud platforms. The solution would contain a variety of patterns, which are combination of stacks representing different middleware.

Challenges

While combining dynamic inventory with the various patterns, the complexity increases because we need to keep track of several ranges of subnets and their allocation. Every stack has to go into separate network for each customer or to different data centers for high availability. In OpenStack, users can create their own networks by providing attributes for CIDR, gateway_ip and allocation_pools in HOT template. Hence, there is a need to make the network more manageable and reusable.

Solution

To solve the complexity, an availability pool can be developed, which will give range of IPs at any given time. You can use the following logic to achieve this, which uses Java as it integrates well with YAML template:

  1. Get all possible IP range
  2. Get used IP ranges
  3. To get next usable IP range subtract the used IP range (2) from all possible IP range (1).

/**
* The method generates all possible IP ranges for this openstack – one time job.
* for example
*
*/

The following method generates all possible IP ranges for this OpenStack (one time job). Example: [192-192].[168-253].[0-255].x ; The ‘x’ in 4th quadrant will be replaced with different values later while passing to YAML generator.

private List getPossibleIpRanges(int q1start, int q1end, int q2start, int q2end, int q3start, int q3end) {
List possibleIps = new ArrayList();
for (int q1 = q1start; q1 <= q1end; q1++) { for (int q2 = q2start; q2 <= q2end; q2++) { for (int q3 = q3start; q3 <= q3end; q3++) { possibleIps.add(q1 + "." + q2 + "." + q3 + ".x"); } } } return possibleIps; }

The following method gives the available IPs by subtracting the used IPs from possible IPs.

public Queue getAvailableIpRange(List possibleIps, List usedIps) {
Iterator iter = possibleIps.iterator();
Queue qu = new LinkedList();
while (iter.hasNext()) {
String ip = iter.next();
if (!usedIps.contains(ip)) {
qu.add(ip);
}
}
return qu;

The response from the GET Web request to https://openstack_ip:port/v2.0/subnets will be like “subnets”:

[{
"name": "",
"network_id": "xxxxxxxxxxxxxxx",
"tenant_id": " xxxxxxxxxxxxxxx",
"allocation_pools": [{"start": "10.10.0.2", "end": "10.10.0.254"}],
"gateway_ip": "10.10.0.1",
"ip_version": 4,
"cidr": "10.10.0.0/24",
"id": " xxxxxxxxxxxxxxx",
"enable_dhcp": true
},
{
"name": "",
"network_id": " xxxxxxxxxxxxxxx",
"tenant_id": " xxxxxxxxxxxxxxx",
"allocation_pools": [{"start": "10.0.0.2", "end": "10.0.0.254"}],
"gateway_ip": "10.0.0.1",
"ip_version": 4,
"cidr": "10.0.0.0/24",
"id": " xxxxxxxxxxxxxxx",
"enable_dhcp": true
}]

From the above JSON response, collect the first three quadrants [10.0.0.x] from all CIDRS.
public List getIpRangesInUse() {
String jsonData = "response of GET Web Request to 'https://openstack_ip:port/v2.0/subnets' to get all subnets in use so far";
List usedIpRange = new ArrayList();
try {
JSONObject jObject = new JSONObject(jsonData);
JSONArray linkArrobj = jObject.getJSONArray("subnets");
for (int i = 0; i < linkArrobj.length(); i++) { JSONObject obj = (JSONObject) linkArrobj.get(i); String rawIpRange = obj.getString("cidr"); String ipRange = rawIpRange.substring(0, rawIpRange.lastIndexOf(".")); usedIpRange.add(ipRange + ".x"); } } catch (Exception e) { e.printStackTrace(); } return usedIpRange; } private final Lock reentrantLock = new ReentrantLock(true); public void provision() { int q1start = 192; int q1end = 192; int q2start = 168; int q2end = 253; int q3start = 0; int q3end = 255; List possibleIpRanges = getPossibleIpRanges(q1start, q1end, q2start, q2end, q3start, q3end);
reentrantLock.lock();//lock till next use
try {


List usedIpRanges = getIpRangesInUse();
Queue pickableList = getAvailableIpRange(possibleIpRanges, usedIpRanges);
String nextUusableIpRange = pickableList.poll(); //will fetch first range, for example: 192.168.12.x
System.out.println("Next Usable Ip Range:" + nextUusableIpRange);
String cidr = nextUusableIpRange.replace("x", "0/26"); //192.168.12.0/26
String gateway_ip = nextUusableIpRange.replace("x", "1"); //192.168.12.1
String allocation_pool_start = nextUusableIpRange.replace("x", "4");//192.168.12.4
String allocation_pool_end = nextUusableIpRange.replace("x", "25"); //192.168.12.25


Map subnet = new LinkedHashMap();
subnet.put("type", "OS::Neutron::Subnet");
Map properties=new LinkedHashMap();
Map network_id=new HashMap(){{put("get_resource", "ffetest1_network");}};
properties.put("network_id",network_id);
properties.put("cidr",cidr);
properties.put("gateway_ip",gateway_ip);
List arr=new ArrayList();
Map m1=new LinkedHashMap();
m1.put("start", allocation_pool_start);
m1.put("end", allocation_pool_end);
arr.add(m1);
properties.put("allocation_pools",arr);
subnet.put("properties", properties);

The subnet map can now be translated into the following YAML snippet using Jackson JSON library:
ffetest1_subnet:
type: OS::Neutron::Subnet
properties:
network_id:
get_resource: ffetest1_network
cidr: 192.168.12.0/26
gateway_ip: 192.168.12.1
allocation_pools:
- start: 192.168.12.4
end: 192.168.12.25

} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();//release lock
}
}

References:
https://wiki.openstack.org/wiki/Neutron/APIv2-specification#List_Subnets

Join The Discussion

Your email address will not be published. Required fields are marked *