How to launch an instance on OpenStack (III): Python novaclient library


The OpenStack project is a libre software cloud computing platform for private and public clouds, which aims to be simple to implement, massively scalable, and feature rich. OpenStack provides an Infrastructure as a Service (IaaS) solution through a set of interrelated services. Each service offers an application programming interface (API) that facilitates this integration.

Users getting started with OpenStack can find useful this and related posts, where different ways of how to launch and instance on OpenStack are given. In the previous posts, how to do this using both OpenStack Dashboard (Horizon) and OpenStack CLI were shown. In this post using the same scenario and starting point, identical result will be achieved, but using OpenStack Python novaclient library instead Horizon or OpenStack CLI. Both sysadmins and devops trying to integrate OpenStack with the rest of their own systems and applications will found this post useful, mainly if they like to use python for these purposes.

Note [19/11/2015]: This post was a little bit outdated because it was written in 2013 using OpenStack Grizzly. Thanks to a comment I realized that there is a change in the way the selected network is defined when an instance is launched, so I’ve made a minor update in this step and now this method must be valid at least up to OpenStack Icehouse (the OpenStack release we’re still using), if you find any other issue, please let me know.

Scenario

The procedure followed is quite general, but it is appropriate to note specific parameters used:

  • OpenStack Grizzly (2013.1) deployed on Debian Wheezy with gplhost repositories, but there should be no major differences with others ditros or later OpenStack releases.
  • OpenStack Quantum with OpenvSwitch plugin in a “Per tenant routers with private networks” setup:
    • Router has IP 10.0.0.1, which is the default gateway for all instances. The router has ability to access public networks.
    • Floating IP network 172.22.196.0/22
    • When an instance is launched a fixed IP from 10.0.0.0/24 subnet is assigned.
  • username: bisharron
  • tenant name: proy-bisharron
  • Authentication url: http://172.22.222.1:5000/v2.0/

The starting point is illustrated in following figure, where the router connected to external and internal networks is represented:

initial network

Software

OpenStack python novaclient must be propperly installed on client computer. If you are using Debian or a Debian derived distribution this is as simple as do:

# apt-get install python-novaclient

Setting environment variables

As explained in previous post, every time nova client is used, authentication information must be provided as parameters in client request. It’s usual to set these authentication parameters as environment variables through an openrc file like this:

#!/bin/bash

# With the addition of Keystone, to use an openstack cloud you should
# authenticate against keystone, which returns a **Token** and **Service
# Catalog**.  The catalog contains the endpoint for all services the
# user/tenant has access to - including nova, glance, keystone, swift.
#
# *NOTE*: Using the 2.0 *auth api* does not mean that compute api is 2.0.  We
# will use the 1.1 *compute api*
export OS_AUTH_URL=http://172.22.222.1:5000/v2.0

# With the addition of Keystone we have standardized on the term **tenant**
# as the entity that owns the resources.
export OS_TENANT_ID=065717b748b44c48b90b0692f72337c0
export OS_TENANT_NAME="proy-bisharron"

# In addition to the owning entity (tenant), openstack stores the entity
# performing the action as the **user**.
export OS_USERNAME=bisharron

# With Keystone you pass the keystone password.
echo "Please enter your OpenStack Password: "
read -s OS_PASSWORD_INPUT
export OS_PASSWORD=$OS_PASSWORD_INPUT

It’s possible and convenient to retrieve this environment variables from a python program, like is suggested by Lorin Hochstein in Python APIs: The best-kept secret of OpenStack, so let’s write and save the following file:

#!/usr/bin/env python
import os

def get_nova_creds():
    d = {}
    d['username'] = os.environ['OS_USERNAME']
    d['api_key'] = os.environ['OS_PASSWORD']
    d['auth_url'] = os.environ['OS_AUTH_URL']
    d['project_id'] = os.environ['OS_TENANT_NAME']
    return d

Using python shell

To make explanation clearer we’ll initially use the python shell, that allows us follow a step-by-step procedure.

A typical example of nova request and the corresponding response from python shell is:

>>> from novaclient.v1_1 import client
>>> from credentials import get_nova_creds
>>> creds = get_nova_creds()
>>> nova = client.Client(**creds)
>>> nova.security_groups.list()
[<SecurityGroup description=default, 
id=d5b08b8d-c8ae-452e-ad7a-89d5a00d5b66, 
name=default, 
rules=[], 
tenant_id=065717b748b44c48b90b0692f72337c0>]

Upload ssh public key

For security reasons, images used in OpenStack do not usually contain a password defined for any user, only publickey ssh is generally allowed. When an instance is spawned, the ssh public key is injected into it and only the holder of the corresponding private key is able to access to the instance.

This time a ssh public key will be read and uploaded to OpenStack, rather than create a new ssh keypair and download the private key (It is assumed that ~/.ssh/openstack-bisharron.pub containing a ssh publick key has previously been created):

>>> f = open('.ssh/openstack-bisharron.pub','r')
>>> publickey = f.readline()[:-1]
>>> keypair = nova.keypairs.create('openstack-bisharron',publickey)
<Keypair: openstack-bisharron>
>>> f.close()

Allocate Floating IP to project

Floating IPs (elastic IPs in Amazon EC2 terminology) allow instances to talk to an external host or access to the instances from an external network. A floating IP can be allocated to a project before or after launching an instance, we’ll do it before.

We need to know available floating IP pools:

>>> nova.floating_ip_pools.list()
[<FloatingIPPool: name=ext_net>]

A list containing only one pool is shown (‘ext_net’). So let’s request a floating IP to ext_net and store the result (a FloatingIP object) in the variable “floating_ip”:

>>> floating_ip = nova.floating_ips.create(nova.floating_ip_pools.list()[0].name)

We can see IP allocated to project:

>>> floating_ip.ip
u'172.22.196.59'

Launch an instance

Show images available:

>>> nova.images.list()
[ <Image: OpenBSD>, 
  <Image: Windows 7 x64>, 
  <Image: Windows Server 2012 SE>, 
  <Image: Bitnami owncloud>, 
  <Image: Bitnami WordPress>, 
  <Image: Debian wheezy>, 
  <Image: Ubuntu 12.04 LTS>, 
  <Image: cirros-0.3.1-x86_64>]

We select the “Debian wheezy” image:

>>> image = nova.images.find(name="Debian wheezy")

In the same way, “m1.tiny” flavor is selected:

>>> flavor = nova.flavors.find(name="m1.tiny")

It’s necessary to connect the new instance at least to one network, so to see available networks:

>>> nova.networks.list()
[<Network: ext_net>, <Network: red interna de bisharron>]

we select “red interna de bisharron” network:

>>> network = nova.networks.find(label="red interna de bisharron")

With all parameters defined, now is possible to launch a new instance:

>>> server = nova.servers.create(name = "debian-test", 
                                 image = image.id, 
                                 flavor = flavor.id, 
                                 nics = [{'net-id':network.id}],
                                 key_name = keypair.name)

After a few seconds the instance is active and a fixed IP 10.0.0.2 has been assigned to it,

>>> server = nova.servers.find(id=server.id)
>>> server.status
u'ACTIVE'
>>> server.addresses
{u'red interna de bisharron': [{u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:fe:fc:de',
   [{u'OS-EXT-IPS:type': u'fixed',
   u'addr': u'10.0.0.2',
   u'version': 4}]}

Floting IP 172.22.196.59 is now associated to port with IP 10.0.0.2:

>>> server.add_floating_ip(floating_ip)

Security Group rules

Instance is launched and floating IP associated so it should be possible to access via ssh, but this is not yet possible due to default firewall behavior. Incoming connections must be explicitly allowed as rules in a security group.

To see available security groups available and select named “default”:

>>> nova.security_groups.list()
[ <SecurityGroup description=default, 
  id=d5b08b8d-c8ae-452e-ad7a-89d5a00d5b66, 
  name=default, 
  rules=[], 
  tenant_id=065717b748b44c48b90b0692f72337c0>]
>>> secgroup = nova.security_groups.find(name="default")

Add a rule to allow incoming ssh connections (22/tcp) and another to allow all incoming icmp connections:

>>> nova.security_group_rules.create(ip_protocol="tcp", 
                                     from_port="22", 
                                     to_port="22", 
                                     cidr="0.0.0.0/0", 
                                     secgroup.id)
< SecurityGroupRule from_port=22, 
  group={}, 
  id=63c00d9c-8865-4a7c-b825-8bd07ce6845b, 
  ip_protocol=tcp, 
  ip_range={u'cidr': u'0.0.0.0/0'}, 
  parent_group_id=d5b08b8d-c8ae-452e-ad7a-89d5a00d5b66, 
  to_port=22>
>>> nova.security_group_rules.create(secgroup.id, 
                                     ip_protocol="icmp", 
                                     from_port=-1, 
                                     cidr="0.0.0.0/0", 
                                     to_port=-1)
< SecurityGroupRule from_port=-1, 
  group={}, 
  id=7667c23e-b3eb-4cb3-bd32-1cbd9775757c, 
  ip_protocol=icmp, 
  ip_range={u'cidr': u'0.0.0.0/0'}, 
  parent_group_id=d5b08b8d-c8ae-452e-ad7a-89d5a00d5b66, 
  to_port=-1>

Access to the launched instance

Now we can ping to the instance:

$ ping 172.22.196.59
PING 172.22.196.59 (172.22.196.59) 56(84) bytes of data.
64 bytes from 172.22.196.59: icmp_req=1 ttl=63 time=441 ms
64 bytes from 172.22.196.59: icmp_req=2 ttl=63 time=0.602 ms
64 bytes from 172.22.196.59: icmp_req=3 ttl=63 time=0.686 ms
^C
--- 172.22.196.59 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.602/147.616/441.562/207.851 ms

And use the ssh command to make a secure connection to the instance (specifying the private key to use):

$ ssh -i ~/.ssh/openstack-bisharron.pem debian@172.22.196.59
The authenticity of host '172.22.196.59 (172.22.196.59)' can't be established.
ECDSA key fingerprint is a7:cc:3a:1d:2b:8d:f4:ad:e7:a6:45:c6:a5:61:85:9b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.22.196.59' (ECDSA) to the list of known hosts.
Linux debian.example.com 3.2.0-4-amd64 #1 SMP Debian 3.2.46-1 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
debian@debian-test:~$

References

Related posts

, , , ,

  1. #1 por Memo García el 10-03-14 - 7:27 pm

    Hi I’m following your tutorial and it’s quite good but when I try to get the network list I got this error.
    “AttributeError: ‘Client’ object has no attribute ‘networks'” any idea why?

    regards

    Me gusta

  2. #3 por Creating an instance el 19-11-15 - 7:20 am

    Hi. I am getting the following error.
    for nic_info in nics:
    TypeError: ‘Network’ object is not iterable

    Me gusta

    • #4 por albertomolina el 19-11-15 - 8:41 pm

      Hi,

      Thanks to your comment I’ve updated the post, so please see the correction (in the server creation step). I hope this help you.

      Me gusta

  3. #5 por devops035 el 9-03-16 - 6:12 pm

    Hi, I don’t understand how you link the instance with a security group in your example.

    Me gusta

    • #6 por albertomolina el 9-03-16 - 8:37 pm

      Hi devops035,

      If no secgroup is defined when launching an instance, default is selected. At least, this is at least the default behaviour in all OpenStack releases I’ve tested.

      Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: