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:
- Carry org-scoped resources alongside the root in
_build_resource_graph instead of raising
- Walk them in
generate_manifest (it currently walks self._root only)
- Teach
diff's _container_descriptor that OrganizationScope has no container (it returns None for AccountScope today)
- 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
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 = TRUEby 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:Accounthonors the name it's given. It previously discarded the argument and named every instanceACCOUNT(the blueprint root sentinel), making the resource unusable for a real account.is_org_adminis tri-state.None= unmanaged and skipped by the diff, so omitting it can't disturb an account that already has ORGADMIN.Falseis refused rather than ignored, because Snowflake won't clear the property from the current account.fetch_accountdoes a realSHOW ACCOUNTSlookup, guarding theACCOUNTsentinel so the blueprint root is never looked up or altered.update_accountemitsALTER ACCOUNT <name> SET IS_ORG_ADMIN = TRUE.create/dropraise with an explanation — Snowcap shouldn't create or destroy accounts.The YAML path works end to end up to planning:
The blocker
blueprint.py:1316:The resource graph is rooted at a single account and everything hangs off it. An
Accountis a sibling of that root, not a child, so it has nowhere to live.Wiring it up needs roughly:
_build_resource_graphinstead of raisinggenerate_manifest(it currently walksself._rootonly)diff's_container_descriptorthatOrganizationScopehas no container (it returnsNoneforAccountScopetoday)Accounthas noowner, unlike most resourcesThat'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:
SNOWFLAKE_ACCOUNTat the primary for that config — no change to Snowcap's connection model(a) seems clearly preferable, but it's a maintainer call.
Prior art
Terraform's
snowflake_accountsupports this:Reads via
SHOW ACCOUNTS; models the property as tri-state (true/false/default) with an explicitcanUpdate = falseguard 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:
ACCOUNTisn't a supported entity, and the docs direct you toALTER ACCOUNToutside 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