Skip to main content

MTN Cloud Python SDK

PyPI version Tests Docs Python 3.10+ License: MIT

A Modern Python SDK for MTN Cloud with typed models, clear resource managers, and practical workflows for compute, networking, storage, archives, security groups, backups, and more.

Docs: mtn-cloud-python

Disclaimer: Unofficial community project. Not affiliated with MTN Nigeria.

Why You'll Like It

  • Simple Pythonic API across core MTN Cloud resources
  • Typed Pydantic models with IDE autocomplete
  • Built-in retry behavior and timeout controls
  • Token or username/password authentication
  • Structured exceptions for better error handling
  • Examples for real-world automation scripts

Installation

pip install mtn-cloud

Documentation

Quick Start

from mtn_cloud import MTNCloud

cloud = MTNCloud(token="your-api-token")

# Verify auth and connectivity
user = cloud.whoami()
print(f"Connected as: {user.username}")
print("Ping:", cloud.ping())

# List a few running instances
running = cloud.instances.list(status="running", max_results=5)
for instance in running:
    print(instance.id, instance.name, instance.status, instance.primary_ip)

Authentication

from mtn_cloud import MTNCloud

# Option 1: token (recommended)
cloud = MTNCloud(token="your-api-token")

# Option 2: environment variable
# export MTN_CLOUD_TOKEN="your-api-token"
cloud = MTNCloud()

# Option 3: username/password
cloud = MTNCloud(username="user@example.com", password="your-password")

Get your API token from MTN Cloud Console: User Icon (top-right) -> User Settings -> API Access.

What You Can Do

1. Discover Reference Data

