Publishing Images and Marketplace Demos

View as Markdown
# Imports (run once)
from air_sdk import AirApi
from air_sdk.endpoints import (
ImagePublishAccessRecord,
MarketplaceDemoPublishAccessRecord,
)
# Authentication (run once)
api = AirApi.with_ngc_config()
# OR api = AirApi.with_api_key(api_key="...")
# OR api = AirApi.with_device_login(email="...", org_num="...")
# ^ use in terminal only — not supported in Jupyter notebooks

The Publish Access Record Lifecycle

A publish access record moves through a set of statuses (the PAR_STATUS type alias in air_sdk.types). The PENDING_* states are awaiting reviewer action:

StatusMeaning
PENDINGFirst-time publish request, awaiting review.
PENDING_ELEVATIONRestricted → public request, awaiting review.
PENDING_RESTRICTIONPublic → restricted request, awaiting review.
PENDING_ALLOWLISTAllow-list change on a restricted resource, awaiting review.
PENDING_UNPUBLISHUnpublish request, awaiting review.
APPROVED_PENDING_IMAGE_PUBLISHApproved, waiting on referenced images to finish publishing.
APPROVEDApproved and live.
DENIEDRejected by a reviewer.
REMOVEDUnpublished.
CANCELLEDWithdrawn by the requester before review.

Requester Flow

The requester actions are the same five on both Image and MarketplaceDemo: request_publish, request_public, request_allowlist_change, request_unpublish, and cancel_publish_access_record. Each returns the updated resource, whose publish_access_record_id points at the PAR the request created.

1. Request to Publish

Submit a resource for review. justification is required. Set prefer_public=False to ask for restricted (allow-list) access, and describe the desired orgs in allowed_orgs_request_text.

# --- Image ---
image_id = '...' # replace with an image you own
image = api.images.request_publish(
image=image_id,
justification='Ready to share with the community.',
prefer_public=True,
)
print(image.publicly_published, image.publish_access_record_id)
# --- Marketplace demo ---
# Demos additionally accept `tags` (assign tag names as part of the request) and
# `publish_images` (auto-publish referenced images that aren't yet visible).
demo_id = '...' # replace with a demo you own
demo = api.marketplace_demos.request_publish(
marketplace_demo=demo_id,
justification='Ready to share with the community.',
prefer_public=True,
publish_images=True,
tags=['networking', 'sonic'],
)
print(demo.publicly_published, demo.publish_access_record_id)

2. Request a Visibility Change

For an already-published resource, request a switch between public and restricted (request_public), or update the allow-list on a restricted resource (request_allowlist_change).

# Elevate to public (prefer_public=True) or restrict (prefer_public=False).
api.images.request_public(
image=image_id, prefer_public=True, justification='Broad interest.'
)
api.marketplace_demos.request_public(
marketplace_demo=demo_id, prefer_public=True, justification='Broad interest.'
)
# Change who may access a restricted resource.
api.images.request_allowlist_change(
image=image_id,
justification='Add partner org.',
allowed_orgs_request_text='Acme Corp and Globex.',
)
api.marketplace_demos.request_allowlist_change(
marketplace_demo=demo_id,
justification='Add partner org.',
allowed_orgs_request_text='Acme Corp and Globex.',
)

3. Request to Unpublish, or Cancel a Pending Request

request_unpublish queues removal for review; cancel_publish_access_record withdraws whatever request is currently pending so you can resubmit.

api.images.request_unpublish(image=image_id, justification='No longer maintained.')
api.marketplace_demos.request_unpublish(
marketplace_demo=demo_id, justification='No longer maintained.'
)
# Withdraw a pending request
api.images.cancel_publish_access_record(image=image_id)
api.marketplace_demos.cancel_publish_access_record(marketplace_demo=demo_id)

Reviewer Flow

Reviewers (community managers) act on the publish access records themselves. The PAR endpoints — api.image_publish_access_records and api.marketplace_demo_publish_access_records — expose the same interface: list, get, approve, deny, and set_visibility.

1. Find Records Awaiting Review

List by status to triage the queue. Both endpoints accept the same filters (status, publicly_published, requested_by_email, requesting_org_display_name, requesting_org_ngc_org_name, plus the resource id).

pending_image_pars: list[ImagePublishAccessRecord] = list(
api.image_publish_access_records.list(status='PENDING')
)
pending_demo_pars: list[MarketplaceDemoPublishAccessRecord] = list(
api.marketplace_demo_publish_access_records.list(status='PENDING')
)
[par.dict() for par in pending_image_pars]

2. Approve

Approve as public (publicly_published=True) or restricted (publicly_published=False with allowed_orgs). When omitted, publicly_published defaults to the record’s prefer_public.

image_par_id = '...' # a pending image PAR id
demo_par_id = '...' # a pending demo PAR id
api.image_publish_access_records.approve(record=image_par_id, publicly_published=True)
api.marketplace_demo_publish_access_records.approve(
record=demo_par_id,
publicly_published=False,
allowed_orgs=['<org-uuid>'],
)

3. Deny

Reject a pending request, optionally with a denial_reason that is surfaced back to the requester.

api.image_publish_access_records.deny(
record=image_par_id, denial_reason='Needs more docs.'
)
api.marketplace_demo_publish_access_records.deny(
record=demo_par_id, denial_reason='Needs more docs.'
)

4. Set Visibility Directly

On an already-approved record, a reviewer can change visibility immediately without a new request. When restricting, allowed_orgs is the full replacement allow-list.

api.image_publish_access_records.set_visibility(
record=image_par_id, publicly_published=True
)
api.marketplace_demo_publish_access_records.set_visibility(
record=demo_par_id,
publicly_published=False,
allowed_orgs=['<org-uuid>'],
)

Privileged Immediate Publish / Unpublish

Privileged callers can publish or unpublish directly, auto-approving the underlying record and skipping the request/review cycle. Use allowed_orgs (org UUIDs) here — the authoritative allow-list, distinct from the free-text allowed_orgs_request_text hint used by the gated request_* actions.

# Images return the updated Image; demos return None.
api.images.publish(image=image_id, prefer_public=True, justification='Curated release.')
api.marketplace_demos.publish(
marketplace_demo=demo_id,
prefer_public=False,
allowed_orgs=['<org-uuid>'],
justification='Curated release.',
publish_images=True,
)
api.images.unpublish(image=image_id)
api.marketplace_demos.unpublish(marketplace_demo=demo_id)

Resource-Specific Differences

The flows are otherwise identical; a few extras exist only on demos:

  • tags — marketplace_demos.request_publish accepts a tags list to assign tag names as part of the request (omit to leave tags unchanged, [] to clear).
  • publish_images — demo publish/visibility requests can cascade to the images the demo references, publishing org-owned images so they reach the demo’s audience. When False (default), a request that needs image publishing is rejected with 400.
  • Return types — image publish/unpublish return the updated Image; the demo equivalents return None.
  • 409 conflicts — while a demo’s images are still cascading, publish, unpublish, and provision may return 409; retry once the cascade settles.