Cloud-Wrangling with Chameleon's Python Library
- March 15, 2021 by
- Jason Anderson
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!
No comments