Skip to content

Recipes

Three complete, real-world workflows. Each assumes an authenticated client:

from mtn_cloud import MTNCloud

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

For isolated patterns (retries, pagination, idempotency), see the Advanced Cookbook.

Provision a Linux VM with SSH

Discover the inputs, open SSH in a security group, provision, and wait until it's reachable.

group = cloud.groups.get_by_name("MTNNG_CLOUD_AZ_1")
itype = cloud.instance_types.get_by_code("MTN-CS10")
pool = cloud.instances.get_resource_pool("my-project", group=group.name)
plans = cloud.instances.list_service_plans(
    zone_id=group.cloud_ids[0], layout_id=itype.default_layout_id, group_id=group.id,
)

sg = cloud.security_groups.create(name="linux-ssh", description="SSH access")
cloud.security_groups.create_rule(
    sg.id, name="allow-ssh", direction="ingress", protocol="tcp",
    port_range="22", source_type="cidr", source="200.200.113.15/32",
)

instance = cloud.instances.create(
    name="linux-web-01",
    cloud=group.name,
    type=itype.code,
    group=group.name,
    layout=itype.default_layout_id,
    plan=plans[0]["id"],
    resource_pool_id=pool.code,
    availability_zone="Lagos-AZ-1-fd1",
    security_group=sg.name,
    create_user=True,
)
instance = cloud.instances.wait_until_running(instance.id, timeout=600)
print("ready:", instance.primary_ip)

SSH keys are uploaded once in the console (User Settings → SSH Keys); the SDK controls the firewall rule and user creation. Then: ssh <your-user>@<instance.primary_ip>.

Back up a folder to MTN Object Storage

Register the provider and bucket idempotently, preview with a dry run, then upload.

from mtn_cloud import NotFoundError

try:
    storage = cloud.storage_buckets.get_by_name("my-s3-storage")
except NotFoundError:
    storage = cloud.storage_buckets.create_s3(
        name="my-s3-storage",
        bucket_name="my-app-objects",
        access_key="your-access-key",                      # from MOS email
        secret_key="your-secret-key",                      # from MOS email
        endpoint="https://ps1csp-s3.ict.mtn.com.ng:9021",
        create_bucket=True,
    )

try:
    archive = cloud.archive_buckets.get_by_name("my-app-archives")
except NotFoundError:
    archive = cloud.archive_buckets.create(
        name="my-app-archives", storage_provider_id=storage.id, visibility="private",
    )

preview = cloud.archive_buckets.upload_directory(
    bucket_name=archive.name, remote_path="/backups/",
    local_directory="./data", recursive=True, dry_run=True,
)
if preview.skipped_count:
    raise RuntimeError(f"{preview.skipped_count} files would be skipped")

result = cloud.archive_buckets.upload_directory(
    bucket_name=archive.name, remote_path="/backups/",
    local_directory="./data", recursive=True, strict=True,
)
print(f"uploaded={result.uploaded_count} failed={result.failed_count}")

Tear down demo resources

Delete in dependency order — instances first, then the firewall and network they used. Deletes are best-effort so one failure doesn't block the rest.

from mtn_cloud import MTNCloudError

def cleanup(manager, items, label):
    for item in items:
        if (item.name or "").startswith("demo-"):
            try:
                manager.delete(item.id)
                print("deleted", label, item.id)
            except MTNCloudError as exc:
                print("skip", label, item.id, exc)

cleanup(cloud.instances, cloud.instances.list(max_results=100), "instance")
cleanup(cloud.security_groups, cloud.security_groups.list(), "security-group")
cleanup(cloud.networks, cloud.networks.list(), "network")

A network or security group can't be deleted while an instance still references it — always remove instances first and let them finish.