Use these lookups before provisioning so your scripts stay deterministic. They all use permission-safe endpoints (the admin-level clouds/plans endpoints are restricted on most tenant accounts — you don't need them).

# Groups (sites) — also carry the cloud/zone IDs you need
group = cloud.groups.get_by_name("MTNNG_CLOUD_AZ_1")
print(group.id, group.name, group.cloud_ids)

# Instance types — each carries its own default_layout_id
itype = cloud.instance_types.get_by_code("MTN-CS10")
print(itype.code, itype.default_layout_id)

# Resource pools — where the instance is hosted (the resource_pool_id)
for pool in cloud.instances.list_resource_pools(group="MTNNG_CLOUD_AZ_1"):
    print(pool.code, pool.name)

# Service plans — CPU/memory/storage tiers for this zone + layout
for plan in cloud.instances.list_service_plans(
    zone_id=group.cloud_ids[0],
    layout_id=itype.default_layout_id,
    group_id=group.id,
):
    print(plan["id"], plan["name"])

A resource pool is required to create an instance — it's where the VM is hosted. provision() (below) discovers it for you; or fetch one yourself with cloud.instances.get_resource_pool("my-project", group="MTNNG_CLOUD_AZ_1").

2. Create an Instance

The guided provision() resolves layout, plan, and resource pool from names — the fastest path:

instance = cloud.instances.provision(
    name="web-01",
    type="MTN-CS10",                # type code
    group="MTNNG_CLOUD_AZ_1",       # also used as the cloud/zone
    plan="G2S4",                    # plan name (or numeric id)
    resource_pool="my-project",     # pool name; auto-selected if the group has only one
)
print(instance.id, instance.status, instance.primary_ip)

For full control over every ID, use create() directly:

instance = cloud.instances.create(
    name="web-01",
    cloud="MTNNG_CLOUD_AZ_1",
    type="MTN-CS10",
    group="MTNNG_CLOUD_AZ_1",
    layout=327,
    plan=6776,
    resource_pool_id="pool-214",    # or the numeric ID 214
    labels=["production", "web"],
)

3. Manage an Instance

instance = cloud.instances.get(123)
print(instance.name, instance.status, instance.primary_ip)

# Action methods from model
instance.stop()
instance.start()
instance.restart()
instance.refresh()

# Or from resource manager
cloud.instances.resize(123, plan_id=6780)
cloud.instances.delete(123, force=True, preserve_volumes=True)

4. Work with Networks

group = cloud.groups.get_by_name("MTNNG_CLOUD_AZ_1")

# List networks
networks = cloud.networks.list(cloud_id=group.cloud_ids[0])
for n in networks[:5]:
    print(n.id, n.name, n.cidr)

# Create an OpenStack network (needs an OpenStack type + a resource pool)
net_type = next(
    t for t in cloud.networks.list_types(openstack_only=True)
    if t.code == "openstackPrivate"
)
pool = cloud.instances.get_resource_pool("my-project", group=group.name)

new_network = cloud.networks.create(
    name="mtn-prod-net",
    cloud_id=group.cloud_ids[0],
    group_id=group.id,
    type_id=net_type.id,
    resource_pool_id=pool.id,
    cidr="10.42.10.0/24",
    gateway="10.42.10.1",
    dns_primary="8.8.8.8",
)

# Inspect subnets
subnets = cloud.networks.list_subnets(new_network.id)
print(f"Subnets: {len(subnets)}")

5. Manage Security Groups

# Create a security group and add rules
sg = cloud.security_groups.create(
    name="web-servers",
    description="HTTP, HTTPS, and SSH access",
)

cloud.security_groups.create_rule(
    sg.id,
    name="allow-ssh",
    direction="ingress",
    protocol="tcp",
    port_range="22",
)

cloud.security_groups.create_rule(
    sg.id,
    name="allow-https",
    direction="ingress",
    protocol="tcp",
    port_range="443",
)

# Use the security group when provisioning
instance = cloud.instances.create(
    name="app-server-01",
    cloud="MTNNG_CLOUD_AZ_1",
    type="MTN-CS10",
    group="MTNNG_CLOUD_AZ_1",
    layout=327,
    plan=6776,
    resource_pool_id="pool-214",
    security_group="web-servers",
)

6. Snapshot Instances

# Create a snapshot before a risky operation
snap = cloud.instances.create_snapshot(
    instance_id=instance.id,
    name="pre-upgrade",
)

# Revert if something goes wrong (stop the instance first)
cloud.instances.stop(instance.id)
cloud.instances.wait_until_stopped(instance.id)
cloud.instances.revert_snapshot(instance.id, snapshot_id=snap.id)

7. Work with Backups

# List configured backups and their status
for backup in cloud.backups.list():
    print(f"{backup.name}: last_run={backup.last_run} status={backup.last_status}")

# Trigger an immediate backup run
cloud.backups.execute(backup_id=42)

# Check execution history
for result in cloud.backups.list_results(backup_id=42):
    print(f"{result.start_date}: {result.status} ({result.size_in_mb} MB)")

# List and execute backup jobs (schedules)
for job in cloud.backups.list_jobs():
    print(f"{job.name}: cron={job.cron_expression}")

8. Work with Storage and Archives

# Create S3-compatible storage provider
storage = cloud.storage_buckets.create_s3(
    name="my-s3-storage",
    bucket_name="my-app-objects",
    access_key="your-access-key",
    secret_key="your-secret-key",
    endpoint="https://ps1csp-s3.ict.mtn.com.ng:9021",
    create_bucket=True,
)

# Create archive bucket linked to storage provider
archive = cloud.archive_buckets.create(
    name="my-app-archives",
    storage_provider_id=storage.id,
    visibility="private",
)

# Upload one file
uploaded = cloud.archive_buckets.upload_file(
    bucket_name=archive.name,
    remote_path="/",
    local_path="./backup.sql",
)
print(uploaded.id, uploaded.name)

# Upload a directory (preserves local folder structure)
summary = cloud.archive_buckets.upload_directory(
    bucket_name=archive.name,
    remote_path="/imports/",
    local_directory="./reports",
    recursive=True,
)
print(
    f"scanned={summary.scanned_count} "
    f"uploaded={summary.uploaded_count} "
    f"failed={summary.failed_count} "
    f"skipped={summary.skipped_count}"
)

# List and download
files = cloud.archive_buckets.list_files(bucket_name=archive.name, remote_path="/", full_tree=True)
if files:
    content = cloud.archive_buckets.download_file(
        bucket_name=archive.name,
        remote_path=files[0].file_path or files[0].name,
    )
    print(f"Downloaded {len(content)} byte(s)")

Storage vs archive model:

  • cloud.storage_buckets: provider configuration (endpoint, credentials, backing bucket)
  • cloud.archive_buckets: logical file container attached to a provider
  • file operations happen through archive APIs

Error Handling

from mtn_cloud import (
    AuthenticationError,
    MTNCloudError,
    NotFoundError,
    QuotaExceededError,
    RateLimitError,
    ResourceConflictError,
    ValidationError,
)

try:
    cloud.instances.get(999999)
except NotFoundError:
    print("Resource not found")
except AuthenticationError:
    print("Authentication failed")
except ValidationError as exc:
    print(f"Validation error: {exc}")
except QuotaExceededError as exc:
    print(f"Quota exceeded: {exc.quota_type} ({exc.current}/{exc.limit})")
except ResourceConflictError as exc:
    print(f"Conflict: {exc}")
except RateLimitError as exc:
    print(f"Rate limited, retry_after={exc.retry_after}")
except MTNCloudError as exc:
    print(f"SDK/API error: {exc}")

Configuration

Environment variables:

Variable Description Default
MTN_CLOUD_TOKEN API access token -
MTN_CLOUD_USERNAME Login username (alternative to token) -
MTN_CLOUD_PASSWORD Login password (alternative to token) -
MTN_CLOUD_URL API base URL https://console.cloud.mtn.ng
MTN_CLOUD_TIMEOUT Request timeout in seconds 30
MTN_CLOUD_MAX_RETRIES Maximum retry attempts 3
MTN_CLOUD_RETRY_DELAY Retry backoff factor 1.0
MTN_CLOUD_VERIFY_SSL Enable SSL verification true
MTN_CLOUD_USER_AGENT Application identity appended to the SDK user agent -
MTN_CLOUD_DEBUG Enable bounded, secret-redacted HTTP debug logs false

Programmatic configuration:

from mtn_cloud import MTNCloud, MTNCloudConfig

config = MTNCloudConfig(
    token="your-token",
    timeout=60,
    max_retries=5,
    retry_delay=1.5,
    verify_ssl=True,
    user_agent="my-automation/1.0",  # appended after the required SDK identity
)

cloud = MTNCloud(config=config)

Tokens and passwords are stored as masked Pydantic secret values, and debug logging recursively redacts credential-shaped fields. The transport retries transient failures only for safe read methods (GET, HEAD, and OPTIONS); create, update, action, and delete requests are never status-retried automatically.

The default mtn-cloud-python/<version> user-agent prefix is required by the MTN Cloud API edge. A configured user_agent is treated as an application suffix so the SDK identity is preserved.

Examples

Script What it demonstrates
examples/basic_usage.py Auth, connectivity, resource listing
examples/create_instance.py End-to-end instance creation scaffold
examples/storage_archive_s3.py Storage provider + archive bucket + file ops
examples/list_storage_buckets.py Storage bucket and archive bucket discovery
examples/upload_archive_directory.py Bulk archive upload from local directory
examples/copy_archive_file.py Archive file copy between buckets

API Notes

  • Some endpoints can be tenant-restricted in specific MTN Cloud environments.
  • Build scripts to discover IDs dynamically (list + get_by_name) before create/update operations.

Contributing

Contributions are welcome. Open an issue or submit a PR.

License

MIT License. See LICENSE for details.

Links

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mtn_cloud-0.3.3.tar.gz (98.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mtn_cloud-0.3.3-py3-none-any.whl (70.9 kB view details)

Uploaded Python 3

File details

Details for the file mtn_cloud-0.3.3.tar.gz.

File metadata

  • Download URL: mtn_cloud-0.3.3.tar.gz
  • Upload date:
  • Size: 98.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mtn_cloud-0.3.3.tar.gz
Algorithm Hash digest
SHA256 06fed8e8f130929503a251dded7b94fcc8f1eba902f832d344d0ef2276b7dda6
MD5 e1e6ddcf057c8b790c36f304240015b3
BLAKE2b-256 6f3f186a2634d32c2cbf085d7296a2d14eb8cbd7665035b757cd348693e7e31b

See more details on using hashes here.

Provenance

The following attestation bundles were made for mtn_cloud-0.3.3.tar.gz:

Publisher: publish.yml on mahveotm/mtn-cloud-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mtn_cloud-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: mtn_cloud-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 70.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mtn_cloud-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 f3d78318992980f71e2842a44822e7f00538d1bab145cfeacb3f46b77feef63e
MD5 ad61cb6aecf43ccf0c69641a4af1104a
BLAKE2b-256 d16237163d7cb03815651b6db475d3b983f89790147194ada0594533587b513f

See more details on using hashes here.

Provenance

The following attestation bundles were made for mtn_cloud-0.3.3-py3-none-any.whl:

Publisher: publish.yml on mahveotm/mtn-cloud-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.3 This release

2 files

0.3.2

2 files

0.3.1

2 files

0.2.19

2 files

0.2.17

2 files

0.2.16

2 files

0.2.15

2 files

0.2.14

2 files

0.2.13

2 files

0.2.12

2 files

0.2.11

2 files

0.2.10

2 files

0.2.9

2 files

0.2.7

2 files

0.2.6

2 files

0.2.5

2 files

0.2.2

2 files

0.1.13

2 files

0.1.11

2 files

0.1.10

2 files

0.1.5

2 files

0.1.4

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page