Skip to content
Merged
236 changes: 236 additions & 0 deletions examples/registry_provider_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Copyright IBM Corp. 2025, 2026
# SPDX-License-Identifier: MPL-2.0

from __future__ import annotations

import argparse
import os

from pytfe import TFEClient, TFEConfig
from pytfe.models import (
RegistryProviderPlatformCreateOptions,
RegistryProviderPlatformID,
RegistryProviderPlatformListOptions,
RegistryProviderVersionID,
)


def _print_header(title: str):
print("\n" + "=" * 80)
print(title)
print("=" * 80)


def main():
parser = argparse.ArgumentParser(
description="Registry Provider Platforms demo for python-tfe SDK"
)
parser.add_argument(
"--address", default=os.getenv("TFE_ADDRESS", "https://app.terraform.io")
)
parser.add_argument("--token", default=os.getenv("TFE_TOKEN", ""))
parser.add_argument("--organization", required=True, help="Organization name")
parser.add_argument(
"--registry-name",
default="private",
help="Registry name (default: private)",
)
parser.add_argument("--namespace", required=True, help="Provider namespace")
parser.add_argument("--name", required=True, help="Provider name")
parser.add_argument(
"--version", required=True, help="Provider version (e.g., 1.0.0)"
)
parser.add_argument(
"--page-size",
type=int,
default=100,
help="Page size for listing platforms",
)
parser.add_argument("--create", action="store_true", help="Create a platform")
parser.add_argument("--read", action="store_true", help="Read a specific platform")
parser.add_argument(
"--delete", action="store_true", help="Delete a specific platform"
)
parser.add_argument(
"--os", dest="os", help="Operating system (e.g., linux, darwin)"
)
parser.add_argument("--arch", help="Architecture (e.g., amd64, arm64)")
parser.add_argument("--shasum", help="SHA256 checksum of the provider binary")
parser.add_argument("--filename", help="Filename of the provider binary zip")
args = parser.parse_args()

cfg = TFEConfig(address=args.address, token=args.token)
client = TFEClient(cfg)

version_id = RegistryProviderVersionID(
organization_name=args.organization,
registry_name=args.registry_name,
namespace=args.namespace,
name=args.name,
version=args.version,
)

# 1) List all platforms for the provider version
_print_header(
f"Listing platforms for {args.registry_name}/{args.namespace}/{args.name} @ {args.version}"
)

list_options = RegistryProviderPlatformListOptions(page_size=args.page_size)

platform_count = 0
for platform in client.registry_provider_platforms.list(
version_id=version_id,
options=list_options,
):
platform_count += 1
print(f"- Platform {platform.os}/{platform.arch} (ID: {platform.id})")
print(f" Filename: {platform.filename}")
print(f" Shasum: {platform.shasum}")
print(f" Provider Binary Uploaded: {platform.provider_binary_uploaded}")
if platform.permissions:
print(" Permissions:")
print(f" Can Delete: {platform.permissions.can_delete}")
print(f" Can Upload Asset: {platform.permissions.can_upload_asset}")
if platform.links:
print(" Links:")
for key, value in platform.links.items():
print(f" {key}: {value}")
print()

if platform_count == 0:
print("No platforms found.")
else:
print(f"Total: {platform_count} platforms")

# 2) Create a new platform (if --create flag is provided)
if args.create:
if not args.os:
print("Error: --os is required for create operation")
return
if not args.arch:
print("Error: --arch is required for create operation")
return
if not args.shasum:
print("Error: --shasum is required for create operation")
return
if not args.filename:
print("Error: --filename is required for create operation")
return

_print_header(f"Creating platform: {args.os}/{args.arch}")

create_options = RegistryProviderPlatformCreateOptions(
os=args.os,
arch=args.arch,
shasum=args.shasum,
filename=args.filename,
)

new_platform = client.registry_provider_platforms.create(
version_id=version_id,
options=create_options,
)

print(f"Created platform: {new_platform.id}")
print(f" OS: {new_platform.os}")
print(f" Arch: {new_platform.arch}")
print(f" Filename: {new_platform.filename}")
print(f" Shasum: {new_platform.shasum}")
print(f" Provider Binary Uploaded: {new_platform.provider_binary_uploaded}")

if new_platform.links:
print("\n Upload URLs:")
if "provider-binary-upload" in new_platform.links:
print(
f" Provider Binary: {new_platform.links['provider-binary-upload']}"
)

# 3) Read a specific platform (if --read flag is provided)
if args.read:
if not args.os:
print("Error: --os is required for read operation")
return
if not args.arch:
print("Error: --arch is required for read operation")
return

_print_header(f"Reading platform: {args.os}/{args.arch}")

platform_id = RegistryProviderPlatformID(
organization_name=args.organization,
registry_name=args.registry_name,
namespace=args.namespace,
name=args.name,
version=args.version,
os=args.os,
arch=args.arch,
)

platform = client.registry_provider_platforms.read(platform_id)

print(f"Platform ID: {platform.id}")
print(f" OS: {platform.os}")
print(f" Arch: {platform.arch}")
print(f" Filename: {platform.filename}")
print(f" Shasum: {platform.shasum}")
print(f" Provider Binary Uploaded: {platform.provider_binary_uploaded}")

