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:
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
- Python APIs: The best-kept secret of OpenStack
- OpenStack API Quick Start
- OpenStack Compute API v2 and Extensions Reference
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 gustaMe gusta
It means that «NetworkManager» object is not present. What version of python-novaclient are you using?
I’m using python-novaclient 2.13 on OpenStack Grizzly and the latest one is 2.17 [1]
[1] https://pypi.python.org/pypi/python-novaclient/
Me gustaMe gusta
Hi. I am getting the following error.
for nic_info in nics:
TypeError: ‘Network’ object is not iterable
Me gustaMe gusta
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 gustaMe gusta
Hi, I don’t understand how you link the instance with a security group in your example.
Me gustaMe gusta
Hi devops035,
If no secgroup is defined when launching an instance, default is selected. At least, this is the default behaviour in all OpenStack releases I’ve tested.
Me gustaMe gusta