Guide: OpenStack Python SDK – Basic Usage: Difference between revisions

From bwCloud-OS
Jump to navigation Jump to search
No edit summary
 
(32 intermediate revisions by the same user not shown)
Line 1: Line 1:
This guide provides a quick introduction to managing your bwCloud-OS resources using the OpenStack Python SDK. It covers basic authentication and common operations for compute, storage, and networking.
This guide provides a quick introduction to managing your bwCloud-OS resources using the OpenStack Python SDK. It covers the most common operations for compute, storage, and networking.
 
In the following, we demonstrate the routines using an interactive Python shell. In practice, these routines are typically used within Python scripts.
 
'''Note:''' In the interactive Python shell, multi-line blocks (e.g., loops or function definitions) are executed after pressing <code>Enter</code> '''twice'''.


In the following, we demonstrate the commands using an interactive Python shell. In practice, these routines are typically used within Python scripts.




Line 13: Line 16:
</pre>
</pre>


Alternatively, you can install it via pip (preferably inside a virtual environment):
Alternatively, you can install it via <code>pip</code> (preferably inside a virtual environment):


<pre>
<pre>
python3 -m venv openstacksdk_venv
python3 -m venv openstacksdk_venv
. openstacksdk_venv/bin/activate
source openstacksdk_venv/bin/activate
pip install openstacksdk
pip install openstacksdk
</pre>
</pre>
Line 28: Line 31:
For details, see the section [[Programmatic Access and Automation#How can I create an application credential?|Create an application credential]].
For details, see the section [[Programmatic Access and Automation#How can I create an application credential?|Create an application credential]].


In the following, we use the  <code>clouds.yaml</code> method.
In the following, we use the  <code>clouds.yaml</code> file.


== Basic Connection ==
== Basic Connection ==
Line 38: Line 41:
</pre>
</pre>


== Compute ==
== Images ==
List available images:
List available images:


Line 49: Line 52:


<pre>
<pre>
with open("/path/to/images/ubuntu-24.04-server-cloudimg-amd64.img", "rb") as img:
import os
 
image_path = "/path/to/images/ubuntu-24.04-server-cloudimg-amd64.img"
if not os.path.isfile(image_path):
    raise FileNotFoundError(f"Image file not found: {image_path}")
 
with open(image_path, "rb") as img:
     image = conn.image.upload_image(
     image = conn.image.upload_image(
         name="ubuntu-24.04",
         name="ubuntu-24.04",
Line 56: Line 65:
         container_format="bare"
         container_format="bare"
     )
     )
    print(image.id)
 
print("Image ID:", image.id)
</pre>
</pre>


Line 69: Line 79:


<pre>
<pre>
conn.image.delete_image("<IMAGE_ID_OR_NAME>")
conn.image.delete_image("<IMAGE_ID>")
</pre>
</pre>
== Compute ==


=== Key Pairs (SSH Access) ===
=== Key Pairs (SSH Access) ===
Line 108: Line 120:
</pre>
</pre>


Create an instance:
Create an instance (ensure that the specified image, flavor, network, and key pair exist):
 
<pre>
<pre>
image = conn.compute.find_image("ubuntu-24.04")
image = conn.compute.find_image("ubuntu-24.04")
Line 122: Line 135:
server = conn.compute.wait_for_server(server)
server = conn.compute.wait_for_server(server)
print("Created:", server.name)
print("Created:", server.name)
</pre>
Show details of an instance:
<pre>
server = conn.compute.find_server("myVM")
if server is None:
    raise ValueError("Server 'myVM' not found")
server = conn.compute.get_server(server.id)
print(server)
</pre>
</pre>


Line 130: Line 154:
conn.compute.delete_server(server.id)
conn.compute.delete_server(server.id)
</pre>
</pre>


== Storage ==
== Storage ==
Line 144: Line 166:
</pre>
</pre>


Create a volume:
Create a volume (size in GB):


<pre>
<pre>
Line 173: Line 195:
</pre>
</pre>


Detach a volume:
Detach a volume from an instance:


<pre>
<pre>
Line 198: Line 220:
</pre>
</pre>


Delete a network:
Delete a network (after detaching all ports from its subnets):


<pre>
<pre>
network = conn.network.find_network("myNet")
network = conn.network.find_network("myNet")
conn.network.delete_network(network.id)
conn.network.delete_network(network.id)
</pre>
=== Subnets, Routers ===
Create a subnet:
<pre>
network = conn.network.create_network(name="myNet")
subnet = conn.network.create_subnet(
    name="mySubnet",
    network_id=network.id,
    ip_version=4,
    cidr="192.168.1.0/24"
)
</pre>
Create a router:
<pre>
router = conn.network.create_router(name="myRouter")
</pre>
Attach a subnet to a router:
<pre>
conn.network.add_interface_to_router(
    router,
    subnet_id=subnet.id
)
</pre>
Set external gateway of a router:
<pre>
external_net = conn.network.find_network("provider_default_net")
conn.network.update_router(
    router,
    external_gateway_info={"network_id": external_net.id}
)
</pre>
Detach a subnet from a router:
<pre>
conn.network.remove_interface_from_router(
    router,
    subnet_id=subnet.id
)
</pre>
Delete a router:
<pre>
conn.network.delete_router(router.id)
</pre>
Delete a subnet (after detaching all ports from the subnet):
<pre>
conn.network.delete_subnet(subnet.id)
</pre>
</pre>


=== Floating IPs ===
=== Floating IPs ===


Create a floating IP:
Create a floating IP (requires access to the provider network):


<pre>
<pre>
fip = conn.network.create_ip(floating_network_id="provider_default_net")
network = conn.network.find_network("provider_default_net")
fip = conn.network.create_ip(floating_network_id=network.id)
print(fip.floating_ip_address)
print(fip.floating_ip_address)
</pre>
List floating IPs:
<pre>
for fip in conn.network.ips():
    print(fip.floating_ip_address, fip.status, fip.port_id)
</pre>
</pre>


Line 218: Line 310:
<pre>
<pre>
server = conn.compute.find_server("myVM")
server = conn.compute.find_server("myVM")
conn.compute.add_floating_ip_to_server(server, fip.floating_ip_address)
port = list(conn.network.ports(device_id=server.id))[0]
conn.network.update_ip(fip, port_id=port.id)
</pre>
</pre>


Line 224: Line 317:


<pre>
<pre>
conn.compute.remove_floating_ip_from_server(server, fip.floating_ip_address)
conn.network.update_ip(fip, port_id=None)
</pre>
</pre>


Delete a floating IP:
Release (delete) a floating IP:


<pre>
<pre>
conn.network.delete_ip(fip.id)
conn.network.delete_ip(fip.id)
</pre>
</pre>


=== Security Groups ===
=== Security Groups ===
Line 249: Line 341:
</pre>
</pre>


Add a rule (HTTP):
Add a rule to a security group (e.g., HTTP access via port 80):


<pre>
<pre>
conn.network.create_security_group_rule(
conn.network.create_security_group_rule(
     security_group_id=sg.id,
     security_group_id=sg.id,
    direction="ingress",
     protocol="tcp",
     protocol="tcp",
     port_range_min=80,
     port_range_min=80,
     port_range_max=80,
     port_range_max=80,
     direction="ingress"
     ethertype="IPv4"
)
)
</pre>
</pre>

Latest revision as of 10:13, 27 April 2026

This guide provides a quick introduction to managing your bwCloud-OS resources using the OpenStack Python SDK. It covers the most common operations for compute, storage, and networking.

In the following, we demonstrate the routines using an interactive Python shell. In practice, these routines are typically used within Python scripts.

Note: In the interactive Python shell, multi-line blocks (e.g., loops or function definitions) are executed after pressing Enter twice.


Prerequisites

Install the OpenStack SDK, e.g. for Ubuntu:

sudo apt install python3-openstacksdk 

Alternatively, you can install it via pip (preferably inside a virtual environment):

python3 -m venv openstacksdk_venv
source openstacksdk_venv/bin/activate
pip install openstacksdk

Authentication

You can either:

  • source an OpenRC file, or
  • use a clouds.yaml file

For details, see the section Create an application credential.

In the following, we use the clouds.yaml file.

Basic Connection

Create a connection in Python:

import openstack
conn = openstack.connect(cloud="openstack")

Images

List available images:

for image in conn.image.images():
    print(image.name, image.id)

Upload a new image:

import os

image_path = "/path/to/images/ubuntu-24.04-server-cloudimg-amd64.img"
if not os.path.isfile(image_path):
    raise FileNotFoundError(f"Image file not found: {image_path}")

with open(image_path, "rb") as img:
    image = conn.image.upload_image(
        name="ubuntu-24.04",
        data=img,
        disk_format="qcow2",
        container_format="bare"
    )

print("Image ID:", image.id)

Show image details:

image = conn.image.get_image("<IMAGE_ID>")
print(image)

Delete an image:

conn.image.delete_image("<IMAGE_ID>")

Compute

Key Pairs (SSH Access)

Create a key pair:

keypair = conn.compute.create_keypair(name="myKey")
with open("myKey.pem", "w") as f:
    f.write(keypair.private_key)

Set correct permissions (outside Python shell):

chmod 600 myKey.pem

List key pairs:

for kp in conn.compute.keypairs():
    print(kp.name)

Delete a key pair:

conn.compute.delete_keypair("myKey")

Instances

List instances:

for server in conn.compute.servers():
    print(server.name, server.status)

Create an instance (ensure that the specified image, flavor, network, and key pair exist):

image = conn.compute.find_image("ubuntu-24.04")
flavor = conn.compute.find_flavor("p1.tiny")
network = conn.network.find_network("myNet")
server = conn.compute.create_server(
    name="myVM",
    image_id=image.id,
    flavor_id=flavor.id,
    networks=[{"uuid": network.id}],
    key_name="myKey"
)
server = conn.compute.wait_for_server(server)
print("Created:", server.name)

Show details of an instance:

server = conn.compute.find_server("myVM")
if server is None:
    raise ValueError("Server 'myVM' not found")

server = conn.compute.get_server(server.id)
print(server)

Delete an instance:

server = conn.compute.find_server("myVM")
conn.compute.delete_server(server.id)

Storage

Volumes

List volumes:

for vol in conn.block_storage.volumes():
    print(vol.name, vol.size)

Create a volume (size in GB):

volume = conn.block_storage.create_volume(
    name="myVolume",
    size=10
)

Delete a volume:

volume = conn.block_storage.find_volume("myVolume")
conn.block_storage.delete_volume(volume.id)

Volume Management for Instances

Attach a volume to an instance:

server = conn.compute.find_server("myVM")
volume = conn.block_storage.find_volume("myVolume")
conn.compute.create_volume_attachment(
    server,
    volumeId=volume.id
)

Detach a volume from an instance:

attachments = conn.compute.volume_attachments(server)
for att in attachments:
    if att.volume_id == volume.id:
        conn.compute.delete_volume_attachment(att.id, server)

Networking

Networks

List networks:

for net in conn.network.networks():
    print(net.name)

Create a network:

network = conn.network.create_network(name="myNet")

Delete a network (after detaching all ports from its subnets):

network = conn.network.find_network("myNet")
conn.network.delete_network(network.id)

Subnets, Routers

Create a subnet:

network = conn.network.create_network(name="myNet")

subnet = conn.network.create_subnet(
    name="mySubnet",
    network_id=network.id,
    ip_version=4,
    cidr="192.168.1.0/24"
)

Create a router:

router = conn.network.create_router(name="myRouter")

Attach a subnet to a router:

conn.network.add_interface_to_router(
    router,
    subnet_id=subnet.id
)

Set external gateway of a router:

external_net = conn.network.find_network("provider_default_net")

conn.network.update_router(
    router,
    external_gateway_info={"network_id": external_net.id}
)

Detach a subnet from a router:

conn.network.remove_interface_from_router(
    router,
    subnet_id=subnet.id
)

Delete a router:

conn.network.delete_router(router.id)

Delete a subnet (after detaching all ports from the subnet):

conn.network.delete_subnet(subnet.id)

Floating IPs

Create a floating IP (requires access to the provider network):

network = conn.network.find_network("provider_default_net")
fip = conn.network.create_ip(floating_network_id=network.id)
print(fip.floating_ip_address)

List floating IPs:

for fip in conn.network.ips():
    print(fip.floating_ip_address, fip.status, fip.port_id)

Associate a floating IP with an instance:

server = conn.compute.find_server("myVM")
port = list(conn.network.ports(device_id=server.id))[0]
conn.network.update_ip(fip, port_id=port.id)

Disassociate a floating IP:

 conn.network.update_ip(fip, port_id=None)

Release (delete) a floating IP:

conn.network.delete_ip(fip.id)

Security Groups

List security groups:

for sg in conn.network.security_groups():
    print(sg.name)

Create a security group:

sg = conn.network.create_security_group(name="mySecGroup")

Add a rule to a security group (e.g., HTTP access via port 80):

conn.network.create_security_group_rule(
    security_group_id=sg.id,
    direction="ingress",
    protocol="tcp",
    port_range_min=80,
    port_range_max=80,
    ethertype="IPv4"
)

Assign security group to an instance:

server = conn.compute.find_server("myVM")
conn.compute.add_security_group_to_server(server, sg.name)

Remove a security group from an instance:

conn.compute.remove_security_group_from_server(server, sg.name)

Delete a security group:

conn.network.delete_security_group(sg.id)