Coding to Various Cloud APIs Using an All encompassing Uber Abstraction Layer
Intro to JClouds
JClouds, a Java framework that helps developers use cloud APIs, at its onset, was a one man shop written by Adrian Cole (@adrianfcole) who is a gifted Java programmer and architect, to say the least. It has since been awarded the open source badge of honor equivalent, by becoming an Apache incubator project with dozens of contributors and thousands of lines of code.
When JClouds was established more than five years ago, its basic premise was to allow developers to realize the potential the cloud had to offer. At that time, there were already the major cloud players – Amazon, Rackspace, HP was just starting off, as was Cloudstack. OpenStack wasn’t even born yet, and there was no real standardization. Cloud was just beginning to take the world by storm, and it was clear that it was going to explode, as everyone needed on-demand resources, as well as the automation and elasticity the cloud had to offer.
That said, it was no easy feat to be able to use cloud services. It was initially very difficult to leverage the cloud, as often times the APIs were not standard or even clear, and many times they didn’t even work.
This project set out to create a Java framework (while it also supports other languages, it is mainly Java) that would hide these cloud APIs from the user – reducing the complexity involved with leveraging the cloud. In this way, the developer could take advantage of the cloud through regular object oriented code that they are familiar with.
The JClouds API can be integrated into any Java project, and makes it possible to provision machines, terminate them, and even run scripts on these VMs. JClouds serves as a framework that enables you to provision pretty much anything on a lot of different clouds, something that was not previously possible.
In addition to its API, JClouds also comes with a CLI, where you can write shell commands. For example, provision an Amazon EC2 instance, where you define the credentials and hardware you’d like. This provides a really easy option for testing, to play around and learn about different clouds.
Imagine you have a shell or bash script, and you need to automatically provision a VM and then run your database on it. You can easily do this by just installing the JClouds CLI and running the commands as if they were shell commands. This is basically like having a built-in CLI to run shell scripts on Amazon EC2, which is very useful.
This was the pre-Chef and Puppet way to automate things, developers would write scripts, and would run them remotely, JClouds made this super easy.
When Chef and Puppet started to take off, JClouds added built-in integration with these tools. This is due to the fact that while shell scripts are generally very useful, they are also very OS dependent and tend to break. Hence, once the world started to move towards configuration management tools, JClouds also natively supported these.
How Cloudify Uses JClouds
By leveraging JClouds from the start, Cloudify was able to support all of the leading clouds and multi-cloud. After writing a simple configuration file that provides the credentials to the specific cloud, it was possible to provision, manage, and monitor your VMs without writing a single line of code. Cloudify built a proprietary interface on top of JClouds, which also enabled functionality for clouds JClouds does not support, making it possible to either write your own code, or request the feature from Cloudify.
The Challenges
No code is perfect, and if your system depends on a third-party application where bugs arise, it is then your problem to fix these, and quickly. The advantage is that JClouds is open source, enabling you to fork the code and fix the bugs yourself. Where it becomes difficult, and this is often times the case with open source software, is understanding code written by someone else, to the level where you can fix the bugs. While the JClouds code is easy to read and understand, it’s more difficult to be able to write the code required to fix the specific bug. This often times incurred enough overhead to require a rollback to a previous version until the bug is fixed in a newer version, delaying the integration of the new features introduced in newer versions.
After investing some time in learning the JClouds code, and contributing bug fixes, we were able to overcome the learning curve, and what was discovered is high quality code that is well-tested across the leading clouds. The initial learning phase of understanding how JClouds built code – and why it initially seemed difficult to contribute – was mainly due to the fact that JClouds employs a Google library called Guice (pronounced “juice”).
This library takes advantage of a coding practice called dependency injection. Dependency injection helps to develop code faster, however, for those unfamiliar with Guice and dependency injection, it may seem quite difficult to understand, at first. If you invest an initial effort to understand Guice and how it works with JClouds, along with dependency injection, leveraging this code ultimately will become infinitely easier.
Dependency injection helps developers avoid code duplication, make the code unitestable and much more modular. It essentially allows the developer to inject their own code instead of the existing code, by writing custom code and hooks, and injecting them at runtime, with no need to recompile or build in advance.
When Such an Abstraction Layer is Needed
An abstraction layer basically provides rapid support for leading clouds, and even automation through an API and CLI. For cloud providers that provide APIs and no SDKs, this type of abstraction layer makes it possible for developers to work with a cloud much more easily than with the tools the cloud provides.
With a constantly evolving cloud landscape, however, a different approach is now possible. Most leading cloud providers out there offer an extensive and well maintained SDK. These SDKs come in many languages and usually contain all the features the cloud has to offer. So the overhead of learning different REST APIs of different clouds is slowly vanishing.
Conclusion
These days a hybrid approach to an abstraction layer enables the developer to take the best from both worlds, where an abstraction layer provides a lot of important functionality rather easily, it should be considered, for the most part, a best effort for supporting cloud APIs. In addition, since the abstraction layer is stricter and less flexible, an ideal scenario would be architecting your system to be able to leverage new SDKs in parallel to the abstraction layer. When you need basic functionality quickly, an abstraction library is generally the right choice. However, if you’re looking to provide more sophisticated functionality, such as networking, or use the latest and greatest in a specific cloud’s API, a direct approach would be preferable.
A good example in this respect is the approach we took with our OpenStack Neutron integration (the OpenStack networking project). We started off with a pure JClouds approach, which worked quite well but was mostly limited to the compute aspect of things. When we wanted to move forward and add also the networking aspect to our infrastructure orchestration process, we took a native OpenStack approach and worked directly with the Nova and Neutron APIs.
Eli Polonsky is on the Cloudify RND team that is working on the new and improved Cloudify 3.0 – which can be found at: https://github.com/CloudifySource.
It’s built in Python leveraging diverse architecture tools including: Riemann, ElasticSearch, Logstash, RabbitMQ, Celery, Ruote workflow engine. Stay tuned for Eli’s contribution to the JClouds project – https://github.com/iliapolo.