Skip to content

Releases: ataila/terraform-provider-ataila

v1.2.0

Choose a tag to compare

@attilamacskasy attilamacskasy released this 07 Oct 05:34

A minor release: additions only, under the stability promise of 1.0.0. A configuration and a state of 1.1.0
plan with no changes.

Added

  • ataila_tenant_quota resource: a tenant's whole quota set, quota = map of dimension (vcpu, ram_gb,
    disk_gb, desktops, vms, ai_tpm, ai_budget_eur_month, gpu) to {limit, policy, note} (policy
    auto by default, approve_always or hard_cap), through GET / PUT /tenants/{id}/quotas. The resource
    owns the set the way the API replaces it: a dimension with a limit on the platform that the configuration
    leaves out loses its limit on the next apply (no limit: every order touching it goes to an approval card), and
    the plan warns, naming it. usage (every dimension: limit, policy, allocated, reserved, remaining), notes
    and warnings are read back. The platform keeps four decimal places; the state keeps the configuration's
    spelling of a limit it rounded. Destroy removes every limit (not gated: the platform treats it as a quota
    change); import by the tenant's id; tenant_id forces a new resource. A tenant that does not exist, a token
    without orders-admin-global and a platform without the endpoints are explained errors.
  • ataila_tenant_quota data source: the same set with set_by and set_at per limit, usage and notes.
  • ataila_catalogue_items data source: the enabled catalogue items in display order — key, kind, name, edition,
    requires_approval, sort_order, and the order form, quota mapping and price basis as JSON text
    (spec_schema_json, quota_dimensions_json, price_hint_json).
  • ataila_orders data source (tenant_id, optional status) and ataila_order data source (id, with
    events): a tenant's orders, read only — approval, rejection and re-runs stay in the portal, and there is
    no order resource. Each order carries its status, the quota check's quota_result and quota_decision, who
    approved or rejected it and why, operation_id, and for an AI gateway key order the delivered key's key_id
    and key_alias (never its value); its spec, quota check, overage and delivery facts are JSON text.
  • ataila_ai_rate_card resource: the list rate of one serving tier, eur_per_1m_input and eur_per_1m_output
    (EUR per one million tokens, six decimal places kept, the configured spelling kept), valid_from (today when
    left out; a past day re-prices the usage since then, a future day schedules the change), note (owned: left
    out, it is cleared), through PUT /ai/rate-card/{tier}. The same rate again changes nothing on the platform, so
    a second apply sends nothing and an apply after a portal change puts the rate back; valid_to reads when a
    change is scheduled after it. Destroy forgets only (the platform never removes a list rate); import by tier.
  • ataila_ai_rate_plan resource: a tenant's whole rate plan, rates = map of tier to
    {eur_per_1m_input, eur_per_1m_output, note}, optional valid_from (sent with each change, not read back),
    through PUT /tenants/{id}/ai-rate-plan. A tier left out goes back to the list rate on the next apply, and the
    plan warns, naming it; effective (what each tier costs the tenant today, its basis and the list rate beside it)
    and contract_included read back. Destroy ends the plan (DELETE, not gated: a price change, nothing removed);
    import by tenant id; tenant_id forces a new resource.
  • ataila_ai_rate_card and ataila_ai_rate_plan data sources: the whole card (per tier current, upcoming,
    seedable; the history) and one tenant's plan (rates, upcoming, effective, contract, the history).
  • ataila_ai_usage data source (tenant_id, optional month, YYYY-MM, default the current month): one tenant's
    month of AI gateway usage, rated — totals, by_key (with rows per tier and model and each key's
    attribution), by_tier (with the rate), by_day, forecast, budget (the ai_budget_eur_month quota against
    the spend), rated_eur, rate_basis, rate_bases, unrated_tiers, rated_complete; the gateway's own shadow
    price as shadow_usd. ataila_ai_gateway_usage (optional month): every tenant's month, rated, and the
    unattributed keys.

Minimum platform, per feature

  • The provider still works with every platform from release 1.0.187 on. Tenant quotas, the catalogue and the
    order reads need platform release 1.0.233 or later (client.ReleaseQuotasOrders); AI usage, the rate card and
    rate plans need 1.0.237 or later (client.ReleaseAIBilling). A configuration that uses one of them on an older
    platform is refused at plan time, before any request, naming both releases.

Contract

  • api/openapi-v1.json is the platform's contract with release 1.0.237's operations (98). Since 1.0.206 it adds
    the five quota, catalogue and order operations (tenant_quotas_get, tenant_quotas_put, catalogue_items_list,
    tenant_orders_list, orders_get; platform 1.0.233) and the seven AI usage and rate operations
    (tenant_ai_usage_get, ai_gateway_usage_get, ai_rate_card_get, ai_rate_card_put, tenant_ai_rate_plan_get,
    tenant_ai_rate_plan_put, tenant_ai_rate_plan_delete; 1.0.237) with their schemas, and from the releases in
    between app_subdomain on projects, the hostname_taken refusal and documented codes; nothing is removed or
    changed (the platform's additive guard checks every release against the contract published with 1.0.0).

Documentation

  • Pages and examples for the three new resources and the eight new data sources, and examples/sp-tenant/: a
    service provider's customer tenant from code — its quota set, an AI gateway key inside it, its own AI rates, and
    its orders and month's rated usage read back; its README shows how to run it with a provider built from a
    checkout (a development override) before a release is published.
  • The README shows the company's logo at the top (docs/images/ataila-logo.png).
  • The documentation link points to the company's website, https://www.ataila.com/developers/terraform, in the
    README and on the registry's overview page.
  • "Switching between OpenTofu and Terraform" (README and the registry's overview page) follows what provider
    1.1.0 did with OpenTofu 1.12.3 and Terraform 1.9.8 on 2026-10-03. Terraform → OpenTofu is not "nothing":
    tofu plan and tofu output work on a Terraform state, but tofu show fails with Failed to load plugin
    schemas … unavailable provider "registry.terraform.io/ataila/ataila"
    until
    tofu state replace-provider registry.terraform.io/ataila/ataila registry.opentofu.org/ataila/ataila (or one
    tofu apply) has run. OpenTofu → Terraform: the error a user meets first is terraform init's Failed to
    query available provider packages … registry.opentofu.org does not have a provider named
    registry.opentofu.org/ataila/ataila
    , quoted now, and the order is terraform state replace-provider, then
    terraform init (again, if it ran before).
  • New, temporary: "OpenTofu until its registry lists the provider". While the OpenTofu registry listing is
    pending (opentofu/registry PR #5669; the signing key, PR #5671, was merged on 2026-10-02), OpenTofu installs
    the provider from a filesystem mirror filled from the GitHub release (the platform archive or the air-gapped
    mirror bundle). tofu init reports it as unauthenticated; the section gives the three commands that check
    the archive against the signed SHA256SUMS instead.

CI

  • The acceptance tests of the quota, catalogue and order objects are in the tenancy domain
    (scripts/ci/acc-domains.sh: Catalogue and Order added); those of AI usage and rates
    (TestAccAI…) in ai-licence-brand.
  • The leak guard allows www.ataila.com, the company's website. The names under the company's earlier website
    domain stay allowed for the released history only; no file names that domain any more.

v1.1.0

Choose a tag to compare

@attilamacskasy attilamacskasy released this 02 Oct 20:15

A minor release: additions only, under the stability promise of 1.0.0. A configuration and a state of 1.0.0
plan with no changes.

Added

  • k8s_quota on ataila_project (resource and data source): a Kubernetes project's namespace quota per
    environment (dev, uat, prod), GPU scheduling included — the eleven quota keys as Kubernetes quantities
    (req_cpu … pods, gpu_exclusive the guaranteed floor in whole cards, gpu_borrow, gpu_shared,
    fair_weight) plus what the platform reports (namespace, cluster, tier, gpu_queue, gpu_enabled,
    overridden, overridden_keys). The resource sends the keys a configuration sets, with reason, through
    PATCH /projects/{id}/k8s-quota/{env} after the project's own change, one request per environment; a key
    left out keeps its current value, a count spelled with leading zeros keeps the configuration's spelling, a
    changed reason alone re-sends the environment's overridden keys unchanged with it. A refusal (quota_refused,
    quota_conflict, 403 without k8s-gpu-admin-global) fails the apply with the platform's reason, and the
    state records what did change (the project's settings, the environments before the refused one), so the next
    plan shows only what is left — also when reading the project back afterwards fails (the state is then built
    from the platform's answers to the requests that went through); on create the project is created and
    tainted, and the error says how to keep it. Setting k8s_quota on a VM-backend project fails validation.
    Removing k8s_quota from the configuration, or destroying the project, changes no quota.
  • app_gateway on ataila_project may read ataila, the value the platform's own project reports (platform
    1.0.206 and later); it cannot be set.

Minimum platform, per feature

  • The provider still works with every platform from release 1.0.187 on. A feature that came later is refused
    only where it is used: k8s_quota needs platform release 1.0.203 or later, and a configuration that sets it
    on an older platform is refused at plan time, on create and on update, before any request, naming both
    releases. On such a platform the attribute reads null, in the resource and in the data source.

Contract

  • api/openapi-v1.json is the platform's export of release 1.0.206, unchanged. Since 1.0.187 it adds
    Project.k8s_quota, KubernetesQuota, KubernetesQuotaPatch, KubernetesQuotaUpdated and the two quota
    operations (PATCH and DELETE /projects/{project_id}/k8s-quota/{env}, platform 1.0.203), and the read-only
    app_gateway value ataila (1.0.206); everything else is unchanged.

CI

  • Lint fails when a copyright notice names another holder than ATAILA Kft.
  • The strict leak guard (leak-guard:strict, scripts/leak-guard.sh --strict) also fails when a commit in the
    scanned history has an author or committer address other than the company's, when a Co-Authored-By trailer
    names another address than the AI assistant's no-reply address, or when an annotated tag in that history has
    another tagger (README, "Leak guard": the public history carries the organisation's identity only). A normal
    run reports such an address and passes. Every mirror job needs the strict guard, so such a commit no longer
    reaches the public repository. Tested on scratch repositories in the leak-guard job.
  • The two commits of the k8s_quota work, made after 1.0.0 with another author address, were re-authored to the
    company address before this release (trees, messages and dates unchanged but for one Co-Authored-By
    trailer, which now names the model as the others do). A temporary job forced the rewritten default branch onto
    the public repository once and was removed again; v1.0.0 and everything before it are unchanged.

v1.0.0

Choose a tag to compare

@attilamacskasy attilamacskasy released this 02 Oct 08:48

The first public release of the OpenTofu and Terraform provider for the ATAILA Cloud Platform, published to both
registries as ataila/ataila.

Stability promise

From this release on, the provider follows semantic versioning. Within 1.x no resource, data source or
attribute is removed or renamed, no attribute changes its type or meaning, and no change needs a configuration
or a state to change: such a change waits for 2.0.0 and is announced in this file first. A minor release adds
(resources, data sources, attributes, accepted values); a patch release fixes. The platform's API v1, which the
provider speaks, changes only by addition. ~> 1.0 takes every 1.x release.

Contract

  • The platform's /api/v1 of platform release 1.0.187 (API 1.0.0), vendored as the platform exports it
    (api/openapi-v1.json). The provider needs platform release 1.0.187 or later (API 1.0.0 or later within
    major version 1) and refuses an older platform when it is configured, naming the minimum: every platform
    since 1.0.155 serves API 1.0.0, but before 1.0.176 the members had other names, and before 1.0.187 the
    Idempotency-Key parameter and the Location header were not declared.

Provider objects

  • 17 resources: ataila_customer, ataila_tenant, ataila_tenant_membership, ataila_user,
    ataila_user_role_grant, ataila_ai_gateway_key, ataila_ai_serving_tier, ataila_project,
    ataila_project_provisioning, ataila_project_member, ataila_project_prod_lock,
    ataila_release_promotion, ataila_ai_model, ataila_ai_model_node_cache, ataila_licence_bundle,
    ataila_brand and ataila_brand_asset.
  • 27 data sources: ataila_meta, ataila_whoami, ataila_customer, ataila_tenant, ataila_tenants,
    ataila_user, ataila_users, ataila_permission_catalog, ataila_ai_gateway, ataila_ai_serving_tiers,
    ataila_project, ataila_projects, ataila_project_stages, ataila_release_state,
    ataila_release_operation, ataila_ai_model, ataila_ai_models, ataila_ai_model_storage,
    ataila_ai_model_launch_catalog, ataila_ai_load_targets, ataila_ai_node, ataila_ai_nodes,
    ataila_dgx_clusters, ataila_licence, ataila_licence_socket_facts, ataila_brand and
    ataila_brand_asset.
  • Both CLIs are first-class: OpenTofu and Terraform 1.6 and later, every change tested against the oldest and
    the newest of each, with one state shared by both.

Upgrading

  • From 0.8.x: nothing changes in a configuration or a state; plan shows no changes. Move the version
    constraint to ~> 1.0.
  • From 0.7.x: the same, plus 0.8.0's changes (nested lists and objects became described nested attributes,
    values and types unchanged).
  • From 0.6.x or older: 0.7.0 renamed every attribute that named an internal system (its section below lists each,
    old and new). The state upgrades itself on the first read; the configuration must use the new names.

Distribution

  • Signed with the organisation's RSA-4096 key, whose public half is docs/signing-key.asc.
  • The GitHub release holds the archives, SHA256SUMS, its signature and the registry manifest, and as extra
    assets the air-gapped mirror bundle (terraform-provider-ataila_1.0.0_mirror.zip) and its .sha256.
  • Problems and questions: support@ataila.com; documentation at https://www.ataila.eu/developers/terraform. The
    public repository's issue tracker is off.

Added since 0.8.0

  • ataila_project_provisioning: running_stages, failed_stages, needs_action_stages and message.
  • ataila_brand data source: attribution and first_party (read-only on the platform).
  • The customer resource and data source state that the GitLab group's live status is not read.
  • The provider refuses a platform older than release 1.0.187 when it is configured (see Contract).
  • Proven end to end on a real platform (release 1.0.196) under both CLIs: read, import, create, no diff,
    drift, frozen keys, the destroy switches, a project with its provisioning, a person, and the audit log.

CI

  • The release job no longer go installs goreleaser: that fetched hundreds of megabytes of goreleaser's own
    modules and filled a shared runner's disk in the v0.8.0 release. It downloads goreleaser's release binary
    for linux/amd64 at a pinned version, checked against a pinned SHA-256 like the CLIs
    (scripts/ci/toolchain.sh, ensure_goreleaser), into the job's .tmp, which is removed after the job. The
    job keeps building with the Go cache lint saves, and saves none.
  • release:dry-run on the default branch exercises that path without a tag: the download, goreleaser check, and a snapshot build for the runner's platform.
  • The Go cache no longer stays in the runners' builds slots: every job but lint removes it after its script,
    and lint, the one job that saves it, drops the build cache first (so the saved cache holds the modules and
    the toolchain). Each job's log ends with the size its slot is left at.
  • Leak guard: the private key pattern also catches the armour of an OpenPGP private key (BEGIN PGP PRIVATE KEY BLOCK between the dashes); it caught the OpenSSH, RSA, EC, DSA, encrypted and plain PKCS#8 headers
    already. Its self-test checks every armour, and scripts/ci/test-leak-guard.sh, run by the leak-guard job,
    plants each in a scratch repository (in the tree and in history) and checks that a public key block, as
    docs/signing-key.asc holds, is no finding.
  • mirror:github never pushes a 0.x tag and publish:github refuses any version below 1.0.0, in their rules
    and in the scripts; scripts/ci/test-mirror-github.sh (run by lint) checks the mirror against a fake public
    repository, and the publisher's unit tests refuse fake 0.x tags.
  • publish:github attaches the air-gapped mirror bundle and its .sha256 to the release, after checking the
    bundle against its sum.
  • The leak guard also refuses GitHub token shapes (classic and fine-grained); their findings are never printed.
  • mirror:github mirrors the default branch only; a release tag is mirrored by mirror:github:tag, which runs
    only after release succeeded, so that no tag reaches the public repository without its release.
  • leak-guard:strict fails if one of the parent group's inherited CI/CD variables holds a value in this
    project's pipelines (they are shadowed by empty project-level variables).
  • The history was rewritten once before publication so that every commit's author and committer, and every
    tag's tagger, is the company address; the trees, messages and dates are unchanged, and v0.4.0 to v0.8.0
    were re-created on the rewritten commits. A temporary job forced the rewritten default branch onto the
    public repository once and was removed again.