@homeflare/alchemy 0.42.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/caddy/index.js +35 -1
- package/dist/caddy/index.js.map +3 -3
- package/dist/launchd/index.js +35 -1
- package/dist/launchd/index.js.map +3 -3
- package/dist/linux/index.js +35 -1
- package/dist/linux/index.js.map +3 -3
- package/dist/litellm/access-group-form.d.ts +26 -0
- package/dist/litellm/access-group-form.d.ts.map +1 -0
- package/dist/litellm/access-group-operations.d.ts +37 -0
- package/dist/litellm/access-group-operations.d.ts.map +1 -0
- package/dist/litellm/access-group-types.d.ts +49 -0
- package/dist/litellm/access-group-types.d.ts.map +1 -0
- package/dist/litellm/access-group.d.ts +55 -0
- package/dist/litellm/access-group.d.ts.map +1 -0
- package/dist/litellm/budget-errors.d.ts +36 -0
- package/dist/litellm/budget-errors.d.ts.map +1 -0
- package/dist/litellm/budget-form.d.ts +50 -0
- package/dist/litellm/budget-form.d.ts.map +1 -0
- package/dist/litellm/budget-operations.d.ts +20 -0
- package/dist/litellm/budget-operations.d.ts.map +1 -0
- package/dist/litellm/budget.d.ts +61 -0
- package/dist/litellm/budget.d.ts.map +1 -0
- package/dist/litellm/credential-errors.d.ts +131 -0
- package/dist/litellm/credential-errors.d.ts.map +1 -0
- package/dist/litellm/credential-form.d.ts +79 -0
- package/dist/litellm/credential-form.d.ts.map +1 -0
- package/dist/litellm/credential-operations.d.ts +84 -0
- package/dist/litellm/credential-operations.d.ts.map +1 -0
- package/dist/litellm/credential-rewrite.d.ts +6 -0
- package/dist/litellm/credential-rewrite.d.ts.map +1 -0
- package/dist/litellm/credential-types.d.ts +87 -0
- package/dist/litellm/credential-types.d.ts.map +1 -0
- package/dist/litellm/credential-values.d.ts +53 -0
- package/dist/litellm/credential-values.d.ts.map +1 -0
- package/dist/litellm/credential.d.ts +83 -0
- package/dist/litellm/credential.d.ts.map +1 -0
- package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
- package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-credential-litellm.d.ts +54 -0
- package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-keys.d.ts +53 -0
- package/dist/litellm/fake-keys.d.ts.map +1 -0
- package/dist/litellm/fake-litellm.d.ts +9 -1
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
- package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm.d.ts +48 -0
- package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-litellm.d.ts +32 -0
- package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-registry-base.d.ts +42 -0
- package/dist/litellm/fake-registry-base.d.ts.map +1 -0
- package/dist/litellm/fake-stack.d.ts +8 -1
- package/dist/litellm/fake-stack.d.ts.map +1 -1
- package/dist/litellm/fake-team-litellm.d.ts +47 -0
- package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-tool-litellm.d.ts +28 -0
- package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
- package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
- package/dist/litellm/index.d.ts +20 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +3201 -2
- package/dist/litellm/index.js.map +70 -5
- package/dist/litellm/key-errors.d.ts +169 -0
- package/dist/litellm/key-errors.d.ts.map +1 -0
- package/dist/litellm/key-form.d.ts +119 -0
- package/dist/litellm/key-form.d.ts.map +1 -0
- package/dist/litellm/key-harness.d.ts +41 -0
- package/dist/litellm/key-harness.d.ts.map +1 -0
- package/dist/litellm/key-metadata-errors.d.ts +30 -0
- package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
- package/dist/litellm/key-metadata.d.ts +22 -0
- package/dist/litellm/key-metadata.d.ts.map +1 -0
- package/dist/litellm/key-operations.d.ts +63 -0
- package/dist/litellm/key-operations.d.ts.map +1 -0
- package/dist/litellm/key-secret.d.ts +33 -0
- package/dist/litellm/key-secret.d.ts.map +1 -0
- package/dist/litellm/key.d.ts +78 -0
- package/dist/litellm/key.d.ts.map +1 -0
- package/dist/litellm/mcp-server-credential.d.ts +50 -0
- package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
- package/dist/litellm/mcp-server-errors.d.ts +101 -0
- package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
- package/dist/litellm/mcp-server-form.d.ts +56 -0
- package/dist/litellm/mcp-server-form.d.ts.map +1 -0
- package/dist/litellm/mcp-server-locate.d.ts +26 -0
- package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
- package/dist/litellm/mcp-server-operations.d.ts +63 -0
- package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
- package/dist/litellm/mcp-server-shadow.d.ts +24 -0
- package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
- package/dist/litellm/mcp-server-types.d.ts +118 -0
- package/dist/litellm/mcp-server-types.d.ts.map +1 -0
- package/dist/litellm/mcp-server-url.d.ts +11 -0
- package/dist/litellm/mcp-server-url.d.ts.map +1 -0
- package/dist/litellm/mcp-server.d.ts +95 -0
- package/dist/litellm/mcp-server.d.ts.map +1 -0
- package/dist/litellm/model-claim.d.ts +24 -0
- package/dist/litellm/model-claim.d.ts.map +1 -0
- package/dist/litellm/model-credential.d.ts +12 -0
- package/dist/litellm/model-credential.d.ts.map +1 -0
- package/dist/litellm/model-errors.d.ts +119 -0
- package/dist/litellm/model-errors.d.ts.map +1 -0
- package/dist/litellm/model-form.d.ts +78 -0
- package/dist/litellm/model-form.d.ts.map +1 -0
- package/dist/litellm/model-locate.d.ts +13 -0
- package/dist/litellm/model-locate.d.ts.map +1 -0
- package/dist/litellm/model-operations.d.ts +59 -0
- package/dist/litellm/model-operations.d.ts.map +1 -0
- package/dist/litellm/model-types.d.ts +91 -0
- package/dist/litellm/model-types.d.ts.map +1 -0
- package/dist/litellm/model.d.ts +88 -0
- package/dist/litellm/model.d.ts.map +1 -0
- package/dist/litellm/operations.d.ts +22 -0
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/litellm/policy-attachment-form.d.ts +19 -0
- package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-operations.d.ts +31 -0
- package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-types.d.ts +48 -0
- package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
- package/dist/litellm/policy-attachment.d.ts +61 -0
- package/dist/litellm/policy-attachment.d.ts.map +1 -0
- package/dist/litellm/policy-form.d.ts +22 -0
- package/dist/litellm/policy-form.d.ts.map +1 -0
- package/dist/litellm/policy-operations.d.ts +42 -0
- package/dist/litellm/policy-operations.d.ts.map +1 -0
- package/dist/litellm/policy-types.d.ts +57 -0
- package/dist/litellm/policy-types.d.ts.map +1 -0
- package/dist/litellm/policy.d.ts +65 -0
- package/dist/litellm/policy.d.ts.map +1 -0
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/litellm/registry-errors.d.ts +62 -0
- package/dist/litellm/registry-errors.d.ts.map +1 -0
- package/dist/litellm/registry-support.d.ts +42 -0
- package/dist/litellm/registry-support.d.ts.map +1 -0
- package/dist/litellm/team-form.d.ts +26 -0
- package/dist/litellm/team-form.d.ts.map +1 -0
- package/dist/litellm/team-members.d.ts +10 -0
- package/dist/litellm/team-members.d.ts.map +1 -0
- package/dist/litellm/team-operations.d.ts +38 -0
- package/dist/litellm/team-operations.d.ts.map +1 -0
- package/dist/litellm/team-permission.d.ts +35 -0
- package/dist/litellm/team-permission.d.ts.map +1 -0
- package/dist/litellm/team-types.d.ts +101 -0
- package/dist/litellm/team-types.d.ts.map +1 -0
- package/dist/litellm/team.d.ts +67 -0
- package/dist/litellm/team.d.ts.map +1 -0
- package/dist/litellm/tool-policy-form.d.ts +21 -0
- package/dist/litellm/tool-policy-form.d.ts.map +1 -0
- package/dist/litellm/tool-policy-operations.d.ts +30 -0
- package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
- package/dist/litellm/tool-policy-types.d.ts +46 -0
- package/dist/litellm/tool-policy-types.d.ts.map +1 -0
- package/dist/litellm/tool-policy.d.ts +62 -0
- package/dist/litellm/tool-policy.d.ts.map +1 -0
- package/dist/litellm/toolset-form.d.ts +20 -0
- package/dist/litellm/toolset-form.d.ts.map +1 -0
- package/dist/litellm/toolset-operations.d.ts +39 -0
- package/dist/litellm/toolset-operations.d.ts.map +1 -0
- package/dist/litellm/toolset-types.d.ts +46 -0
- package/dist/litellm/toolset-types.d.ts.map +1 -0
- package/dist/litellm/toolset.d.ts +55 -0
- package/dist/litellm/toolset.d.ts.map +1 -0
- package/dist/openbao/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role-wire.d.ts.map +1 -1
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
- package/dist/openbao/index.js +43 -6
- package/dist/openbao/index.js.map +5 -5
- package/dist/ownership/rows.d.ts +11 -0
- package/dist/ownership/rows.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +32 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +28 -9
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/database.d.ts +1 -1
- package/dist/postgres/database.d.ts.map +1 -1
- package/dist/postgres/fake-grants-parse.d.ts +37 -0
- package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
- package/dist/postgres/fake-grants-read.d.ts +61 -0
- package/dist/postgres/fake-grants-read.d.ts.map +1 -0
- package/dist/postgres/fake-grants-sql.d.ts +46 -0
- package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
- package/dist/postgres/fake-grants-write.d.ts +29 -0
- package/dist/postgres/fake-grants-write.d.ts.map +1 -0
- package/dist/postgres/fake-role-sql.d.ts +40 -0
- package/dist/postgres/fake-role-sql.d.ts.map +1 -0
- package/dist/postgres/fake-schema-sql.d.ts +42 -0
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
- package/dist/postgres/fake-sql-parse.d.ts +23 -0
- package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
- package/dist/postgres/fake-sql-quote.d.ts +12 -0
- package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
- package/dist/postgres/fake-sql.d.ts +42 -0
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/grants-attrs.d.ts +115 -0
- package/dist/postgres/grants-attrs.d.ts.map +1 -0
- package/dist/postgres/grants-declare.d.ts +88 -0
- package/dist/postgres/grants-declare.d.ts.map +1 -0
- package/dist/postgres/grants-diff.d.ts +25 -0
- package/dist/postgres/grants-diff.d.ts.map +1 -0
- package/dist/postgres/grants-errors.d.ts +137 -0
- package/dist/postgres/grants-errors.d.ts.map +1 -0
- package/dist/postgres/grants-existence.d.ts +14 -0
- package/dist/postgres/grants-existence.d.ts.map +1 -0
- package/dist/postgres/grants-ops.d.ts +65 -0
- package/dist/postgres/grants-ops.d.ts.map +1 -0
- package/dist/postgres/grants-ownership.d.ts +18 -0
- package/dist/postgres/grants-ownership.d.ts.map +1 -0
- package/dist/postgres/grants-plan-restore.d.ts +22 -0
- package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
- package/dist/postgres/grants-plan.d.ts +65 -0
- package/dist/postgres/grants-plan.d.ts.map +1 -0
- package/dist/postgres/grants-read-defaults.d.ts +17 -0
- package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
- package/dist/postgres/grants-read.d.ts +77 -0
- package/dist/postgres/grants-read.d.ts.map +1 -0
- package/dist/postgres/grants-refuse.d.ts +25 -0
- package/dist/postgres/grants-refuse.d.ts.map +1 -0
- package/dist/postgres/grants-sql.d.ts +42 -0
- package/dist/postgres/grants-sql.d.ts.map +1 -0
- package/dist/postgres/grants-words.d.ts +29 -0
- package/dist/postgres/grants-words.d.ts.map +1 -0
- package/dist/postgres/grants.d.ts +37 -0
- package/dist/postgres/grants.d.ts.map +1 -0
- package/dist/postgres/index.d.ts +35 -8
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +2063 -39
- package/dist/postgres/index.js.map +47 -7
- package/dist/postgres/installed-classifier.d.ts +13 -0
- package/dist/postgres/installed-classifier.d.ts.map +1 -0
- package/dist/postgres/providers.d.ts +17 -7
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +25 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -0
- package/dist/postgres/role-attrs.d.ts +109 -0
- package/dist/postgres/role-attrs.d.ts.map +1 -0
- package/dist/postgres/role-diff.d.ts +22 -0
- package/dist/postgres/role-diff.d.ts.map +1 -0
- package/dist/postgres/role-errors.d.ts +126 -0
- package/dist/postgres/role-errors.d.ts.map +1 -0
- package/dist/postgres/role-membership-sql.d.ts +75 -0
- package/dist/postgres/role-membership-sql.d.ts.map +1 -0
- package/dist/postgres/role-provider.d.ts +11 -0
- package/dist/postgres/role-provider.d.ts.map +1 -0
- package/dist/postgres/role-scram.d.ts +6 -0
- package/dist/postgres/role-scram.d.ts.map +1 -0
- package/dist/postgres/role-secrets.d.ts +30 -0
- package/dist/postgres/role-secrets.d.ts.map +1 -0
- package/dist/postgres/role-sql.d.ts +68 -0
- package/dist/postgres/role-sql.d.ts.map +1 -0
- package/dist/postgres/role.d.ts +57 -0
- package/dist/postgres/role.d.ts.map +1 -0
- package/dist/postgres/schema-assert.d.ts +50 -0
- package/dist/postgres/schema-assert.d.ts.map +1 -0
- package/dist/postgres/schema-attrs.d.ts +51 -0
- package/dist/postgres/schema-attrs.d.ts.map +1 -0
- package/dist/postgres/schema-delete.d.ts +28 -0
- package/dist/postgres/schema-delete.d.ts.map +1 -0
- package/dist/postgres/schema-diff.d.ts +14 -0
- package/dist/postgres/schema-diff.d.ts.map +1 -0
- package/dist/postgres/schema-errors.d.ts +139 -0
- package/dist/postgres/schema-errors.d.ts.map +1 -0
- package/dist/postgres/schema-identity.d.ts +8 -0
- package/dist/postgres/schema-identity.d.ts.map +1 -0
- package/dist/postgres/schema-reconcile.d.ts +12 -0
- package/dist/postgres/schema-reconcile.d.ts.map +1 -0
- package/dist/postgres/schema-sql.d.ts +45 -0
- package/dist/postgres/schema-sql.d.ts.map +1 -0
- package/dist/postgres/schema-test-kit.d.ts +67 -0
- package/dist/postgres/schema-test-kit.d.ts.map +1 -0
- package/dist/postgres/schema.d.ts +54 -0
- package/dist/postgres/schema.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-types.d.ts +57 -0
- package/dist/proxmox/ceph-flag-types.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-wire.d.ts +77 -0
- package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag.d.ts +15 -50
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +10 -13
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/index.js +806 -740
- package/dist/proxmox/index.js.map +9 -8
- package/dist/release/fake-engine.d.ts +10 -0
- package/dist/release/fake-engine.d.ts.map +1 -1
- package/dist/release/index.js +35 -1
- package/dist/release/index.js.map +3 -3
- package/dist/valkey/acl-attrs.d.ts +94 -0
- package/dist/valkey/acl-attrs.d.ts.map +1 -0
- package/dist/valkey/acl-compare.d.ts +28 -0
- package/dist/valkey/acl-compare.d.ts.map +1 -0
- package/dist/valkey/acl-connection.d.ts +6 -0
- package/dist/valkey/acl-connection.d.ts.map +1 -0
- package/dist/valkey/acl-form.d.ts +62 -0
- package/dist/valkey/acl-form.d.ts.map +1 -0
- package/dist/valkey/acl-managed.d.ts +4 -0
- package/dist/valkey/acl-managed.d.ts.map +1 -0
- package/dist/valkey/acl-ops.d.ts +37 -0
- package/dist/valkey/acl-ops.d.ts.map +1 -0
- package/dist/valkey/acl-profiles.d.ts +53 -0
- package/dist/valkey/acl-profiles.d.ts.map +1 -0
- package/dist/valkey/acl-reconcile.d.ts +26 -0
- package/dist/valkey/acl-reconcile.d.ts.map +1 -0
- package/dist/valkey/acl.d.ts +24 -0
- package/dist/valkey/acl.d.ts.map +1 -0
- package/dist/valkey/connection-service.d.ts +22 -0
- package/dist/valkey/connection-service.d.ts.map +1 -0
- package/dist/valkey/connection.d.ts +59 -0
- package/dist/valkey/connection.d.ts.map +1 -0
- package/dist/valkey/errors.d.ts +165 -0
- package/dist/valkey/errors.d.ts.map +1 -0
- package/dist/valkey/fake-acl.d.ts +29 -0
- package/dist/valkey/fake-acl.d.ts.map +1 -0
- package/dist/valkey/fake-valkey.d.ts +35 -0
- package/dist/valkey/fake-valkey.d.ts.map +1 -0
- package/dist/valkey/handler-test-fixture.d.ts +20 -0
- package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
- package/dist/valkey/index.d.ts +18 -0
- package/dist/valkey/index.d.ts.map +1 -0
- package/dist/valkey/index.js +964 -0
- package/dist/valkey/index.js.map +27 -0
- package/dist/valkey/instance-attrs.d.ts +46 -0
- package/dist/valkey/instance-attrs.d.ts.map +1 -0
- package/dist/valkey/instance-form.d.ts +22 -0
- package/dist/valkey/instance-form.d.ts.map +1 -0
- package/dist/valkey/instance.d.ts +48 -0
- package/dist/valkey/instance.d.ts.map +1 -0
- package/dist/valkey/provider-socket-fixture.d.ts +8 -0
- package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
- package/dist/valkey/providers.d.ts +16 -0
- package/dist/valkey/providers.d.ts.map +1 -0
- package/dist/valkey/resp.d.ts +38 -0
- package/dist/valkey/resp.d.ts.map +1 -0
- package/dist/valkey/transport-error.d.ts +36 -0
- package/dist/valkey/transport-error.d.ts.map +1 -0
- package/dist/valkey/transport.d.ts +50 -0
- package/dist/valkey/transport.d.ts.map +1 -0
- package/docs/litellm-access-group.md +105 -0
- package/docs/litellm-budget.md +55 -0
- package/docs/litellm-credential.md +60 -0
- package/docs/litellm-key-metadata.md +56 -0
- package/docs/litellm-key.md +194 -0
- package/docs/litellm-mcp.md +187 -0
- package/docs/litellm-model.md +111 -0
- package/docs/litellm-policy-attachment.md +86 -0
- package/docs/litellm-policy.md +103 -0
- package/docs/litellm-team.md +117 -0
- package/docs/litellm-tool-policy.md +90 -0
- package/docs/litellm-toolset.md +92 -0
- package/docs/litellm.md +16 -8
- package/docs/peers.md +15 -6
- package/docs/postgres-grants-example.md +55 -0
- package/docs/postgres-grants.md +157 -0
- package/docs/postgres-role.md +114 -0
- package/docs/postgres-schema.md +139 -0
- package/docs/postgres.md +39 -0
- package/docs/proxmox-sdk-migration.md +45 -0
- package/docs/valkey-transport.md +29 -0
- package/docs/valkey.md +187 -0
- package/package.json +7 -3
- package/src/litellm/access-group-form.ts +105 -0
- package/src/litellm/access-group-operations.ts +92 -0
- package/src/litellm/access-group-types.ts +49 -0
- package/src/litellm/access-group.test.ts +197 -0
- package/src/litellm/access-group.ts +151 -0
- package/src/litellm/budget-errors.ts +38 -0
- package/src/litellm/budget-form.ts +94 -0
- package/src/litellm/budget-operations.ts +51 -0
- package/src/litellm/budget.test.ts +105 -0
- package/src/litellm/budget.ts +127 -0
- package/src/litellm/credential-errors.ts +183 -0
- package/src/litellm/credential-form.test.ts +151 -0
- package/src/litellm/credential-form.ts +211 -0
- package/src/litellm/credential-guards.test.ts +241 -0
- package/src/litellm/credential-operations.ts +208 -0
- package/src/litellm/credential-recovery.test.ts +93 -0
- package/src/litellm/credential-rewrite.test.ts +164 -0
- package/src/litellm/credential-rewrite.ts +50 -0
- package/src/litellm/credential-types.ts +117 -0
- package/src/litellm/credential-values.ts +94 -0
- package/src/litellm/credential.test.ts +218 -0
- package/src/litellm/credential.ts +227 -0
- package/src/litellm/fake-access-group-litellm.ts +127 -0
- package/src/litellm/fake-credential-litellm.ts +216 -0
- package/src/litellm/fake-keys.ts +190 -0
- package/src/litellm/fake-litellm.ts +66 -7
- package/src/litellm/fake-mcp-litellm.ts +214 -0
- package/src/litellm/fake-model-litellm-post-update.ts +103 -0
- package/src/litellm/fake-model-litellm.ts +233 -0
- package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
- package/src/litellm/fake-policy-litellm.ts +186 -0
- package/src/litellm/fake-registry-base.ts +69 -0
- package/src/litellm/fake-stack.ts +17 -1
- package/src/litellm/fake-team-litellm.ts +229 -0
- package/src/litellm/fake-tool-litellm.ts +88 -0
- package/src/litellm/fake-toolset-litellm.ts +110 -0
- package/src/litellm/index.ts +153 -0
- package/src/litellm/key-delete.test.ts +212 -0
- package/src/litellm/key-errors.ts +241 -0
- package/src/litellm/key-form.ts +200 -0
- package/src/litellm/key-harness.ts +121 -0
- package/src/litellm/key-metadata-errors.ts +49 -0
- package/src/litellm/key-metadata.test.ts +156 -0
- package/src/litellm/key-metadata.ts +74 -0
- package/src/litellm/key-operations.ts +184 -0
- package/src/litellm/key-rotation.test.ts +110 -0
- package/src/litellm/key-scope.test.ts +135 -0
- package/src/litellm/key-secret.test.ts +248 -0
- package/src/litellm/key-secret.ts +137 -0
- package/src/litellm/key-transport.test.ts +166 -0
- package/src/litellm/key.test.ts +231 -0
- package/src/litellm/key.ts +213 -0
- package/src/litellm/mcp-server-adopt.test.ts +86 -0
- package/src/litellm/mcp-server-alias.test.ts +184 -0
- package/src/litellm/mcp-server-credential.ts +85 -0
- package/src/litellm/mcp-server-errors.ts +141 -0
- package/src/litellm/mcp-server-exports.test.ts +15 -0
- package/src/litellm/mcp-server-form.test.ts +241 -0
- package/src/litellm/mcp-server-form.ts +233 -0
- package/src/litellm/mcp-server-handlers.test.ts +150 -0
- package/src/litellm/mcp-server-locate.ts +66 -0
- package/src/litellm/mcp-server-operations.ts +111 -0
- package/src/litellm/mcp-server-registry.test.ts +146 -0
- package/src/litellm/mcp-server-retype.test.ts +114 -0
- package/src/litellm/mcp-server-shadow.test.ts +91 -0
- package/src/litellm/mcp-server-shadow.ts +45 -0
- package/src/litellm/mcp-server-tools.test.ts +85 -0
- package/src/litellm/mcp-server-types.ts +143 -0
- package/src/litellm/mcp-server-url.ts +66 -0
- package/src/litellm/mcp-server.test.ts +213 -0
- package/src/litellm/mcp-server.ts +225 -0
- package/src/litellm/model-claim.ts +69 -0
- package/src/litellm/model-credential.ts +45 -0
- package/src/litellm/model-errors.ts +168 -0
- package/src/litellm/model-foreign-row.test.ts +173 -0
- package/src/litellm/model-form.test.ts +228 -0
- package/src/litellm/model-form.ts +223 -0
- package/src/litellm/model-locate.test.ts +128 -0
- package/src/litellm/model-locate.ts +67 -0
- package/src/litellm/model-operations.test.ts +93 -0
- package/src/litellm/model-operations.ts +146 -0
- package/src/litellm/model-params-preserve.test.ts +119 -0
- package/src/litellm/model-recovery.test.ts +57 -0
- package/src/litellm/model-types.ts +112 -0
- package/src/litellm/model.test.ts +222 -0
- package/src/litellm/model.ts +237 -0
- package/src/litellm/operations.ts +1 -1
- package/src/litellm/policy-attachment-form.ts +103 -0
- package/src/litellm/policy-attachment-operations.ts +74 -0
- package/src/litellm/policy-attachment-types.ts +48 -0
- package/src/litellm/policy-attachment.test.ts +198 -0
- package/src/litellm/policy-attachment.ts +178 -0
- package/src/litellm/policy-form.ts +122 -0
- package/src/litellm/policy-operations.ts +112 -0
- package/src/litellm/policy-types.ts +58 -0
- package/src/litellm/policy.test.ts +214 -0
- package/src/litellm/policy.ts +146 -0
- package/src/litellm/providers.ts +25 -1
- package/src/litellm/registry-errors.ts +88 -0
- package/src/litellm/registry-exports.test.ts +66 -0
- package/src/litellm/registry-support.ts +109 -0
- package/src/litellm/team-form.ts +140 -0
- package/src/litellm/team-members.test.ts +150 -0
- package/src/litellm/team-members.ts +58 -0
- package/src/litellm/team-operations.ts +90 -0
- package/src/litellm/team-permission.ts +159 -0
- package/src/litellm/team-read.test.ts +89 -0
- package/src/litellm/team-types.ts +106 -0
- package/src/litellm/team.test.ts +206 -0
- package/src/litellm/team.ts +159 -0
- package/src/litellm/tool-policy-form.ts +94 -0
- package/src/litellm/tool-policy-operations.ts +58 -0
- package/src/litellm/tool-policy-types.ts +48 -0
- package/src/litellm/tool-policy.test.ts +172 -0
- package/src/litellm/tool-policy.ts +125 -0
- package/src/litellm/toolset-form.ts +104 -0
- package/src/litellm/toolset-operations.ts +90 -0
- package/src/litellm/toolset-types.ts +47 -0
- package/src/litellm/toolset.test.ts +198 -0
- package/src/litellm/toolset.ts +151 -0
- package/src/openbao/auth-role-form.test.ts +37 -0
- package/src/openbao/auth-role-form.ts +12 -1
- package/src/openbao/auth-role-wire.test.ts +1 -0
- package/src/openbao/auth-role-wire.ts +13 -1
- package/src/openbao/distilled-retry.test.ts +1 -0
- package/src/openbao/fake-engines-roles.ts +7 -1
- package/src/ownership/ownership.test.ts +33 -1
- package/src/ownership/rows.ts +53 -0
- package/src/postgres/connection.ts +72 -3
- package/src/postgres/database-bigint-serialization.test.ts +1 -0
- package/src/postgres/database-refusals.test.ts +2 -2
- package/src/postgres/database-sql.ts +40 -12
- package/src/postgres/database.ts +3 -2
- package/src/postgres/fake-grants-parse.ts +189 -0
- package/src/postgres/fake-grants-read.ts +250 -0
- package/src/postgres/fake-grants-sql.ts +207 -0
- package/src/postgres/fake-grants-write.ts +90 -0
- package/src/postgres/fake-role-sql.ts +220 -0
- package/src/postgres/fake-schema-semantics.test.ts +36 -0
- package/src/postgres/fake-schema-sql.ts +146 -0
- package/src/postgres/fake-sql-parse.ts +86 -0
- package/src/postgres/fake-sql-quote.ts +36 -0
- package/src/postgres/fake-sql.ts +161 -46
- package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
- package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
- package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
- package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
- package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
- package/src/postgres/grants-acl.test.ts +61 -0
- package/src/postgres/grants-attrs.ts +185 -0
- package/src/postgres/grants-database.test.ts +158 -0
- package/src/postgres/grants-declare.ts +172 -0
- package/src/postgres/grants-delete-proof.test.ts +154 -0
- package/src/postgres/grants-diff.ts +101 -0
- package/src/postgres/grants-errors.ts +215 -0
- package/src/postgres/grants-existence-guards.test.ts +113 -0
- package/src/postgres/grants-existence.ts +101 -0
- package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
- package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
- package/src/postgres/grants-lifecycle.test.ts +181 -0
- package/src/postgres/grants-ops.ts +229 -0
- package/src/postgres/grants-owner-revoke.test.ts +121 -0
- package/src/postgres/grants-ownership.ts +49 -0
- package/src/postgres/grants-plan-collateral.test.ts +202 -0
- package/src/postgres/grants-plan-diff.test.ts +204 -0
- package/src/postgres/grants-plan-restore.ts +43 -0
- package/src/postgres/grants-plan-revocations.test.ts +69 -0
- package/src/postgres/grants-plan.test.ts +148 -0
- package/src/postgres/grants-plan.ts +245 -0
- package/src/postgres/grants-provenance.test.ts +134 -0
- package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
- package/src/postgres/grants-read-absent.test.ts +91 -0
- package/src/postgres/grants-read-defaults.ts +51 -0
- package/src/postgres/grants-read.ts +250 -0
- package/src/postgres/grants-refusals.test.ts +136 -0
- package/src/postgres/grants-refuse.ts +119 -0
- package/src/postgres/grants-relkind-wire.test.ts +111 -0
- package/src/postgres/grants-repair-plan.test.ts +201 -0
- package/src/postgres/grants-sql.test.ts +128 -0
- package/src/postgres/grants-sql.ts +144 -0
- package/src/postgres/grants-words.ts +34 -0
- package/src/postgres/grants.ts +110 -0
- package/src/postgres/index.ts +137 -7
- package/src/postgres/installed-classifier.ts +36 -0
- package/src/postgres/providers.ts +44 -7
- package/src/postgres/psql-executor-escaping.test.ts +67 -0
- package/src/postgres/psql-executor.test.ts +167 -0
- package/src/postgres/psql-executor.ts +170 -0
- package/src/postgres/role-adopt.test.ts +98 -0
- package/src/postgres/role-attrs.ts +134 -0
- package/src/postgres/role-diff.ts +89 -0
- package/src/postgres/role-errors.ts +198 -0
- package/src/postgres/role-guard.test.ts +60 -0
- package/src/postgres/role-identity.test.ts +185 -0
- package/src/postgres/role-lifecycle.test.ts +228 -0
- package/src/postgres/role-membership-sql.ts +198 -0
- package/src/postgres/role-password.test.ts +158 -0
- package/src/postgres/role-privilege.test.ts +80 -0
- package/src/postgres/role-provenance.test.ts +200 -0
- package/src/postgres/role-provider.ts +104 -0
- package/src/postgres/role-refusals.test.ts +250 -0
- package/src/postgres/role-scram.test.ts +38 -0
- package/src/postgres/role-scram.ts +38 -0
- package/src/postgres/role-secrets.ts +46 -0
- package/src/postgres/role-sql.ts +211 -0
- package/src/postgres/role-valid-until.test.ts +68 -0
- package/src/postgres/role.ts +218 -0
- package/src/postgres/schema-assert.ts +139 -0
- package/src/postgres/schema-attrs.ts +71 -0
- package/src/postgres/schema-delete-proofs.test.ts +192 -0
- package/src/postgres/schema-delete.ts +96 -0
- package/src/postgres/schema-diff.ts +44 -0
- package/src/postgres/schema-drop-2bp01.test.ts +146 -0
- package/src/postgres/schema-errors.ts +209 -0
- package/src/postgres/schema-handlers.test.ts +193 -0
- package/src/postgres/schema-identity.ts +39 -0
- package/src/postgres/schema-lifecycle.test.ts +246 -0
- package/src/postgres/schema-race.test.ts +70 -0
- package/src/postgres/schema-reconcile.ts +100 -0
- package/src/postgres/schema-refusals.test.ts +144 -0
- package/src/postgres/schema-socket.test.ts +161 -0
- package/src/postgres/schema-sql.ts +130 -0
- package/src/postgres/schema-takeover.test.ts +149 -0
- package/src/postgres/schema-test-kit.ts +85 -0
- package/src/postgres/schema.ts +130 -0
- package/src/proxmox/ceph-flag-types.ts +70 -0
- package/src/proxmox/ceph-flag-wire.test.ts +72 -0
- package/src/proxmox/ceph-flag-wire.ts +123 -0
- package/src/proxmox/ceph-flag.ts +77 -130
- package/src/proxmox/ceph-osd-write.ts +10 -13
- package/src/release/binary-alias.test.ts +3 -3
- package/src/release/binary-claims.test.ts +3 -3
- package/src/release/binary-directory-umask.test.ts +65 -0
- package/src/release/fake-engine.ts +15 -0
- package/src/valkey/acl-attrs.ts +98 -0
- package/src/valkey/acl-compare.ts +57 -0
- package/src/valkey/acl-connection.ts +13 -0
- package/src/valkey/acl-delete.test.ts +127 -0
- package/src/valkey/acl-form.ts +239 -0
- package/src/valkey/acl-managed.ts +13 -0
- package/src/valkey/acl-ops.ts +122 -0
- package/src/valkey/acl-ownership.test.ts +118 -0
- package/src/valkey/acl-prefix.test.ts +38 -0
- package/src/valkey/acl-profiles.ts +81 -0
- package/src/valkey/acl-reconcile.ts +180 -0
- package/src/valkey/acl-reserved.test.ts +69 -0
- package/src/valkey/acl-revocation.test.ts +94 -0
- package/src/valkey/acl-seat-prefix.test.ts +111 -0
- package/src/valkey/acl-validation.test.ts +54 -0
- package/src/valkey/acl.test.ts +215 -0
- package/src/valkey/acl.ts +169 -0
- package/src/valkey/connection-service.ts +46 -0
- package/src/valkey/connection.ts +180 -0
- package/src/valkey/errors.ts +239 -0
- package/src/valkey/fake-acl.ts +128 -0
- package/src/valkey/fake-valkey.ts +224 -0
- package/src/valkey/handler-test-fixture.ts +43 -0
- package/src/valkey/handlers.test.ts +205 -0
- package/src/valkey/index.ts +54 -0
- package/src/valkey/instance-attrs.ts +48 -0
- package/src/valkey/instance-form.ts +104 -0
- package/src/valkey/instance.test.ts +108 -0
- package/src/valkey/instance.ts +160 -0
- package/src/valkey/provider-socket-fixture.ts +71 -0
- package/src/valkey/providers.test.ts +129 -0
- package/src/valkey/providers.ts +21 -0
- package/src/valkey/resp.ts +212 -0
- package/src/valkey/transport-bounds.test.ts +150 -0
- package/src/valkey/transport-error.ts +37 -0
- package/src/valkey/transport.test.ts +158 -0
- package/src/valkey/transport.ts +109 -0
- package/src/valkey/upstream-bounds.test.ts +14 -0
package/dist/proxmox/index.js
CHANGED
|
@@ -1745,143 +1745,57 @@ var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect
|
|
|
1745
1745
|
})));
|
|
1746
1746
|
// src/proxmox/ceph-flag.ts
|
|
1747
1747
|
import { Resource as Resource5 } from "alchemy";
|
|
1748
|
-
import * as Provider5 from "alchemy/Provider";
|
|
1749
|
-
import * as Effect16 from "effect/Effect";
|
|
1750
|
-
|
|
1751
|
-
// src/proxmox/resource.ts
|
|
1752
1748
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1749
|
+
import * as Provider5 from "alchemy/Provider";
|
|
1753
1750
|
import * as Effect15 from "effect/Effect";
|
|
1754
1751
|
|
|
1755
|
-
// src/proxmox/
|
|
1752
|
+
// src/proxmox/ceph-flag-wire.ts
|
|
1753
|
+
import * as cluster3 from "@distilled.cloud/proxmox/cluster";
|
|
1756
1754
|
import * as Effect14 from "effect/Effect";
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
method;
|
|
1762
|
-
path;
|
|
1763
|
-
constructor(status, method, path, detail) {
|
|
1764
|
-
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
1765
|
-
this.status = status;
|
|
1766
|
-
this.method = method;
|
|
1767
|
-
this.path = path;
|
|
1768
|
-
this.name = "PveError";
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
1772
|
-
var encode = (form) => {
|
|
1773
|
-
const params = new URLSearchParams;
|
|
1774
|
-
for (const [key, value] of Object.entries(form)) {
|
|
1775
|
-
if (typeof value === "string")
|
|
1776
|
-
params.append(key, value);
|
|
1777
|
-
else
|
|
1778
|
-
for (const item of value)
|
|
1779
|
-
params.append(key, item);
|
|
1780
|
-
}
|
|
1781
|
-
return params.toString();
|
|
1782
|
-
};
|
|
1783
|
-
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
1784
|
-
const url = `${apiBase}/${path}`;
|
|
1785
|
-
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
1786
|
-
};
|
|
1787
|
-
var executeOne = (target, credential, method, path, form, apiBase) => Effect14.gen(function* () {
|
|
1788
|
-
const client = yield* HttpClient5.HttpClient;
|
|
1789
|
-
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
1790
|
-
return yield* client.execute(request).pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1791
|
-
});
|
|
1792
|
-
var readResponse = (response, method, path) => Effect14.gen(function* () {
|
|
1793
|
-
if (response.status < 200 || response.status >= 300) {
|
|
1794
|
-
const detail = yield* response.text.pipe(Effect14.orElseSucceed(() => ""));
|
|
1795
|
-
return yield* Effect14.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1796
|
-
}
|
|
1797
|
-
const body = yield* response.json.pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1798
|
-
return body.data;
|
|
1799
|
-
});
|
|
1800
|
-
var pveWith = (target, credential, method, path, form) => Effect14.gen(function* () {
|
|
1801
|
-
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
1802
|
-
return yield* readResponse(response, method, path);
|
|
1803
|
-
});
|
|
1804
|
-
var pve = (target, role, method, path, form) => Effect14.gen(function* () {
|
|
1805
|
-
const credential = yield* leased(target, role);
|
|
1806
|
-
return yield* pveWith(target, credential, method, path, form);
|
|
1755
|
+
var CEPH_FLAG_UPDATE = "pve:PUT /cluster/ceph/flags/{flag}";
|
|
1756
|
+
var attributesOf3 = (live, props) => ({
|
|
1757
|
+
flag: props.flag,
|
|
1758
|
+
value: bool(live)
|
|
1807
1759
|
});
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
const { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(spec);
|
|
1812
|
-
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect15.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect15.orElseSucceed(() => {
|
|
1813
|
-
return;
|
|
1814
|
-
}));
|
|
1815
|
-
return {
|
|
1816
|
-
guardCreate: guardCreate2,
|
|
1817
|
-
guardUpdate: guardUpdate2,
|
|
1818
|
-
read,
|
|
1819
|
-
diff: (news, output) => Effect15.gen(function* () {
|
|
1820
|
-
if (!isResolved5(news))
|
|
1821
|
-
return;
|
|
1822
|
-
yield* guardCreate2(news, output === undefined);
|
|
1823
|
-
yield* guardUpdate2(news);
|
|
1824
|
-
if (output === undefined)
|
|
1825
|
-
return;
|
|
1826
|
-
const live = yield* read(news);
|
|
1827
|
-
if (live === undefined) {
|
|
1828
|
-
yield* guardCreate2(news, true);
|
|
1829
|
-
return { action: "update" };
|
|
1830
|
-
}
|
|
1831
|
-
if (spec.matches(live, news))
|
|
1832
|
-
return { action: "noop" };
|
|
1833
|
-
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
1834
|
-
}),
|
|
1835
|
-
reconcile: (news) => Effect15.gen(function* () {
|
|
1836
|
-
const live = yield* read(news);
|
|
1837
|
-
yield* guardCreate2(news, live === undefined);
|
|
1838
|
-
yield* guardUpdate2(news);
|
|
1839
|
-
if (live === undefined) {
|
|
1840
|
-
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
1841
|
-
} else if (spec.updateForm !== undefined) {
|
|
1842
|
-
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
1843
|
-
if (form !== undefined) {
|
|
1844
|
-
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
const after = yield* read(news);
|
|
1848
|
-
if (after === undefined) {
|
|
1849
|
-
return yield* Effect15.die(new Error(`${spec.path(news)}: the write returned no error but the object is still absent. ` + 'PVE wraps every answer in {"data":...} and can report success on a call that did ' + "nothing -- read back rather than trusting the status code."));
|
|
1850
|
-
}
|
|
1851
|
-
return after;
|
|
1852
|
-
}),
|
|
1853
|
-
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
1854
|
-
};
|
|
1855
|
-
};
|
|
1856
|
-
var pveHandlers = (spec) => {
|
|
1857
|
-
const ops = pveOperations(spec);
|
|
1858
|
-
return {
|
|
1859
|
-
list: () => Effect15.succeed([]),
|
|
1860
|
-
read: ({ olds }) => ops.read(olds),
|
|
1861
|
-
diff: ({ news, output }) => ops.diff(news, output),
|
|
1862
|
-
reconcile: ({ news }) => ops.reconcile(news),
|
|
1863
|
-
delete: ({ olds }) => ops.destroy(olds)
|
|
1864
|
-
};
|
|
1760
|
+
var scalarFlagOrDie = (live, props) => {
|
|
1761
|
+
const scalar = typeof live === "boolean" || live === 0 || live === 1 || live === "0" || live === "1";
|
|
1762
|
+
return scalar ? Effect14.succeed(live) : Effect14.die(new Error(`cluster/ceph/flags/${props.flag}: GET answered ${JSON.stringify(live)}, not a bare ` + "boolean. This endpoint's success is a scalar; an empty object is what the protocol " + 'substitutes for `{"data":null}`. Check `ceph osd dump | head -1` and the cluster ' + "log rather than trust a coerced `false`."));
|
|
1865
1763
|
};
|
|
1764
|
+
var readClusterCephFlag = (props) => runPve(props.target, "read", false, cluster3.getClusterCephFlag({ flag: props.flag })).pipe(Effect14.flatMap((live) => scalarFlagOrDie(live, props)), Effect14.map((live) => attributesOf3(live, props)));
|
|
1765
|
+
var readClusterCephFlagForDiff = (props) => readOrUnreadable(readClusterCephFlag(props));
|
|
1766
|
+
var updateForm = (props) => ({ value: flag(props.value) ?? "0" });
|
|
1767
|
+
var writeClusterCephFlag = (props) => runPve(props.target, "provision", true, cluster3.putClusterCephFlag({ flag: props.flag, value: updateForm(props).value }));
|
|
1866
1768
|
|
|
1867
1769
|
// src/proxmox/ceph-flag.ts
|
|
1868
1770
|
var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
|
|
1869
|
-
var
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1771
|
+
var matches3 = (attributes, props) => attributes.value === props.value;
|
|
1772
|
+
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect15.succeed(ProxmoxCephFlag.Provider.of({
|
|
1773
|
+
list: () => Effect15.succeed([]),
|
|
1774
|
+
read: ({ olds }) => readClusterCephFlag(olds),
|
|
1775
|
+
diff: Effect15.fn(function* ({ news, output }) {
|
|
1776
|
+
if (!isResolved5(news))
|
|
1777
|
+
return;
|
|
1778
|
+
yield* guardWrite2(CEPH_FLAG_UPDATE, updateForm(news), false);
|
|
1779
|
+
if (output === undefined)
|
|
1780
|
+
return;
|
|
1781
|
+
const live = yield* readClusterCephFlagForDiff(news);
|
|
1782
|
+
if (live === UNREADABLE) {
|
|
1783
|
+
yield* unreadableWarning("Proxmox.CephFlag", news.flag, news.target.mount, mintTier(news.target, "read"));
|
|
1784
|
+
return { action: "noop" };
|
|
1785
|
+
}
|
|
1786
|
+
return { action: matches3(live, news) ? "noop" : "update" };
|
|
1787
|
+
}),
|
|
1788
|
+
delete: () => Effect15.void,
|
|
1789
|
+
reconcile: Effect15.fn(function* ({ news }) {
|
|
1790
|
+
const live = yield* readClusterCephFlag(news);
|
|
1791
|
+
const form = formToSend(matches3, live, news, updateForm(news));
|
|
1792
|
+
if (form !== undefined) {
|
|
1793
|
+
yield* guardWrite2(CEPH_FLAG_UPDATE, updateForm(news), false);
|
|
1794
|
+
yield* writeClusterCephFlag(news);
|
|
1795
|
+
}
|
|
1796
|
+
const after = yield* readClusterCephFlag(news);
|
|
1883
1797
|
if (after.value !== news.value) {
|
|
1884
|
-
return yield*
|
|
1798
|
+
return yield* Effect15.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
|
|
1885
1799
|
}
|
|
1886
1800
|
return after;
|
|
1887
1801
|
})
|
|
@@ -1890,11 +1804,11 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect16.s
|
|
|
1890
1804
|
import { Resource as Resource6 } from "alchemy";
|
|
1891
1805
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1892
1806
|
import * as Provider6 from "alchemy/Provider";
|
|
1893
|
-
import * as
|
|
1807
|
+
import * as Effect17 from "effect/Effect";
|
|
1894
1808
|
|
|
1895
1809
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1896
1810
|
import * as nodes2 from "@distilled.cloud/proxmox/nodes";
|
|
1897
|
-
import * as
|
|
1811
|
+
import * as Effect16 from "effect/Effect";
|
|
1898
1812
|
|
|
1899
1813
|
// src/proxmox/ceph-fs-wire.ts
|
|
1900
1814
|
var readRow = (live, props) => {
|
|
@@ -1922,40 +1836,40 @@ var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task fi
|
|
|
1922
1836
|
var notDestroyed = (props) => new Error(`${objectPath(props)}: the destroy task finished but the filesystem is still in ` + `GET nodes/${props.node}/ceph/fs. PVE refuses to destroy a CephFS while a PVE storage entry ` + "of type cephfs still references it and is not disabled.");
|
|
1923
1837
|
|
|
1924
1838
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1925
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(
|
|
1839
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect16.map((rows) => readRow(rows, props)));
|
|
1926
1840
|
var toDistilledCreate = (props) => ({
|
|
1927
1841
|
...createForm2(props),
|
|
1928
1842
|
name: props.name,
|
|
1929
1843
|
node: props.node
|
|
1930
1844
|
});
|
|
1931
|
-
var settleTask = (props, upid) =>
|
|
1845
|
+
var settleTask = (props, upid) => Effect16.gen(function* () {
|
|
1932
1846
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1933
|
-
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
1847
|
+
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect16.orElseSucceed(() => {
|
|
1934
1848
|
return;
|
|
1935
1849
|
}));
|
|
1936
1850
|
if (status?.status === "stopped") {
|
|
1937
1851
|
if (status.exitstatus === "OK")
|
|
1938
1852
|
return;
|
|
1939
|
-
return yield*
|
|
1853
|
+
return yield* Effect16.die(new Error(`${objectPath(props)}: PVE task ${upid} finished with "${status.exitstatus ?? "no exit status"}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${props.node}/tasks/${upid}/log\`.`));
|
|
1940
1854
|
}
|
|
1941
|
-
yield*
|
|
1855
|
+
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1942
1856
|
}
|
|
1943
|
-
return yield*
|
|
1857
|
+
return yield* Effect16.die(new Error(`${objectPath(props)}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its status could not be read. Check the ` + "task log, and check that the `read` role holds Sys.Audit on " + `/nodes/${props.node} -- each call mints a new token, so the poller is never the task ` + "owner and is answered 403 rather than told to wait."));
|
|
1944
1858
|
});
|
|
1945
|
-
var createFs = (props) =>
|
|
1859
|
+
var createFs = (props) => Effect16.gen(function* () {
|
|
1946
1860
|
const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
|
|
1947
1861
|
if (upid === "") {
|
|
1948
|
-
return yield*
|
|
1862
|
+
return yield* Effect16.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
|
|
1949
1863
|
}
|
|
1950
1864
|
yield* settleTask(props, upid);
|
|
1951
1865
|
});
|
|
1952
|
-
var destroyFs = (props) =>
|
|
1866
|
+
var destroyFs = (props) => Effect16.gen(function* () {
|
|
1953
1867
|
const upid = yield* runPve(props.target, "provision", true, nodes2.deleteNodeCephFs({
|
|
1954
1868
|
node: props.node,
|
|
1955
1869
|
name: props.name,
|
|
1956
1870
|
...props["remove-pools"] === true ? { remove_pools: "1" } : {},
|
|
1957
1871
|
...props["remove-storages"] === true ? { remove_storages: "1" } : {}
|
|
1958
|
-
})).pipe(
|
|
1872
|
+
})).pipe(Effect16.catchTag("CephFsNotFound", () => Effect16.succeed("")));
|
|
1959
1873
|
if (upid !== "")
|
|
1960
1874
|
yield* settleTask(props, upid);
|
|
1961
1875
|
});
|
|
@@ -1964,12 +1878,12 @@ var destroyFs = (props) => Effect17.gen(function* () {
|
|
|
1964
1878
|
var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
|
|
1965
1879
|
defaultRemovalPolicy: "retain"
|
|
1966
1880
|
});
|
|
1967
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
1968
|
-
list: () =>
|
|
1969
|
-
read:
|
|
1881
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect17.succeed(ProxmoxCephFs.Provider.of({
|
|
1882
|
+
list: () => Effect17.succeed([]),
|
|
1883
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1970
1884
|
return yield* readFs(olds);
|
|
1971
1885
|
}),
|
|
1972
|
-
diff:
|
|
1886
|
+
diff: Effect17.fn(function* ({ news, output }) {
|
|
1973
1887
|
if (!isResolved6(news))
|
|
1974
1888
|
return;
|
|
1975
1889
|
yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
|
|
@@ -1985,34 +1899,34 @@ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succe
|
|
|
1985
1899
|
}
|
|
1986
1900
|
return { action: "noop" };
|
|
1987
1901
|
}),
|
|
1988
|
-
reconcile:
|
|
1902
|
+
reconcile: Effect17.fn(function* ({ news }) {
|
|
1989
1903
|
const live = yield* readFs(news);
|
|
1990
1904
|
if (live !== undefined)
|
|
1991
1905
|
return live;
|
|
1992
1906
|
yield* createFs(news);
|
|
1993
1907
|
const after = yield* readFs(news);
|
|
1994
1908
|
if (after === undefined)
|
|
1995
|
-
return yield*
|
|
1909
|
+
return yield* Effect17.die(notCreated2(news));
|
|
1996
1910
|
return after;
|
|
1997
1911
|
}),
|
|
1998
|
-
delete:
|
|
1912
|
+
delete: Effect17.fn(function* ({ olds }) {
|
|
1999
1913
|
if ((yield* readFs(olds)) === undefined)
|
|
2000
1914
|
return;
|
|
2001
1915
|
yield* destroyFs(olds);
|
|
2002
1916
|
const after = yield* readFs(olds);
|
|
2003
1917
|
if (after !== undefined)
|
|
2004
|
-
return yield*
|
|
1918
|
+
return yield* Effect17.die(notDestroyed(olds));
|
|
2005
1919
|
})
|
|
2006
1920
|
})));
|
|
2007
1921
|
// src/proxmox/ceph-osd.ts
|
|
2008
1922
|
import { Resource as Resource7 } from "alchemy";
|
|
2009
1923
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2010
1924
|
import * as Provider7 from "alchemy/Provider";
|
|
2011
|
-
import * as
|
|
1925
|
+
import * as Effect20 from "effect/Effect";
|
|
2012
1926
|
|
|
2013
1927
|
// src/proxmox/ceph-osd-tree.ts
|
|
2014
1928
|
import * as nodes3 from "@distilled.cloud/proxmox/nodes";
|
|
2015
|
-
import * as
|
|
1929
|
+
import * as Effect18 from "effect/Effect";
|
|
2016
1930
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
2017
1931
|
var osdLeaves = (tree) => {
|
|
2018
1932
|
const root = tree["root"];
|
|
@@ -2038,23 +1952,23 @@ var osdAttributes = (leaf, props) => ({
|
|
|
2038
1952
|
status: text(leaf["status"]),
|
|
2039
1953
|
total_space: num(leaf["total_space"], 0)
|
|
2040
1954
|
});
|
|
2041
|
-
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(
|
|
1955
|
+
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(Effect18.map((t) => {
|
|
2042
1956
|
const leaf = findOsd(t, props.osdid);
|
|
2043
1957
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
2044
1958
|
}));
|
|
2045
1959
|
|
|
2046
1960
|
// src/proxmox/ceph-osd-write.ts
|
|
2047
1961
|
import * as nodes4 from "@distilled.cloud/proxmox/nodes";
|
|
2048
|
-
import * as
|
|
1962
|
+
import * as Effect19 from "effect/Effect";
|
|
2049
1963
|
var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
|
|
2050
1964
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
2051
1965
|
var createOsdForm = (props, dev) => ({
|
|
2052
1966
|
dev,
|
|
2053
1967
|
...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
|
|
2054
1968
|
});
|
|
2055
|
-
var createOsd =
|
|
1969
|
+
var createOsd = Effect19.fn(function* (news) {
|
|
2056
1970
|
if (news.dev === undefined) {
|
|
2057
|
-
return yield*
|
|
1971
|
+
return yield* Effect19.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
|
|
2058
1972
|
}
|
|
2059
1973
|
const form = createOsdForm(news, news.dev);
|
|
2060
1974
|
yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
|
|
@@ -2065,7 +1979,7 @@ var createOsd = Effect20.fn(function* (news) {
|
|
|
2065
1979
|
}));
|
|
2066
1980
|
const created = yield* readOsd(news);
|
|
2067
1981
|
if (created === undefined) {
|
|
2068
|
-
return yield*
|
|
1982
|
+
return yield* Effect19.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
|
|
2069
1983
|
}
|
|
2070
1984
|
return created;
|
|
2071
1985
|
});
|
|
@@ -2081,12 +1995,12 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
2081
1995
|
});
|
|
2082
1996
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
2083
1997
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
2084
|
-
var
|
|
2085
|
-
list: () =>
|
|
2086
|
-
read:
|
|
1998
|
+
var handlers = {
|
|
1999
|
+
list: () => Effect20.succeed([]),
|
|
2000
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2087
2001
|
return yield* readOsd(olds);
|
|
2088
2002
|
}),
|
|
2089
|
-
diff:
|
|
2003
|
+
diff: Effect20.fn(function* ({
|
|
2090
2004
|
news,
|
|
2091
2005
|
output
|
|
2092
2006
|
}) {
|
|
@@ -2099,27 +2013,27 @@ var handlers2 = {
|
|
|
2099
2013
|
return { action: "update" };
|
|
2100
2014
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
2101
2015
|
}),
|
|
2102
|
-
reconcile:
|
|
2016
|
+
reconcile: Effect20.fn(function* ({ news }) {
|
|
2103
2017
|
const live = yield* readOsd(news);
|
|
2104
2018
|
if (live === undefined) {
|
|
2105
2019
|
return yield* createOsd(news);
|
|
2106
2020
|
}
|
|
2107
2021
|
if (!settled(live, news)) {
|
|
2108
|
-
return yield*
|
|
2022
|
+
return yield* Effect20.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
|
|
2109
2023
|
}
|
|
2110
2024
|
return live;
|
|
2111
2025
|
}),
|
|
2112
|
-
delete:
|
|
2026
|
+
delete: Effect20.fn(function* ({ olds }) {
|
|
2113
2027
|
yield* destroyOsd(olds);
|
|
2114
2028
|
})
|
|
2115
2029
|
};
|
|
2116
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
2030
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect20.succeed(ProxmoxCephOsd.Provider.of(handlers)));
|
|
2117
2031
|
// src/proxmox/ceph-pool.ts
|
|
2118
2032
|
import { Resource as Resource8 } from "alchemy";
|
|
2119
2033
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2120
2034
|
import * as Provider8 from "alchemy/Provider";
|
|
2121
2035
|
import * as nodes7 from "@distilled.cloud/proxmox/nodes";
|
|
2122
|
-
import * as
|
|
2036
|
+
import * as Effect23 from "effect/Effect";
|
|
2123
2037
|
|
|
2124
2038
|
// src/proxmox/ceph-pool-form.ts
|
|
2125
2039
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -2148,22 +2062,22 @@ var createBody = (props) => ({
|
|
|
2148
2062
|
|
|
2149
2063
|
// src/proxmox/ceph-pool-settle.ts
|
|
2150
2064
|
import * as nodes5 from "@distilled.cloud/proxmox/nodes";
|
|
2151
|
-
import * as
|
|
2152
|
-
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(
|
|
2153
|
-
var settle = (props, read, done) =>
|
|
2065
|
+
import * as Effect21 from "effect/Effect";
|
|
2066
|
+
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(Effect21.flatMap((rows) => rows.some((row) => row.pool_name === props.name) ? Effect21.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect21.void));
|
|
2067
|
+
var settle = (props, read, done) => Effect21.gen(function* () {
|
|
2154
2068
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
2155
2069
|
const live = yield* read(props);
|
|
2156
2070
|
if (done(live))
|
|
2157
2071
|
return live;
|
|
2158
|
-
yield*
|
|
2072
|
+
yield* Effect21.sleep("2 seconds");
|
|
2159
2073
|
}
|
|
2160
2074
|
return yield* read(props);
|
|
2161
2075
|
});
|
|
2162
2076
|
|
|
2163
2077
|
// src/proxmox/ceph-pool-wire.ts
|
|
2164
2078
|
import * as nodes6 from "@distilled.cloud/proxmox/nodes";
|
|
2165
|
-
import * as
|
|
2166
|
-
var
|
|
2079
|
+
import * as Effect22 from "effect/Effect";
|
|
2080
|
+
var attributesOf4 = (live, props) => {
|
|
2167
2081
|
const row = live;
|
|
2168
2082
|
if (typeof row["name"] !== "string")
|
|
2169
2083
|
return;
|
|
@@ -2185,7 +2099,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2185
2099
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2186
2100
|
};
|
|
2187
2101
|
};
|
|
2188
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(
|
|
2102
|
+
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect22.map((live) => attributesOf4(live, props)), Effect22.catchTag("CephPoolNotFound", () => Effect22.succeed(undefined)));
|
|
2189
2103
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2190
2104
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2191
2105
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2202,11 +2116,11 @@ var toDistilledUpdate = (props) => ({
|
|
|
2202
2116
|
var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
|
|
2203
2117
|
defaultRemovalPolicy: "retain"
|
|
2204
2118
|
});
|
|
2205
|
-
var
|
|
2206
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
2207
|
-
list: () =>
|
|
2119
|
+
var matches4 = (attributes, props) => same(props.size, attributes.size, attributes.nosizechange) && same(props.min_size, attributes.min_size, attributes.nosizechange) && same(props.pg_autoscale_mode, attributes.pg_autoscale_mode) && same(hint(props.pg_num_min), attributes.pg_num_min, attributes.nopgchange) && same(props.crush_rule, attributes.crush_rule, attributes.crush_rule === "") && same(hint(props.target_size), attributes.target_size);
|
|
2120
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.succeed(ProxmoxCephPool.Provider.of({
|
|
2121
|
+
list: () => Effect23.succeed([]),
|
|
2208
2122
|
read: ({ olds }) => readPoolStatus(olds),
|
|
2209
|
-
diff:
|
|
2123
|
+
diff: Effect23.fn(function* ({ news, output }) {
|
|
2210
2124
|
if (!isResolved8(news))
|
|
2211
2125
|
return;
|
|
2212
2126
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
|
|
@@ -2218,9 +2132,9 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2218
2132
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), true);
|
|
2219
2133
|
return { action: "update" };
|
|
2220
2134
|
}
|
|
2221
|
-
return
|
|
2135
|
+
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
2222
2136
|
}),
|
|
2223
|
-
reconcile:
|
|
2137
|
+
reconcile: Effect23.fn(function* ({ news }) {
|
|
2224
2138
|
const live = yield* readPoolStatus(news);
|
|
2225
2139
|
let upid;
|
|
2226
2140
|
if (live === undefined) {
|
|
@@ -2228,36 +2142,36 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2228
2142
|
yield* confirmAbsent(news, object(news));
|
|
2229
2143
|
upid = yield* runPve(news.target, "provision", true, nodes7.createNodeCephPool(toDistilledCreate2(news)));
|
|
2230
2144
|
} else {
|
|
2231
|
-
const form = formToSend(
|
|
2145
|
+
const form = formToSend(matches4, live, news, updateBody(news));
|
|
2232
2146
|
if (form !== undefined) {
|
|
2233
2147
|
yield* guardWrite2(CEPH_POOL_UPDATE, updateBody(news), false);
|
|
2234
2148
|
upid = yield* runPve(news.target, "provision", true, nodes7.putNodeCephPool(toDistilledUpdate(news)));
|
|
2235
2149
|
}
|
|
2236
2150
|
}
|
|
2237
|
-
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined &&
|
|
2238
|
-
if (after === undefined || !
|
|
2239
|
-
return yield*
|
|
2151
|
+
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined && matches4(row, news));
|
|
2152
|
+
if (after === undefined || !matches4(after, news)) {
|
|
2153
|
+
return yield* Effect23.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
|
|
2240
2154
|
}
|
|
2241
2155
|
return after;
|
|
2242
2156
|
}),
|
|
2243
|
-
delete:
|
|
2157
|
+
delete: Effect23.fn(function* ({ olds }) {
|
|
2244
2158
|
yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
|
|
2245
2159
|
const left = yield* settle(olds, readPoolStatus, (row) => row === undefined);
|
|
2246
2160
|
if (left !== undefined) {
|
|
2247
|
-
return yield*
|
|
2161
|
+
return yield* Effect23.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
|
|
2248
2162
|
}
|
|
2249
2163
|
})
|
|
2250
2164
|
})));
|
|
2251
2165
|
// src/proxmox/firewall-alias.ts
|
|
2252
2166
|
import { Resource as Resource9 } from "alchemy";
|
|
2253
2167
|
import * as Provider9 from "alchemy/Provider";
|
|
2254
|
-
import * as
|
|
2168
|
+
import * as Effect25 from "effect/Effect";
|
|
2255
2169
|
|
|
2256
2170
|
// src/proxmox/firewall-alias-lifecycle.ts
|
|
2257
2171
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2258
|
-
import * as
|
|
2172
|
+
import * as cluster4 from "@distilled.cloud/proxmox/cluster";
|
|
2259
2173
|
import { ProxmoxParseError as ProxmoxParseError2 } from "@distilled.cloud/proxmox/Errors";
|
|
2260
|
-
import * as
|
|
2174
|
+
import * as Effect24 from "effect/Effect";
|
|
2261
2175
|
|
|
2262
2176
|
// src/proxmox/firewall-alias-form.ts
|
|
2263
2177
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -2299,20 +2213,20 @@ var firewallAliasSpec = {
|
|
|
2299
2213
|
|
|
2300
2214
|
// src/proxmox/firewall-alias-lifecycle.ts
|
|
2301
2215
|
var { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(firewallAliasSpec);
|
|
2302
|
-
var readFirewallAlias = (props) => runPve(props.target, "read", false,
|
|
2216
|
+
var readFirewallAlias = (props) => runPve(props.target, "read", false, cluster4.getClusterFirewallAlias({ name: props.name })).pipe(Effect24.flatMap((live) => {
|
|
2303
2217
|
if (live === null || typeof live !== "object" || Array.isArray(live) || !("name" in live) || typeof live.name !== "string" || fold(live.name) !== fold(props.name) || !("cidr" in live) || typeof live.cidr !== "string" || cidr(live.cidr) === "") {
|
|
2304
|
-
return
|
|
2218
|
+
return Effect24.fail(new ProxmoxParseError2({
|
|
2305
2219
|
body: undefined,
|
|
2306
2220
|
cause: "Firewall alias response does not match the requested vendor identity"
|
|
2307
2221
|
}));
|
|
2308
2222
|
}
|
|
2309
|
-
return
|
|
2310
|
-
}),
|
|
2311
|
-
var deleteFirewallAlias = (props) => runPve(props.target, "provision", true,
|
|
2223
|
+
return Effect24.succeed(firewallAliasSpec.attributes({ ...live }, props));
|
|
2224
|
+
}), Effect24.catchTag("FirewallAliasNotFound", () => Effect24.succeed(undefined)));
|
|
2225
|
+
var deleteFirewallAlias = (props) => runPve(props.target, "provision", true, cluster4.deleteClusterFirewallAlias({ name: props.name }));
|
|
2312
2226
|
var firewallAliasHandlers = {
|
|
2313
|
-
list: () =>
|
|
2227
|
+
list: () => Effect24.succeed([]),
|
|
2314
2228
|
read: ({ olds }) => readFirewallAlias(olds),
|
|
2315
|
-
diff:
|
|
2229
|
+
diff: Effect24.fn(function* ({
|
|
2316
2230
|
news,
|
|
2317
2231
|
output
|
|
2318
2232
|
}) {
|
|
@@ -2331,20 +2245,20 @@ var firewallAliasHandlers = {
|
|
|
2331
2245
|
}
|
|
2332
2246
|
return { action: firewallAliasSpec.matches(live, news) ? "noop" : "update" };
|
|
2333
2247
|
}),
|
|
2334
|
-
reconcile:
|
|
2248
|
+
reconcile: Effect24.fn(function* ({ news }) {
|
|
2335
2249
|
const live = yield* readFirewallAlias(news);
|
|
2336
2250
|
yield* guardCreate2(news, live === undefined);
|
|
2337
2251
|
yield* guardUpdate2(news);
|
|
2338
2252
|
if (live === undefined) {
|
|
2339
|
-
yield* runPve(news.target, "provision", true,
|
|
2253
|
+
yield* runPve(news.target, "provision", true, cluster4.createClusterFirewallAlias(firewallAliasSpec.createForm(news)));
|
|
2340
2254
|
} else {
|
|
2341
2255
|
const form = formToSend(firewallAliasSpec.matches, live, news, firewallAliasSpec.updateForm(news));
|
|
2342
2256
|
if (form !== undefined)
|
|
2343
|
-
yield* runPve(news.target, "provision", true,
|
|
2257
|
+
yield* runPve(news.target, "provision", true, cluster4.putClusterFirewallAlias({ ...form, name: news.name }));
|
|
2344
2258
|
}
|
|
2345
2259
|
const after = yield* readFirewallAlias(news);
|
|
2346
2260
|
if (after === undefined)
|
|
2347
|
-
return yield*
|
|
2261
|
+
return yield* Effect24.fail(new Error(`${firewallAliasSpec.path(news)}: write returned success but the resource is still absent`));
|
|
2348
2262
|
return after;
|
|
2349
2263
|
}),
|
|
2350
2264
|
delete: ({ olds }) => deleteFirewallAlias(olds)
|
|
@@ -2352,17 +2266,17 @@ var firewallAliasHandlers = {
|
|
|
2352
2266
|
|
|
2353
2267
|
// src/proxmox/firewall-alias.ts
|
|
2354
2268
|
var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
|
|
2355
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
2269
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect25.succeed(ProxmoxFirewallAlias.Provider.of(firewallAliasHandlers)));
|
|
2356
2270
|
// src/proxmox/group.ts
|
|
2357
2271
|
import { Resource as Resource10 } from "alchemy";
|
|
2358
2272
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2359
2273
|
import * as Provider10 from "alchemy/Provider";
|
|
2360
2274
|
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2361
|
-
import * as
|
|
2275
|
+
import * as Effect27 from "effect/Effect";
|
|
2362
2276
|
|
|
2363
2277
|
// src/proxmox/group-wire.ts
|
|
2364
2278
|
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2365
|
-
import * as
|
|
2279
|
+
import * as Effect26 from "effect/Effect";
|
|
2366
2280
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2367
2281
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2368
2282
|
var storedComment = (comment2) => {
|
|
@@ -2377,34 +2291,34 @@ var createForm3 = (props) => ({
|
|
|
2377
2291
|
comment: storedComment(props.comment),
|
|
2378
2292
|
groupid: props.groupid
|
|
2379
2293
|
});
|
|
2380
|
-
var
|
|
2294
|
+
var updateForm2 = (props) => ({
|
|
2381
2295
|
comment: storedComment(props.comment),
|
|
2382
2296
|
groupid: props.groupid
|
|
2383
2297
|
});
|
|
2384
|
-
var
|
|
2298
|
+
var attributesOf5 = (live, props) => ({
|
|
2385
2299
|
comment: text(live.comment),
|
|
2386
2300
|
groupid: props.groupid,
|
|
2387
2301
|
members: memberList(live.members)
|
|
2388
2302
|
});
|
|
2389
|
-
var
|
|
2390
|
-
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(
|
|
2391
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(
|
|
2303
|
+
var matches5 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2304
|
+
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf5(live, props)));
|
|
2305
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.catchTag("GroupNotFound", () => Effect26.succeed(undefined)));
|
|
2392
2306
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2393
2307
|
|
|
2394
2308
|
// src/proxmox/group.ts
|
|
2395
2309
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2396
2310
|
defaultRemovalPolicy: "retain"
|
|
2397
2311
|
});
|
|
2398
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
2399
|
-
list: () =>
|
|
2400
|
-
read:
|
|
2312
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succeed(ProxmoxGroup.Provider.of({
|
|
2313
|
+
list: () => Effect27.succeed([]),
|
|
2314
|
+
read: Effect27.fn(function* ({ olds, output }) {
|
|
2401
2315
|
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2402
2316
|
}),
|
|
2403
|
-
diff:
|
|
2317
|
+
diff: Effect27.fn(function* ({ news, output }) {
|
|
2404
2318
|
if (!isResolved10(news))
|
|
2405
2319
|
return;
|
|
2406
2320
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
2407
|
-
yield* guardWrite2(GROUP_UPDATE,
|
|
2321
|
+
yield* guardWrite2(GROUP_UPDATE, updateForm2(news), false);
|
|
2408
2322
|
if (output === undefined)
|
|
2409
2323
|
return;
|
|
2410
2324
|
const live = yield* readGroupOrFail(news);
|
|
@@ -2416,31 +2330,149 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect28.succee
|
|
|
2416
2330
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), true);
|
|
2417
2331
|
return { action: "update" };
|
|
2418
2332
|
}
|
|
2419
|
-
return
|
|
2333
|
+
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
2420
2334
|
}),
|
|
2421
|
-
reconcile:
|
|
2335
|
+
reconcile: Effect27.fn(function* ({ news }) {
|
|
2422
2336
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2423
2337
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2424
|
-
yield* guardWrite2(GROUP_UPDATE,
|
|
2338
|
+
yield* guardWrite2(GROUP_UPDATE, updateForm2(news), false);
|
|
2425
2339
|
if (before === undefined) {
|
|
2426
2340
|
yield* runPve(news.target, "provision", true, access4.createAccessGroup(createForm3(news)));
|
|
2427
|
-
} else if (!
|
|
2428
|
-
yield* runPve(news.target, "provision", true, access4.putAccessGroup(
|
|
2341
|
+
} else if (!matches5(before, news)) {
|
|
2342
|
+
yield* runPve(news.target, "provision", true, access4.putAccessGroup(updateForm2(news)));
|
|
2429
2343
|
}
|
|
2430
2344
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2431
2345
|
if (after === undefined) {
|
|
2432
|
-
return yield*
|
|
2346
|
+
return yield* Effect27.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group is ` + 'still absent. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- read back rather than trusting the status code."));
|
|
2433
2347
|
}
|
|
2434
2348
|
return after;
|
|
2435
2349
|
}),
|
|
2436
|
-
delete:
|
|
2350
|
+
delete: Effect27.fn(function* ({ olds }) {
|
|
2437
2351
|
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2438
2352
|
})
|
|
2439
2353
|
})));
|
|
2440
2354
|
// src/proxmox/ha-resource.ts
|
|
2441
2355
|
import { Resource as Resource11 } from "alchemy";
|
|
2442
2356
|
import * as Provider11 from "alchemy/Provider";
|
|
2357
|
+
import * as Effect30 from "effect/Effect";
|
|
2358
|
+
|
|
2359
|
+
// src/proxmox/resource.ts
|
|
2360
|
+
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2443
2361
|
import * as Effect29 from "effect/Effect";
|
|
2362
|
+
|
|
2363
|
+
// src/proxmox/client.ts
|
|
2364
|
+
import * as Effect28 from "effect/Effect";
|
|
2365
|
+
import * as HttpClient5 from "effect/unstable/http/HttpClient";
|
|
2366
|
+
import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
|
|
2367
|
+
class PveError extends Error {
|
|
2368
|
+
status;
|
|
2369
|
+
method;
|
|
2370
|
+
path;
|
|
2371
|
+
constructor(status, method, path, detail) {
|
|
2372
|
+
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
2373
|
+
this.status = status;
|
|
2374
|
+
this.method = method;
|
|
2375
|
+
this.path = path;
|
|
2376
|
+
this.name = "PveError";
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
2380
|
+
var encode = (form) => {
|
|
2381
|
+
const params = new URLSearchParams;
|
|
2382
|
+
for (const [key, value] of Object.entries(form)) {
|
|
2383
|
+
if (typeof value === "string")
|
|
2384
|
+
params.append(key, value);
|
|
2385
|
+
else
|
|
2386
|
+
for (const item of value)
|
|
2387
|
+
params.append(key, item);
|
|
2388
|
+
}
|
|
2389
|
+
return params.toString();
|
|
2390
|
+
};
|
|
2391
|
+
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
2392
|
+
const url = `${apiBase}/${path}`;
|
|
2393
|
+
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
2394
|
+
};
|
|
2395
|
+
var executeOne = (target, credential, method, path, form, apiBase) => Effect28.gen(function* () {
|
|
2396
|
+
const client = yield* HttpClient5.HttpClient;
|
|
2397
|
+
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
2398
|
+
return yield* client.execute(request).pipe(Effect28.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
2399
|
+
});
|
|
2400
|
+
var readResponse = (response, method, path) => Effect28.gen(function* () {
|
|
2401
|
+
if (response.status < 200 || response.status >= 300) {
|
|
2402
|
+
const detail = yield* response.text.pipe(Effect28.orElseSucceed(() => ""));
|
|
2403
|
+
return yield* Effect28.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
2404
|
+
}
|
|
2405
|
+
const body2 = yield* response.json.pipe(Effect28.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
2406
|
+
return body2.data;
|
|
2407
|
+
});
|
|
2408
|
+
var pveWith = (target, credential, method, path, form) => Effect28.gen(function* () {
|
|
2409
|
+
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect28.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
2410
|
+
return yield* readResponse(response, method, path);
|
|
2411
|
+
});
|
|
2412
|
+
var pve = (target, role, method, path, form) => Effect28.gen(function* () {
|
|
2413
|
+
const credential = yield* leased(target, role);
|
|
2414
|
+
return yield* pveWith(target, credential, method, path, form);
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
// src/proxmox/resource.ts
|
|
2418
|
+
var pveOperations = (spec) => {
|
|
2419
|
+
const { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(spec);
|
|
2420
|
+
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect29.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect29.orElseSucceed(() => {
|
|
2421
|
+
return;
|
|
2422
|
+
}));
|
|
2423
|
+
return {
|
|
2424
|
+
guardCreate: guardCreate3,
|
|
2425
|
+
guardUpdate: guardUpdate3,
|
|
2426
|
+
read,
|
|
2427
|
+
diff: (news, output) => Effect29.gen(function* () {
|
|
2428
|
+
if (!isResolved11(news))
|
|
2429
|
+
return;
|
|
2430
|
+
yield* guardCreate3(news, output === undefined);
|
|
2431
|
+
yield* guardUpdate3(news);
|
|
2432
|
+
if (output === undefined)
|
|
2433
|
+
return;
|
|
2434
|
+
const live = yield* read(news);
|
|
2435
|
+
if (live === undefined) {
|
|
2436
|
+
yield* guardCreate3(news, true);
|
|
2437
|
+
return { action: "update" };
|
|
2438
|
+
}
|
|
2439
|
+
if (spec.matches(live, news))
|
|
2440
|
+
return { action: "noop" };
|
|
2441
|
+
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
2442
|
+
}),
|
|
2443
|
+
reconcile: (news) => Effect29.gen(function* () {
|
|
2444
|
+
const live = yield* read(news);
|
|
2445
|
+
yield* guardCreate3(news, live === undefined);
|
|
2446
|
+
yield* guardUpdate3(news);
|
|
2447
|
+
if (live === undefined) {
|
|
2448
|
+
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
2449
|
+
} else if (spec.updateForm !== undefined) {
|
|
2450
|
+
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
2451
|
+
if (form !== undefined) {
|
|
2452
|
+
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
const after = yield* read(news);
|
|
2456
|
+
if (after === undefined) {
|
|
2457
|
+
return yield* Effect29.die(new Error(`${spec.path(news)}: the write returned no error but the object is still absent. ` + 'PVE wraps every answer in {"data":...} and can report success on a call that did ' + "nothing -- read back rather than trusting the status code."));
|
|
2458
|
+
}
|
|
2459
|
+
return after;
|
|
2460
|
+
}),
|
|
2461
|
+
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
2462
|
+
};
|
|
2463
|
+
};
|
|
2464
|
+
var pveHandlers = (spec) => {
|
|
2465
|
+
const ops = pveOperations(spec);
|
|
2466
|
+
return {
|
|
2467
|
+
list: () => Effect29.succeed([]),
|
|
2468
|
+
read: ({ olds }) => ops.read(olds),
|
|
2469
|
+
diff: ({ news, output }) => ops.diff(news, output),
|
|
2470
|
+
reconcile: ({ news }) => ops.reconcile(news),
|
|
2471
|
+
delete: ({ olds }) => ops.destroy(olds)
|
|
2472
|
+
};
|
|
2473
|
+
};
|
|
2474
|
+
|
|
2475
|
+
// src/proxmox/ha-resource.ts
|
|
2444
2476
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2445
2477
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2446
2478
|
var shape3 = (props) => ({
|
|
@@ -2449,7 +2481,7 @@ var shape3 = (props) => ({
|
|
|
2449
2481
|
max_restart: String(props.max_restart ?? 1),
|
|
2450
2482
|
state: props.state ?? "started"
|
|
2451
2483
|
});
|
|
2452
|
-
var
|
|
2484
|
+
var handlers2 = pveHandlers({
|
|
2453
2485
|
attributes: (live, props) => ({
|
|
2454
2486
|
comment: typeof live["comment"] === "string" ? live["comment"] : "",
|
|
2455
2487
|
max_relocate: num(live["max_relocate"], 1),
|
|
@@ -2468,11 +2500,11 @@ var handlers3 = pveHandlers({
|
|
|
2468
2500
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2469
2501
|
updateForm: shape3
|
|
2470
2502
|
});
|
|
2471
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2503
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect30.succeed(ProxmoxHaResource.Provider.of(handlers2)));
|
|
2472
2504
|
// src/proxmox/ha-rule.ts
|
|
2473
2505
|
import { Resource as Resource12 } from "alchemy";
|
|
2474
2506
|
import * as Provider12 from "alchemy/Provider";
|
|
2475
|
-
import * as
|
|
2507
|
+
import * as Effect31 from "effect/Effect";
|
|
2476
2508
|
|
|
2477
2509
|
// src/proxmox/ha-rule-form.ts
|
|
2478
2510
|
var nodeList = (value) => {
|
|
@@ -2520,7 +2552,7 @@ var clearList = (props) => Object.entries(optional(props)).filter(([, value]) =>
|
|
|
2520
2552
|
|
|
2521
2553
|
// src/proxmox/ha-rule.ts
|
|
2522
2554
|
var ProxmoxHaRule = Resource12("Proxmox.HaRule");
|
|
2523
|
-
var
|
|
2555
|
+
var handlers3 = pveHandlers({
|
|
2524
2556
|
attributes: (live, props) => {
|
|
2525
2557
|
const liveType = text(live["type"]);
|
|
2526
2558
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -2549,43 +2581,43 @@ var handlers4 = pveHandlers({
|
|
|
2549
2581
|
return withClears(fields, clear);
|
|
2550
2582
|
}
|
|
2551
2583
|
});
|
|
2552
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2584
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect31.succeed(ProxmoxHaRule.Provider.of(handlers3)));
|
|
2553
2585
|
// src/proxmox/lxc.ts
|
|
2554
2586
|
import { Resource as Resource13 } from "alchemy";
|
|
2555
|
-
import { isResolved as
|
|
2587
|
+
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2556
2588
|
import * as Provider13 from "alchemy/Provider";
|
|
2557
|
-
import * as
|
|
2589
|
+
import * as Effect42 from "effect/Effect";
|
|
2558
2590
|
|
|
2559
2591
|
// src/ownership/adopt.ts
|
|
2560
2592
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2561
2593
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2562
2594
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2563
|
-
import * as
|
|
2595
|
+
import * as Effect35 from "effect/Effect";
|
|
2564
2596
|
import * as Option5 from "effect/Option";
|
|
2565
2597
|
|
|
2566
2598
|
// src/ownership/resume.ts
|
|
2567
2599
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2568
2600
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2569
|
-
import * as
|
|
2601
|
+
import * as Effect32 from "effect/Effect";
|
|
2570
2602
|
import * as Option2 from "effect/Option";
|
|
2571
2603
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2572
2604
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2573
|
-
var note = (key, instanceId) =>
|
|
2574
|
-
const bag = yield*
|
|
2605
|
+
var note = (key, instanceId) => Effect32.gen(function* () {
|
|
2606
|
+
const bag = yield* Effect32.serviceOption(Artifacts);
|
|
2575
2607
|
if (Option2.isSome(bag))
|
|
2576
2608
|
yield* bag.value.set(key, instanceId);
|
|
2577
2609
|
});
|
|
2578
|
-
var noted = (key, instanceId) =>
|
|
2579
|
-
const bag = yield*
|
|
2610
|
+
var noted = (key, instanceId) => Effect32.gen(function* () {
|
|
2611
|
+
const bag = yield* Effect32.serviceOption(Artifacts);
|
|
2580
2612
|
if (Option2.isNone(bag))
|
|
2581
2613
|
return false;
|
|
2582
2614
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2583
2615
|
});
|
|
2584
|
-
var noteUnfinished = (instanceId) =>
|
|
2585
|
-
var noteResume = (instanceId, recovered) =>
|
|
2616
|
+
var noteUnfinished = (instanceId) => Effect32.as(note(UNFINISHED, instanceId), undefined);
|
|
2617
|
+
var noteResume = (instanceId, recovered) => Effect32.gen(function* () {
|
|
2586
2618
|
yield* noteUnfinished(instanceId);
|
|
2587
|
-
const unproven = () =>
|
|
2588
|
-
const found = yield* recovered.pipe(
|
|
2619
|
+
const unproven = () => Effect32.succeed(undefined);
|
|
2620
|
+
const found = yield* recovered.pipe(Effect32.catch(unproven), Effect32.catchDefect(unproven));
|
|
2589
2621
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2590
2622
|
return;
|
|
2591
2623
|
yield* note(PROVEN, instanceId);
|
|
@@ -2596,7 +2628,7 @@ var provingResumes = (service) => {
|
|
|
2596
2628
|
const { diff, read } = service;
|
|
2597
2629
|
if (diff === undefined || read === undefined)
|
|
2598
2630
|
return service;
|
|
2599
|
-
const proving = (input) =>
|
|
2631
|
+
const proving = (input) => Effect32.gen(function* () {
|
|
2600
2632
|
if (input.output === undefined) {
|
|
2601
2633
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2602
2634
|
}
|
|
@@ -2608,12 +2640,12 @@ var provingResumes = (service) => {
|
|
|
2608
2640
|
// src/ownership/rows.ts
|
|
2609
2641
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2610
2642
|
import { State, isActionState } from "alchemy/State/State";
|
|
2611
|
-
import * as
|
|
2643
|
+
import * as Effect34 from "effect/Effect";
|
|
2612
2644
|
import * as Option4 from "effect/Option";
|
|
2613
2645
|
|
|
2614
2646
|
// src/ownership/whole.ts
|
|
2615
2647
|
import { Stack } from "alchemy/Stack";
|
|
2616
|
-
import * as
|
|
2648
|
+
import * as Effect33 from "effect/Effect";
|
|
2617
2649
|
import * as Option3 from "effect/Option";
|
|
2618
2650
|
var absent = (value) => value === undefined || value === null;
|
|
2619
2651
|
var isPlainObject = (value) => {
|
|
@@ -2639,22 +2671,22 @@ var carries = (declared, recorded) => {
|
|
|
2639
2671
|
}
|
|
2640
2672
|
return true;
|
|
2641
2673
|
};
|
|
2642
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2674
|
+
var wholeDeclaration = (fqn, props) => Effect33.map(Effect33.serviceOption(Stack), (stack) => {
|
|
2643
2675
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2644
2676
|
return declared !== undefined && carries(declared.Props, props);
|
|
2645
2677
|
});
|
|
2646
2678
|
|
|
2647
2679
|
// src/ownership/rows.ts
|
|
2648
|
-
var storeOf =
|
|
2649
|
-
const stack = yield*
|
|
2650
|
-
const state = yield*
|
|
2680
|
+
var storeOf = Effect34.gen(function* () {
|
|
2681
|
+
const stack = yield* Effect34.serviceOption(Stack2);
|
|
2682
|
+
const state = yield* Effect34.serviceOption(State);
|
|
2651
2683
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2652
2684
|
return;
|
|
2653
2685
|
const store = yield* state.value;
|
|
2654
2686
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2655
2687
|
return { resources: stack.value.resources, store, where };
|
|
2656
2688
|
});
|
|
2657
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2689
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect34.orElseSucceed(() => {
|
|
2658
2690
|
return;
|
|
2659
2691
|
}));
|
|
2660
2692
|
var generationOf = (row, instanceId) => {
|
|
@@ -2667,7 +2699,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2667
2699
|
}
|
|
2668
2700
|
return;
|
|
2669
2701
|
};
|
|
2670
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2702
|
+
var recordedGeneration = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2671
2703
|
const found = yield* storeOf;
|
|
2672
2704
|
if (found === undefined)
|
|
2673
2705
|
return;
|
|
@@ -2678,14 +2710,48 @@ var recordedGeneration = (fqn, instanceId) => Effect33.gen(function* () {
|
|
|
2678
2710
|
}
|
|
2679
2711
|
return;
|
|
2680
2712
|
});
|
|
2681
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2713
|
+
var recordedInstance = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2682
2714
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2683
2715
|
if (generation === undefined)
|
|
2684
2716
|
return "absent";
|
|
2685
2717
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2686
2718
|
});
|
|
2687
|
-
var isCreate = (fqn, instanceId) =>
|
|
2688
|
-
var
|
|
2719
|
+
var isCreate = (fqn, instanceId) => Effect34.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
2720
|
+
var idOf = (attr) => {
|
|
2721
|
+
if (typeof attr !== "object" || attr === null)
|
|
2722
|
+
return;
|
|
2723
|
+
const id = attr.id;
|
|
2724
|
+
return typeof id === "string" && id !== "" ? id : undefined;
|
|
2725
|
+
};
|
|
2726
|
+
var olderGenerationIds = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2727
|
+
const found = yield* storeOf;
|
|
2728
|
+
if (found === undefined)
|
|
2729
|
+
return [];
|
|
2730
|
+
const ids = [];
|
|
2731
|
+
for (const at of [fqn, ...found.resources[fqn]?.FormerFqns ?? []]) {
|
|
2732
|
+
collectOlder(yield* rowAt(found.store, found.where, at), instanceId, ids);
|
|
2733
|
+
}
|
|
2734
|
+
return ids;
|
|
2735
|
+
});
|
|
2736
|
+
var collectOlder = (row, instanceId, ids) => {
|
|
2737
|
+
let at = row;
|
|
2738
|
+
let seen = false;
|
|
2739
|
+
while (typeof at === "object" && at !== null && !isActionState(at)) {
|
|
2740
|
+
const generation = at;
|
|
2741
|
+
if (!seen) {
|
|
2742
|
+
seen = generation.instanceId === instanceId;
|
|
2743
|
+
at = generation.old;
|
|
2744
|
+
continue;
|
|
2745
|
+
}
|
|
2746
|
+
if (generation.instanceId !== instanceId) {
|
|
2747
|
+
const id = idOf(generation.attr);
|
|
2748
|
+
if (id !== undefined)
|
|
2749
|
+
ids.push(id);
|
|
2750
|
+
}
|
|
2751
|
+
at = generation.old;
|
|
2752
|
+
}
|
|
2753
|
+
};
|
|
2754
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2689
2755
|
const found = yield* storeOf;
|
|
2690
2756
|
if (found === undefined)
|
|
2691
2757
|
return;
|
|
@@ -2694,32 +2760,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect33.gen(function* () {
|
|
|
2694
2760
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2695
2761
|
return;
|
|
2696
2762
|
}
|
|
2697
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2763
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect34.ignore);
|
|
2698
2764
|
});
|
|
2699
2765
|
|
|
2700
2766
|
// src/ownership/adopt.ts
|
|
2701
|
-
var adoptEnabled = (fqn) =>
|
|
2702
|
-
const stack = yield*
|
|
2767
|
+
var adoptEnabled = (fqn) => Effect35.gen(function* () {
|
|
2768
|
+
const stack = yield* Effect35.serviceOption(Stack3);
|
|
2703
2769
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2704
2770
|
if (scoped !== undefined)
|
|
2705
2771
|
return scoped;
|
|
2706
|
-
const policy = yield*
|
|
2772
|
+
const policy = yield* Effect35.serviceOption(AdoptPolicy);
|
|
2707
2773
|
if (Option5.isSome(policy))
|
|
2708
2774
|
return policy.value;
|
|
2709
|
-
const context = yield*
|
|
2775
|
+
const context = yield* Effect35.serviceOption(AlchemyContext);
|
|
2710
2776
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2711
2777
|
});
|
|
2712
|
-
var adoptable = (owner) =>
|
|
2778
|
+
var adoptable = (owner) => Effect35.gen(function* () {
|
|
2713
2779
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2714
2780
|
return true;
|
|
2715
2781
|
return yield* unfinished(owner.instanceId);
|
|
2716
2782
|
});
|
|
2717
|
-
var adoptsAtApply = (owner) =>
|
|
2783
|
+
var adoptsAtApply = (owner) => Effect35.gen(function* () {
|
|
2718
2784
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2719
2785
|
return false;
|
|
2720
2786
|
return yield* adoptable(owner);
|
|
2721
2787
|
});
|
|
2722
|
-
var refuseTakeover = (owner, what) =>
|
|
2788
|
+
var refuseTakeover = (owner, what) => Effect35.gen(function* () {
|
|
2723
2789
|
if (owner.output !== undefined)
|
|
2724
2790
|
return;
|
|
2725
2791
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2729,25 +2795,25 @@ var refuseTakeover = (owner, what) => Effect34.gen(function* () {
|
|
|
2729
2795
|
return;
|
|
2730
2796
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2731
2797
|
const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
|
|
2732
|
-
return yield*
|
|
2798
|
+
return yield* Effect35.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
|
|
2733
2799
|
});
|
|
2734
2800
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2735
2801
|
|
|
2736
2802
|
// src/ownership/probe.ts
|
|
2737
2803
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2738
|
-
import * as
|
|
2739
|
-
var provenOurs = (ask, settled2) =>
|
|
2804
|
+
import * as Effect36 from "effect/Effect";
|
|
2805
|
+
var provenOurs = (ask, settled2) => Effect36.gen(function* () {
|
|
2740
2806
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2741
2807
|
if (recorded === "absent")
|
|
2742
2808
|
return false;
|
|
2743
2809
|
if (recorded === "partial") {
|
|
2744
|
-
yield*
|
|
2810
|
+
yield* Effect36.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
|
|
2745
2811
|
return false;
|
|
2746
2812
|
}
|
|
2747
|
-
const unproven = (reason) =>
|
|
2748
|
-
return yield* settled2.pipe(
|
|
2813
|
+
const unproven = (reason) => Effect36.as(Effect36.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
|
|
2814
|
+
return yield* settled2.pipe(Effect36.catch(unproven), Effect36.catchDefect(unproven));
|
|
2749
2815
|
});
|
|
2750
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2816
|
+
var ownedRead = (ask, found, settled2) => Effect36.gen(function* () {
|
|
2751
2817
|
if (found === undefined || ask.output !== undefined)
|
|
2752
2818
|
return found;
|
|
2753
2819
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -2805,8 +2871,8 @@ var optionMap = (value, family, defaultKey) => {
|
|
|
2805
2871
|
return out;
|
|
2806
2872
|
};
|
|
2807
2873
|
var sameMap = (left, right) => left.size === right.size && [...left].every(([key, value]) => right.get(key) === value);
|
|
2808
|
-
var sortedForm = (
|
|
2809
|
-
var printMap = (
|
|
2874
|
+
var sortedForm = (map14) => [...map14].map(([key, value]) => `${key}=${value}`).sort().join(",");
|
|
2875
|
+
var printMap = (map14, lead = []) => [...lead.filter((key) => map14.has(key)), ...[...map14.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map14.get(key) ?? ""}`).join(",");
|
|
2810
2876
|
var netMaps = (declared, live) => {
|
|
2811
2877
|
const want = optionMap(declared, "net");
|
|
2812
2878
|
const have = optionMap(live, "net");
|
|
@@ -3202,11 +3268,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
3202
3268
|
};
|
|
3203
3269
|
|
|
3204
3270
|
// src/proxmox/lxc-adoption.ts
|
|
3205
|
-
import * as
|
|
3271
|
+
import * as Effect41 from "effect/Effect";
|
|
3206
3272
|
|
|
3207
3273
|
// src/ownership/adopting.ts
|
|
3208
|
-
import * as
|
|
3209
|
-
var adopting = (owner, settled2) =>
|
|
3274
|
+
import * as Effect37 from "effect/Effect";
|
|
3275
|
+
var adopting = (owner, settled2) => Effect37.gen(function* () {
|
|
3210
3276
|
if (owner.output === undefined)
|
|
3211
3277
|
return false;
|
|
3212
3278
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -3218,7 +3284,7 @@ var adopting = (owner, settled2) => Effect36.gen(function* () {
|
|
|
3218
3284
|
});
|
|
3219
3285
|
|
|
3220
3286
|
// src/proxmox/lxc-lifecycle.ts
|
|
3221
|
-
import * as
|
|
3287
|
+
import * as Effect40 from "effect/Effect";
|
|
3222
3288
|
import * as nodes10 from "@distilled.cloud/proxmox/nodes";
|
|
3223
3289
|
|
|
3224
3290
|
// src/proxmox/lxc-errors.ts
|
|
@@ -3227,44 +3293,44 @@ class LxcRefusedError extends Error {
|
|
|
3227
3293
|
}
|
|
3228
3294
|
|
|
3229
3295
|
// src/proxmox/lxc-read.ts
|
|
3230
|
-
import * as
|
|
3296
|
+
import * as cluster5 from "@distilled.cloud/proxmox/cluster";
|
|
3231
3297
|
import * as nodes8 from "@distilled.cloud/proxmox/nodes";
|
|
3232
|
-
import * as
|
|
3233
|
-
var readLive = (where) =>
|
|
3298
|
+
import * as Effect38 from "effect/Effect";
|
|
3299
|
+
var readLive = (where) => Effect38.gen(function* () {
|
|
3234
3300
|
const credential = yield* leased(where.target, "read");
|
|
3235
|
-
const answer = yield* runPveWith(where.target, credential, false, nodes8.getNodeLxcConfig({ node: where.node, vmid: String(where.vmid) })).pipe(
|
|
3301
|
+
const answer = yield* runPveWith(where.target, credential, false, nodes8.getNodeLxcConfig({ node: where.node, vmid: String(where.vmid) })).pipe(Effect38.map((data) => ({ data, error: undefined })), Effect38.catchTag("LxcConfigNotFound", (error) => Effect38.succeed({ data: undefined, error })));
|
|
3236
3302
|
if (answer.error === undefined) {
|
|
3237
3303
|
const live = answer.data;
|
|
3238
3304
|
if (live === null || typeof live !== "object" || Array.isArray(live) || !("digest" in live) || typeof live.digest !== "string" || live.digest === "") {
|
|
3239
|
-
return yield*
|
|
3305
|
+
return yield* Effect38.fail(new LxcRefusedError(`CT ${String(where.vmid)}: config read did not return a valid digest-bearing config.`));
|
|
3240
3306
|
}
|
|
3241
3307
|
return live;
|
|
3242
3308
|
}
|
|
3243
|
-
const rows = yield* runPveWith(where.target, credential, false,
|
|
3309
|
+
const rows = yield* runPveWith(where.target, credential, false, cluster5.listClusterResources({ type: "vm" }));
|
|
3244
3310
|
if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !["lxc", "qemu"].includes(row.type))) {
|
|
3245
|
-
return yield*
|
|
3311
|
+
return yield* Effect38.fail(new LxcRefusedError("The cluster guest index did not identify its rows."));
|
|
3246
3312
|
}
|
|
3247
3313
|
const found = rows.find((row) => Number(row.vmid) === where.vmid);
|
|
3248
3314
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3249
|
-
return yield*
|
|
3315
|
+
return yield* Effect38.fail(answer.error);
|
|
3250
3316
|
}
|
|
3251
3317
|
if (found !== undefined) {
|
|
3252
|
-
return yield*
|
|
3318
|
+
return yield* Effect38.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
|
|
3253
3319
|
}
|
|
3254
3320
|
return;
|
|
3255
3321
|
});
|
|
3256
3322
|
|
|
3257
3323
|
// src/proxmox/lxc-task.ts
|
|
3258
3324
|
import * as nodes9 from "@distilled.cloud/proxmox/nodes";
|
|
3259
|
-
import * as
|
|
3260
|
-
var lxcTask = (where, operation, what, polls) =>
|
|
3325
|
+
import * as Effect39 from "effect/Effect";
|
|
3326
|
+
var lxcTask = (where, operation, what, polls) => Effect39.gen(function* () {
|
|
3261
3327
|
const credential = yield* mint(where.target, "provision");
|
|
3262
3328
|
const upid = text(yield* runPveWith(where.target, credential, true, operation));
|
|
3263
3329
|
if (upid === "")
|
|
3264
|
-
return yield*
|
|
3330
|
+
return yield* Effect39.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
3265
3331
|
let exit = "still running when this provider stopped waiting";
|
|
3266
3332
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
3267
|
-
const status = yield* runPveWith(where.target, credential, false, nodes9.getNodeTaskStatus({ node: where.node, upid })).pipe(
|
|
3333
|
+
const status = yield* runPveWith(where.target, credential, false, nodes9.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect39.orElseSucceed(() => {
|
|
3268
3334
|
return;
|
|
3269
3335
|
}));
|
|
3270
3336
|
if (status === undefined || status.status === undefined) {
|
|
@@ -3275,10 +3341,10 @@ var lxcTask = (where, operation, what, polls) => Effect38.gen(function* () {
|
|
|
3275
3341
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
3276
3342
|
break;
|
|
3277
3343
|
}
|
|
3278
|
-
yield*
|
|
3344
|
+
yield* Effect39.sleep("1 second");
|
|
3279
3345
|
}
|
|
3280
3346
|
if (exit !== "OK")
|
|
3281
|
-
return yield*
|
|
3347
|
+
return yield* Effect39.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
3282
3348
|
});
|
|
3283
3349
|
|
|
3284
3350
|
// src/proxmox/lxc-lifecycle.ts
|
|
@@ -3289,13 +3355,13 @@ var LXC_ENDPOINTS = {
|
|
|
3289
3355
|
};
|
|
3290
3356
|
var CREATE_POLLS = 180;
|
|
3291
3357
|
var TASK_POLLS = 60;
|
|
3292
|
-
var
|
|
3358
|
+
var attributesOf6 = (where, live) => ({
|
|
3293
3359
|
config: storedConfig(live),
|
|
3294
3360
|
node: where.node,
|
|
3295
3361
|
rawKeys: rawKeysOf(live),
|
|
3296
3362
|
vmid: where.vmid
|
|
3297
3363
|
});
|
|
3298
|
-
var createGuest = (props) =>
|
|
3364
|
+
var createGuest = (props) => Effect40.gen(function* () {
|
|
3299
3365
|
const form = createForm4(props);
|
|
3300
3366
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3301
3367
|
return yield* lxcTask(props, nodes10.createNodeLxc({
|
|
@@ -3305,7 +3371,7 @@ var createGuest = (props) => Effect39.gen(function* () {
|
|
|
3305
3371
|
ostemplate: text(form["ostemplate"])
|
|
3306
3372
|
}), `create CT ${String(props.vmid)}`, CREATE_POLLS);
|
|
3307
3373
|
});
|
|
3308
|
-
var updateGuest = (props, change, digest) =>
|
|
3374
|
+
var updateGuest = (props, change, digest) => Effect40.gen(function* () {
|
|
3309
3375
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3310
3376
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3311
3377
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3317,47 +3383,47 @@ var updateGuest = (props, change, digest) => Effect39.gen(function* () {
|
|
|
3317
3383
|
yield* lxcTask(props, nodes10.putNodeLxcResize({ ...grown, node: props.node, vmid: String(props.vmid) }), `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS);
|
|
3318
3384
|
}
|
|
3319
3385
|
});
|
|
3320
|
-
var destroyGuest = (where, declared) =>
|
|
3386
|
+
var destroyGuest = (where, declared) => Effect40.gen(function* () {
|
|
3321
3387
|
const live = yield* readLive(where);
|
|
3322
3388
|
if (live === undefined)
|
|
3323
3389
|
return;
|
|
3324
3390
|
const drift = judge(declared, live).drift;
|
|
3325
3391
|
if (drift.length > 0) {
|
|
3326
|
-
return yield*
|
|
3392
|
+
return yield* Effect40.fail(new LxcRefusedError(`destroy CT ${String(where.vmid)}: the guest on ${where.node} no longer matches its last ` + `declaration (${drift.join(", ")}), so it may not be the guest this stack made. ` + "Nothing was deleted. Delete it by hand if it should go, or declare it again."));
|
|
3327
3393
|
}
|
|
3328
3394
|
yield* lxcTask(where, nodes10.deleteNodeLxc({ node: where.node, vmid: String(where.vmid) }), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3329
3395
|
});
|
|
3330
3396
|
|
|
3331
3397
|
// src/proxmox/lxc-adoption.ts
|
|
3332
3398
|
var adoptionRefusal = (props, drift) => `CT ${String(props.vmid)} on ${props.node}: adopting it would change ${drift.join(", ")}. An ` + "adoption never changes a guest, so nothing is written. Declare what is live for these keys " + "(the plan names keys, never values) and plan again; change them after the adoption, as an " + "update.";
|
|
3333
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3399
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect41.gen(function* () {
|
|
3334
3400
|
if (change.drift.length === 0)
|
|
3335
3401
|
return;
|
|
3336
|
-
const settled2 = (recorded) =>
|
|
3402
|
+
const settled2 = (recorded) => Effect41.sync(() => judge(recorded, live).drift.length === 0);
|
|
3337
3403
|
if (!(yield* adopting(owner, settled2)))
|
|
3338
3404
|
return;
|
|
3339
|
-
return yield*
|
|
3405
|
+
return yield* Effect41.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3340
3406
|
});
|
|
3341
3407
|
|
|
3342
3408
|
// src/proxmox/lxc.ts
|
|
3343
3409
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3344
|
-
var refused = (reasons) =>
|
|
3410
|
+
var refused = (reasons) => Effect42.fail(new LxcRefusedError(reasons.join(`
|
|
3345
3411
|
`)));
|
|
3346
|
-
var diff = (owner, news, olds) =>
|
|
3412
|
+
var diff = (owner, news, olds) => Effect42.gen(function* () {
|
|
3347
3413
|
const { output } = owner;
|
|
3348
3414
|
const identity2 = identityRefusals(news, olds, output);
|
|
3349
3415
|
if (identity2.length > 0)
|
|
3350
3416
|
return yield* refused(identity2);
|
|
3351
3417
|
if (output === undefined)
|
|
3352
3418
|
return;
|
|
3353
|
-
if (!
|
|
3419
|
+
if (!isResolved12(news))
|
|
3354
3420
|
return;
|
|
3355
3421
|
const live = yield* readLive(news);
|
|
3356
3422
|
if (live === undefined) {
|
|
3357
3423
|
const refusals = createRefusals(news);
|
|
3358
3424
|
if (refusals.length > 0)
|
|
3359
3425
|
return yield* refused(refusals);
|
|
3360
|
-
yield*
|
|
3426
|
+
yield* Effect42.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: the cluster lists no guest with this ` + "vmid -- a deploy CREATES it again from ostemplate, with new, empty volumes.");
|
|
3361
3427
|
return { action: "update" };
|
|
3362
3428
|
}
|
|
3363
3429
|
const change = judge(news, live);
|
|
@@ -3368,10 +3434,10 @@ var diff = (owner, news, olds) => Effect41.gen(function* () {
|
|
|
3368
3434
|
if (change.drift.length === 0 && !moved)
|
|
3369
3435
|
return { action: "noop" };
|
|
3370
3436
|
const what = change.drift.length === 0 ? `the guest is on ${news.node} now, not ${output.node} -- a deploy re-records it, ` + "writing nothing." : `live config differs from the declaration in ${change.drift.join(", ")} -- a ` + "deploy writes these.";
|
|
3371
|
-
yield*
|
|
3437
|
+
yield* Effect42.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3372
3438
|
return { action: "update" };
|
|
3373
3439
|
});
|
|
3374
|
-
var reconcile = (owner, news) =>
|
|
3440
|
+
var reconcile = (owner, news) => Effect42.gen(function* () {
|
|
3375
3441
|
const { output } = owner;
|
|
3376
3442
|
const identity2 = identityRefusals(news, news, output);
|
|
3377
3443
|
if (identity2.length > 0)
|
|
@@ -3410,22 +3476,22 @@ var reconcile = (owner, news) => Effect41.gen(function* () {
|
|
|
3410
3476
|
`CT ${String(news.vmid)}: after the write, ${left.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value (tags are lower-cased by default) -- " + "declare what it stores."
|
|
3411
3477
|
]);
|
|
3412
3478
|
}
|
|
3413
|
-
return
|
|
3479
|
+
return attributesOf6(news, after);
|
|
3414
3480
|
});
|
|
3415
3481
|
var whereOf = (olds, output) => ({
|
|
3416
3482
|
node: output?.node ?? olds.node,
|
|
3417
3483
|
target: olds.target,
|
|
3418
3484
|
vmid: output?.vmid ?? olds.vmid
|
|
3419
3485
|
});
|
|
3420
|
-
var read = (owner, olds) =>
|
|
3486
|
+
var read = (owner, olds) => Effect42.gen(function* () {
|
|
3421
3487
|
const where = whereOf(olds, owner.output);
|
|
3422
3488
|
const live = yield* readLive(where);
|
|
3423
3489
|
if (live === undefined)
|
|
3424
3490
|
return;
|
|
3425
|
-
const settled2 =
|
|
3426
|
-
return yield* ownedRead(owner,
|
|
3491
|
+
const settled2 = Effect42.sync(() => judge(olds, live).drift.length === 0);
|
|
3492
|
+
return yield* ownedRead(owner, attributesOf6(where, live), settled2);
|
|
3427
3493
|
});
|
|
3428
|
-
var
|
|
3494
|
+
var handlers4 = {
|
|
3429
3495
|
delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
|
|
3430
3496
|
diff: ({
|
|
3431
3497
|
fqn,
|
|
@@ -3434,7 +3500,7 @@ var handlers5 = {
|
|
|
3434
3500
|
olds,
|
|
3435
3501
|
output
|
|
3436
3502
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3437
|
-
list: () =>
|
|
3503
|
+
list: () => Effect42.succeed([]),
|
|
3438
3504
|
read: ({
|
|
3439
3505
|
fqn,
|
|
3440
3506
|
instanceId,
|
|
@@ -3448,11 +3514,11 @@ var handlers5 = {
|
|
|
3448
3514
|
output
|
|
3449
3515
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3450
3516
|
};
|
|
3451
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3517
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect42.succeed(ProxmoxLxc.Provider.of(handlers4)).pipe(Effect42.map(provingResumes)));
|
|
3452
3518
|
// src/proxmox/metric-server.ts
|
|
3453
3519
|
import { Resource as Resource14 } from "alchemy";
|
|
3454
|
-
import { isResolved as
|
|
3455
|
-
import * as
|
|
3520
|
+
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3521
|
+
import * as cluster7 from "@distilled.cloud/proxmox/cluster";
|
|
3456
3522
|
|
|
3457
3523
|
// src/proxmox/metric-server-form.ts
|
|
3458
3524
|
var UNSET2 = -1;
|
|
@@ -3566,15 +3632,15 @@ var metricServerSpec = {
|
|
|
3566
3632
|
};
|
|
3567
3633
|
|
|
3568
3634
|
// src/proxmox/metric-server-distilled.ts
|
|
3569
|
-
import * as
|
|
3635
|
+
import * as cluster6 from "@distilled.cloud/proxmox/cluster";
|
|
3570
3636
|
import { ProxmoxParseError as ProxmoxParseError3 } from "@distilled.cloud/proxmox/Errors";
|
|
3571
|
-
import * as
|
|
3637
|
+
import * as Effect43 from "effect/Effect";
|
|
3572
3638
|
import * as Schema2 from "effect/Schema";
|
|
3573
|
-
var readMetricServerRow = (props) => runPve(props.target, "read", false,
|
|
3639
|
+
var readMetricServerRow = (props) => runPve(props.target, "read", false, cluster6.getClusterMetricsServer({ id: props.id })).pipe(Effect43.flatMap((body4) => Schema2.decodeUnknownEffect(Schema2.Record(Schema2.String, Schema2.Unknown))(body4).pipe(Effect43.mapError(() => new ProxmoxParseError3({
|
|
3574
3640
|
body: undefined,
|
|
3575
3641
|
cause: "Metric server response must be an object"
|
|
3576
|
-
})))),
|
|
3577
|
-
var readMetricServer = (props) => readMetricServerRow(props).pipe(
|
|
3642
|
+
})))), Effect43.catchTag("MetricServerNotFound", () => Effect43.succeed(undefined)), Effect43.catchTag("NotFound", () => Effect43.succeed(undefined)));
|
|
3643
|
+
var readMetricServer = (props) => readMetricServerRow(props).pipe(Effect43.map((row) => row === undefined ? undefined : metricServerSpec.attributes(row, props)));
|
|
3578
3644
|
var metricServerRequest = (props, form) => ({
|
|
3579
3645
|
...asForm2({
|
|
3580
3646
|
api_path_prefix: form["api-path-prefix"],
|
|
@@ -3599,22 +3665,22 @@ var metricServerRequest = (props, form) => ({
|
|
|
3599
3665
|
port: String(props.port),
|
|
3600
3666
|
server: props.server
|
|
3601
3667
|
});
|
|
3602
|
-
var deleteMetricServer = (props) =>
|
|
3668
|
+
var deleteMetricServer = (props) => Effect43.gen(function* () {
|
|
3603
3669
|
if ((yield* readMetricServerRow(props)) === undefined)
|
|
3604
3670
|
return;
|
|
3605
|
-
yield* runPve(props.target, "provision", true,
|
|
3671
|
+
yield* runPve(props.target, "provision", true, cluster6.deleteClusterMetricsServer({ id: props.id }));
|
|
3606
3672
|
});
|
|
3607
3673
|
|
|
3608
3674
|
// src/proxmox/metric-server.ts
|
|
3609
3675
|
import * as Provider14 from "alchemy/Provider";
|
|
3610
|
-
import * as
|
|
3676
|
+
import * as Effect44 from "effect/Effect";
|
|
3611
3677
|
var ProxmoxMetricServer = Resource14("Proxmox.MetricServer");
|
|
3612
3678
|
var { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(metricServerSpec);
|
|
3613
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
3614
|
-
list: () =>
|
|
3679
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect44.succeed(ProxmoxMetricServer.Provider.of({
|
|
3680
|
+
list: () => Effect44.succeed([]),
|
|
3615
3681
|
read: ({ olds }) => readMetricServer(olds),
|
|
3616
|
-
diff:
|
|
3617
|
-
if (!
|
|
3682
|
+
diff: Effect44.fn(function* ({ news, output }) {
|
|
3683
|
+
if (!isResolved13(news))
|
|
3618
3684
|
return;
|
|
3619
3685
|
yield* guardCreate3(news, output === undefined);
|
|
3620
3686
|
yield* guardUpdate3(news);
|
|
@@ -3627,36 +3693,36 @@ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, E
|
|
|
3627
3693
|
}
|
|
3628
3694
|
return { action: metricServerSpec.matches(live, news) ? "noop" : "update" };
|
|
3629
3695
|
}),
|
|
3630
|
-
reconcile:
|
|
3696
|
+
reconcile: Effect44.fn(function* ({ news }) {
|
|
3631
3697
|
const live = yield* readMetricServer(news);
|
|
3632
3698
|
yield* guardCreate3(news, live === undefined);
|
|
3633
3699
|
yield* guardUpdate3(news);
|
|
3634
3700
|
if (live === undefined) {
|
|
3635
|
-
yield* runPve(news.target, "provision", true,
|
|
3701
|
+
yield* runPve(news.target, "provision", true, cluster7.updateClusterMetricsServer({
|
|
3636
3702
|
...metricServerRequest(news, metricServerSpec.createForm(news)),
|
|
3637
3703
|
type: news.type
|
|
3638
3704
|
}));
|
|
3639
3705
|
} else {
|
|
3640
3706
|
const form = formToSend(metricServerSpec.matches, live, news, metricServerSpec.updateForm(news));
|
|
3641
3707
|
if (form !== undefined)
|
|
3642
|
-
yield* runPve(news.target, "provision", true,
|
|
3708
|
+
yield* runPve(news.target, "provision", true, cluster7.putClusterMetricsServer(metricServerRequest(news, form)));
|
|
3643
3709
|
}
|
|
3644
3710
|
const after = yield* readMetricServer(news);
|
|
3645
3711
|
if (after === undefined)
|
|
3646
|
-
return yield*
|
|
3712
|
+
return yield* Effect44.fail(new Error(`${metricServerSpec.path(news)}: write returned success but the resource is still absent`));
|
|
3647
3713
|
return after;
|
|
3648
3714
|
}),
|
|
3649
3715
|
delete: ({ olds }) => deleteMetricServer(olds)
|
|
3650
3716
|
})));
|
|
3651
3717
|
// src/proxmox/network-apply.ts
|
|
3652
3718
|
import { Resource as Resource15 } from "alchemy";
|
|
3653
|
-
import { isResolved as
|
|
3719
|
+
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3654
3720
|
import * as Provider15 from "alchemy/Provider";
|
|
3655
|
-
import * as
|
|
3721
|
+
import * as Effect47 from "effect/Effect";
|
|
3656
3722
|
|
|
3657
3723
|
// src/proxmox/network-apply-run.ts
|
|
3658
3724
|
import * as nodes12 from "@distilled.cloud/proxmox/nodes";
|
|
3659
|
-
import * as
|
|
3725
|
+
import * as Effect46 from "effect/Effect";
|
|
3660
3726
|
|
|
3661
3727
|
// src/proxmox/apply-endpoints.ts
|
|
3662
3728
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3665,10 +3731,10 @@ var guardNetworkApply = guardForm(NETWORK_APPLY_ENDPOINT, {}, true);
|
|
|
3665
3731
|
var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
3666
3732
|
|
|
3667
3733
|
// src/proxmox/network-apply-read.ts
|
|
3668
|
-
import * as
|
|
3734
|
+
import * as cluster8 from "@distilled.cloud/proxmox/cluster";
|
|
3669
3735
|
import * as nodes11 from "@distilled.cloud/proxmox/nodes";
|
|
3670
|
-
import * as
|
|
3671
|
-
var stagedDiff = (target, node) =>
|
|
3736
|
+
import * as Effect45 from "effect/Effect";
|
|
3737
|
+
var stagedDiff = (target, node) => Effect45.gen(function* () {
|
|
3672
3738
|
const credential = yield* leased(target, "read");
|
|
3673
3739
|
const live = yield* runPveWith(target, credential, false, nodes11.listNodeNetwork({ node }));
|
|
3674
3740
|
return Array.isArray(live) ? "" : live.changes;
|
|
@@ -3680,36 +3746,36 @@ var pendingLines = (diff2) => {
|
|
|
3680
3746
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
3681
3747
|
return Math.max(changed, 1);
|
|
3682
3748
|
};
|
|
3683
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
3684
|
-
var clusterHealth = (target) => runPve(target, "read", false,
|
|
3749
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect45.map(pendingLines));
|
|
3750
|
+
var clusterHealth = (target) => runPve(target, "read", false, cluster8.listClusterStatus({})).pipe(Effect45.map((rows) => {
|
|
3685
3751
|
const all = rows ?? [];
|
|
3686
|
-
const
|
|
3752
|
+
const cluster9 = all.find((row) => row.type === "cluster");
|
|
3687
3753
|
return {
|
|
3688
3754
|
offline: all.filter((row) => row.type === "node" && !bool(row.online)).map((row) => text(row.name, "<unnamed>")),
|
|
3689
|
-
quorate:
|
|
3755
|
+
quorate: cluster9 === undefined ? true : bool(cluster9.quorate)
|
|
3690
3756
|
};
|
|
3691
3757
|
}));
|
|
3692
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
3758
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect45.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
3693
3759
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
3694
3760
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
3695
3761
|
var ATTEMPTS = 30;
|
|
3696
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
3762
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect45.gen(function* () {
|
|
3697
3763
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
3698
|
-
const status = yield* runPveWith(target, credential, false, nodes11.getNodeTaskStatus({ node, upid })).pipe(
|
|
3764
|
+
const status = yield* runPveWith(target, credential, false, nodes11.getNodeTaskStatus({ node, upid })).pipe(Effect45.orElseSucceed(() => {
|
|
3699
3765
|
return;
|
|
3700
3766
|
}));
|
|
3701
3767
|
if (status === undefined)
|
|
3702
3768
|
return UNREACHABLE;
|
|
3703
3769
|
if (status.status === "stopped")
|
|
3704
3770
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
3705
|
-
yield*
|
|
3771
|
+
yield* Effect45.sleep("1 second");
|
|
3706
3772
|
}
|
|
3707
3773
|
return STILL_RUNNING;
|
|
3708
3774
|
});
|
|
3709
3775
|
|
|
3710
3776
|
// src/proxmox/network-apply-run.ts
|
|
3711
|
-
var refuse = (node, why) =>
|
|
3712
|
-
var applyNetwork = (props) =>
|
|
3777
|
+
var refuse = (node, why) => Effect46.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3778
|
+
var applyNetwork = (props) => Effect46.gen(function* () {
|
|
3713
3779
|
const node = props.node;
|
|
3714
3780
|
const staged = yield* pendingCount(props.target, node);
|
|
3715
3781
|
if (staged === 0)
|
|
@@ -3741,27 +3807,27 @@ var applyNetwork = (props) => Effect45.gen(function* () {
|
|
|
3741
3807
|
|
|
3742
3808
|
// src/proxmox/network-apply.ts
|
|
3743
3809
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3744
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3745
|
-
var diff2 = (news) =>
|
|
3746
|
-
if (!
|
|
3810
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect47.map((pending) => ({ node: props.node, pending })));
|
|
3811
|
+
var diff2 = (news) => Effect47.gen(function* () {
|
|
3812
|
+
if (!isResolved14(news))
|
|
3747
3813
|
return;
|
|
3748
3814
|
const { pending } = yield* read2(news);
|
|
3749
3815
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3750
3816
|
});
|
|
3751
|
-
var
|
|
3752
|
-
delete: () =>
|
|
3817
|
+
var handlers5 = {
|
|
3818
|
+
delete: () => Effect47.void,
|
|
3753
3819
|
diff: ({ news }) => diff2(news),
|
|
3754
|
-
list: () =>
|
|
3820
|
+
list: () => Effect47.succeed([]),
|
|
3755
3821
|
read: ({ olds }) => read2(olds),
|
|
3756
3822
|
reconcile: ({ news }) => applyNetwork(news)
|
|
3757
3823
|
};
|
|
3758
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3824
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect47.succeed(ProxmoxNetworkApply.Provider.of(handlers5)));
|
|
3759
3825
|
// src/proxmox/node-network.ts
|
|
3760
3826
|
import { Resource as Resource16 } from "alchemy";
|
|
3761
|
-
import { isResolved as
|
|
3827
|
+
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
3762
3828
|
import * as Provider16 from "alchemy/Provider";
|
|
3763
3829
|
import * as nodes14 from "@distilled.cloud/proxmox/nodes";
|
|
3764
|
-
import * as
|
|
3830
|
+
import * as Effect49 from "effect/Effect";
|
|
3765
3831
|
|
|
3766
3832
|
// src/proxmox/node-network-form.ts
|
|
3767
3833
|
var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
|
|
@@ -3794,7 +3860,7 @@ var createForm5 = (props) => ({
|
|
|
3794
3860
|
...body4(props),
|
|
3795
3861
|
iface: props.iface
|
|
3796
3862
|
});
|
|
3797
|
-
var
|
|
3863
|
+
var updateForm3 = (props) => {
|
|
3798
3864
|
const clear = [
|
|
3799
3865
|
...props.cidr === undefined ? ["cidr"] : [],
|
|
3800
3866
|
...props.bridge_vlan_aware === false ? ["bridge_vlan_aware"] : []
|
|
@@ -3804,8 +3870,8 @@ var updateForm2 = (props) => {
|
|
|
3804
3870
|
|
|
3805
3871
|
// src/proxmox/node-network-wire.ts
|
|
3806
3872
|
import * as nodes13 from "@distilled.cloud/proxmox/nodes";
|
|
3807
|
-
import * as
|
|
3808
|
-
var
|
|
3873
|
+
import * as Effect48 from "effect/Effect";
|
|
3874
|
+
var attributesOf7 = (live, props) => {
|
|
3809
3875
|
const data = live;
|
|
3810
3876
|
const liveType = text(data["type"]);
|
|
3811
3877
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -3838,16 +3904,16 @@ var attributesOf6 = (live, props) => {
|
|
|
3838
3904
|
"vlan-raw-device": text(data["vlan-raw-device"])
|
|
3839
3905
|
};
|
|
3840
3906
|
};
|
|
3841
|
-
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes13.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(
|
|
3907
|
+
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes13.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect48.catchTag("NetworkInterfaceNotFound", () => Effect48.succeed(undefined)))).pipe(Effect48.map((live) => {
|
|
3842
3908
|
if (live === UNREADABLE)
|
|
3843
3909
|
return UNREADABLE;
|
|
3844
|
-
return live === undefined ? undefined :
|
|
3910
|
+
return live === undefined ? undefined : attributesOf7(live, props);
|
|
3845
3911
|
}));
|
|
3846
|
-
var readInterface = (props) => readInterfaceOrFail(props).pipe(
|
|
3912
|
+
var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect48.orElseSucceed(() => {
|
|
3847
3913
|
return;
|
|
3848
3914
|
}));
|
|
3849
3915
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
3850
|
-
var
|
|
3916
|
+
var matches6 = (attributes, props) => attributes.cidr === (props.cidr ?? "") && same2(props.gateway, attributes.gateway) && same2(props.autostart, attributes.autostart) && same2(props.mtu, attributes.mtu) && sameComment(props.comments, attributes.comments) && sameList(props.bridge_ports, attributes.bridge_ports) && sameList(props.bridge_vids, attributes.bridge_vids) && same2(props.bridge_vlan_aware, attributes.bridge_vlan_aware) && sameList(props.slaves, attributes.slaves) && same2(props.bond_mode, attributes.bond_mode) && same2(props.bond_xmit_hash_policy, attributes.bond_xmit_hash_policy) && same2(props["bond-primary"], attributes["bond-primary"]) && same2(props["vlan-id"], attributes["vlan-id"]) && same2(props["vlan-raw-device"], attributes["vlan-raw-device"]);
|
|
3851
3917
|
|
|
3852
3918
|
// src/proxmox/node-network.ts
|
|
3853
3919
|
var ProxmoxNodeNetwork = Resource16("Proxmox.NodeNetwork", {
|
|
@@ -3864,20 +3930,20 @@ var toDistilledCreate3 = (props) => ({
|
|
|
3864
3930
|
node: props.node
|
|
3865
3931
|
});
|
|
3866
3932
|
var toDistilledUpdate2 = (props) => ({
|
|
3867
|
-
...toDistilled(
|
|
3933
|
+
...toDistilled(updateForm3(props)),
|
|
3868
3934
|
iface: props.iface,
|
|
3869
3935
|
node: props.node
|
|
3870
3936
|
});
|
|
3871
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3872
|
-
list: () =>
|
|
3873
|
-
read:
|
|
3937
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect49.succeed(ProxmoxNodeNetwork.Provider.of({
|
|
3938
|
+
list: () => Effect49.succeed([]),
|
|
3939
|
+
read: Effect49.fn(function* ({ olds, output }) {
|
|
3874
3940
|
return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
|
|
3875
3941
|
}),
|
|
3876
|
-
diff:
|
|
3877
|
-
if (!
|
|
3942
|
+
diff: Effect49.fn(function* ({ news, output }) {
|
|
3943
|
+
if (!isResolved15(news))
|
|
3878
3944
|
return;
|
|
3879
3945
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
|
|
3880
|
-
yield* guardWrite2(NODE_NETWORK_UPDATE,
|
|
3946
|
+
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm3(news), false);
|
|
3881
3947
|
if (output === undefined)
|
|
3882
3948
|
return;
|
|
3883
3949
|
const live = yield* readInterfaceOrFail(news);
|
|
@@ -3889,35 +3955,35 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3889
3955
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), true);
|
|
3890
3956
|
return { action: "update" };
|
|
3891
3957
|
}
|
|
3892
|
-
return
|
|
3958
|
+
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
3893
3959
|
}),
|
|
3894
|
-
reconcile:
|
|
3960
|
+
reconcile: Effect49.fn(function* ({ news }) {
|
|
3895
3961
|
const before = dropUnreadable4(yield* readInterface(news));
|
|
3896
3962
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
|
|
3897
|
-
yield* guardWrite2(NODE_NETWORK_UPDATE,
|
|
3963
|
+
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm3(news), false);
|
|
3898
3964
|
if (before === undefined) {
|
|
3899
3965
|
yield* runPve(news.target, "provision", true, nodes14.createNodeNetwork(toDistilledCreate3(news)));
|
|
3900
|
-
} else if (!
|
|
3966
|
+
} else if (!matches6(before, news)) {
|
|
3901
3967
|
yield* runPve(news.target, "provision", true, nodes14.putNodeNetwork2(toDistilledUpdate2(news)));
|
|
3902
3968
|
}
|
|
3903
3969
|
const after = dropUnreadable4(yield* readInterface(news));
|
|
3904
3970
|
if (after === undefined) {
|
|
3905
|
-
return yield*
|
|
3971
|
+
return yield* Effect49.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
|
|
3906
3972
|
}
|
|
3907
3973
|
return after;
|
|
3908
3974
|
}),
|
|
3909
|
-
delete:
|
|
3975
|
+
delete: Effect49.fn(function* ({ olds }) {
|
|
3910
3976
|
yield* runPve(olds.target, "provision", true, nodes14.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
|
|
3911
3977
|
})
|
|
3912
3978
|
})));
|
|
3913
3979
|
// src/proxmox/notification-matcher.ts
|
|
3914
3980
|
import { Resource as Resource17 } from "alchemy";
|
|
3915
3981
|
import * as Provider17 from "alchemy/Provider";
|
|
3916
|
-
import * as
|
|
3982
|
+
import * as Effect53 from "effect/Effect";
|
|
3917
3983
|
|
|
3918
3984
|
// src/proxmox/notification-matcher-lifecycle.ts
|
|
3919
|
-
import { isResolved as
|
|
3920
|
-
import * as
|
|
3985
|
+
import { isResolved as isResolved16 } from "alchemy/Diff";
|
|
3986
|
+
import * as Effect52 from "effect/Effect";
|
|
3921
3987
|
|
|
3922
3988
|
// src/proxmox/notification-matcher-form.ts
|
|
3923
3989
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3994,49 +4060,49 @@ var matcherUpdateForm = (fields) => {
|
|
|
3994
4060
|
};
|
|
3995
4061
|
|
|
3996
4062
|
// src/proxmox/notification-matcher-distilled.ts
|
|
3997
|
-
import * as
|
|
3998
|
-
import * as
|
|
4063
|
+
import * as cluster9 from "@distilled.cloud/proxmox/cluster";
|
|
4064
|
+
import * as Effect51 from "effect/Effect";
|
|
3999
4065
|
|
|
4000
4066
|
// src/proxmox/notification-sdk-input.ts
|
|
4001
4067
|
import { ProxmoxParseError as ProxmoxParseError4 } from "@distilled.cloud/proxmox/Errors";
|
|
4002
4068
|
import * as Data2 from "effect/Data";
|
|
4003
|
-
import * as
|
|
4069
|
+
import * as Effect50 from "effect/Effect";
|
|
4004
4070
|
import * as Schema3 from "effect/Schema";
|
|
4005
4071
|
|
|
4006
4072
|
class NotificationRequestInvalid extends Data2.TaggedError("NotificationRequestInvalid") {
|
|
4007
4073
|
}
|
|
4008
|
-
var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(
|
|
4009
|
-
var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(
|
|
4074
|
+
var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(Effect50.mapError(() => new NotificationRequestInvalid({ operation: "PVE notification write" })));
|
|
4075
|
+
var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(Effect50.as(body5), Effect50.mapError(() => new ProxmoxParseError4({
|
|
4010
4076
|
body: undefined,
|
|
4011
4077
|
cause: "PVE notification response does not match its SDK schema"
|
|
4012
4078
|
})));
|
|
4013
4079
|
|
|
4014
4080
|
// src/proxmox/notification-matcher-distilled.ts
|
|
4015
|
-
var readMatcher = (props) => runPve(props.target, "read", false,
|
|
4081
|
+
var readMatcher = (props) => runPve(props.target, "read", false, cluster9.getClusterNotificationMatcher({ name: props.name })).pipe(Effect51.flatMap(notificationResponse(cluster9.GetClusterNotificationMatcherResponse)), Effect51.map((live) => matcherAttributes({
|
|
4016
4082
|
...live,
|
|
4017
4083
|
"invert-match": live.invert_match,
|
|
4018
4084
|
"match-calendar": live.match_calendar,
|
|
4019
4085
|
"match-field": live.match_field,
|
|
4020
4086
|
"match-severity": live.match_severity
|
|
4021
|
-
}, props.name)),
|
|
4022
|
-
var createMatcher = (props) =>
|
|
4023
|
-
const input = yield* notificationRequest(
|
|
4024
|
-
yield* runPve(props.target, "provision", true,
|
|
4087
|
+
}, props.name)), Effect51.catchTag("NotFound", () => Effect51.succeed(undefined)));
|
|
4088
|
+
var createMatcher = (props) => Effect51.gen(function* () {
|
|
4089
|
+
const input = yield* notificationRequest(cluster9.CreateClusterNotificationMatcherRequest, matcherCreateForm(props));
|
|
4090
|
+
yield* runPve(props.target, "provision", true, cluster9.createClusterNotificationMatcher(input));
|
|
4025
4091
|
});
|
|
4026
|
-
var updateMatcher = (props) =>
|
|
4027
|
-
const input = yield* notificationRequest(
|
|
4092
|
+
var updateMatcher = (props) => Effect51.gen(function* () {
|
|
4093
|
+
const input = yield* notificationRequest(cluster9.PutClusterNotificationMatcherRequest, {
|
|
4028
4094
|
...matcherUpdateForm(props),
|
|
4029
4095
|
name: props.name
|
|
4030
4096
|
});
|
|
4031
|
-
yield* runPve(props.target, "provision", true,
|
|
4097
|
+
yield* runPve(props.target, "provision", true, cluster9.putClusterNotificationMatcher(input));
|
|
4032
4098
|
});
|
|
4033
|
-
var deleteMatcher = (props) => runPve(props.target, "provision", true,
|
|
4099
|
+
var deleteMatcher = (props) => runPve(props.target, "provision", true, cluster9.deleteClusterNotificationMatcher({ name: props.name })).pipe(Effect51.catchTag("NotFound", () => Effect51.void));
|
|
4034
4100
|
|
|
4035
4101
|
// src/proxmox/notification-matcher-lifecycle.ts
|
|
4036
|
-
var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(
|
|
4102
|
+
var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(Effect52.andThen(guardForm("pve:PUT /cluster/notifications/matchers/{name}", matcherUpdateForm(props), false)));
|
|
4037
4103
|
var matcherHandlers = {
|
|
4038
|
-
list: () =>
|
|
4039
|
-
read: ({ olds }) =>
|
|
4104
|
+
list: () => Effect52.succeed([]),
|
|
4105
|
+
read: ({ olds }) => Effect52.gen(function* () {
|
|
4040
4106
|
const live = yield* readMatcher(olds);
|
|
4041
4107
|
yield* guard(olds, live === undefined);
|
|
4042
4108
|
return live;
|
|
@@ -4045,8 +4111,8 @@ var matcherHandlers = {
|
|
|
4045
4111
|
news,
|
|
4046
4112
|
olds,
|
|
4047
4113
|
output
|
|
4048
|
-
}) =>
|
|
4049
|
-
if (!
|
|
4114
|
+
}) => Effect52.gen(function* () {
|
|
4115
|
+
if (!isResolved16(news))
|
|
4050
4116
|
return;
|
|
4051
4117
|
if (olds.name !== news.name)
|
|
4052
4118
|
return { action: "replace" };
|
|
@@ -4060,7 +4126,7 @@ var matcherHandlers = {
|
|
|
4060
4126
|
}
|
|
4061
4127
|
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
4062
4128
|
}),
|
|
4063
|
-
reconcile: ({ news }) =>
|
|
4129
|
+
reconcile: ({ news }) => Effect52.gen(function* () {
|
|
4064
4130
|
const live = yield* readMatcher(news);
|
|
4065
4131
|
yield* guard(news, live === undefined);
|
|
4066
4132
|
if (live === undefined)
|
|
@@ -4069,7 +4135,7 @@ var matcherHandlers = {
|
|
|
4069
4135
|
yield* updateMatcher(news);
|
|
4070
4136
|
const after = yield* readMatcher(news);
|
|
4071
4137
|
if (after === undefined)
|
|
4072
|
-
return yield*
|
|
4138
|
+
return yield* Effect52.die(new Error(`Notification matcher ${news.name}: write returned but read-back is absent.`));
|
|
4073
4139
|
return after;
|
|
4074
4140
|
}),
|
|
4075
4141
|
delete: ({ olds }) => deleteMatcher(olds)
|
|
@@ -4077,15 +4143,15 @@ var matcherHandlers = {
|
|
|
4077
4143
|
|
|
4078
4144
|
// src/proxmox/notification-matcher.ts
|
|
4079
4145
|
var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
|
|
4080
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
4146
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect53.succeed(ProxmoxNotificationMatcher.Provider.of(matcherHandlers)));
|
|
4081
4147
|
// src/proxmox/notification-target.ts
|
|
4082
4148
|
import { Resource as Resource18 } from "alchemy";
|
|
4083
4149
|
import * as Provider18 from "alchemy/Provider";
|
|
4084
|
-
import * as
|
|
4150
|
+
import * as Effect56 from "effect/Effect";
|
|
4085
4151
|
|
|
4086
4152
|
// src/proxmox/notification-target-lifecycle.ts
|
|
4087
|
-
import { isResolved as
|
|
4088
|
-
import * as
|
|
4153
|
+
import { isResolved as isResolved17 } from "alchemy/Diff";
|
|
4154
|
+
import * as Effect55 from "effect/Effect";
|
|
4089
4155
|
|
|
4090
4156
|
// src/proxmox/notification-target-endpoint.ts
|
|
4091
4157
|
var ENDPOINTS = {
|
|
@@ -4168,30 +4234,30 @@ var targetSpec = {
|
|
|
4168
4234
|
};
|
|
4169
4235
|
|
|
4170
4236
|
// src/proxmox/notification-target-distilled.ts
|
|
4171
|
-
import * as
|
|
4172
|
-
import * as
|
|
4237
|
+
import * as cluster10 from "@distilled.cloud/proxmox/cluster";
|
|
4238
|
+
import * as Effect54 from "effect/Effect";
|
|
4173
4239
|
var read3 = (props) => {
|
|
4174
4240
|
const request = { name: props.name };
|
|
4175
4241
|
switch (props.type) {
|
|
4176
4242
|
case "gotify":
|
|
4177
|
-
return
|
|
4243
|
+
return cluster10.getClusterNotificationEndpointGotify(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointGotifyResponse)), Effect54.map((row) => ({ ...row })));
|
|
4178
4244
|
case "sendmail":
|
|
4179
|
-
return
|
|
4245
|
+
return cluster10.getClusterNotificationEndpointSendmail(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointSendmailResponse)), Effect54.map((row) => ({
|
|
4180
4246
|
...row,
|
|
4181
4247
|
"from-address": row.from_address,
|
|
4182
4248
|
"mailto-user": row.mailto_user
|
|
4183
4249
|
})));
|
|
4184
4250
|
case "smtp":
|
|
4185
|
-
return
|
|
4251
|
+
return cluster10.getClusterNotificationEndpointSmtp(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointSmtpResponse)), Effect54.map((row) => ({
|
|
4186
4252
|
...row,
|
|
4187
4253
|
"from-address": row.from_address,
|
|
4188
4254
|
"mailto-user": row.mailto_user
|
|
4189
4255
|
})));
|
|
4190
4256
|
case "webhook":
|
|
4191
|
-
return
|
|
4257
|
+
return cluster10.getClusterNotificationEndpointWebhook(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointWebhookResponse)), Effect54.map((row) => ({ ...row })));
|
|
4192
4258
|
}
|
|
4193
4259
|
};
|
|
4194
|
-
var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(
|
|
4260
|
+
var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(Effect54.map((row) => targetSpec.attributes(row, props)), Effect54.catchTag("NotFound", () => Effect54.succeed(undefined)));
|
|
4195
4261
|
var fields = (props, create) => {
|
|
4196
4262
|
const form = {
|
|
4197
4263
|
...create ? createShape(props) : shape4(props),
|
|
@@ -4225,40 +4291,40 @@ var fields = (props, create) => {
|
|
|
4225
4291
|
};
|
|
4226
4292
|
var validateTargetWrite = (props, create) => {
|
|
4227
4293
|
const schema = create ? {
|
|
4228
|
-
sendmail:
|
|
4229
|
-
smtp:
|
|
4230
|
-
gotify:
|
|
4231
|
-
webhook:
|
|
4294
|
+
sendmail: cluster10.CreateClusterNotificationEndpointSendmailRequest,
|
|
4295
|
+
smtp: cluster10.CreateClusterNotificationEndpointSmtpRequest,
|
|
4296
|
+
gotify: cluster10.CreateClusterNotificationEndpointGotifyRequest,
|
|
4297
|
+
webhook: cluster10.CreateClusterNotificationEndpointWebhookRequest
|
|
4232
4298
|
}[props.type] : {
|
|
4233
|
-
sendmail:
|
|
4234
|
-
smtp:
|
|
4235
|
-
gotify:
|
|
4236
|
-
webhook:
|
|
4299
|
+
sendmail: cluster10.PutClusterNotificationEndpointSendmailRequest,
|
|
4300
|
+
smtp: cluster10.PutClusterNotificationEndpointSmtpRequest,
|
|
4301
|
+
gotify: cluster10.PutClusterNotificationEndpointGotifyRequest,
|
|
4302
|
+
webhook: cluster10.PutClusterNotificationEndpointWebhookRequest
|
|
4237
4303
|
}[props.type];
|
|
4238
|
-
return notificationRequest(schema, fields(props, create)).pipe(
|
|
4304
|
+
return notificationRequest(schema, fields(props, create)).pipe(Effect54.asVoid);
|
|
4239
4305
|
};
|
|
4240
4306
|
var createTarget = (props) => {
|
|
4241
4307
|
const form = fields(props, true);
|
|
4242
|
-
const operation = props.type === "sendmail" ? notificationRequest(
|
|
4308
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster10.CreateClusterNotificationEndpointSendmailRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster10.CreateClusterNotificationEndpointSmtpRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster10.CreateClusterNotificationEndpointGotifyRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointGotify)) : notificationRequest(cluster10.CreateClusterNotificationEndpointWebhookRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointWebhook));
|
|
4243
4309
|
return runPve(props.target, "provision", true, operation);
|
|
4244
4310
|
};
|
|
4245
4311
|
var updateTarget = (props) => {
|
|
4246
4312
|
const form = fields(props, false);
|
|
4247
|
-
const operation = props.type === "sendmail" ? notificationRequest(
|
|
4313
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster10.PutClusterNotificationEndpointSendmailRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster10.PutClusterNotificationEndpointSmtpRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster10.PutClusterNotificationEndpointGotifyRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointGotify)) : notificationRequest(cluster10.PutClusterNotificationEndpointWebhookRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointWebhook));
|
|
4248
4314
|
return runPve(props.target, "provision", true, operation);
|
|
4249
4315
|
};
|
|
4250
4316
|
var deleteTarget = (props) => {
|
|
4251
4317
|
const request = { name: props.name };
|
|
4252
|
-
const operation = props.type === "sendmail" ?
|
|
4253
|
-
return runPve(props.target, "provision", true, operation).pipe(
|
|
4318
|
+
const operation = props.type === "sendmail" ? cluster10.deleteClusterNotificationEndpointSendmail(request) : props.type === "smtp" ? cluster10.deleteClusterNotificationEndpointSmtp(request) : props.type === "gotify" ? cluster10.deleteClusterNotificationEndpointGotify(request) : cluster10.deleteClusterNotificationEndpointWebhook(request);
|
|
4319
|
+
return runPve(props.target, "provision", true, operation).pipe(Effect54.catchTag("NotFound", () => Effect54.void));
|
|
4254
4320
|
};
|
|
4255
4321
|
|
|
4256
4322
|
// src/proxmox/notification-target-lifecycle.ts
|
|
4257
4323
|
var { guardCreate: guardCreate4, guardUpdate: guardUpdate4 } = specGuards(targetSpec);
|
|
4258
|
-
var guard2 = (props, create) => guardCreate4(props, create).pipe(
|
|
4324
|
+
var guard2 = (props, create) => guardCreate4(props, create).pipe(Effect55.andThen(guardUpdate4(props)));
|
|
4259
4325
|
var targetHandlers = {
|
|
4260
|
-
list: () =>
|
|
4261
|
-
read: ({ olds }) =>
|
|
4326
|
+
list: () => Effect55.succeed([]),
|
|
4327
|
+
read: ({ olds }) => Effect55.gen(function* () {
|
|
4262
4328
|
const live = yield* readTarget(olds);
|
|
4263
4329
|
yield* guard2(olds, live === undefined);
|
|
4264
4330
|
return live;
|
|
@@ -4267,8 +4333,8 @@ var targetHandlers = {
|
|
|
4267
4333
|
news,
|
|
4268
4334
|
olds,
|
|
4269
4335
|
output
|
|
4270
|
-
}) =>
|
|
4271
|
-
if (!
|
|
4336
|
+
}) => Effect55.gen(function* () {
|
|
4337
|
+
if (!isResolved17(news))
|
|
4272
4338
|
return;
|
|
4273
4339
|
if (olds.name !== news.name || olds.type !== news.type) {
|
|
4274
4340
|
const destination = yield* readTarget(news);
|
|
@@ -4286,7 +4352,7 @@ var targetHandlers = {
|
|
|
4286
4352
|
}
|
|
4287
4353
|
return { action: targetSpec.matches(live, news) ? "noop" : "update" };
|
|
4288
4354
|
}),
|
|
4289
|
-
reconcile: ({ news }) =>
|
|
4355
|
+
reconcile: ({ news }) => Effect55.gen(function* () {
|
|
4290
4356
|
const live = yield* readTarget(news);
|
|
4291
4357
|
yield* guard2(news, live === undefined);
|
|
4292
4358
|
if (live === undefined)
|
|
@@ -4295,7 +4361,7 @@ var targetHandlers = {
|
|
|
4295
4361
|
yield* updateTarget(news);
|
|
4296
4362
|
const after = yield* readTarget(news);
|
|
4297
4363
|
if (after === undefined)
|
|
4298
|
-
return yield*
|
|
4364
|
+
return yield* Effect55.die(new Error(`Notification target ${news.name}: write returned but read-back is absent.`));
|
|
4299
4365
|
return after;
|
|
4300
4366
|
}),
|
|
4301
4367
|
delete: ({ olds }) => deleteTarget(olds)
|
|
@@ -4303,15 +4369,15 @@ var targetHandlers = {
|
|
|
4303
4369
|
|
|
4304
4370
|
// src/proxmox/notification-target.ts
|
|
4305
4371
|
var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
|
|
4306
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
4372
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect56.succeed(ProxmoxNotificationTarget.Provider.of(targetHandlers)));
|
|
4307
4373
|
// src/proxmox/pbs-datastore.ts
|
|
4308
4374
|
import { Resource as Resource19 } from "alchemy";
|
|
4309
4375
|
import * as Provider19 from "alchemy/Provider";
|
|
4310
|
-
import * as
|
|
4376
|
+
import * as Effect62 from "effect/Effect";
|
|
4311
4377
|
|
|
4312
4378
|
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4313
|
-
import { isResolved as
|
|
4314
|
-
import * as
|
|
4379
|
+
import { isResolved as isResolved18 } from "alchemy/Diff";
|
|
4380
|
+
import * as Effect61 from "effect/Effect";
|
|
4315
4381
|
|
|
4316
4382
|
// src/proxmox/pbs-datastore-form.ts
|
|
4317
4383
|
var attributes = (live, props) => ({
|
|
@@ -4336,7 +4402,7 @@ var attributes = (live, props) => ({
|
|
|
4336
4402
|
"verify-new": bool(live["verify-new"])
|
|
4337
4403
|
});
|
|
4338
4404
|
var same4 = (declared, live) => declared === undefined || declared === live;
|
|
4339
|
-
var
|
|
4405
|
+
var matches7 = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
|
|
4340
4406
|
var set2 = (key, value) => value === undefined ? {} : { [key]: value };
|
|
4341
4407
|
var count = (value) => value === undefined ? undefined : String(value);
|
|
4342
4408
|
var mutable = (props) => ({
|
|
@@ -4363,23 +4429,23 @@ var createForm6 = (props) => ({
|
|
|
4363
4429
|
path: props.path,
|
|
4364
4430
|
...props.backend === undefined ? {} : { backend: props.backend }
|
|
4365
4431
|
});
|
|
4366
|
-
var
|
|
4432
|
+
var updateForm4 = (props) => mutable(props);
|
|
4367
4433
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
4368
4434
|
|
|
4369
4435
|
// src/proxmox/pbs-datastore-wire.ts
|
|
4370
4436
|
import * as config from "@distilled.cloud/proxmox-backup/config";
|
|
4371
|
-
import * as
|
|
4437
|
+
import * as Effect58 from "effect/Effect";
|
|
4372
4438
|
|
|
4373
4439
|
// src/proxmox/distilled-pbs.ts
|
|
4374
4440
|
import { credentials } from "@distilled.cloud/proxmox-backup/Credentials";
|
|
4375
4441
|
import * as Retry from "@distilled.cloud/proxmox-backup/Retry";
|
|
4376
|
-
import * as
|
|
4377
|
-
var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none,
|
|
4442
|
+
import * as Effect57 from "effect/Effect";
|
|
4443
|
+
var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none, Effect57.provide(credentials({
|
|
4378
4444
|
baseUrl: target.api,
|
|
4379
4445
|
secret: credential.secret,
|
|
4380
4446
|
tokenId: credential.tokenId
|
|
4381
|
-
})),
|
|
4382
|
-
var runPbs = (target, role, op) =>
|
|
4447
|
+
})), Effect57.timeout(timeout5));
|
|
4448
|
+
var runPbs = (target, role, op) => Effect57.gen(function* () {
|
|
4383
4449
|
const credential = yield* leased(target, role);
|
|
4384
4450
|
return yield* runPbsWith(target, credential, op);
|
|
4385
4451
|
});
|
|
@@ -4410,7 +4476,7 @@ var createRequest = (props) => ({
|
|
|
4410
4476
|
...props.backend === undefined ? {} : { backend: props.backend }
|
|
4411
4477
|
});
|
|
4412
4478
|
var updateRequest = (props) => ({
|
|
4413
|
-
...members(
|
|
4479
|
+
...members(updateForm4(props)),
|
|
4414
4480
|
name: props.name
|
|
4415
4481
|
});
|
|
4416
4482
|
var wire = (row) => ({
|
|
@@ -4429,53 +4495,53 @@ var wire = (row) => ({
|
|
|
4429
4495
|
"prune-schedule": row.prune_schedule,
|
|
4430
4496
|
"verify-new": row.verify_new
|
|
4431
4497
|
});
|
|
4432
|
-
var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(
|
|
4498
|
+
var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(Effect58.map((live) => attributes(wire(live), props)), Effect58.catchTag("DatastoreNotFound", () => Effect58.succeed(undefined)));
|
|
4433
4499
|
var createOne = (props) => runPbs(props.target, "provision", config.createConfigDatastore(createRequest(props)));
|
|
4434
4500
|
var updateOne = (props) => runPbs(props.target, "provision", config.putConfigDatastore(updateRequest(props)));
|
|
4435
|
-
var deleteOne = (props) =>
|
|
4501
|
+
var deleteOne = (props) => Effect58.gen(function* () {
|
|
4436
4502
|
if ((yield* readOne(props)) === undefined)
|
|
4437
4503
|
return;
|
|
4438
4504
|
return yield* runPbs(props.target, "provision", config.deleteConfigDatastore({ name: props.name }));
|
|
4439
4505
|
});
|
|
4440
4506
|
|
|
4441
4507
|
// src/proxmox/pbs-datastore-guard.ts
|
|
4442
|
-
import * as
|
|
4508
|
+
import * as Effect59 from "effect/Effect";
|
|
4443
4509
|
var samePath = (left, right) => {
|
|
4444
4510
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
4445
4511
|
return trim(left) === trim(right);
|
|
4446
4512
|
};
|
|
4447
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
4448
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
4449
|
-
var settle2 = (read4, done) =>
|
|
4513
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect59.void : Effect59.die(new Error(`${object2(props)}: declared path ${props.path} but PBS holds ${live.path}. \`path\` ` + "is create-only, so this cannot be reconciled and will NOT be planned as a silent " + "noop: backups would keep landing in the old directory behind a green plan. Correct " + "the declaration, or remove the datastore and declare a new one -- the contents live, " + "because `destroy-data` is never sent."));
|
|
4514
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect59.void : Effect59.die(new Error(`${object2(props)}: declared backend ${props.backend} but PBS holds ` + `${live.backend === "" ? "(none — a local datastore)" : live.backend}. \`backend\` ` + "is create-only: PBS has no update for it, so this cannot be reconciled and will NOT " + "be planned as a silent noop. Correct the declaration to match what is really there, " + "or remove the datastore and declare a new one -- the contents live, because " + "`destroy-data` is never sent."));
|
|
4515
|
+
var settle2 = (read4, done) => Effect59.gen(function* () {
|
|
4450
4516
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
4451
4517
|
const live = yield* read4;
|
|
4452
4518
|
if (done(live))
|
|
4453
4519
|
return live;
|
|
4454
|
-
yield*
|
|
4520
|
+
yield* Effect59.sleep("2 seconds");
|
|
4455
4521
|
}
|
|
4456
4522
|
return yield* read4;
|
|
4457
4523
|
});
|
|
4458
4524
|
|
|
4459
4525
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
4460
|
-
import * as
|
|
4526
|
+
import * as Effect60 from "effect/Effect";
|
|
4461
4527
|
var DATASTORE_ENDPOINT = {
|
|
4462
4528
|
create: "pbs:POST /config/datastore",
|
|
4463
4529
|
update: "pbs:PUT /config/datastore/{name}"
|
|
4464
4530
|
};
|
|
4465
|
-
var guardDatastoreForms = (props) =>
|
|
4531
|
+
var guardDatastoreForms = (props) => Effect60.gen(function* () {
|
|
4466
4532
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
|
|
4467
|
-
yield* guardForm(DATASTORE_ENDPOINT.update,
|
|
4533
|
+
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm4(props), false);
|
|
4468
4534
|
});
|
|
4469
4535
|
|
|
4470
4536
|
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4471
|
-
var
|
|
4472
|
-
list: () =>
|
|
4537
|
+
var handlers6 = {
|
|
4538
|
+
list: () => Effect61.succeed([]),
|
|
4473
4539
|
read: ({ olds }) => readOne(olds),
|
|
4474
4540
|
diff: ({
|
|
4475
4541
|
news,
|
|
4476
4542
|
output
|
|
4477
|
-
}) =>
|
|
4478
|
-
if (!
|
|
4543
|
+
}) => Effect61.gen(function* () {
|
|
4544
|
+
if (!isResolved18(news))
|
|
4479
4545
|
return;
|
|
4480
4546
|
yield* guardDatastoreForms(news);
|
|
4481
4547
|
if (output === undefined)
|
|
@@ -4485,9 +4551,9 @@ var handlers7 = {
|
|
|
4485
4551
|
return { action: "update" };
|
|
4486
4552
|
yield* guardPath(live, news);
|
|
4487
4553
|
yield* guardBackend(live, news);
|
|
4488
|
-
return
|
|
4554
|
+
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
4489
4555
|
}),
|
|
4490
|
-
reconcile:
|
|
4556
|
+
reconcile: Effect61.fn(function* ({ news }) {
|
|
4491
4557
|
yield* guardDatastoreForms(news);
|
|
4492
4558
|
const live = yield* readOne(news);
|
|
4493
4559
|
if (live === undefined) {
|
|
@@ -4495,22 +4561,22 @@ var handlers7 = {
|
|
|
4495
4561
|
} else {
|
|
4496
4562
|
yield* guardPath(live, news);
|
|
4497
4563
|
yield* guardBackend(live, news);
|
|
4498
|
-
const form = formToSend(
|
|
4564
|
+
const form = formToSend(matches7, live, news, updateForm4(news));
|
|
4499
4565
|
if (form !== undefined) {
|
|
4500
4566
|
yield* updateOne(news);
|
|
4501
4567
|
}
|
|
4502
4568
|
}
|
|
4503
|
-
const after = yield* settle2(readOne(news), (row) => row !== undefined &&
|
|
4504
|
-
if (after === undefined || !
|
|
4505
|
-
return yield*
|
|
4569
|
+
const after = yield* settle2(readOne(news), (row) => row !== undefined && matches7(row, news));
|
|
4570
|
+
if (after === undefined || !matches7(after, news)) {
|
|
4571
|
+
return yield* Effect61.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + "match the declaration after 120s. Check the PBS task list " + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
|
|
4506
4572
|
}
|
|
4507
4573
|
return after;
|
|
4508
4574
|
}),
|
|
4509
|
-
delete:
|
|
4575
|
+
delete: Effect61.fn(function* ({ olds }) {
|
|
4510
4576
|
yield* deleteOne(olds);
|
|
4511
4577
|
const left = yield* settle2(readOne(olds), (row) => row === undefined);
|
|
4512
4578
|
if (left !== undefined) {
|
|
4513
|
-
return yield*
|
|
4579
|
+
return yield* Effect61.die(new Error(`${object2(olds)}: the DELETE returned no error but the datastore is still in ` + "datastore.cfg after 120s. Either a backup, verify or GC task still holds it, " + "or the provision role lacks Datastore.Allocate on /datastore/" + `${olds.name}. Read the task log with \`proxmox-backup-manager task log <upid>\`.`));
|
|
4514
4580
|
}
|
|
4515
4581
|
})
|
|
4516
4582
|
};
|
|
@@ -4519,36 +4585,36 @@ var handlers7 = {
|
|
|
4519
4585
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
4520
4586
|
defaultRemovalPolicy: "retain"
|
|
4521
4587
|
});
|
|
4522
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
4588
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect62.succeed(PbsDatastore.Provider.of(handlers6)));
|
|
4523
4589
|
// src/proxmox/pbs-notification-matcher.ts
|
|
4524
4590
|
import { Resource as Resource20 } from "alchemy";
|
|
4525
4591
|
import * as Provider20 from "alchemy/Provider";
|
|
4526
|
-
import { isResolved as
|
|
4527
|
-
import * as
|
|
4592
|
+
import { isResolved as isResolved19 } from "alchemy/Diff";
|
|
4593
|
+
import * as Effect65 from "effect/Effect";
|
|
4528
4594
|
|
|
4529
4595
|
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4530
4596
|
import * as config2 from "@distilled.cloud/proxmox-backup/config";
|
|
4531
|
-
import * as
|
|
4597
|
+
import * as Effect64 from "effect/Effect";
|
|
4532
4598
|
|
|
4533
4599
|
// src/proxmox/pbs-notification-input.ts
|
|
4534
4600
|
import * as Data3 from "effect/Data";
|
|
4535
|
-
import * as
|
|
4601
|
+
import * as Effect63 from "effect/Effect";
|
|
4536
4602
|
import * as Schema4 from "effect/Schema";
|
|
4537
4603
|
|
|
4538
4604
|
class PbsNotificationInputRefusal extends Data3.TaggedError("PbsNotificationInputRefusal") {
|
|
4539
4605
|
}
|
|
4540
|
-
var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(
|
|
4606
|
+
var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(Effect63.mapError(() => new PbsNotificationInputRefusal({
|
|
4541
4607
|
message: "PBS notification fields do not match the SDK request schema; no PBS request was sent."
|
|
4542
4608
|
})));
|
|
4543
4609
|
|
|
4544
4610
|
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4545
|
-
var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(
|
|
4611
|
+
var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(Effect64.map((row) => matcherAttributes({
|
|
4546
4612
|
...row,
|
|
4547
4613
|
"invert-match": row.invert_match,
|
|
4548
4614
|
"match-calendar": row.match_calendar,
|
|
4549
4615
|
"match-field": row.match_field,
|
|
4550
4616
|
"match-severity": row.match_severity
|
|
4551
|
-
}, props.name)),
|
|
4617
|
+
}, props.name)), Effect64.catchTag("NotFound", () => Effect64.succeed(undefined)));
|
|
4552
4618
|
var requestFields = (props, form) => ({
|
|
4553
4619
|
...form,
|
|
4554
4620
|
invert_match: form["invert-match"],
|
|
@@ -4557,23 +4623,23 @@ var requestFields = (props, form) => ({
|
|
|
4557
4623
|
match_severity: form["match-severity"],
|
|
4558
4624
|
name: props.name
|
|
4559
4625
|
});
|
|
4560
|
-
var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(
|
|
4561
|
-
var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(
|
|
4562
|
-
var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(
|
|
4626
|
+
var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect64.flatMap(config2.createConfigNotificationMatcher)));
|
|
4627
|
+
var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect64.flatMap(config2.putConfigNotificationMatcher)));
|
|
4628
|
+
var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(Effect64.catchTag("NotFound", () => Effect64.void));
|
|
4563
4629
|
|
|
4564
4630
|
// src/proxmox/pbs-notification-matcher.ts
|
|
4565
4631
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
4566
4632
|
var guardCreate5 = (props, requirePresence) => guardForm("pbs:POST /config/notifications/matchers", matcherCreateForm(props), requirePresence);
|
|
4567
4633
|
var guardUpdate5 = (props) => guardForm("pbs:PUT /config/notifications/matchers/{name}", matcherUpdateForm(props), false);
|
|
4568
|
-
var
|
|
4569
|
-
list: () =>
|
|
4634
|
+
var handlers7 = {
|
|
4635
|
+
list: () => Effect65.succeed([]),
|
|
4570
4636
|
read: ({ olds }) => readMatcher2(olds),
|
|
4571
4637
|
diff: ({
|
|
4572
4638
|
news,
|
|
4573
4639
|
olds,
|
|
4574
4640
|
output
|
|
4575
|
-
}) =>
|
|
4576
|
-
if (!
|
|
4641
|
+
}) => Effect65.gen(function* () {
|
|
4642
|
+
if (!isResolved19(news))
|
|
4577
4643
|
return;
|
|
4578
4644
|
yield* guardCreate5(news, output === undefined);
|
|
4579
4645
|
yield* guardUpdate5(news);
|
|
@@ -4588,7 +4654,7 @@ var handlers8 = {
|
|
|
4588
4654
|
}
|
|
4589
4655
|
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
4590
4656
|
}),
|
|
4591
|
-
reconcile: ({ news }) =>
|
|
4657
|
+
reconcile: ({ news }) => Effect65.gen(function* () {
|
|
4592
4658
|
const live = yield* readMatcher2(news);
|
|
4593
4659
|
yield* guardCreate5(news, live === undefined);
|
|
4594
4660
|
yield* guardUpdate5(news);
|
|
@@ -4598,24 +4664,24 @@ var handlers8 = {
|
|
|
4598
4664
|
yield* updateMatcher2(news, matcherUpdateForm(news));
|
|
4599
4665
|
const after = yield* readMatcher2(news);
|
|
4600
4666
|
if (after === undefined)
|
|
4601
|
-
return yield*
|
|
4667
|
+
return yield* Effect65.fail(new Error(`config/notifications/matchers/${news.name}: the write returned no error but the matcher is still absent.`));
|
|
4602
4668
|
return after;
|
|
4603
4669
|
}),
|
|
4604
4670
|
delete: ({ olds }) => deleteMatcher2(olds)
|
|
4605
4671
|
};
|
|
4606
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
4672
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect65.succeed(PbsNotificationMatcher.Provider.of(handlers7)));
|
|
4607
4673
|
// src/proxmox/pbs-notification-target.ts
|
|
4608
4674
|
import { Resource as Resource21 } from "alchemy";
|
|
4609
4675
|
import * as Provider21 from "alchemy/Provider";
|
|
4610
|
-
import * as
|
|
4676
|
+
import * as Effect68 from "effect/Effect";
|
|
4611
4677
|
|
|
4612
4678
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4613
|
-
import { isResolved as
|
|
4614
|
-
import * as
|
|
4679
|
+
import { isResolved as isResolved20 } from "alchemy/Diff";
|
|
4680
|
+
import * as Effect67 from "effect/Effect";
|
|
4615
4681
|
|
|
4616
4682
|
// src/proxmox/pbs-notification-target-distilled.ts
|
|
4617
4683
|
import * as config3 from "@distilled.cloud/proxmox-backup/config";
|
|
4618
|
-
import * as
|
|
4684
|
+
import * as Effect66 from "effect/Effect";
|
|
4619
4685
|
|
|
4620
4686
|
// src/proxmox/pbs-notification-target-wire.ts
|
|
4621
4687
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
@@ -4716,22 +4782,22 @@ var requestFields2 = (props, form) => ({
|
|
|
4716
4782
|
var read4 = (props) => {
|
|
4717
4783
|
switch (props.type) {
|
|
4718
4784
|
case "sendmail":
|
|
4719
|
-
return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(
|
|
4785
|
+
return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(Effect66.map((row) => ({
|
|
4720
4786
|
...row,
|
|
4721
4787
|
"from-address": row.from_address,
|
|
4722
4788
|
"mailto-user": row.mailto_user
|
|
4723
4789
|
})));
|
|
4724
4790
|
case "smtp":
|
|
4725
|
-
return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(
|
|
4791
|
+
return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(Effect66.map((row) => ({
|
|
4726
4792
|
...row,
|
|
4727
4793
|
"from-address": row.from_address,
|
|
4728
4794
|
"mailto-user": row.mailto_user
|
|
4729
4795
|
})));
|
|
4730
4796
|
case "webhook":
|
|
4731
|
-
return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(
|
|
4797
|
+
return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(Effect66.map((row) => ({ ...row })));
|
|
4732
4798
|
}
|
|
4733
4799
|
};
|
|
4734
|
-
var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(
|
|
4800
|
+
var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(Effect66.map((row) => targetAttributes(row, props)), Effect66.catchTag("NotFound", () => Effect66.succeed(undefined)));
|
|
4735
4801
|
var validateTargetWrite2 = (props, form, mode) => {
|
|
4736
4802
|
const schema = mode === "create" ? {
|
|
4737
4803
|
sendmail: config3.CreateConfigNotificationEndpointSendmailRequest,
|
|
@@ -4742,22 +4808,22 @@ var validateTargetWrite2 = (props, form, mode) => {
|
|
|
4742
4808
|
smtp: config3.PutConfigNotificationEndpointSmtpRequest,
|
|
4743
4809
|
webhook: config3.PutConfigNotificationEndpointWebhookRequest
|
|
4744
4810
|
}[props.type];
|
|
4745
|
-
return notificationInput(schema, requestFields2(props, form)).pipe(
|
|
4811
|
+
return notificationInput(schema, requestFields2(props, form)).pipe(Effect66.asVoid);
|
|
4746
4812
|
};
|
|
4747
4813
|
var createTarget2 = (props, form) => {
|
|
4748
4814
|
const fields2 = requestFields2(props, form);
|
|
4749
|
-
const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(
|
|
4815
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.CreateConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointSmtp)) : notificationInput(config3.CreateConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointWebhook));
|
|
4750
4816
|
return runPbs(props.target, "provision", operation);
|
|
4751
4817
|
};
|
|
4752
4818
|
var updateTarget2 = (props, form) => {
|
|
4753
4819
|
const fields2 = requestFields2(props, form);
|
|
4754
|
-
const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(
|
|
4820
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.PutConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointSmtp)) : notificationInput(config3.PutConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointWebhook));
|
|
4755
4821
|
return runPbs(props.target, "provision", operation);
|
|
4756
4822
|
};
|
|
4757
4823
|
var deleteTarget2 = (props) => {
|
|
4758
4824
|
const request = { name: props.name };
|
|
4759
4825
|
const operation = props.type === "sendmail" ? config3.deleteConfigNotificationEndpointSendmail(request) : props.type === "smtp" ? config3.deleteConfigNotificationEndpointSmtp(request) : config3.deleteConfigNotificationEndpointWebhook(request);
|
|
4760
|
-
return runPbs(props.target, "provision", operation).pipe(
|
|
4826
|
+
return runPbs(props.target, "provision", operation).pipe(Effect66.catchTag("NotFound", () => Effect66.void));
|
|
4761
4827
|
};
|
|
4762
4828
|
|
|
4763
4829
|
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
@@ -4948,7 +5014,7 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4948
5014
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4949
5015
|
var refuse2 = (props) => {
|
|
4950
5016
|
const reasons = refusals(props);
|
|
4951
|
-
return reasons.length === 0 ?
|
|
5017
|
+
return reasons.length === 0 ? Effect67.void : Effect67.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4952
5018
|
};
|
|
4953
5019
|
var toCarry = (live, props, groups, sealed) => {
|
|
4954
5020
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4960,17 +5026,17 @@ var requireValues = (props, groups, carry) => {
|
|
|
4960
5026
|
...carry.header ? groups.header.missing : [],
|
|
4961
5027
|
...carry.sealed ? groups.sealed.missing : []
|
|
4962
5028
|
];
|
|
4963
|
-
return missing.length === 0 ?
|
|
5029
|
+
return missing.length === 0 ? Effect67.void : Effect67.die(new Error(`${path(props)}: this write must send write-only values, and ${missing.join(", ")} ` + "is unset or empty in the deploying environment. Export it and deploy again."));
|
|
4964
5030
|
};
|
|
4965
|
-
var
|
|
4966
|
-
list: () =>
|
|
4967
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
5031
|
+
var handlers8 = {
|
|
5032
|
+
list: () => Effect67.succeed([]),
|
|
5033
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect67.void).pipe(Effect67.andThen(readTarget2(olds)), Effect67.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
4968
5034
|
diff: ({
|
|
4969
5035
|
news,
|
|
4970
5036
|
olds,
|
|
4971
5037
|
output
|
|
4972
|
-
}) =>
|
|
4973
|
-
if (output === undefined || !
|
|
5038
|
+
}) => Effect67.gen(function* () {
|
|
5039
|
+
if (output === undefined || !isResolved20(news))
|
|
4974
5040
|
return;
|
|
4975
5041
|
yield* refuse2(news);
|
|
4976
5042
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -4991,7 +5057,7 @@ var handlers9 = {
|
|
|
4991
5057
|
return { action: "update" };
|
|
4992
5058
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4993
5059
|
}),
|
|
4994
|
-
reconcile: ({ news, output }) =>
|
|
5060
|
+
reconcile: ({ news, output }) => Effect67.gen(function* () {
|
|
4995
5061
|
yield* refuse2(news);
|
|
4996
5062
|
const groups = resolveGroups(news);
|
|
4997
5063
|
const live = yield* readTarget2(news);
|
|
@@ -5016,7 +5082,7 @@ var handlers9 = {
|
|
|
5016
5082
|
}
|
|
5017
5083
|
const after = yield* readTarget2(news);
|
|
5018
5084
|
if (after === undefined) {
|
|
5019
|
-
return yield*
|
|
5085
|
+
return yield* Effect67.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
5020
5086
|
}
|
|
5021
5087
|
return { ...after, sealed };
|
|
5022
5088
|
}),
|
|
@@ -5025,15 +5091,15 @@ var handlers9 = {
|
|
|
5025
5091
|
|
|
5026
5092
|
// src/proxmox/pbs-notification-target.ts
|
|
5027
5093
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
5028
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
5094
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect68.succeed(PbsNotificationTarget.Provider.of(handlers8)));
|
|
5029
5095
|
// src/proxmox/pbs-prune-job.ts
|
|
5030
5096
|
import { Resource as Resource22 } from "alchemy";
|
|
5031
5097
|
import * as Provider22 from "alchemy/Provider";
|
|
5032
|
-
import * as
|
|
5098
|
+
import * as Effect71 from "effect/Effect";
|
|
5033
5099
|
|
|
5034
5100
|
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
5035
|
-
import { isResolved as
|
|
5036
|
-
import * as
|
|
5101
|
+
import { isResolved as isResolved21 } from "alchemy/Diff";
|
|
5102
|
+
import * as Effect70 from "effect/Effect";
|
|
5037
5103
|
|
|
5038
5104
|
// src/proxmox/pbs-prune-job-form.ts
|
|
5039
5105
|
var KEEP_KEYS = [
|
|
@@ -5111,7 +5177,7 @@ var spec = {
|
|
|
5111
5177
|
|
|
5112
5178
|
// src/proxmox/pbs-prune-job-wire.ts
|
|
5113
5179
|
import * as config4 from "@distilled.cloud/proxmox-backup/config";
|
|
5114
|
-
import * as
|
|
5180
|
+
import * as Effect69 from "effect/Effect";
|
|
5115
5181
|
var members2 = (form) => ({
|
|
5116
5182
|
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
5117
5183
|
...form["disable"] === undefined ? {} : { disable: form["disable"] },
|
|
@@ -5146,10 +5212,10 @@ var wire2 = (row) => ({
|
|
|
5146
5212
|
"keep-yearly": row.keep_yearly,
|
|
5147
5213
|
"max-depth": row.max_depth
|
|
5148
5214
|
});
|
|
5149
|
-
var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(
|
|
5215
|
+
var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(Effect69.map((row) => spec.attributes(wire2(row), props)), Effect69.catchTag("PruneJobNotFound", () => Effect69.succeed(undefined)));
|
|
5150
5216
|
var createOne2 = (props) => runPbs(props.target, "provision", config4.createConfigPrune(createRequest2(props)));
|
|
5151
5217
|
var updateOne2 = (props) => runPbs(props.target, "provision", config4.putConfigPrune(updateRequest2(props)));
|
|
5152
|
-
var deleteOne2 = (props) =>
|
|
5218
|
+
var deleteOne2 = (props) => Effect69.gen(function* () {
|
|
5153
5219
|
if ((yield* readOne2(props)) === undefined)
|
|
5154
5220
|
return;
|
|
5155
5221
|
return yield* runPbs(props.target, "provision", config4.deleteConfigPrune({ id: props.id }));
|
|
@@ -5157,14 +5223,14 @@ var deleteOne2 = (props) => Effect68.gen(function* () {
|
|
|
5157
5223
|
|
|
5158
5224
|
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
5159
5225
|
var { guardCreate: guardCreate6, guardUpdate: guardUpdate6 } = specGuards(spec);
|
|
5160
|
-
var
|
|
5161
|
-
list: () =>
|
|
5226
|
+
var handlers9 = {
|
|
5227
|
+
list: () => Effect70.succeed([]),
|
|
5162
5228
|
read: ({ olds }) => readOne2(olds),
|
|
5163
5229
|
diff: ({
|
|
5164
5230
|
news,
|
|
5165
5231
|
output
|
|
5166
|
-
}) =>
|
|
5167
|
-
if (!
|
|
5232
|
+
}) => Effect70.gen(function* () {
|
|
5233
|
+
if (!isResolved21(news))
|
|
5168
5234
|
return;
|
|
5169
5235
|
yield* guardCreate6(news, output === undefined);
|
|
5170
5236
|
yield* guardUpdate6(news);
|
|
@@ -5177,7 +5243,7 @@ var handlers10 = {
|
|
|
5177
5243
|
}
|
|
5178
5244
|
return { action: spec.matches(live, news) ? "noop" : "update" };
|
|
5179
5245
|
}),
|
|
5180
|
-
reconcile: ({ news }) =>
|
|
5246
|
+
reconcile: ({ news }) => Effect70.gen(function* () {
|
|
5181
5247
|
const live = yield* readOne2(news);
|
|
5182
5248
|
yield* guardCreate6(news, live === undefined);
|
|
5183
5249
|
yield* guardUpdate6(news);
|
|
@@ -5187,7 +5253,7 @@ var handlers10 = {
|
|
|
5187
5253
|
yield* updateOne2(news);
|
|
5188
5254
|
const after = yield* readOne2(news);
|
|
5189
5255
|
if (after === undefined) {
|
|
5190
|
-
return yield*
|
|
5256
|
+
return yield* Effect70.fail(new Error(`${spec.path(news)}: write succeeded but job is absent.`));
|
|
5191
5257
|
}
|
|
5192
5258
|
return after;
|
|
5193
5259
|
}),
|
|
@@ -5196,15 +5262,15 @@ var handlers10 = {
|
|
|
5196
5262
|
|
|
5197
5263
|
// src/proxmox/pbs-prune-job.ts
|
|
5198
5264
|
var PbsPruneJob = Resource22("Pbs.PruneJob");
|
|
5199
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
5265
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect71.succeed(PbsPruneJob.Provider.of(handlers9)));
|
|
5200
5266
|
// src/proxmox/pbs-sync-job.ts
|
|
5201
5267
|
import { Resource as Resource23 } from "alchemy";
|
|
5202
5268
|
import * as Provider23 from "alchemy/Provider";
|
|
5203
|
-
import * as
|
|
5269
|
+
import * as Effect74 from "effect/Effect";
|
|
5204
5270
|
|
|
5205
5271
|
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5206
|
-
import { isResolved as
|
|
5207
|
-
import * as
|
|
5272
|
+
import { isResolved as isResolved22 } from "alchemy/Diff";
|
|
5273
|
+
import * as Effect73 from "effect/Effect";
|
|
5208
5274
|
|
|
5209
5275
|
// src/proxmox/pbs-sync-job-form.ts
|
|
5210
5276
|
var UNSET4 = -1;
|
|
@@ -5281,7 +5347,7 @@ var spec2 = {
|
|
|
5281
5347
|
|
|
5282
5348
|
// src/proxmox/pbs-sync-job-wire.ts
|
|
5283
5349
|
import * as config5 from "@distilled.cloud/proxmox-backup/config";
|
|
5284
|
-
import * as
|
|
5350
|
+
import * as Effect72 from "effect/Effect";
|
|
5285
5351
|
var members3 = (form) => ({
|
|
5286
5352
|
...form["remote-store"] === undefined ? {} : { remote_store: form["remote-store"] },
|
|
5287
5353
|
...form["remove-vanished"] === undefined ? {} : { remove_vanished: form["remove-vanished"] },
|
|
@@ -5320,10 +5386,10 @@ var wire3 = (row) => ({
|
|
|
5320
5386
|
"sync-direction": row.sync_direction,
|
|
5321
5387
|
"group-filter": row.group_filter
|
|
5322
5388
|
});
|
|
5323
|
-
var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(
|
|
5389
|
+
var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(Effect72.map((row) => spec2.attributes(wire3(row), props)), Effect72.catchTag("SyncJobNotFound", () => Effect72.succeed(undefined)));
|
|
5324
5390
|
var createOne3 = (props) => runPbs(props.target, "provision", config5.syncConfig(createRequest3(props)));
|
|
5325
5391
|
var updateOne3 = (props) => runPbs(props.target, "provision", config5.putConfigSync(updateRequest3(props)));
|
|
5326
|
-
var deleteOne3 = (props) =>
|
|
5392
|
+
var deleteOne3 = (props) => Effect72.gen(function* () {
|
|
5327
5393
|
if ((yield* readOne3(props)) === undefined)
|
|
5328
5394
|
return;
|
|
5329
5395
|
return yield* runPbs(props.target, "provision", config5.deleteConfigSync({ id: props.id }));
|
|
@@ -5331,11 +5397,11 @@ var deleteOne3 = (props) => Effect71.gen(function* () {
|
|
|
5331
5397
|
|
|
5332
5398
|
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5333
5399
|
var { guardCreate: guardCreate7, guardUpdate: guardUpdate7 } = specGuards(spec2);
|
|
5334
|
-
var
|
|
5335
|
-
list: () =>
|
|
5400
|
+
var handlers10 = {
|
|
5401
|
+
list: () => Effect73.succeed([]),
|
|
5336
5402
|
read: ({ olds }) => readOne3(olds),
|
|
5337
|
-
diff: ({ news, output }) =>
|
|
5338
|
-
if (!
|
|
5403
|
+
diff: ({ news, output }) => Effect73.gen(function* () {
|
|
5404
|
+
if (!isResolved22(news))
|
|
5339
5405
|
return;
|
|
5340
5406
|
yield* guardCreate7(news, output === undefined);
|
|
5341
5407
|
yield* guardUpdate7(news);
|
|
@@ -5348,7 +5414,7 @@ var handlers11 = {
|
|
|
5348
5414
|
}
|
|
5349
5415
|
return { action: spec2.matches(live, news) ? "noop" : "update" };
|
|
5350
5416
|
}),
|
|
5351
|
-
reconcile: ({ news }) =>
|
|
5417
|
+
reconcile: ({ news }) => Effect73.gen(function* () {
|
|
5352
5418
|
const live = yield* readOne3(news);
|
|
5353
5419
|
yield* guardCreate7(news, live === undefined);
|
|
5354
5420
|
yield* guardUpdate7(news);
|
|
@@ -5358,7 +5424,7 @@ var handlers11 = {
|
|
|
5358
5424
|
yield* updateOne3(news);
|
|
5359
5425
|
const after = yield* readOne3(news);
|
|
5360
5426
|
if (after === undefined) {
|
|
5361
|
-
return yield*
|
|
5427
|
+
return yield* Effect73.fail(new Error(`${spec2.path(news)}: write succeeded but job is absent.`));
|
|
5362
5428
|
}
|
|
5363
5429
|
return after;
|
|
5364
5430
|
}),
|
|
@@ -5367,15 +5433,15 @@ var handlers11 = {
|
|
|
5367
5433
|
|
|
5368
5434
|
// src/proxmox/pbs-sync-job.ts
|
|
5369
5435
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
5370
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
5436
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect74.succeed(PbsSyncJob.Provider.of(handlers10)));
|
|
5371
5437
|
// src/proxmox/pbs-verify-job.ts
|
|
5372
5438
|
import { Resource as Resource24 } from "alchemy";
|
|
5373
5439
|
import * as Provider24 from "alchemy/Provider";
|
|
5374
|
-
import * as
|
|
5440
|
+
import * as Effect77 from "effect/Effect";
|
|
5375
5441
|
|
|
5376
5442
|
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5377
|
-
import { isResolved as
|
|
5378
|
-
import * as
|
|
5443
|
+
import { isResolved as isResolved23 } from "alchemy/Diff";
|
|
5444
|
+
import * as Effect76 from "effect/Effect";
|
|
5379
5445
|
|
|
5380
5446
|
// src/proxmox/pbs-verify-job-form.ts
|
|
5381
5447
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -5422,7 +5488,7 @@ var spec3 = {
|
|
|
5422
5488
|
|
|
5423
5489
|
// src/proxmox/pbs-verify-job-wire.ts
|
|
5424
5490
|
import * as config6 from "@distilled.cloud/proxmox-backup/config";
|
|
5425
|
-
import * as
|
|
5491
|
+
import * as Effect75 from "effect/Effect";
|
|
5426
5492
|
var members4 = (form) => ({
|
|
5427
5493
|
...form["ignore-verified"] === undefined ? {} : { ignore_verified: form["ignore-verified"] },
|
|
5428
5494
|
...form["store"] === undefined ? {} : { store: form["store"] },
|
|
@@ -5447,10 +5513,10 @@ var wire4 = (row) => ({
|
|
|
5447
5513
|
"max-depth": row.max_depth,
|
|
5448
5514
|
"outdated-after": row.outdated_after
|
|
5449
5515
|
});
|
|
5450
|
-
var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(
|
|
5516
|
+
var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(Effect75.map((row) => spec3.attributes(wire4(row), props)), Effect75.catchTag("VerifyJobNotFound", () => Effect75.succeed(undefined)));
|
|
5451
5517
|
var createOne4 = (props) => runPbs(props.target, "provision", config6.verifyConfig(createRequest4(props)));
|
|
5452
5518
|
var updateOne4 = (props) => runPbs(props.target, "provision", config6.putConfigVerify(updateRequest4(props)));
|
|
5453
|
-
var deleteOne4 = (props) =>
|
|
5519
|
+
var deleteOne4 = (props) => Effect75.gen(function* () {
|
|
5454
5520
|
if ((yield* readOne4(props)) === undefined)
|
|
5455
5521
|
return;
|
|
5456
5522
|
return yield* runPbs(props.target, "provision", config6.deleteConfigVerify({ id: props.id }));
|
|
@@ -5458,14 +5524,14 @@ var deleteOne4 = (props) => Effect74.gen(function* () {
|
|
|
5458
5524
|
|
|
5459
5525
|
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5460
5526
|
var { guardCreate: guardCreate8, guardUpdate: guardUpdate8 } = specGuards(spec3);
|
|
5461
|
-
var
|
|
5462
|
-
list: () =>
|
|
5527
|
+
var handlers11 = {
|
|
5528
|
+
list: () => Effect76.succeed([]),
|
|
5463
5529
|
read: ({ olds }) => readOne4(olds),
|
|
5464
5530
|
diff: ({
|
|
5465
5531
|
news,
|
|
5466
5532
|
output
|
|
5467
|
-
}) =>
|
|
5468
|
-
if (!
|
|
5533
|
+
}) => Effect76.gen(function* () {
|
|
5534
|
+
if (!isResolved23(news))
|
|
5469
5535
|
return;
|
|
5470
5536
|
yield* guardCreate8(news, output === undefined);
|
|
5471
5537
|
yield* guardUpdate8(news);
|
|
@@ -5478,7 +5544,7 @@ var handlers12 = {
|
|
|
5478
5544
|
}
|
|
5479
5545
|
return { action: spec3.matches(live, news) ? "noop" : "update" };
|
|
5480
5546
|
}),
|
|
5481
|
-
reconcile: ({ news }) =>
|
|
5547
|
+
reconcile: ({ news }) => Effect76.gen(function* () {
|
|
5482
5548
|
const live = yield* readOne4(news);
|
|
5483
5549
|
yield* guardCreate8(news, live === undefined);
|
|
5484
5550
|
yield* guardUpdate8(news);
|
|
@@ -5488,7 +5554,7 @@ var handlers12 = {
|
|
|
5488
5554
|
yield* updateOne4(news);
|
|
5489
5555
|
const after = yield* readOne4(news);
|
|
5490
5556
|
if (after === undefined) {
|
|
5491
|
-
return yield*
|
|
5557
|
+
return yield* Effect76.fail(new Error(`${spec3.path(news)}: write succeeded but job is absent.`));
|
|
5492
5558
|
}
|
|
5493
5559
|
return after;
|
|
5494
5560
|
}),
|
|
@@ -5497,15 +5563,15 @@ var handlers12 = {
|
|
|
5497
5563
|
|
|
5498
5564
|
// src/proxmox/pbs-verify-job.ts
|
|
5499
5565
|
var PbsVerifyJob = Resource24("Pbs.VerifyJob");
|
|
5500
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
5566
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect77.succeed(PbsVerifyJob.Provider.of(handlers11)));
|
|
5501
5567
|
// src/proxmox/pool.ts
|
|
5502
5568
|
import { Resource as Resource25 } from "alchemy";
|
|
5503
|
-
import { isResolved as
|
|
5569
|
+
import { isResolved as isResolved24 } from "alchemy/Diff";
|
|
5504
5570
|
import * as Provider25 from "alchemy/Provider";
|
|
5505
5571
|
import * as pools from "@distilled.cloud/proxmox/pools";
|
|
5506
5572
|
import { ProxmoxParseError as ProxmoxParseError5 } from "@distilled.cloud/proxmox/Errors";
|
|
5507
5573
|
import * as Schema5 from "effect/Schema";
|
|
5508
|
-
import * as
|
|
5574
|
+
import * as Effect78 from "effect/Effect";
|
|
5509
5575
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
5510
5576
|
var poolCreateForm = (props) => ({
|
|
5511
5577
|
comment: props.comment ?? "",
|
|
@@ -5531,16 +5597,16 @@ var spec4 = {
|
|
|
5531
5597
|
updateForm: poolUpdateForm
|
|
5532
5598
|
};
|
|
5533
5599
|
var { guardCreate: guardCreate9, guardUpdate: guardUpdate9 } = specGuards(spec4);
|
|
5534
|
-
var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(
|
|
5600
|
+
var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(Effect78.flatMap((live) => Schema5.decodeUnknownEffect(Schema5.toType(pools.GetPoolResponse))(live).pipe(Effect78.mapError(() => new ProxmoxParseError5({
|
|
5535
5601
|
body: undefined,
|
|
5536
5602
|
cause: "Pool response does not match its vendor schema"
|
|
5537
|
-
})),
|
|
5538
|
-
var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(
|
|
5539
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
5540
|
-
list: () =>
|
|
5603
|
+
})), Effect78.as(live))), Effect78.map((live) => spec4.attributes({ ...live }, props)), Effect78.catchTag("PoolNotFound", () => Effect78.succeed(undefined)), Effect78.catchTag("NotFound", () => Effect78.succeed(undefined)));
|
|
5604
|
+
var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(Effect78.catchTag("PoolNotFound", () => Effect78.void), Effect78.catchTag("NotFound", () => Effect78.void));
|
|
5605
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect78.succeed(ProxmoxPool.Provider.of({
|
|
5606
|
+
list: () => Effect78.succeed([]),
|
|
5541
5607
|
read: ({ olds }) => readPool(olds),
|
|
5542
|
-
diff:
|
|
5543
|
-
if (!
|
|
5608
|
+
diff: Effect78.fn(function* ({ news, output }) {
|
|
5609
|
+
if (!isResolved24(news))
|
|
5544
5610
|
return;
|
|
5545
5611
|
yield* guardCreate9(news, output === undefined);
|
|
5546
5612
|
yield* guardUpdate9(news);
|
|
@@ -5553,7 +5619,7 @@ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect77.succeed(
|
|
|
5553
5619
|
}
|
|
5554
5620
|
return { action: spec4.matches(live, news) ? "noop" : "update" };
|
|
5555
5621
|
}),
|
|
5556
|
-
reconcile:
|
|
5622
|
+
reconcile: Effect78.fn(function* ({ news }) {
|
|
5557
5623
|
const live = yield* readPool(news);
|
|
5558
5624
|
yield* guardCreate9(news, live === undefined);
|
|
5559
5625
|
yield* guardUpdate9(news);
|
|
@@ -5569,7 +5635,7 @@ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect77.succeed(
|
|
|
5569
5635
|
}
|
|
5570
5636
|
const after = yield* readPool(news);
|
|
5571
5637
|
if (after === undefined)
|
|
5572
|
-
return yield*
|
|
5638
|
+
return yield* Effect78.fail(new Error(`pools/${news.poolid}: write returned success but the pool is still absent`));
|
|
5573
5639
|
return after;
|
|
5574
5640
|
}),
|
|
5575
5641
|
delete: ({ olds }) => deletePool2(olds)
|
|
@@ -5766,14 +5832,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
5766
5832
|
// src/proxmox/provision-declare.ts
|
|
5767
5833
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
5768
5834
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
5769
|
-
import * as
|
|
5835
|
+
import * as Effect82 from "effect/Effect";
|
|
5770
5836
|
|
|
5771
5837
|
// src/proxmox/role.ts
|
|
5772
5838
|
import { Resource as Resource26 } from "alchemy";
|
|
5773
|
-
import { isResolved as
|
|
5839
|
+
import { isResolved as isResolved25 } from "alchemy/Diff";
|
|
5774
5840
|
import * as Provider26 from "alchemy/Provider";
|
|
5775
5841
|
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
5776
|
-
import * as
|
|
5842
|
+
import * as Effect79 from "effect/Effect";
|
|
5777
5843
|
|
|
5778
5844
|
// src/proxmox/role-wire.ts
|
|
5779
5845
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -5783,36 +5849,36 @@ var createForm7 = (props) => ({
|
|
|
5783
5849
|
privs: canonical2(props.privs).join(","),
|
|
5784
5850
|
roleid: props.roleid
|
|
5785
5851
|
});
|
|
5786
|
-
var
|
|
5852
|
+
var updateForm5 = (props) => ({
|
|
5787
5853
|
privs: canonical2(props.privs).join(","),
|
|
5788
5854
|
roleid: props.roleid
|
|
5789
5855
|
});
|
|
5790
5856
|
var find2 = (rows, roleid) => rows.find((row) => row.roleid === roleid);
|
|
5791
|
-
var
|
|
5857
|
+
var attributesOf8 = (row, props) => ({
|
|
5792
5858
|
privs: canonical2(row.privs === undefined ? [] : row.privs.split(",")),
|
|
5793
5859
|
roleid: props.roleid
|
|
5794
5860
|
});
|
|
5795
|
-
var
|
|
5861
|
+
var matches8 = (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(",");
|
|
5796
5862
|
|
|
5797
5863
|
// src/proxmox/role.ts
|
|
5798
5864
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
5799
|
-
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(
|
|
5865
|
+
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect79.map((rows) => {
|
|
5800
5866
|
if (rows === UNREADABLE)
|
|
5801
5867
|
return UNREADABLE;
|
|
5802
5868
|
const row = find2(rows, props.roleid);
|
|
5803
|
-
return row === undefined ? undefined :
|
|
5869
|
+
return row === undefined ? undefined : attributesOf8(row, props);
|
|
5804
5870
|
}));
|
|
5805
5871
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
5806
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
5807
|
-
list: () =>
|
|
5808
|
-
read:
|
|
5872
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect79.succeed(ProxmoxRole.Provider.of({
|
|
5873
|
+
list: () => Effect79.succeed([]),
|
|
5874
|
+
read: Effect79.fn(function* ({ olds }) {
|
|
5809
5875
|
return dropUnreadable5(yield* readRole(olds));
|
|
5810
5876
|
}),
|
|
5811
|
-
diff:
|
|
5812
|
-
if (!
|
|
5877
|
+
diff: Effect79.fn(function* ({ news, output }) {
|
|
5878
|
+
if (!isResolved25(news))
|
|
5813
5879
|
return;
|
|
5814
5880
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
|
|
5815
|
-
yield* guardWrite2(ROLE_UPDATE,
|
|
5881
|
+
yield* guardWrite2(ROLE_UPDATE, updateForm5(news), false);
|
|
5816
5882
|
if (output === undefined)
|
|
5817
5883
|
return;
|
|
5818
5884
|
const live = yield* readRole(news);
|
|
@@ -5824,38 +5890,38 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect78.succeed(
|
|
|
5824
5890
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), true);
|
|
5825
5891
|
return { action: "update" };
|
|
5826
5892
|
}
|
|
5827
|
-
return
|
|
5893
|
+
return matches8(live, news) ? { action: "noop" } : { action: "update" };
|
|
5828
5894
|
}),
|
|
5829
|
-
reconcile:
|
|
5895
|
+
reconcile: Effect79.fn(function* ({ news }) {
|
|
5830
5896
|
const before = dropUnreadable5(yield* readRole(news));
|
|
5831
5897
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
|
|
5832
|
-
yield* guardWrite2(ROLE_UPDATE,
|
|
5898
|
+
yield* guardWrite2(ROLE_UPDATE, updateForm5(news), false);
|
|
5833
5899
|
if (before === undefined) {
|
|
5834
5900
|
yield* runPve(news.target, "provision", true, access5.createAccessRole(createForm7(news)));
|
|
5835
|
-
} else if (!
|
|
5836
|
-
yield* runPve(news.target, "provision", true, access5.putAccessRole(
|
|
5901
|
+
} else if (!matches8(before, news)) {
|
|
5902
|
+
yield* runPve(news.target, "provision", true, access5.putAccessRole(updateForm5(news)));
|
|
5837
5903
|
}
|
|
5838
5904
|
const after = dropUnreadable5(yield* readRole(news));
|
|
5839
5905
|
if (after === undefined) {
|
|
5840
|
-
return yield*
|
|
5906
|
+
return yield* Effect79.die(new Error(`access/roles/${news.roleid}: the write returned no error but the role is ` + 'still absent. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- read back rather than trusting the status code."));
|
|
5841
5907
|
}
|
|
5842
5908
|
return after;
|
|
5843
5909
|
}),
|
|
5844
|
-
delete:
|
|
5910
|
+
delete: Effect79.fn(function* ({ olds }) {
|
|
5845
5911
|
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
5846
5912
|
})
|
|
5847
5913
|
})));
|
|
5848
5914
|
|
|
5849
5915
|
// src/proxmox/user.ts
|
|
5850
5916
|
import { Resource as Resource27 } from "alchemy";
|
|
5851
|
-
import { isResolved as
|
|
5917
|
+
import { isResolved as isResolved26 } from "alchemy/Diff";
|
|
5852
5918
|
import * as Provider27 from "alchemy/Provider";
|
|
5853
5919
|
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
5854
|
-
import * as
|
|
5920
|
+
import * as Effect81 from "effect/Effect";
|
|
5855
5921
|
|
|
5856
5922
|
// src/proxmox/user-wire.ts
|
|
5857
5923
|
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
5858
|
-
import * as
|
|
5924
|
+
import * as Effect80 from "effect/Effect";
|
|
5859
5925
|
var USER_CREATE = "pve:POST /access/users";
|
|
5860
5926
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
5861
5927
|
var int2 = (value) => {
|
|
@@ -5881,11 +5947,11 @@ var createForm8 = (props) => ({
|
|
|
5881
5947
|
...shape8(props),
|
|
5882
5948
|
userid: props.userid
|
|
5883
5949
|
});
|
|
5884
|
-
var
|
|
5950
|
+
var updateForm6 = (props) => ({
|
|
5885
5951
|
...shape8(props),
|
|
5886
5952
|
userid: props.userid
|
|
5887
5953
|
});
|
|
5888
|
-
var
|
|
5954
|
+
var attributesOf9 = (live, props) => ({
|
|
5889
5955
|
comment: text(live.comment),
|
|
5890
5956
|
email: text(live.email),
|
|
5891
5957
|
enable: bool(live.enable, true),
|
|
@@ -5896,23 +5962,23 @@ var attributesOf8 = (live, props) => ({
|
|
|
5896
5962
|
tokens: tokenNames(live.tokens),
|
|
5897
5963
|
userid: props.userid
|
|
5898
5964
|
});
|
|
5899
|
-
var
|
|
5900
|
-
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(
|
|
5901
|
-
var readUser = (props) => readUserOrFail(props).pipe(
|
|
5965
|
+
var matches9 = (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(",");
|
|
5966
|
+
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect80.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
|
|
5967
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect80.catchTag("UserNotFound", () => Effect80.succeed(undefined)));
|
|
5902
5968
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
5903
5969
|
|
|
5904
5970
|
// src/proxmox/user.ts
|
|
5905
5971
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
5906
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
5907
|
-
list: () =>
|
|
5908
|
-
read:
|
|
5972
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect81.succeed(ProxmoxUser.Provider.of({
|
|
5973
|
+
list: () => Effect81.succeed([]),
|
|
5974
|
+
read: Effect81.fn(function* ({ olds, output }) {
|
|
5909
5975
|
return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
5910
5976
|
}),
|
|
5911
|
-
diff:
|
|
5912
|
-
if (!
|
|
5977
|
+
diff: Effect81.fn(function* ({ news, output }) {
|
|
5978
|
+
if (!isResolved26(news))
|
|
5913
5979
|
return;
|
|
5914
5980
|
yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
|
|
5915
|
-
yield* guardWrite2(USER_UPDATE,
|
|
5981
|
+
yield* guardWrite2(USER_UPDATE, updateForm6(news), false);
|
|
5916
5982
|
if (output === undefined)
|
|
5917
5983
|
return;
|
|
5918
5984
|
const live = yield* readUserOrFail(news);
|
|
@@ -5924,31 +5990,31 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect80.succeed(
|
|
|
5924
5990
|
yield* guardWrite2(USER_CREATE, createForm8(news), true);
|
|
5925
5991
|
return { action: "update" };
|
|
5926
5992
|
}
|
|
5927
|
-
return
|
|
5993
|
+
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
5928
5994
|
}),
|
|
5929
|
-
reconcile:
|
|
5995
|
+
reconcile: Effect81.fn(function* ({ news }) {
|
|
5930
5996
|
const before = dropUnreadable6(yield* readUser(news));
|
|
5931
5997
|
yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
|
|
5932
|
-
yield* guardWrite2(USER_UPDATE,
|
|
5998
|
+
yield* guardWrite2(USER_UPDATE, updateForm6(news), false);
|
|
5933
5999
|
if (before === undefined) {
|
|
5934
6000
|
yield* runPve(news.target, "provision", true, access7.createAccessUser(createForm8(news)));
|
|
5935
|
-
} else if (!
|
|
5936
|
-
yield* runPve(news.target, "provision", true, access7.putAccessUser(
|
|
6001
|
+
} else if (!matches9(before, news)) {
|
|
6002
|
+
yield* runPve(news.target, "provision", true, access7.putAccessUser(updateForm6(news)));
|
|
5937
6003
|
}
|
|
5938
6004
|
const after = dropUnreadable6(yield* readUser(news));
|
|
5939
6005
|
if (after === undefined) {
|
|
5940
|
-
return yield*
|
|
6006
|
+
return yield* Effect81.die(new Error(`access/users/${news.userid}: the write returned no error but the account is ` + 'still absent. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- read back rather than trusting the status code."));
|
|
5941
6007
|
}
|
|
5942
6008
|
return after;
|
|
5943
6009
|
}),
|
|
5944
|
-
delete:
|
|
6010
|
+
delete: Effect81.fn(function* ({ olds }) {
|
|
5945
6011
|
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
5946
6012
|
})
|
|
5947
6013
|
})));
|
|
5948
6014
|
|
|
5949
6015
|
// src/proxmox/provision-declare.ts
|
|
5950
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
5951
|
-
const baseline = yield*
|
|
6016
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect82.gen(function* () {
|
|
6017
|
+
const baseline = yield* Effect82.try({
|
|
5952
6018
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
5953
6019
|
try: () => provisionBaseline(names2)
|
|
5954
6020
|
});
|
|
@@ -5962,13 +6028,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
5962
6028
|
target
|
|
5963
6029
|
}));
|
|
5964
6030
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
5965
|
-
const users = yield*
|
|
6031
|
+
const users = yield* Effect82.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
5966
6032
|
comment: user.comment,
|
|
5967
6033
|
groups: [...user.groups],
|
|
5968
6034
|
target,
|
|
5969
6035
|
userid: user.userid
|
|
5970
6036
|
}))));
|
|
5971
|
-
const grants = yield*
|
|
6037
|
+
const grants = yield* Effect82.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
5972
6038
|
path: "/",
|
|
5973
6039
|
propagate: true,
|
|
5974
6040
|
roleid: grant.roleid,
|
|
@@ -5981,12 +6047,12 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
5981
6047
|
// src/proxmox/qemu.ts
|
|
5982
6048
|
import { Resource as Resource28 } from "alchemy";
|
|
5983
6049
|
import * as Provider28 from "alchemy/Provider";
|
|
5984
|
-
import * as
|
|
6050
|
+
import * as Effect86 from "effect/Effect";
|
|
5985
6051
|
|
|
5986
6052
|
// src/proxmox/qemu-lifecycle.ts
|
|
5987
|
-
import { isResolved as
|
|
6053
|
+
import { isResolved as isResolved27 } from "alchemy/Diff";
|
|
5988
6054
|
import * as nodes17 from "@distilled.cloud/proxmox/nodes";
|
|
5989
|
-
import * as
|
|
6055
|
+
import * as Effect85 from "effect/Effect";
|
|
5990
6056
|
|
|
5991
6057
|
// src/proxmox/qemu-props.ts
|
|
5992
6058
|
var NOT_CONFIG2 = new Set(["node", "target", "vmid"]);
|
|
@@ -6047,7 +6113,7 @@ var createForm9 = (props) => ({
|
|
|
6047
6113
|
...form(props),
|
|
6048
6114
|
vmid: String(props.vmid)
|
|
6049
6115
|
});
|
|
6050
|
-
var
|
|
6116
|
+
var updateForm7 = form;
|
|
6051
6117
|
|
|
6052
6118
|
// src/proxmox/qemu-errors.ts
|
|
6053
6119
|
class QemuRefusedError extends Error {
|
|
@@ -6142,7 +6208,7 @@ var netPairs = (value) => new Map(value.split(",").map((part) => part.trim()).fi
|
|
|
6142
6208
|
const at = part.indexOf("=");
|
|
6143
6209
|
return at === -1 ? [part, ""] : [part.slice(0, at), part.slice(at + 1)];
|
|
6144
6210
|
}));
|
|
6145
|
-
var modelKey = (
|
|
6211
|
+
var modelKey = (map32) => NIC_MODELS.find((model) => map32.has(model));
|
|
6146
6212
|
var netMaps2 = (declared2, live) => {
|
|
6147
6213
|
const want = netPairs(declared2);
|
|
6148
6214
|
const have = netPairs(live);
|
|
@@ -6213,44 +6279,44 @@ var judge2 = (props, config7) => {
|
|
|
6213
6279
|
var identityRefusal = (vmid, was) => was === undefined || vmid === was ? undefined : `vmid: ${String(was)} -> ${String(vmid)} is a different VM. Declare it as a new resource; ` + "this one is retained when its declaration goes.";
|
|
6214
6280
|
|
|
6215
6281
|
// src/proxmox/qemu-read.ts
|
|
6216
|
-
import * as
|
|
6282
|
+
import * as cluster11 from "@distilled.cloud/proxmox/cluster";
|
|
6217
6283
|
import * as nodes15 from "@distilled.cloud/proxmox/nodes";
|
|
6218
|
-
import * as
|
|
6284
|
+
import * as Effect83 from "effect/Effect";
|
|
6219
6285
|
var guestTypes = ["lxc", "qemu"];
|
|
6220
|
-
var readVm = (props) =>
|
|
6286
|
+
var readVm = (props) => Effect83.gen(function* () {
|
|
6221
6287
|
const credential = yield* leased(props.target, "read");
|
|
6222
|
-
const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(
|
|
6288
|
+
const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(Effect83.map((data) => ({ data, error: undefined })), Effect83.catchTag("QemuConfigNotFound", (error) => Effect83.succeed({ data: undefined, error })));
|
|
6223
6289
|
if (answer.error === undefined) {
|
|
6224
6290
|
const live = answer.data;
|
|
6225
6291
|
if (typeof live.digest !== "string" || live.digest === "") {
|
|
6226
|
-
return yield*
|
|
6292
|
+
return yield* Effect83.fail(new QemuRefusedError(`VM ${String(props.vmid)}: config read did not return a digest-bearing config.`));
|
|
6227
6293
|
}
|
|
6228
6294
|
return live;
|
|
6229
6295
|
}
|
|
6230
|
-
const rows = yield* runPveWith(props.target, credential, false,
|
|
6296
|
+
const rows = yield* runPveWith(props.target, credential, false, cluster11.listClusterResources({ type: "vm" }));
|
|
6231
6297
|
if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !guestTypes.includes(row.type))) {
|
|
6232
|
-
return yield*
|
|
6298
|
+
return yield* Effect83.fail(new QemuRefusedError("The cluster guest index did not identify its rows."));
|
|
6233
6299
|
}
|
|
6234
6300
|
const found = rows.find((row) => Number(row.vmid) === props.vmid);
|
|
6235
6301
|
if (found === undefined)
|
|
6236
6302
|
return;
|
|
6237
6303
|
if (found.node === props.node && found.type === "qemu")
|
|
6238
|
-
return yield*
|
|
6239
|
-
return yield*
|
|
6304
|
+
return yield* Effect83.fail(answer.error);
|
|
6305
|
+
return yield* Effect83.fail(new QemuRefusedError(`vmid ${String(props.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a VM on ${props.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
|
|
6240
6306
|
});
|
|
6241
6307
|
|
|
6242
6308
|
// src/proxmox/qemu-task.ts
|
|
6243
6309
|
import * as nodes16 from "@distilled.cloud/proxmox/nodes";
|
|
6244
|
-
import * as
|
|
6245
|
-
var qemuTask = (props, operation, what, polls) =>
|
|
6310
|
+
import * as Effect84 from "effect/Effect";
|
|
6311
|
+
var qemuTask = (props, operation, what, polls) => Effect84.gen(function* () {
|
|
6246
6312
|
const credential = yield* mint(props.target, "provision");
|
|
6247
6313
|
const upid = text(yield* runPveWith(props.target, credential, true, operation));
|
|
6248
6314
|
if (upid === "") {
|
|
6249
|
-
return yield*
|
|
6315
|
+
return yield* Effect84.fail(new QemuRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
6250
6316
|
}
|
|
6251
6317
|
let exit = "still running when this provider stopped waiting";
|
|
6252
6318
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
6253
|
-
const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
6319
|
+
const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect84.orElseSucceed(() => {
|
|
6254
6320
|
return;
|
|
6255
6321
|
}));
|
|
6256
6322
|
if (status === undefined || status.status === undefined) {
|
|
@@ -6261,66 +6327,66 @@ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
|
|
|
6261
6327
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
6262
6328
|
break;
|
|
6263
6329
|
}
|
|
6264
|
-
yield*
|
|
6330
|
+
yield* Effect84.sleep("1 second");
|
|
6265
6331
|
}
|
|
6266
6332
|
if (exit !== "OK") {
|
|
6267
|
-
return yield*
|
|
6333
|
+
return yield* Effect84.fail(new QemuRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
|
|
6268
6334
|
}
|
|
6269
6335
|
});
|
|
6270
6336
|
|
|
6271
6337
|
// src/proxmox/qemu-lifecycle.ts
|
|
6272
6338
|
var CREATE_POLLS2 = 180;
|
|
6273
6339
|
var DELETE_POLLS = 60;
|
|
6274
|
-
var
|
|
6340
|
+
var attributesOf10 = (live, props) => ({
|
|
6275
6341
|
config: storedConfig2(live),
|
|
6276
6342
|
node: props.node,
|
|
6277
6343
|
vmid: props.vmid
|
|
6278
6344
|
});
|
|
6279
|
-
var
|
|
6345
|
+
var matches10 = (attributes2, props) => declaredKeys2(props).filter(isManagedKey2).every((key) => attributes2.config[key] === wireValue2(declaredValue2(props, key)));
|
|
6280
6346
|
var spec5 = {
|
|
6281
|
-
attributes:
|
|
6347
|
+
attributes: attributesOf10,
|
|
6282
6348
|
collection: (props) => `nodes/${props.node}/qemu`,
|
|
6283
6349
|
createForm: createForm9,
|
|
6284
6350
|
endpoint: {
|
|
6285
6351
|
create: "pve:POST /nodes/{node}/qemu",
|
|
6286
6352
|
update: "pve:PUT /nodes/{node}/qemu/{vmid}/config"
|
|
6287
6353
|
},
|
|
6288
|
-
matches:
|
|
6354
|
+
matches: matches10,
|
|
6289
6355
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
6290
|
-
updateForm:
|
|
6356
|
+
updateForm: updateForm7
|
|
6291
6357
|
};
|
|
6292
6358
|
var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
|
|
6293
|
-
var readQemu = (props) => readVm(props).pipe(
|
|
6294
|
-
var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(
|
|
6359
|
+
var readQemu = (props) => readVm(props).pipe(Effect85.map((live) => live === undefined ? undefined : attributesOf10(live, props)));
|
|
6360
|
+
var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect85.catchTag("QemuConfigNotFound", () => Effect85.void));
|
|
6295
6361
|
var refuseUnmanaged = (props) => {
|
|
6296
6362
|
const refused2 = formRefusals(props);
|
|
6297
|
-
return refused2.length === 0 ?
|
|
6363
|
+
return refused2.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(refused2.join(`
|
|
6298
6364
|
`)));
|
|
6299
6365
|
};
|
|
6300
|
-
var refuseChange = (change) => change.refuse.length === 0 ?
|
|
6366
|
+
var refuseChange = (change) => change.refuse.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(change.refuse.join(`
|
|
6301
6367
|
`)));
|
|
6302
6368
|
var qemuHandlers = {
|
|
6303
|
-
list: () =>
|
|
6304
|
-
read:
|
|
6369
|
+
list: () => Effect85.succeed([]),
|
|
6370
|
+
read: Effect85.fn(function* ({
|
|
6305
6371
|
fqn,
|
|
6306
6372
|
instanceId,
|
|
6307
6373
|
olds,
|
|
6308
6374
|
output
|
|
6309
6375
|
}) {
|
|
6310
6376
|
const found = yield* readQemu(olds);
|
|
6311
|
-
const settled2 =
|
|
6377
|
+
const settled2 = Effect85.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
|
|
6312
6378
|
return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
|
|
6313
6379
|
}),
|
|
6314
|
-
diff:
|
|
6380
|
+
diff: Effect85.fn(function* ({
|
|
6315
6381
|
news,
|
|
6316
6382
|
olds,
|
|
6317
6383
|
output
|
|
6318
6384
|
}) {
|
|
6319
|
-
if (!
|
|
6385
|
+
if (!isResolved27(news))
|
|
6320
6386
|
return;
|
|
6321
6387
|
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
|
|
6322
6388
|
if (identity2 !== undefined)
|
|
6323
|
-
return yield*
|
|
6389
|
+
return yield* Effect85.fail(new QemuRefusedError(identity2));
|
|
6324
6390
|
yield* refuseUnmanaged(news);
|
|
6325
6391
|
yield* guardCreate10(news, output === undefined);
|
|
6326
6392
|
yield* guardUpdate10(news);
|
|
@@ -6328,7 +6394,7 @@ var qemuHandlers = {
|
|
|
6328
6394
|
return;
|
|
6329
6395
|
const live = yield* readQemu(news);
|
|
6330
6396
|
if (live === undefined) {
|
|
6331
|
-
yield*
|
|
6397
|
+
yield* Effect85.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
|
|
6332
6398
|
yield* guardCreate10(news, true);
|
|
6333
6399
|
return { action: "update" };
|
|
6334
6400
|
}
|
|
@@ -6336,7 +6402,7 @@ var qemuHandlers = {
|
|
|
6336
6402
|
yield* refuseChange(change);
|
|
6337
6403
|
return { action: change.drift.length === 0 ? "noop" : "update" };
|
|
6338
6404
|
}),
|
|
6339
|
-
reconcile:
|
|
6405
|
+
reconcile: Effect85.fn(function* ({
|
|
6340
6406
|
fqn,
|
|
6341
6407
|
instanceId,
|
|
6342
6408
|
news,
|
|
@@ -6345,7 +6411,7 @@ var qemuHandlers = {
|
|
|
6345
6411
|
}) {
|
|
6346
6412
|
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
|
|
6347
6413
|
if (identity2 !== undefined)
|
|
6348
|
-
return yield*
|
|
6414
|
+
return yield* Effect85.fail(new QemuRefusedError(identity2));
|
|
6349
6415
|
yield* refuseUnmanaged(news);
|
|
6350
6416
|
const live = yield* readQemu(news);
|
|
6351
6417
|
yield* guardCreate10(news, live === undefined);
|
|
@@ -6362,11 +6428,11 @@ var qemuHandlers = {
|
|
|
6362
6428
|
}
|
|
6363
6429
|
const after = yield* readQemu(news);
|
|
6364
6430
|
if (after === undefined) {
|
|
6365
|
-
return yield*
|
|
6431
|
+
return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
|
|
6366
6432
|
}
|
|
6367
6433
|
const left = judge2(news, after.config);
|
|
6368
6434
|
if (left.drift.length > 0) {
|
|
6369
|
-
return yield*
|
|
6435
|
+
return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
|
|
6370
6436
|
}
|
|
6371
6437
|
return after;
|
|
6372
6438
|
}),
|
|
@@ -6375,16 +6441,16 @@ var qemuHandlers = {
|
|
|
6375
6441
|
|
|
6376
6442
|
// src/proxmox/qemu.ts
|
|
6377
6443
|
var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
|
|
6378
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
6444
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect86.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
|
|
6379
6445
|
// src/proxmox/storage-download.ts
|
|
6380
6446
|
import { Resource as Resource29 } from "alchemy";
|
|
6381
6447
|
import * as Provider29 from "alchemy/Provider";
|
|
6382
|
-
import * as
|
|
6448
|
+
import * as Effect89 from "effect/Effect";
|
|
6383
6449
|
|
|
6384
6450
|
// src/proxmox/storage-download-lifecycle.ts
|
|
6385
|
-
import { isResolved as
|
|
6451
|
+
import { isResolved as isResolved28 } from "alchemy/Diff";
|
|
6386
6452
|
import * as nodes19 from "@distilled.cloud/proxmox/nodes";
|
|
6387
|
-
import * as
|
|
6453
|
+
import * as Effect88 from "effect/Effect";
|
|
6388
6454
|
|
|
6389
6455
|
// src/proxmox/storage-download-identity.ts
|
|
6390
6456
|
var PINNED = [
|
|
@@ -6419,16 +6485,16 @@ class StorageDownloadRefusedError extends Error {
|
|
|
6419
6485
|
|
|
6420
6486
|
// src/proxmox/storage-download-task.ts
|
|
6421
6487
|
import * as nodes18 from "@distilled.cloud/proxmox/nodes";
|
|
6422
|
-
import * as
|
|
6423
|
-
var storageDownloadTask = (where, operation, what, polls) =>
|
|
6488
|
+
import * as Effect87 from "effect/Effect";
|
|
6489
|
+
var storageDownloadTask = (where, operation, what, polls) => Effect87.gen(function* () {
|
|
6424
6490
|
const credential = yield* mint(where.target, "provision");
|
|
6425
6491
|
const upid = text(yield* runPveWith(where.target, credential, true, operation));
|
|
6426
6492
|
if (upid === "") {
|
|
6427
|
-
return yield*
|
|
6493
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
6428
6494
|
}
|
|
6429
6495
|
let exit = "still running when this provider stopped waiting";
|
|
6430
6496
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
6431
|
-
const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(
|
|
6497
|
+
const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect87.orElseSucceed(() => {
|
|
6432
6498
|
return;
|
|
6433
6499
|
}));
|
|
6434
6500
|
if (status === undefined || status.status === undefined) {
|
|
@@ -6439,10 +6505,10 @@ var storageDownloadTask = (where, operation, what, polls) => Effect86.gen(functi
|
|
|
6439
6505
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
6440
6506
|
break;
|
|
6441
6507
|
}
|
|
6442
|
-
yield*
|
|
6508
|
+
yield* Effect87.sleep("1 second");
|
|
6443
6509
|
}
|
|
6444
6510
|
if (exit !== "OK") {
|
|
6445
|
-
return yield*
|
|
6511
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
|
|
6446
6512
|
}
|
|
6447
6513
|
});
|
|
6448
6514
|
|
|
@@ -6468,14 +6534,14 @@ var createRefusals2 = (props) => {
|
|
|
6468
6534
|
}
|
|
6469
6535
|
return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
|
|
6470
6536
|
};
|
|
6471
|
-
var readDownload = (props) =>
|
|
6537
|
+
var readDownload = (props) => Effect88.gen(function* () {
|
|
6472
6538
|
const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
|
|
6473
6539
|
content: "import",
|
|
6474
6540
|
node: props.node,
|
|
6475
6541
|
storage: props.storage
|
|
6476
6542
|
}));
|
|
6477
6543
|
if (!Array.isArray(rows)) {
|
|
6478
|
-
return yield*
|
|
6544
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
|
|
6479
6545
|
}
|
|
6480
6546
|
const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
|
|
6481
6547
|
if (found === undefined)
|
|
@@ -6489,7 +6555,7 @@ var readDownload = (props) => Effect87.gen(function* () {
|
|
|
6489
6555
|
volid: text(found.volid, "")
|
|
6490
6556
|
};
|
|
6491
6557
|
});
|
|
6492
|
-
var destroyDownload = (props) =>
|
|
6558
|
+
var destroyDownload = (props) => Effect88.gen(function* () {
|
|
6493
6559
|
const live = yield* readDownload(props);
|
|
6494
6560
|
if (live === undefined)
|
|
6495
6561
|
return;
|
|
@@ -6500,26 +6566,26 @@ var destroyDownload = (props) => Effect87.gen(function* () {
|
|
|
6500
6566
|
}), `delete ${live.volid}`, DELETE_POLLS2);
|
|
6501
6567
|
});
|
|
6502
6568
|
var storageDownloadHandlers = {
|
|
6503
|
-
list: () =>
|
|
6504
|
-
read:
|
|
6569
|
+
list: () => Effect88.succeed([]),
|
|
6570
|
+
read: Effect88.fn(function* ({
|
|
6505
6571
|
fqn,
|
|
6506
6572
|
instanceId,
|
|
6507
6573
|
olds,
|
|
6508
6574
|
output
|
|
6509
6575
|
}) {
|
|
6510
6576
|
const found = yield* readDownload(olds);
|
|
6511
|
-
return yield* ownedRead({ fqn, instanceId, output }, found,
|
|
6577
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, Effect88.succeed(true));
|
|
6512
6578
|
}),
|
|
6513
|
-
diff:
|
|
6579
|
+
diff: Effect88.fn(function* ({
|
|
6514
6580
|
news,
|
|
6515
6581
|
olds,
|
|
6516
6582
|
output
|
|
6517
6583
|
}) {
|
|
6518
|
-
if (!
|
|
6584
|
+
if (!isResolved28(news))
|
|
6519
6585
|
return;
|
|
6520
6586
|
const refused2 = createRefusals2(news);
|
|
6521
6587
|
if (refused2.length > 0) {
|
|
6522
|
-
return yield*
|
|
6588
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6523
6589
|
`)));
|
|
6524
6590
|
}
|
|
6525
6591
|
if (output === undefined)
|
|
@@ -6529,11 +6595,11 @@ var storageDownloadHandlers = {
|
|
|
6529
6595
|
return { action: "replace" };
|
|
6530
6596
|
const live = yield* readDownload(news);
|
|
6531
6597
|
if (identity2.kind === "pin-changed" && live !== undefined) {
|
|
6532
|
-
return yield*
|
|
6598
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(identity2.refuse));
|
|
6533
6599
|
}
|
|
6534
6600
|
return { action: live === undefined ? "update" : "noop" };
|
|
6535
6601
|
}),
|
|
6536
|
-
reconcile:
|
|
6602
|
+
reconcile: Effect88.fn(function* ({
|
|
6537
6603
|
fqn,
|
|
6538
6604
|
instanceId,
|
|
6539
6605
|
news,
|
|
@@ -6541,7 +6607,7 @@ var storageDownloadHandlers = {
|
|
|
6541
6607
|
}) {
|
|
6542
6608
|
const refused2 = createRefusals2(news);
|
|
6543
6609
|
if (refused2.length > 0) {
|
|
6544
|
-
return yield*
|
|
6610
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6545
6611
|
`)));
|
|
6546
6612
|
}
|
|
6547
6613
|
const live = yield* readDownload(news);
|
|
@@ -6552,7 +6618,7 @@ var storageDownloadHandlers = {
|
|
|
6552
6618
|
}
|
|
6553
6619
|
const after = yield* readDownload(news);
|
|
6554
6620
|
if (after === undefined) {
|
|
6555
|
-
return yield*
|
|
6621
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
|
|
6556
6622
|
}
|
|
6557
6623
|
return after;
|
|
6558
6624
|
}),
|
|
@@ -6561,17 +6627,17 @@ var storageDownloadHandlers = {
|
|
|
6561
6627
|
|
|
6562
6628
|
// src/proxmox/storage-download.ts
|
|
6563
6629
|
var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
|
|
6564
|
-
var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload,
|
|
6630
|
+
var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect89.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
|
|
6565
6631
|
// src/proxmox/replication-job.ts
|
|
6566
6632
|
import { Resource as Resource30 } from "alchemy";
|
|
6567
6633
|
import * as Provider30 from "alchemy/Provider";
|
|
6568
|
-
import * as
|
|
6634
|
+
import * as Effect91 from "effect/Effect";
|
|
6569
6635
|
|
|
6570
6636
|
// src/proxmox/replication-job-lifecycle.ts
|
|
6571
|
-
import { isResolved as
|
|
6572
|
-
import * as
|
|
6637
|
+
import { isResolved as isResolved29 } from "alchemy/Diff";
|
|
6638
|
+
import * as cluster12 from "@distilled.cloud/proxmox/cluster";
|
|
6573
6639
|
import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
|
|
6574
|
-
import * as
|
|
6640
|
+
import * as Effect90 from "effect/Effect";
|
|
6575
6641
|
import * as Schema6 from "effect/Schema";
|
|
6576
6642
|
|
|
6577
6643
|
// src/proxmox/replication-job-form.ts
|
|
@@ -6632,21 +6698,21 @@ var malformed = () => new ProxmoxParseError6({
|
|
|
6632
6698
|
body: undefined,
|
|
6633
6699
|
cause: "Replication job response does not match the requested vendor identity"
|
|
6634
6700
|
});
|
|
6635
|
-
var readReplicationJob = (props) => runPve(props.target, "read", false,
|
|
6701
|
+
var readReplicationJob = (props) => runPve(props.target, "read", false, cluster12.getClusterReplication({ id: jobId(props) })).pipe(Effect90.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster12.GetClusterReplicationResponse))({
|
|
6636
6702
|
...live,
|
|
6637
6703
|
guest: int(live.guest, Number.NaN),
|
|
6638
6704
|
jobnum: int(live.jobnum, Number.NaN),
|
|
6639
6705
|
rate: undefined
|
|
6640
|
-
}).pipe(
|
|
6641
|
-
var deleteReplicationJob = (props) => runPve(props.target, "provision", true,
|
|
6706
|
+
}).pipe(Effect90.mapError(malformed), Effect90.as(live))), Effect90.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect90.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect90.fail(malformed())), Effect90.catchTag("ReplicationJobNotFound", () => Effect90.succeed(undefined)));
|
|
6707
|
+
var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster12.deleteClusterReplication({ id: jobId(props) })).pipe(Effect90.catchTag("ReplicationJobNotFound", () => Effect90.void));
|
|
6642
6708
|
var replicationJobHandlers = {
|
|
6643
|
-
list: () =>
|
|
6709
|
+
list: () => Effect90.succeed([]),
|
|
6644
6710
|
read: ({ olds }) => readReplicationJob(olds),
|
|
6645
|
-
diff:
|
|
6711
|
+
diff: Effect90.fn(function* ({
|
|
6646
6712
|
news,
|
|
6647
6713
|
output
|
|
6648
6714
|
}) {
|
|
6649
|
-
if (!
|
|
6715
|
+
if (!isResolved29(news))
|
|
6650
6716
|
return;
|
|
6651
6717
|
yield* guardCreate11(news, output === undefined);
|
|
6652
6718
|
yield* guardUpdate11(news);
|
|
@@ -6659,20 +6725,20 @@ var replicationJobHandlers = {
|
|
|
6659
6725
|
}
|
|
6660
6726
|
return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
|
|
6661
6727
|
}),
|
|
6662
|
-
reconcile:
|
|
6728
|
+
reconcile: Effect90.fn(function* ({ news }) {
|
|
6663
6729
|
const live = yield* readReplicationJob(news);
|
|
6664
6730
|
yield* guardCreate11(news, live === undefined);
|
|
6665
6731
|
yield* guardUpdate11(news);
|
|
6666
6732
|
if (live === undefined) {
|
|
6667
|
-
yield* runPve(news.target, "provision", true,
|
|
6733
|
+
yield* runPve(news.target, "provision", true, cluster12.createClusterReplication(replicationJobSpec.createForm(news)));
|
|
6668
6734
|
} else {
|
|
6669
6735
|
const form2 = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
|
|
6670
6736
|
if (form2 !== undefined)
|
|
6671
|
-
yield* runPve(news.target, "provision", true,
|
|
6737
|
+
yield* runPve(news.target, "provision", true, cluster12.putClusterReplication({ ...form2, id: jobId(news) }));
|
|
6672
6738
|
}
|
|
6673
6739
|
const after = yield* readReplicationJob(news);
|
|
6674
6740
|
if (after === undefined)
|
|
6675
|
-
return yield*
|
|
6741
|
+
return yield* Effect90.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
|
|
6676
6742
|
return after;
|
|
6677
6743
|
}),
|
|
6678
6744
|
delete: ({ olds }) => deleteReplicationJob(olds)
|
|
@@ -6680,15 +6746,15 @@ var replicationJobHandlers = {
|
|
|
6680
6746
|
|
|
6681
6747
|
// src/proxmox/replication-job.ts
|
|
6682
6748
|
var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
|
|
6683
|
-
var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob,
|
|
6749
|
+
var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect91.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
|
|
6684
6750
|
// src/proxmox/sdn-apply.ts
|
|
6685
6751
|
import { Resource as Resource31 } from "alchemy";
|
|
6686
|
-
import { isResolved as
|
|
6752
|
+
import { isResolved as isResolved30 } from "alchemy/Diff";
|
|
6687
6753
|
import * as Provider31 from "alchemy/Provider";
|
|
6688
|
-
import * as
|
|
6754
|
+
import * as Effect93 from "effect/Effect";
|
|
6689
6755
|
|
|
6690
6756
|
// src/proxmox/sdn-apply-read.ts
|
|
6691
|
-
import * as
|
|
6757
|
+
import * as Effect92 from "effect/Effect";
|
|
6692
6758
|
var MARKED = [
|
|
6693
6759
|
"cluster/sdn/zones",
|
|
6694
6760
|
"cluster/sdn/vnets",
|
|
@@ -6697,7 +6763,7 @@ var MARKED = [
|
|
|
6697
6763
|
"cluster/sdn/route-maps"
|
|
6698
6764
|
];
|
|
6699
6765
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
6700
|
-
var markedPending = (target) =>
|
|
6766
|
+
var markedPending = (target) => Effect92.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect92.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect92.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
6701
6767
|
var fabricStaged = (staged, running) => {
|
|
6702
6768
|
if (staged === undefined && running === undefined)
|
|
6703
6769
|
return 0;
|
|
@@ -6705,9 +6771,9 @@ var fabricStaged = (staged, running) => {
|
|
|
6705
6771
|
return "inconsistent";
|
|
6706
6772
|
return staged === running ? 0 : 1;
|
|
6707
6773
|
};
|
|
6708
|
-
var fabricPending = (target) =>
|
|
6774
|
+
var fabricPending = (target) => Effect92.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect92.map(canonical3), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect92.flatMap(([staged, running]) => {
|
|
6709
6775
|
const verdict = fabricStaged(staged, running);
|
|
6710
|
-
return verdict === "inconsistent" ?
|
|
6776
|
+
return verdict === "inconsistent" ? Effect92.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect92.succeed(verdict);
|
|
6711
6777
|
}));
|
|
6712
6778
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
6713
6779
|
var sortDeep = (value) => {
|
|
@@ -6720,23 +6786,23 @@ var sortDeep = (value) => {
|
|
|
6720
6786
|
}
|
|
6721
6787
|
return value;
|
|
6722
6788
|
};
|
|
6723
|
-
var sdnPendingCount = (target) =>
|
|
6789
|
+
var sdnPendingCount = (target) => Effect92.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect92.map(([marked, fabric]) => marked + fabric));
|
|
6724
6790
|
|
|
6725
6791
|
// src/proxmox/sdn-apply.ts
|
|
6726
6792
|
var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
|
|
6727
|
-
var read5 = (props) => sdnPendingCount(props.target).pipe(
|
|
6728
|
-
var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply,
|
|
6729
|
-
list: () =>
|
|
6730
|
-
read:
|
|
6793
|
+
var read5 = (props) => sdnPendingCount(props.target).pipe(Effect93.map((pending) => ({ pending })));
|
|
6794
|
+
var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect93.succeed(ProxmoxSdnApply.Provider.of({
|
|
6795
|
+
list: () => Effect93.succeed([]),
|
|
6796
|
+
read: Effect93.fn(function* ({ olds }) {
|
|
6731
6797
|
return yield* read5(olds);
|
|
6732
6798
|
}),
|
|
6733
|
-
diff:
|
|
6734
|
-
if (!
|
|
6799
|
+
diff: Effect93.fn(function* ({ news }) {
|
|
6800
|
+
if (!isResolved30(news))
|
|
6735
6801
|
return;
|
|
6736
6802
|
const { pending } = yield* read5(news);
|
|
6737
6803
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
6738
6804
|
}),
|
|
6739
|
-
reconcile:
|
|
6805
|
+
reconcile: Effect93.fn(function* ({ news }) {
|
|
6740
6806
|
const staged = yield* read5(news);
|
|
6741
6807
|
if (staged.pending === 0)
|
|
6742
6808
|
return staged;
|
|
@@ -6744,16 +6810,16 @@ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect92.
|
|
|
6744
6810
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
6745
6811
|
const after = yield* read5(news);
|
|
6746
6812
|
if (after.pending !== 0) {
|
|
6747
|
-
return yield*
|
|
6813
|
+
return yield* Effect93.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
|
|
6748
6814
|
}
|
|
6749
6815
|
return after;
|
|
6750
6816
|
}),
|
|
6751
|
-
delete: () =>
|
|
6817
|
+
delete: () => Effect93.void
|
|
6752
6818
|
})));
|
|
6753
6819
|
// src/proxmox/sdn-subnet.ts
|
|
6754
6820
|
import { Resource as Resource32 } from "alchemy";
|
|
6755
6821
|
import * as Provider32 from "alchemy/Provider";
|
|
6756
|
-
import * as
|
|
6822
|
+
import * as Effect94 from "effect/Effect";
|
|
6757
6823
|
|
|
6758
6824
|
// src/proxmox/sdn-subnet-form.ts
|
|
6759
6825
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -6777,14 +6843,14 @@ var createForm10 = (props) => ({
|
|
|
6777
6843
|
subnet: props.cidr,
|
|
6778
6844
|
type: "subnet"
|
|
6779
6845
|
});
|
|
6780
|
-
var
|
|
6846
|
+
var updateForm8 = (props) => {
|
|
6781
6847
|
const clear = Object.entries(optional3(props)).filter(([, value]) => value === undefined).map(([key]) => key);
|
|
6782
6848
|
return withClears(body5(props), clear);
|
|
6783
6849
|
};
|
|
6784
6850
|
|
|
6785
6851
|
// src/proxmox/sdn-subnet.ts
|
|
6786
6852
|
var ProxmoxSdnSubnet = Resource32("Proxmox.SdnSubnet");
|
|
6787
|
-
var
|
|
6853
|
+
var handlers12 = pveHandlers({
|
|
6788
6854
|
attributes: (live, props) => {
|
|
6789
6855
|
const liveVnet = text(live["vnet"]);
|
|
6790
6856
|
if (liveVnet !== "" && liveVnet !== props.vnet)
|
|
@@ -6811,13 +6877,13 @@ var handlers13 = pveHandlers({
|
|
|
6811
6877
|
},
|
|
6812
6878
|
matches: (attributes2, props) => attributes2.gateway === (props.gateway ?? "") && attributes2.snat === (props.snat === true) && attributes2.dnszoneprefix === (props.dnszoneprefix ?? "") && attributes2.dhcpDnsServer === (props.dhcpDnsServer ?? "") && attributes2.dhcpRange === declaredRanges(props.dhcpRange),
|
|
6813
6879
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
6814
|
-
updateForm:
|
|
6880
|
+
updateForm: updateForm8
|
|
6815
6881
|
});
|
|
6816
|
-
var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet,
|
|
6882
|
+
var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect94.succeed(ProxmoxSdnSubnet.Provider.of(handlers12)));
|
|
6817
6883
|
// src/proxmox/sdn-vnet.ts
|
|
6818
6884
|
import { Resource as Resource33 } from "alchemy";
|
|
6819
6885
|
import * as Provider33 from "alchemy/Provider";
|
|
6820
|
-
import * as
|
|
6886
|
+
import * as Effect95 from "effect/Effect";
|
|
6821
6887
|
var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
|
|
6822
6888
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
6823
6889
|
var shape10 = (props) => {
|
|
@@ -6830,14 +6896,14 @@ var shape10 = (props) => {
|
|
|
6830
6896
|
...props.tag === undefined ? {} : { tag: String(props.tag) }
|
|
6831
6897
|
};
|
|
6832
6898
|
};
|
|
6833
|
-
var
|
|
6899
|
+
var updateForm9 = (props) => {
|
|
6834
6900
|
const unset2 = [
|
|
6835
6901
|
...(props.alias ?? "") === "" ? ["alias"] : [],
|
|
6836
6902
|
...props.tag === undefined ? ["tag"] : []
|
|
6837
6903
|
];
|
|
6838
6904
|
return withClears(shape10(props), unset2);
|
|
6839
6905
|
};
|
|
6840
|
-
var
|
|
6906
|
+
var handlers13 = pveHandlers({
|
|
6841
6907
|
readRole: "provision",
|
|
6842
6908
|
attributes: (live, props) => ({
|
|
6843
6909
|
alias: typeof live["alias"] === "string" ? live["alias"] : "",
|
|
@@ -6853,13 +6919,13 @@ var handlers14 = pveHandlers({
|
|
|
6853
6919
|
endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
|
|
6854
6920
|
matches: (attributes2, props) => attributes2.zone === props.zone && attributes2.alias === (props.alias ?? "") && attributes2.tag === props.tag && attributes2.vlanaware === (props.vlanaware === true) && attributes2.isolatePorts === (props.isolatePorts === true),
|
|
6855
6921
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
6856
|
-
updateForm:
|
|
6922
|
+
updateForm: updateForm9
|
|
6857
6923
|
});
|
|
6858
|
-
var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet,
|
|
6924
|
+
var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect95.succeed(ProxmoxSdnVnet.Provider.of(handlers13)));
|
|
6859
6925
|
// src/proxmox/sdn-zone.ts
|
|
6860
6926
|
import { Resource as Resource34 } from "alchemy";
|
|
6861
6927
|
import * as Provider34 from "alchemy/Provider";
|
|
6862
|
-
import * as
|
|
6928
|
+
import * as Effect96 from "effect/Effect";
|
|
6863
6929
|
var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
|
|
6864
6930
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
6865
6931
|
var body6 = (props) => ({
|
|
@@ -6880,7 +6946,7 @@ var clearable = {
|
|
|
6880
6946
|
vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
|
|
6881
6947
|
vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
|
|
6882
6948
|
};
|
|
6883
|
-
var
|
|
6949
|
+
var handlers14 = pveHandlers({
|
|
6884
6950
|
readRole: "provision",
|
|
6885
6951
|
attributes: (live, props) => {
|
|
6886
6952
|
const liveType = text(live["type"]);
|
|
@@ -6912,13 +6978,13 @@ var handlers15 = pveHandlers({
|
|
|
6912
6978
|
return withClears(fields2, clear);
|
|
6913
6979
|
}
|
|
6914
6980
|
});
|
|
6915
|
-
var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone,
|
|
6981
|
+
var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect96.succeed(ProxmoxSdnZone.Provider.of(handlers14)));
|
|
6916
6982
|
// src/proxmox/storage.ts
|
|
6917
6983
|
import { Resource as Resource35 } from "alchemy";
|
|
6918
|
-
import { isResolved as
|
|
6984
|
+
import { isResolved as isResolved31 } from "alchemy/Diff";
|
|
6919
6985
|
import * as Provider35 from "alchemy/Provider";
|
|
6920
6986
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
6921
|
-
import * as
|
|
6987
|
+
import * as Effect98 from "effect/Effect";
|
|
6922
6988
|
|
|
6923
6989
|
// src/proxmox/storage-plugin-options.ts
|
|
6924
6990
|
var SHARED_ACCEPTED_TYPES = new Set(["dir", "lvm", "btrfs", "esxi"]);
|
|
@@ -6926,12 +6992,12 @@ var sharedAccepted = (type) => SHARED_ACCEPTED_TYPES.has(type);
|
|
|
6926
6992
|
|
|
6927
6993
|
// src/proxmox/storage-wire.ts
|
|
6928
6994
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
6929
|
-
import * as
|
|
6995
|
+
import * as Effect97 from "effect/Effect";
|
|
6930
6996
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
6931
6997
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
6932
6998
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
6933
6999
|
var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
6934
|
-
var
|
|
7000
|
+
var attributesOf11 = (live, props) => {
|
|
6935
7001
|
const data = live;
|
|
6936
7002
|
return {
|
|
6937
7003
|
comment: str2(data["comment"]),
|
|
@@ -6945,8 +7011,8 @@ var attributesOf10 = (live, props) => {
|
|
|
6945
7011
|
type: str2(data["type"], props.type)
|
|
6946
7012
|
};
|
|
6947
7013
|
};
|
|
6948
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
6949
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
7014
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect97.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf11(live, props)));
|
|
7015
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect97.catchTag("StorageNotFound", () => Effect97.succeed(undefined)));
|
|
6950
7016
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
6951
7017
|
var changedProps = (live, props) => ({
|
|
6952
7018
|
...sameList2(props.content, live.content) ? {} : { content: props.content },
|
|
@@ -6957,7 +7023,7 @@ var changedProps = (live, props) => ({
|
|
|
6957
7023
|
...same7(props.preallocation, live.preallocation) ? {} : { preallocation: props.preallocation },
|
|
6958
7024
|
...same7(props.comment, live.comment) ? {} : { comment: props.comment }
|
|
6959
7025
|
});
|
|
6960
|
-
var
|
|
7026
|
+
var matches11 = (attributes2, props) => !sharedAccepted(props.type) && !same7(props.shared, attributes2.shared) ? Effect97.die(new Error(`storage/${props.storage}: declared shared: ${String(props.shared)}, but PVE reports ` + `${String(attributes2.shared)} and '${props.type}' storages never accept a 'shared' ` + "write (storage-plugin-options.ts) -- remove the declared shared or set it to match " + "what PVE already reports; this value can never be applied.")) : Effect97.succeed(Object.keys(changedProps(attributes2, props)).length === 0);
|
|
6961
7027
|
|
|
6962
7028
|
// src/proxmox/storage-form.ts
|
|
6963
7029
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
@@ -6980,7 +7046,7 @@ var createForm11 = (props) => ({
|
|
|
6980
7046
|
storage: props.storage,
|
|
6981
7047
|
type: props.type
|
|
6982
7048
|
});
|
|
6983
|
-
var
|
|
7049
|
+
var updateForm10 = (props, live) => ({
|
|
6984
7050
|
...mutable2(props.type, live === undefined ? props : changedProps(live, props)),
|
|
6985
7051
|
storage: props.storage
|
|
6986
7052
|
});
|
|
@@ -6991,16 +7057,16 @@ var toDistilledUpdate3 = (form2) => underscored(form2);
|
|
|
6991
7057
|
var ProxmoxStorage = Resource35("Proxmox.Storage", {
|
|
6992
7058
|
defaultRemovalPolicy: "retain"
|
|
6993
7059
|
});
|
|
6994
|
-
var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage,
|
|
6995
|
-
list: () =>
|
|
6996
|
-
read:
|
|
7060
|
+
var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.succeed(ProxmoxStorage.Provider.of({
|
|
7061
|
+
list: () => Effect98.succeed([]),
|
|
7062
|
+
read: Effect98.fn(function* ({ olds, output }) {
|
|
6997
7063
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
6998
7064
|
}),
|
|
6999
|
-
diff:
|
|
7000
|
-
if (!
|
|
7065
|
+
diff: Effect98.fn(function* ({ news, output }) {
|
|
7066
|
+
if (!isResolved31(news))
|
|
7001
7067
|
return;
|
|
7002
7068
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
7003
|
-
yield* guardWrite2(STORAGE_UPDATE,
|
|
7069
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm10(news, undefined), false);
|
|
7004
7070
|
if (output === undefined)
|
|
7005
7071
|
return;
|
|
7006
7072
|
const live = yield* readStorageOrFail(news);
|
|
@@ -7012,61 +7078,61 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.su
|
|
|
7012
7078
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), true);
|
|
7013
7079
|
return { action: "update" };
|
|
7014
7080
|
}
|
|
7015
|
-
return (yield*
|
|
7081
|
+
return (yield* matches11(live, news)) ? { action: "noop" } : { action: "update" };
|
|
7016
7082
|
}),
|
|
7017
|
-
reconcile:
|
|
7083
|
+
reconcile: Effect98.fn(function* ({ news }) {
|
|
7018
7084
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
7019
7085
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
7020
|
-
const update2 =
|
|
7086
|
+
const update2 = updateForm10(news, before);
|
|
7021
7087
|
yield* guardWrite2(STORAGE_UPDATE, update2, false);
|
|
7022
7088
|
if (before === undefined) {
|
|
7023
7089
|
yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
|
|
7024
|
-
} else if (!(yield*
|
|
7090
|
+
} else if (!(yield* matches11(before, news))) {
|
|
7025
7091
|
yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate3(update2)));
|
|
7026
7092
|
}
|
|
7027
7093
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
7028
7094
|
if (after === undefined) {
|
|
7029
|
-
return yield*
|
|
7095
|
+
return yield* Effect98.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
|
|
7030
7096
|
}
|
|
7031
7097
|
return after;
|
|
7032
7098
|
}),
|
|
7033
|
-
delete:
|
|
7099
|
+
delete: Effect98.fn(function* ({ olds }) {
|
|
7034
7100
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
7035
7101
|
})
|
|
7036
7102
|
})));
|
|
7037
7103
|
// src/proxmox/zfs-pool.ts
|
|
7038
7104
|
import { Resource as Resource36 } from "alchemy";
|
|
7039
|
-
import { isResolved as
|
|
7105
|
+
import { isResolved as isResolved32 } from "alchemy/Diff";
|
|
7040
7106
|
import * as Provider36 from "alchemy/Provider";
|
|
7041
|
-
import * as
|
|
7107
|
+
import * as Effect101 from "effect/Effect";
|
|
7042
7108
|
|
|
7043
7109
|
// src/proxmox/zfs-pool-wire.ts
|
|
7044
7110
|
import * as nodes20 from "@distilled.cloud/proxmox/nodes";
|
|
7045
|
-
import * as
|
|
7111
|
+
import * as Effect99 from "effect/Effect";
|
|
7046
7112
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
7047
7113
|
const vdev = entry;
|
|
7048
7114
|
const nested = leafDevices(vdev.children);
|
|
7049
7115
|
return nested.length > 0 ? nested : [text(vdev.name)].filter((name) => name !== "");
|
|
7050
7116
|
}) : [];
|
|
7051
|
-
var
|
|
7117
|
+
var attributesOf12 = (live, props) => ({
|
|
7052
7118
|
devices: leafDevices(live.children).join(","),
|
|
7053
7119
|
errors: text(live.errors, "unknown"),
|
|
7054
7120
|
name: props.name,
|
|
7055
7121
|
node: props.node,
|
|
7056
7122
|
state: text(live.state, "unknown")
|
|
7057
7123
|
});
|
|
7058
|
-
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(
|
|
7124
|
+
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect99.map((live) => {
|
|
7059
7125
|
if (live === UNREADABLE)
|
|
7060
7126
|
return UNREADABLE;
|
|
7061
|
-
return text(live.name) === "" ? undefined :
|
|
7127
|
+
return text(live.name) === "" ? undefined : attributesOf12(live, props);
|
|
7062
7128
|
}));
|
|
7063
|
-
var readPool2 = (props) => readPoolOrFail(props).pipe(
|
|
7129
|
+
var readPool2 = (props) => readPoolOrFail(props).pipe(Effect99.orElseSucceed(() => {
|
|
7064
7130
|
return;
|
|
7065
7131
|
}));
|
|
7066
7132
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
7067
7133
|
|
|
7068
7134
|
// src/proxmox/zfs-pool-form.ts
|
|
7069
|
-
import * as
|
|
7135
|
+
import * as Effect100 from "effect/Effect";
|
|
7070
7136
|
import * as nodes21 from "@distilled.cloud/proxmox/nodes";
|
|
7071
7137
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
7072
7138
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
@@ -7087,25 +7153,25 @@ var toDistilledCreate5 = (props) => {
|
|
|
7087
7153
|
};
|
|
7088
7154
|
};
|
|
7089
7155
|
var SETTLE_ATTEMPTS = 30;
|
|
7090
|
-
var createPool2 = (props, read6) =>
|
|
7156
|
+
var createPool2 = (props, read6) => Effect100.gen(function* () {
|
|
7091
7157
|
const existing = yield* read6(props);
|
|
7092
7158
|
if (existing !== undefined)
|
|
7093
7159
|
return existing;
|
|
7094
7160
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
7095
|
-
return yield*
|
|
7161
|
+
return yield* Effect100.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
|
|
7096
7162
|
}
|
|
7097
7163
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
7098
7164
|
const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
7099
|
-
const settle3 = (attempts) =>
|
|
7165
|
+
const settle3 = (attempts) => Effect100.gen(function* () {
|
|
7100
7166
|
const live = yield* read6(props);
|
|
7101
7167
|
if (live !== undefined || attempts <= 0)
|
|
7102
7168
|
return live;
|
|
7103
|
-
yield*
|
|
7169
|
+
yield* Effect100.sleep("2 seconds");
|
|
7104
7170
|
return yield* settle3(attempts - 1);
|
|
7105
7171
|
});
|
|
7106
7172
|
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
7107
7173
|
if (after === undefined) {
|
|
7108
|
-
return yield*
|
|
7174
|
+
return yield* Effect100.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
|
|
7109
7175
|
}
|
|
7110
7176
|
return after;
|
|
7111
7177
|
});
|
|
@@ -7115,13 +7181,13 @@ var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.del
|
|
|
7115
7181
|
var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
|
|
7116
7182
|
defaultRemovalPolicy: "retain"
|
|
7117
7183
|
});
|
|
7118
|
-
var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool,
|
|
7119
|
-
list: () =>
|
|
7120
|
-
read:
|
|
7184
|
+
var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect101.succeed(ProxmoxZfsPool.Provider.of({
|
|
7185
|
+
list: () => Effect101.succeed([]),
|
|
7186
|
+
read: Effect101.fn(function* ({ olds, output }) {
|
|
7121
7187
|
return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
|
|
7122
7188
|
}),
|
|
7123
|
-
diff:
|
|
7124
|
-
if (!
|
|
7189
|
+
diff: Effect101.fn(function* ({ news, output }) {
|
|
7190
|
+
if (!isResolved32(news))
|
|
7125
7191
|
return;
|
|
7126
7192
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
7127
7193
|
if (output === undefined)
|
|
@@ -7137,10 +7203,10 @@ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.s
|
|
|
7137
7203
|
}
|
|
7138
7204
|
return { action: "noop" };
|
|
7139
7205
|
}),
|
|
7140
|
-
reconcile:
|
|
7141
|
-
return yield* createPool2(news, (props) => readPool2(props).pipe(
|
|
7206
|
+
reconcile: Effect101.fn(function* ({ news }) {
|
|
7207
|
+
return yield* createPool2(news, (props) => readPool2(props).pipe(Effect101.map(dropUnreadable8)));
|
|
7142
7208
|
}),
|
|
7143
|
-
delete:
|
|
7209
|
+
delete: Effect101.fn(function* ({ olds }) {
|
|
7144
7210
|
yield* destroyPool(olds);
|
|
7145
7211
|
})
|
|
7146
7212
|
})));
|
|
@@ -7223,5 +7289,5 @@ export {
|
|
|
7223
7289
|
violations
|
|
7224
7290
|
};
|
|
7225
7291
|
|
|
7226
|
-
//# debugId=
|
|
7292
|
+
//# debugId=E0B844E10EA9EF3D64756E2164756E21
|
|
7227
7293
|
//# sourceMappingURL=index.js.map
|