Skip to content

frostmoln_container_registry_artifacts (Data Source) ​

Lists the artifacts — image manifests — in ONE repository of this tenant's container registry namespace.

The whole repository is returned: this data source follows the API's pagination itself and assembles every page, because Terraform has no notion of a partial list and a truncated one would silently plan against a registry that is missing images.

OBSERVATIONAL, like storage_used_bytes on frostmoln_container_registry: artifacts appear on docker push, tags move between them, and pulled_at advances whenever anything pulls. Expect the values to differ on every refresh, and do not build a configuration that plans a change from them.

A tenant that has NOT enabled its registry is an error here, not an empty list — an empty list would make "this tenant has no registry" and "this repository holds no images" indistinguishable. A repository that does not exist is an error for the same reason.

THERE IS NO ARTIFACT RESOURCE, AND THAT IS DELIBERATE. The API can delete an artifact — fm registry image delete <repository> <digest>, the Remove button in the portal, or DELETE /registry/artifacts — but Terraform is not where that belongs, for three reasons.

FIRST, THIS PROVIDER IS ALREADY NON-DESTRUCTIVE FOR REGISTRY CONTENT. frostmoln_container_registry's own Delete removes the registry from state and destroys nothing, warning that the namespace and its images survive. An artifact resource would be the single exception — the one registry object a terraform destroy in an unrelated module could actually annihilate, and it would annihilate content a pipeline pushed and Terraform never made.

SECOND, THE DIGEST IS MINTED BY A BUILD OUTSIDE TERRAFORM. Hardcode one and it is stale on the next push; compute it from this data source and the resource is keyed off a value this very schema documents as observational and expected to change on every refresh — a perpetual destroy/create plan.

THIRD, DRIFT IS GUARANTEED AND ONE-DIRECTIONAL. A fm registry image delete, a portal Remove or a tag overwrite makes the object vanish underneath state, and every later plan proposes recreating something Terraform cannot create.

If declarative cleanup is ever genuinely wanted, the object to model is the RETENTION POLICY on the tenant's namespace — a real desired-state object — never the artifact. Meanwhile: use this data source to FIND what to remove, and remove it with a tool that knows it is destroying content.

Example Usage ​

terraform
# Every artifact in one repository. `repository` is RELATIVE to the tenant's
# namespace - the `name` of a frostmoln_container_registry_repositories entry,
# never a full image reference - and it may contain "/".
data "frostmoln_container_registry_artifacts" "api_server" {
  repository = "team/api-server"
}

# Untagged, orphaned manifests: an EMPTY tag list means a later push moved the
# tag this artifact used to carry onto new content. It can no longer be pulled by
# name, only by digest, and it still occupies the namespace's storage. Listing
# them is the point, not an error.
output "orphaned_digests" {
  value = [
    for a in data.frostmoln_container_registry_artifacts.api_server.artifacts :
    a.digest if length(a.tags) == 0
  ]
}

# pulled_at is NULL - never a zero timestamp, never "unknown" - for an artifact
# nothing has ever fetched, so a null test is a sound one.
output "never_pulled_digests" {
  value = [
    for a in data.frostmoln_container_registry_artifacts.api_server.artifacts :
    a.digest if a.pulled_at == null
  ]
}

# DO NOT sum size_bytes to work out storage usage. A layer shared between
# artifacts is stored once and counted once against the cap, but counted in full
# in every artifact that references it, so a sum overstates the namespace - and
# deleting an artifact frees only the layers nothing else references. The
# registry's own figure is the only correct one.
data "frostmoln_container_registry" "current" {}

output "namespace_storage_used_bytes" {
  value = data.frostmoln_container_registry.current.storage_used_bytes
}

# size_bytes answers "how big is this image", which is a fair question per
# artifact - it is only the addition that is wrong.
output "artifact_sizes_by_digest" {
  value = {
    for a in data.frostmoln_container_registry_artifacts.api_server.artifacts :
    a.digest => a.size_bytes
  }
}

# WHAT TO DO WITH THE ANSWER. There is no artifact RESOURCE and there will not
# be one: Terraform never pushed these images, so wrapping them in a resource
# would give it a Delete with no Create — and turn any `terraform destroy` into
# the silent removal of content a pipeline produced. Use the list to decide, and
# delete deliberately, with a tool that knows it is destroying something:
#
#   fm registry image delete web/api sha256:<digest>
#
# Every untagged manifest in the repository, ready to pipe:
output "untagged_digests" {
  value = [for a in data.frostmoln_container_registry_artifacts.api_server.artifacts : a.digest if length(a.tags) == 0]
}

Schema ​

Required ​

  • repository (String) The repository to list, RELATIVE to the tenant's namespace — the name of a frostmoln_container_registry_repositories entry, not a full image reference and not prefixed with the endpoint or namespace. It may contain /. A repository that does not exist is an error, not an empty list.

Read-Only ​

  • artifacts (Attributes List) Every artifact in the repository, tagged and untagged alike. (see below for nested schema)

Nested Schema for artifacts ​

Read-Only:

  • digest (String) The artifact's content digest (sha256:...) — the immutable reference, <endpoint>/<namespace>/<repository>@<digest>. Unlike a tag it cannot be moved to different content by a later push.

  • pulled_at (String) When the artifact was last pulled, RFC 3339.

    NULL MEANS NEVER PULLED. It does not mean "unknown", and it is never reported as a zero or epoch timestamp — so a.pulled_at == null is a sound test for an image that nothing has ever fetched. OBSERVATIONAL: a single pull between two refreshes changes it.

  • pushed_at (String) When the artifact was pushed, RFC 3339.

  • size_bytes (Number) The size of THIS artifact in bytes, as the registry reports it for the artifact alone.

    DO NOT SUM THESE, and do not compare a sum with storage_used_bytes on frostmoln_container_registry. A layer shared between artifacts in the same namespace is counted ONCE against that namespace's cap, but counted IN FULL in every artifact that references it — so a sum over this list overstates what the namespace occupies, usually by a lot, since images built from a common base share nearly all of their bytes. For the same reason, deleting an artifact frees only the layers nothing else references, which is normally far fewer bytes than this number. This attribute answers "how big is this image", never "how much quota does it cost"; storage_used_bytes is the only correct answer to the second.

  • tags (List of String) The tags pointing at this artifact, without any repository prefix.

    AN EMPTY LIST IS NOT AN ERROR AND NOT A MISSING VALUE: it means the artifact is an UNTAGGED, ORPHANED manifest — a later push moved the tag it used to carry onto new content. Such an artifact can no longer be pulled by name, only by digest, and it still consumes the namespace's storage. They are listed deliberately, precisely so a configuration can find them.