if platform.permissions:
print(" Permissions:")
print(f" Can Delete: {platform.permissions.can_delete}")
print(f" Can Upload Asset: {platform.permissions.can_upload_asset}")

if platform.links:
print(" Links:")
for key, value in platform.links.items():
print(f" {key}: {value}")

# 4) Delete a platform (if --delete flag is provided)
if args.delete:
if not args.os:
print("Error: --os is required for delete operation")
return
if not args.arch:
print("Error: --arch is required for delete operation")
return

_print_header(f"Deleting platform: {args.os}/{args.arch}")

platform_id = RegistryProviderPlatformID(
organization_name=args.organization,
registry_name=args.registry_name,
namespace=args.namespace,
name=args.name,
version=args.version,
os=args.os,
arch=args.arch,
)

try:
platform_to_delete = client.registry_provider_platforms.read(platform_id)
print("Platform to delete:")
print(f" ID: {platform_to_delete.id}")
print(f" OS/Arch: {platform_to_delete.os}/{platform_to_delete.arch}")
print(f" Filename: {platform_to_delete.filename}")
except Exception as e:
print(f"Error reading platform: {e}")
return

client.registry_provider_platforms.delete(platform_id)
print(f"\n Successfully deleted platform: {args.os}/{args.arch}")

# List remaining platforms
_print_header("Listing platforms after deletion")
remaining_count = 0
for platform in client.registry_provider_platforms.list(version_id=version_id):
remaining_count += 1
print(f"- {platform.os}/{platform.arch} (ID: {platform.id})")

if remaining_count == 0:
print("No platforms remaining.")
else:
print(f"Total remaining: {remaining_count} platforms")


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions src/pytfe/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .resources.query_run import QueryRuns
from .resources.registry_module import RegistryModules
from .resources.registry_provider import RegistryProviders
from .resources.registry_provider_platform import RegistryProviderPlatforms
from .resources.registry_provider_version import RegistryProviderVersions
from .resources.reserved_tag_key import ReservedTagKeys
from .resources.run import Runs
Expand Down Expand Up @@ -83,6 +84,7 @@ def __init__(self, config: TFEConfig | None = None):
self.registry_modules = RegistryModules(self._transport)
self.registry_providers = RegistryProviders(self._transport)
self.registry_provider_versions = RegistryProviderVersions(self._transport)
self.registry_provider_platforms = RegistryProviderPlatforms(self._transport)

# State and execution resources
self.state_versions = StateVersions(self._transport)
Expand Down
60 changes: 60 additions & 0 deletions src/pytfe/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,63 @@ class InvalidTeamProjectAccessIDError(InvalidValues):

def __init__(self, message: str = "invalid value for team project access ID"):
super().__init__(message)


# Registry Provider Platform errors
class RequiredOSError(RequiredFieldMissing):
"""Raised when a required OS field is missing."""

def __init__(self, message: str = "os is required"):
super().__init__(message)


class RequiredArchError(RequiredFieldMissing):
"""Raised when a required architecture field is missing."""

def __init__(self, message: str = "arch is required"):
super().__init__(message)


class RequiredShasumError(RequiredFieldMissing):
"""Raised when a required shasum field is missing."""

def __init__(self, message: str = "shasum is required"):
super().__init__(message)


class RequiredFilenameError(RequiredFieldMissing):
"""Raised when a required filename field is missing."""

def __init__(self, message: str = "filename is required"):
super().__init__(message)


class InvalidOSError(InvalidValues):
"""Raised when an invalid OS field is provided."""

def __init__(self, message: str = "invalid value for os"):
super().__init__(message)


class InvalidArchError(InvalidValues):
"""Raised when an invalid architecture field is provided."""

def __init__(self, message: str = "invalid value for arch"):
super().__init__(message)


class InvalidNamespaceError(InvalidValues):
"""Raised when an invalid namespace field is provided."""

def __init__(self, message: str = "invalid value for namespace"):
super().__init__(message)


class InvalidRegistryNameError(InvalidValues):
"""Raised when an invalid registry name field is provided."""

def __init__(
self,
message: str = "invalid value for registry-name. It must be either private or public",
):
super().__init__(message)
16 changes: 16 additions & 0 deletions src/pytfe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@
RegistryProviderPermissions,
RegistryProviderReadOptions,
)
from .registry_provider_platform import (
RegistryProviderPlatform,
RegistryProviderPlatformCreateOptions,
RegistryProviderPlatformID,
RegistryProviderPlatformListOptions,
RegistryProviderPlatformPermissions,
)
from .registry_provider_version import (
RegistryProviderVersion,
RegistryProviderVersionCreateOptions,
Expand Down Expand Up @@ -500,6 +507,12 @@
"RegistryProviderVersionID",
"RegistryProviderVersionListOptions",
"RegistryProviderVersionPermissions",
# Registry provider platforms
"RegistryProviderPlatform",
"RegistryProviderPlatformCreateOptions",
"RegistryProviderPlatformID",
"RegistryProviderPlatformListOptions",
"RegistryProviderPlatformPermissions",
# Query runs
"QueryRun",
"QueryRunActions",
Expand Down Expand Up @@ -706,3 +719,6 @@

# Rebuild models with forward references after all models are loaded
PolicyCheck.model_rebuild()
RegistryProvider.model_rebuild()
RegistryProviderVersion.model_rebuild()
RegistryProviderPlatform.model_rebuild()
Loading
Loading