Skip to content

Support enabling ORGADMIN (IS_ORG_ADMIN) on an account #46

Description

@noel

Summary

Snowcap can't enable the ORGADMIN role on an account. Configs that grant ORGADMIN fail in any account where it isn't already enabled, and the only fix is to run ALTER ACCOUNT ... SET IS_ORG_ADMIN = TRUE by hand.

#45 makes that failure legible (the error now says Snowcap can't do it and what to run instead). This issue tracks actually supporting it.

Groundwork already done

Pushed on wip/account-is-org-admin — tested, but inert, so not opened as a PR:

  • Account honors the name it's given. It previously discarded the argument and named every instance ACCOUNT (the blueprint root sentinel), making the resource unusable for a real account.
  • is_org_admin is tri-state. None = unmanaged and skipped by the diff, so omitting it can't disturb an account that already has ORGADMIN. False is refused rather than ignored, because Snowflake won't clear the property from the current account.
  • fetch_account does a real SHOW ACCOUNTS lookup, guarding the ACCOUNT sentinel so the blueprint root is never looked up or altered.
  • update_account emits ALTER ACCOUNT <name> SET IS_ORG_ADMIN = TRUE. create/drop raise with an explanation — Snowcap shouldn't create or destroy accounts.
  • 31 tests, full suite green.

The YAML path works end to end up to planning:

accounts:
  - name: SNOWCAP
    is_org_admin: true

The blocker

blueprint.py:1316:

org_scoped, acct_scoped, db_scoped, schema_scoped = _split_by_scope(self._staged)
if len(org_scoped) > 0:
    raise Exception("Blueprint cannot contain an Account resource")

The resource graph is rooted at a single account and everything hangs off it. An Account is a sibling of that root, not a child, so it has nowhere to live.

Wiring it up needs roughly:

  1. Carry org-scoped resources alongside the root in _build_resource_graph instead of raising
  2. Walk them in generate_manifest (it currently walks self._root only)
  3. Teach diff's _container_descriptor that OrganizationScope has no container (it returns None for AccountScope today)
  4. Confirm the ownership and privilege paths behave — Account has no owner, unlike most resources

That's the planning path every resource type flows through, which is why it's here rather than in a PR.

Design question

Even with the graph fixed, Snowcap connects to one account per run. Enabling ORGADMIN on account X requires a session on a different account (the primary) as ORGADMIN. So either:

  • (a) Point SNOWFLAKE_ACCOUNT at the primary for that config — no change to Snowcap's connection model
  • (b) Open a second connection for org-scoped resources — much larger change to session handling

(a) seems clearly preferable, but it's a maintainer call.

Prior art

Terraform's snowflake_account supports this:

client.Accounts.Alter(ctx, &sdk.AlterAccountOptions{
    Name: &id,
    Set: &sdk.AccountSet{ OrgAdmin: sdk.Bool(true) },
})

Reads via SHOW ACCOUNTS; models the property as tri-state (true/false/default) with an explicit canUpdate = false guard for transitions Snowflake rejects — the same constraint handled on the WIP branch.

Worth noting Terraform got this as a byproduct of full account lifecycle management, and its resource model is flat — no root container — so it never hit this blocker. Snowflake DCM Projects can't do it at all: ACCOUNT isn't a supported entity, and the docs direct you to ALTER ACCOUNT outside DCM.

Caveat

The ORGADMIN path on the WIP branch is untested against a live account — verifying it needs ORGADMIN on an organization's primary account.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions