Cloud-Wrangling with Chameleon's Python Library

Chances are, if you're using Chameleon today, you're probably utilizing either the GUI or the CLI (or a mixture of both.) Did you know there's a Python library that makes it easy to script your Chameleon experiments? In January we announced the public release of python-chi, the official Python library for CHI (Chameleon Infrastructure), which is exactly that.

 

Why a separate library? Chameleon's cloud technology is built on OpenStack, and so Chameleon users (and operators!) benefit from a lot of work already invested by the open source community into the various service APIs and client libraries. Yet, the general-purpose nature of these APIs can make it excessively challenging to express what is really a simple use case on Chameleon. For example, here's how one might create a lease and launch a node via just the OpenStack Python libraries:

 

lease_name = "my-lease"

node_type = "compute_haswell"

node_count = 2

image_name = "my-image"

 

from datetime import datetime, timedelta

import json

from dateutil import tz

from time import sleep

from blazarclient.client import Client as BlazarClient

from glanceclient.client import Client as GlanceClient

from keystoneauth1.session import Session

from keystoneauth1.identity.v3 import ApplicationCredential

from novaclient.client import Client as NovaClient

 

# Create authentication context

credential_name = os.getenv('OS_APPLICATION_CREDENTIAL_NAME')

credential_secret = os.getenv('OS_APPLICATION_CREDENTIAL_SECRET')

auth = ApplicationCredential(auth_url="https://chi.uc.chameleoncloud.org:5000/v3", application_credential_name=credential_name, application_credential_secret=credential_secret, username="", user_domain_name="chameleon")

session = Session(auth=auth)

 

# Request a lease for nodes for 1 hour

start_date = datetime.now(tz=tz.tzutc()) + timedelta(seconds=70)

end_date = start_date + timedelta(hours=1)

blazar = BlazarClient('1', service_type='reservation', session=session)

lease = blazar.lease.create(

    name=lease_name, start=start_date, end=end_date,

    reservations=[{'resource_type': 'physical:host', 'resource_properties': json.dumps(['=', '$node_type', node_type]), 'hypervisor_properties': '', 'min': str(node_count), 'max': str(node_count)}], events=[])

 

# Wait for lease to start

# TODO: wait for lease to become ACTIVE before proceeding instead of sleeping!

sleep(120)

 

# Launch bare metal instances against the lease

nova = NovaClient('2.10', session=session)

glance = GlanceClient('2', session=session)

reservation_id = json.loads(lease.get('reservations')).get('id')

image_id = next((img for img in glance.images.list() if img.name == image_name)).id

flavor_id = next((f for f in nova.flavors.list() if f.name == 'baremetal')).id

server = nova.servers.create(name="my-server", image=image_id, flavor=flavor_id, 

scheduler_hints={'reservation': reservation_id},

     key_name='my-keypair',

     nics=[{'net-id': network_id, 'v4-fixed-ip': ''}],

     min_count=node_count,

     max_count=node_count)


 

And here's the same using python-chi:

 

lease_name = "my-lease"

node_type = "compute_haswell"

node_count = 2

image_name = "my-image"

 

import chi

 

# Create authentication context (most info automatically sourced from env)

chi.use_site('CHI@UC')

 

# Request a lease for nodes for 1 hour

reservations = []

chi.lease.add_node_reservation(reservations, count=node_count, 

node_type=node_type)

start_date, end_date = chi.lease.lease_duration(hours=1)

lease = chi.lease.create_lease(lease_name, reservations, start_date=start_date,

                     end_date=end_date)

 

# Wait for lease to start

chi.lease.wait_for_active(lease.id)

 

# Launch bare metal instances against the lease

reservation_id = get_node_reservation(lease.id)

server = create_server(server_name, reservation_id=reservation_id,

image_name=image_name, count=node_count)

 

The Python library is designed to leverage the Pareto principle: by focusing on the most-commonly-used 20% of features of OpenStack, we can ideally handle 80% of individual use cases on Chameleon, namely:

  • Making leases for bare metal nodes, networks, or IPs

  • Launching bare metal instances against a lease

  • Assigning floating IPs to instances

  • Creating isolated networks that can NAT to the internet

 

You can build a lot of interesting things with these blocks. For example, you could set up a daily script that checks in the morning if there are available nodes, makes a reservation for a node starting at 9:00AM and launches your bare metal snapshot and emails you when the server is up and running, with a link to login. Or, you could script a complicated network setup as part of a Jupyter Notebook, where you need to create multiple networks and connect them together in various ways. In fact, just to give you a peek behind the curtain, we at Chameleon use this library to implement automated health checks of each cloud site, and even have some custom bots we call "hammers" that run around fixing simple problems for us.

 

If you're using the Jupyter interface, python-chi is already pre-installed on your Jupyter server, allowing you to script your Chameleon experiments easily within a Jupyter Notebook. You can also download the library to your workstation by following the installation instructions here. If you want to just play around a bit more, check out a few of our interactive tutorials on the documentation, where you can learn about the basics.

 

Have fun, and let us know how you use this library in your research and experimentation!


Add a comment

No comments