diff --git a/README.md b/README.md index fd45098..98513ee 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,10 @@ release set. Override individual selectors with `runtime.sitectl.package_versions` when intentionally testing or promoting a different compatible release set. -All non-ISLE presets use the coordinated sitectl v1.0.0 core/plugin release. -ISLE intentionally remains on its last released compatibility set—sitectl -v0.40.0, sitectl-drupal v0.12.0, and sitectl-isle v0.19.0—until its remaining -components are ready for a coordinated v1 release. Keep ISLE on that complete -set rather than mixing its pre-v1 plugin with v1 packages. +All presets use their coordinated sitectl v1.0.0 core/plugin release set. The +ISLE preset selects the `libops/isle` v1.1.0 template; every other application +preset remains on its v1.0.0 template contract. Keep each preset's complete +template and package set together when promoting an override. GCP deployments have two Terraform ownership layers. Apply [`modules/gcp-foundation`](modules/gcp-foundation/README.md) once per service @@ -64,7 +63,7 @@ No resources. | [name](#input\_name) | Deployment name. | `string` | n/a | yes | | [cloud\_provider](#input\_cloud\_provider) | Compatibility selector for the root GCP entrypoint. Use providers/do or providers/linode for other clouds. | `string` | `"gcp"` | no | | [gcp](#input\_gcp) | Google Cloud infrastructure settings. |
object({
project_id = optional(string, "")
project_number = optional(string, "")
region = optional(string, "us-east5")
zone = optional(string, "us-east5-b")

identity = optional(object({
vm_service_account_email = optional(string, "")
app_service_account_email = optional(string, "")
app_credentials_enabled = optional(bool, false)
}), {})

instance = optional(object({
machine_type = optional(string, "n4-standard-2")
os = optional(string, "cos-125-19216-220-185")
production = optional(bool, false)
}), {})

disks = optional(object({
type = optional(string, "hyperdisk-balanced")
docker_volumes_size_gb = optional(number, 50)
}), {})

network = optional(object({
create = optional(bool, true)
project_id = optional(string, "")
name = optional(string, "")
subnetwork = optional(string, "")
ip_cidr_range = optional(string, "10.42.0.0/24")
mtu = optional(number, 1460)
power_button_allowed_ips = optional(list(string), [])
power_button_ip_depth = optional(number)
ssh_ipv4 = optional(list(string), [])
ssh_ipv6 = optional(list(string), [])
}), {})

snapshots = optional(object({
enabled = optional(bool, false)
}), {})

overlay = optional(object({
source_instance = optional(string, "")
volume_names = optional(list(string), [])
}), {})

cloud_init = optional(object({
initcmd = optional(list(string), [])
runcmd = optional(list(string), [])
}), {})

artifact_registry = optional(object({
repository = optional(string, "")
location = optional(string, "us")
}), {})

power_management = optional(object({
enabled = optional(bool, false)
start_role = optional(string, "")
suspend_role = optional(string, "")
frontend = optional(object({
image = string
port = optional(number, 8080)
cpu = optional(string, "1000m")
memory = optional(string, "1Gi")
}), null)
}), {})

rollout = optional(object({
enabled = optional(bool, false)
release_url = optional(string, "")
release_sha256 = optional(string, "")
port = optional(number, 8081)
jwks_uri = optional(string, "")
jwt_audience = optional(string, "")
custom_claims = optional(string, "")
allowed_ipv4 = optional(list(string), ["10.0.0.0/8"])
}), {})
})
| `{}` | no | -| [runtime](#input\_runtime) | Provider-neutral compose/runtime settings. |
object({
rootfs = optional(string, "")
rootfs_archive_url = optional(string, "")
rootfs_archive_sha256 = optional(string, "")
users = optional(map(list(string)), {})

compose = optional(object({
primary = optional(string, "")
ingress_port = optional(number, 80)
ingress = optional(object({
letsencrypt = optional(bool, false)
bot_mitigation = optional(bool, false)
mode = optional(string, "")
domain = optional(string, "")
acme_email = optional(string, "")
trusted_ips = optional(list(string), [])
max_upload_size = optional(string, "")
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
branch = optional(string, "main")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
project_dir = optional(string)
compose_project_name = optional(string)
ingress_port = optional(number)
ingress = optional(object({
letsencrypt = optional(bool)
bot_mitigation = optional(bool)
mode = optional(string)
domain = optional(string)
acme_email = optional(string)
trusted_ips = optional(list(string))
max_upload_size = optional(string)
upload_timeout = optional(string)
}), {})
sitectl_context_name = optional(string)
sitectl_plugin = optional(string)
sitectl_environment = optional(string)
sitectl_packages = optional(list(string))
sitectl_verify_args = optional(list(string))
docker_compose_init = optional(list(string))
docker_compose_up = optional(list(string))
docker_compose_down = optional(list(string))
docker_compose_rollout = optional(list(string))
})), {})
init = optional(list(string))
up = optional(list(string))
down = optional(list(string))
rollout = optional(list(string))
}), {})

sitectl = optional(object({
packages = optional(list(string))
version = optional(string, "latest")
package_versions = optional(map(string), {})
context_name = optional(string, "")
plugin = optional(string, "core")
environment = optional(string, "production")
verify_args = optional(list(string), [])
}), {})

docker = optional(object({
# renovate: datasource=github-releases depName=docker-compose packageName=docker/compose versioning=semver
compose_version = optional(string, "v5.3.1")
# renovate: datasource=github-releases depName=docker-buildx packageName=docker/buildx versioning=semver
buildx_version = optional(string, "v0.35.0")
}), {})

managed_runtime = optional(object({
enabled = optional(bool, true)
internal_services_enabled = optional(bool, false)
internal_services_auto_update = optional(bool, false)
artifacts = optional(list(object({
name = string
url = string
sha256 = string
path = string
mode = optional(string, "0755")
owner = optional(string, "root")
group = optional(string, "root")
restart = optional(string, "")
})), [])
}), {})

vault = optional(object({
addr = optional(string, "")
namespace = optional(string, "")
role = optional(string, "")
agent_enabled = optional(bool, false)
auth_method = optional(string, "auto")
gcp_auth_mount_path = optional(string, "auth/gcp")
agent_token_path = optional(string, "/mnt/disks/data/vault/token")
agent_additional_config = optional(string, "")
agent_templates = optional(list(object({
destination = string
contents = string
perms = optional(string, "0640")
command = optional(string, "")
})), [])
}), {})

extra_env = optional(map(string), {})
})
| `{}` | no | +| [runtime](#input\_runtime) | Provider-neutral compose/runtime settings. |
object({
rootfs = optional(string, "")
rootfs_archive_url = optional(string, "")
rootfs_archive_sha256 = optional(string, "")
users = optional(map(list(string)), {})

compose = optional(object({
primary = optional(string, "")
ingress_port = optional(number, 80)
ingress = optional(object({
letsencrypt = optional(bool, false)
bot_mitigation = optional(bool, false)
mode = optional(string, "")
domain = optional(string, "")
acme_email = optional(string, "")
trusted_ips = optional(list(string), [])
max_upload_size = optional(string, "")
upload_timeout = optional(string, "")
}), {})
repo = optional(string, "")
branch = optional(string, "")
projects = optional(map(object({
docker_compose_repo = string
docker_compose_branch = optional(string)
project_dir = optional(string)
compose_project_name = optional(string)
ingress_port = optional(number)
ingress = optional(object({
letsencrypt = optional(bool)
bot_mitigation = optional(bool)
mode = optional(string)
domain = optional(string)
acme_email = optional(string)
trusted_ips = optional(list(string))
max_upload_size = optional(string)
upload_timeout = optional(string)
}), {})
sitectl_context_name = optional(string)
sitectl_plugin = optional(string)
sitectl_environment = optional(string)
sitectl_packages = optional(list(string))
sitectl_verify_args = optional(list(string))
docker_compose_init = optional(list(string))
docker_compose_up = optional(list(string))
docker_compose_down = optional(list(string))
docker_compose_rollout = optional(list(string))
})), {})
init = optional(list(string))
up = optional(list(string))
down = optional(list(string))
rollout = optional(list(string))
}), {})

sitectl = optional(object({
packages = optional(list(string))
version = optional(string, "latest")
package_versions = optional(map(string), {})
context_name = optional(string, "")
plugin = optional(string, "core")
environment = optional(string, "production")
verify_args = optional(list(string), [])
}), {})

docker = optional(object({
# renovate: datasource=github-releases depName=docker-compose packageName=docker/compose versioning=semver
compose_version = optional(string, "v5.3.1")
# renovate: datasource=github-releases depName=docker-buildx packageName=docker/buildx versioning=semver
buildx_version = optional(string, "v0.35.0")
}), {})

managed_runtime = optional(object({
enabled = optional(bool, true)
internal_services_enabled = optional(bool, false)
internal_services_auto_update = optional(bool, false)
artifacts = optional(list(object({
name = string
url = string
sha256 = string
path = string
mode = optional(string, "0755")
owner = optional(string, "root")
group = optional(string, "root")
restart = optional(string, "")
})), [])
}), {})

vault = optional(object({
addr = optional(string, "")
namespace = optional(string, "")
role = optional(string, "")
agent_enabled = optional(bool, false)
auth_method = optional(string, "auto")
gcp_auth_mount_path = optional(string, "auth/gcp")
agent_token_path = optional(string, "/mnt/disks/data/vault/token")
agent_additional_config = optional(string, "")
agent_templates = optional(list(object({
destination = string
contents = string
perms = optional(string, "0640")
command = optional(string, "")
})), [])
}), {})

extra_env = optional(map(string), {})
})
| `{}` | no | | [template](#input\_template) | Optional compose template preset. Supported values are archivesspace, ojs, isle, drupal, wp, omeka-s, and omeka-classic. Explicit runtime settings override preset defaults. | `string` | `""` | no | ## Outputs diff --git a/ansible/README.md b/ansible/README.md index ab7285f..603885c 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -90,7 +90,7 @@ all: sitectl: environment: production package_versions: - sitectl-isle: v0.19.0 + sitectl-isle: v1.0.0 wp-prod.example.edu: ansible_user: debian cloud_compose_name: wp-prod diff --git a/ci/config-management-smoke-inner.sh b/ci/config-management-smoke-inner.sh index 8489319..63ef32d 100755 --- a/ci/config-management-smoke-inner.sh +++ b/ci/config-management-smoke-inner.sh @@ -262,9 +262,9 @@ assert env["DOCKER_COMPOSE_REPO"] == "https://github.com/libops/isle" assert env["SITECTL_PLUGIN"] == "isle" assert "sitectl-isle" in env["SITECTL_PACKAGES"].split() assert json.loads(env["SITECTL_PACKAGE_VERSIONS"]) == { - "sitectl": "v0.40.0", - "sitectl-drupal": "v0.12.0", - "sitectl-isle": "v0.19.0", + "sitectl": "v1.0.0", + "sitectl-drupal": "v1.0.0", + "sitectl-isle": "v1.0.0", } assert project["docker_compose_repo"] == "https://github.com/libops/isle" assert project["project_dir"] == "/mnt/disks/data/libops/isle/main" diff --git a/ci/terraform-validate.sh b/ci/terraform-validate.sh index 977e2d1..17e0156 100644 --- a/ci/terraform-validate.sh +++ b/ci/terraform-validate.sh @@ -34,10 +34,10 @@ validate_public_provider_graph() { expected_sources=$'hashicorp/cloudinit\nhashicorp/google\nhashicorp/time' ;; providers/do) - expected_sources=$'digitalocean/digitalocean\nhashicorp/cloudinit' + expected_sources='digitalocean/digitalocean' ;; providers/linode) - expected_sources=$'hashicorp/cloudinit\nlinode/linode' + expected_sources='linode/linode' ;; *) return 0 diff --git a/docs/managed-runtime.md b/docs/managed-runtime.md index d418ff9..630426f 100644 --- a/docs/managed-runtime.md +++ b/docs/managed-runtime.md @@ -26,10 +26,11 @@ core and plugins independently. The provider-neutral backward-compatible fallback only for an installed package with neither a template selector nor an explicit per-package selector. -The ISLE preset is an intentional temporary exception to the v1 defaults. It -stays on sitectl v0.40.0, sitectl-drupal v0.12.0, and sitectl-isle v0.19.0 until -the remaining ISLE components can ship together as v1. Do not combine the -pre-v1 ISLE plugin with the v1 core or Drupal plugin. +All presets select coordinated sitectl v1 release packages. The ISLE preset +uses the `libops/isle` v1.1.0 template with sitectl, sitectl-drupal, and +sitectl-isle v1.0.0. Every other application preset remains on its v1.0.0 +template contract. Override the template or package selectors only as one +reviewed, compatible release set. Omitting `runtime.sitectl.packages` selects the template's package set. An explicit list replaces that set; `packages = []` or `packages = ["sitectl"]` @@ -50,9 +51,9 @@ runtime = { "sitectl-isle", ] package_versions = { - sitectl = "v0.40.0" - sitectl-drupal = "v0.12.0" - sitectl-isle = "v0.19.0" + sitectl = "v1.0.0" + sitectl-drupal = "v1.0.0" + sitectl-isle = "v1.0.0" } plugin = "isle" } diff --git a/docs/runtime-contracts.md b/docs/runtime-contracts.md index 927e7db..9ad177c 100644 --- a/docs/runtime-contracts.md +++ b/docs/runtime-contracts.md @@ -122,7 +122,9 @@ The generated app env file exports `COMPOSE_BIND_PORT` for that purpose. `docker_compose_branch` (the `runtime.compose.branch` input at the public module boundary) accepts either a branch/tag name or a full 40-character Git -commit. The source-preparation and `init` phases follow a configured moving ref. +commit. When the public input is omitted or empty, the selected template +preset supplies its reviewed branch; the no-preset registry default remains +`main`. The source-preparation and `init` phases follow a configured moving ref. An ordinary `up` or service restart instead validates and preserves the commit selected by the last successful init or rollout. This keeps a detached feature or pull-request deployment operable until an explicit rollout selects another diff --git a/internal/contracttest/template_version_test.go b/internal/contracttest/template_version_test.go index afc30ad..ba1b401 100644 --- a/internal/contracttest/template_version_test.go +++ b/internal/contracttest/template_version_test.go @@ -14,6 +14,7 @@ type templateRegistry struct { type templateDefinition struct { Branch string `json:"branch"` + ExtraEnv map[string]string `json:"extra_env"` Packages []string `json:"packages"` PackageVersions map[string]string `json:"package_versions"` } @@ -39,12 +40,10 @@ func TestTemplateVersionContract(t *testing.T) { "sitectl": "v1.0.0", "sitectl-drupal": "v1.0.0", }, - // ISLE remains on its last released pre-v1 compatibility set until - // the outstanding ISLE components are ready for a coordinated v1. "isle": { - "sitectl": "v0.40.0", - "sitectl-drupal": "v0.12.0", - "sitectl-isle": "v0.19.0", + "sitectl": "v1.0.0", + "sitectl-drupal": "v1.0.0", + "sitectl-isle": "v1.0.0", }, "ojs": { "sitectl": "v1.0.0", @@ -81,8 +80,19 @@ func TestTemplateVersionContract(t *testing.T) { if !maps.Equal(definition.PackageVersions, expected) { t.Errorf("template %q package versions diverged:\nexpected %s\nactual %s", name, prettyJSON(t, expected), prettyJSON(t, definition.PackageVersions)) } - if definition.Branch != "v1.0.0" { - t.Errorf("template %q branch = %q, want stable contract v1.0.0", name, definition.Branch) + expectedBranch := "v1.0.0" + if name == "isle" { + expectedBranch = "v1.1.0" + } + if definition.Branch != expectedBranch { + t.Errorf("template %q branch = %q, want stable contract %s", name, definition.Branch, expectedBranch) + } + expectedExtraEnv := map[string]string{} + if name == "isle" { + expectedExtraEnv["ISLANDORA_TAG"] = "6.3.19" + } + if !maps.Equal(definition.ExtraEnv, expectedExtraEnv) { + t.Errorf("template %q application environment diverged:\nexpected %s\nactual %s", name, prettyJSON(t, expectedExtraEnv), prettyJSON(t, definition.ExtraEnv)) } } @@ -122,6 +132,7 @@ func TestTemplateVersionContract(t *testing.T) { requireContains(t, content, "if contains(keys(local.template.package_versions), package)", relativePath+" template package-version filter") requireContains(t, content, "package_versions = merge(local.template_sitectl_package_versions, local.input_sitectl.package_versions)", relativePath+" explicit package-version override") requireContains(t, content, "local.input_sitectl.packages == null ? local.template.packages : local.input_sitectl.packages", relativePath+" omitted-package handling") + requireContains(t, content, "extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env)", relativePath+" template application environment merge") } for _, relativePath := range []string{"examples/binpack/main.tf", "docs/examples.md"} { diff --git a/main.tf b/main.tf index 74fa2e2..dab7d7c 100644 --- a/main.tf +++ b/main.tf @@ -40,6 +40,7 @@ locals { } runtime = merge(var.runtime, { + extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env) compose = merge(local.input_compose, { repo = ( trimspace(local.input_compose.repo) != "" diff --git a/providers/do/main.tf b/providers/do/main.tf index a2a6625..f182566 100644 --- a/providers/do/main.tf +++ b/providers/do/main.tf @@ -2,10 +2,6 @@ terraform { required_version = ">= 1.3.0" required_providers { - cloudinit = { - source = "hashicorp/cloudinit" - version = "~> 2.3" - } digitalocean = { source = "digitalocean/digitalocean" version = "~> 2.0" @@ -35,6 +31,7 @@ locals { } runtime = merge(var.runtime, { + extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env) compose = merge(local.input_compose, { repo = ( trimspace(local.input_compose.repo) != "" diff --git a/providers/do/template_versions.tftest.hcl b/providers/do/template_versions.tftest.hcl index 103be07..781c11c 100644 --- a/providers/do/template_versions.tftest.hcl +++ b/providers/do/template_versions.tftest.hcl @@ -1,4 +1,3 @@ -mock_provider "cloudinit" {} mock_provider "digitalocean" {} run "custom_package_set_merges_only_applicable_template_versions" { @@ -27,6 +26,16 @@ run "custom_package_set_merges_only_applicable_template_versions" { } error_message = "The DigitalOcean entrypoint must filter template selectors and preserve explicit overrides." } + + assert { + condition = local.runtime.compose.branch == "v1.1.0" + error_message = "The DigitalOcean entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied." + } + + assert { + condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19" + error_message = "The DigitalOcean ISLE preset must supply its required application environment." + } } run "explicit_core_only_package_set_disables_template_plugins" { @@ -46,7 +55,7 @@ run "explicit_core_only_package_set_disables_template_plugins" { assert { condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == { - sitectl = "v0.40.0" + sitectl = "v1.0.0" } error_message = "The DigitalOcean entrypoint must preserve an explicit core-only package set." } diff --git a/providers/do/variables.tf b/providers/do/variables.tf index 60de3c9..2031d40 100644 --- a/providers/do/variables.tf +++ b/providers/do/variables.tf @@ -76,7 +76,7 @@ variable "runtime" { upload_timeout = optional(string, "") }), {}) repo = optional(string, "") - branch = optional(string, "main") + branch = optional(string, "") projects = optional(map(object({ docker_compose_repo = string docker_compose_branch = optional(string) diff --git a/providers/gcp/main.tf b/providers/gcp/main.tf index f81a1f1..308a9d3 100644 --- a/providers/gcp/main.tf +++ b/providers/gcp/main.tf @@ -39,6 +39,7 @@ locals { } runtime = merge(var.runtime, { + extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env) compose = merge(local.input_compose, { repo = ( trimspace(local.input_compose.repo) != "" diff --git a/providers/gcp/template_versions.tftest.hcl b/providers/gcp/template_versions.tftest.hcl index ab65579..dd10162 100644 --- a/providers/gcp/template_versions.tftest.hcl +++ b/providers/gcp/template_versions.tftest.hcl @@ -36,6 +36,16 @@ run "custom_package_set_merges_only_applicable_template_versions" { } error_message = "The GCP entrypoint must filter template selectors and preserve explicit overrides." } + + assert { + condition = local.runtime.compose.branch == "v1.1.0" + error_message = "The GCP entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied." + } + + assert { + condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19" + error_message = "The GCP ISLE preset must supply its required application environment." + } } run "explicit_core_only_package_set_disables_template_plugins" { @@ -57,7 +67,7 @@ run "explicit_core_only_package_set_disables_template_plugins" { assert { condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == { - sitectl = "v0.40.0" + sitectl = "v1.0.0" } error_message = "The GCP entrypoint must preserve an explicit core-only package set." } diff --git a/providers/gcp/variables.tf b/providers/gcp/variables.tf index d041df4..0cbf042 100644 --- a/providers/gcp/variables.tf +++ b/providers/gcp/variables.tf @@ -206,7 +206,7 @@ variable "runtime" { upload_timeout = optional(string, "") }), {}) repo = optional(string, "") - branch = optional(string, "main") + branch = optional(string, "") projects = optional(map(object({ docker_compose_repo = string docker_compose_branch = optional(string) diff --git a/providers/linode/main.tf b/providers/linode/main.tf index f43f9f6..19078c2 100644 --- a/providers/linode/main.tf +++ b/providers/linode/main.tf @@ -2,10 +2,6 @@ terraform { required_version = ">= 1.3.0" required_providers { - cloudinit = { - source = "hashicorp/cloudinit" - version = "~> 2.3" - } linode = { source = "linode/linode" version = "~> 4.0" @@ -35,6 +31,7 @@ locals { } runtime = merge(var.runtime, { + extra_env = merge(try(local.template.extra_env, {}), var.runtime.extra_env) compose = merge(local.input_compose, { repo = ( trimspace(local.input_compose.repo) != "" diff --git a/providers/linode/template_versions.tftest.hcl b/providers/linode/template_versions.tftest.hcl index 76f04a4..460b3a2 100644 --- a/providers/linode/template_versions.tftest.hcl +++ b/providers/linode/template_versions.tftest.hcl @@ -1,4 +1,3 @@ -mock_provider "cloudinit" {} mock_provider "linode" {} run "custom_package_set_merges_only_applicable_template_versions" { @@ -32,6 +31,16 @@ run "custom_package_set_merges_only_applicable_template_versions" { } error_message = "The Linode entrypoint must filter template selectors and preserve explicit overrides." } + + assert { + condition = local.runtime.compose.branch == "v1.1.0" + error_message = "The Linode entrypoint must inherit the ISLE v1.1.0 template branch when no override is supplied." + } + + assert { + condition = local.runtime.extra_env.ISLANDORA_TAG == "6.3.19" + error_message = "The Linode ISLE preset must supply its required application environment." + } } run "explicit_core_only_package_set_disables_template_plugins" { @@ -56,7 +65,7 @@ run "explicit_core_only_package_set_disables_template_plugins" { assert { condition = local.runtime.sitectl.packages == tolist(["sitectl"]) && local.runtime.sitectl.package_versions == { - sitectl = "v0.40.0" + sitectl = "v1.0.0" } error_message = "The Linode entrypoint must preserve an explicit core-only package set." } diff --git a/providers/linode/variables.tf b/providers/linode/variables.tf index 4ad3d7d..7d46c50 100644 --- a/providers/linode/variables.tf +++ b/providers/linode/variables.tf @@ -88,7 +88,7 @@ variable "runtime" { upload_timeout = optional(string, "") }), {}) repo = optional(string, "") - branch = optional(string, "main") + branch = optional(string, "") projects = optional(map(object({ docker_compose_repo = string docker_compose_branch = optional(string) diff --git a/salt/cloud-compose/README.md b/salt/cloud-compose/README.md index a05e5d4..9c4937e 100644 --- a/salt/cloud-compose/README.md +++ b/salt/cloud-compose/README.md @@ -111,7 +111,7 @@ cloud_compose: sitectl: environment: production package_versions: - sitectl-isle: v0.19.0 + sitectl-isle: v1.0.0 ``` Apply: diff --git a/template_versions.tftest.hcl b/template_versions.tftest.hcl index bf9f3c9..b33564c 100644 --- a/template_versions.tftest.hcl +++ b/template_versions.tftest.hcl @@ -33,6 +33,11 @@ run "default_template_uses_v1_core" { } error_message = "The default template must select the released sitectl v1 core." } + + assert { + condition = local.compose.branch == "main" + error_message = "The no-preset path must retain the registry's main branch fallback." + } } run "non_isle_template_uses_v1_release_set" { @@ -59,9 +64,14 @@ run "non_isle_template_uses_v1_release_set" { } error_message = "Non-ISLE templates must select their coordinated sitectl v1 release set." } + + assert { + condition = local.compose.branch == "v1.0.0" + error_message = "Non-ISLE templates must retain their stable v1.0.0 template contract." + } } -run "isle_template_uses_released_pre_v1_package_set" { +run "isle_template_uses_v1_release_set" { command = plan variables { @@ -80,11 +90,55 @@ run "isle_template_uses_released_pre_v1_package_set" { assert { condition = local.sitectl.package_versions == { - sitectl = "v0.40.0" - sitectl-drupal = "v0.12.0" - sitectl-isle = "v0.19.0" + sitectl = "v1.0.0" + sitectl-drupal = "v1.0.0" + sitectl-isle = "v1.0.0" } - error_message = "The Isle template must select its reviewed core and plugin release set by default." + error_message = "The ISLE template must select its coordinated sitectl v1 release set by default." + } + + assert { + condition = local.compose.branch == "v1.1.0" + error_message = "The ISLE preset must select the stable v1.1.0 template contract." + } + + assert { + condition = ( + length(keys(local.runtime.extra_env)) == 1 && + local.runtime.extra_env.ISLANDORA_TAG == "6.3.19" + ) + error_message = "The ISLE preset must supply the minimum supported Islandora image tag." + } +} + +run "explicit_application_environment_overrides_template_defaults" { + command = plan + + variables { + name = "template-versions" + cloud_provider = "gcp" + template = "isle" + gcp = { + project_id = "test-project" + project_number = "123456789" + } + runtime = { + rootfs_archive_url = "https://example.invalid/cloud-compose.tar.gz" + rootfs_archive_sha256 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + extra_env = { + ISLANDORA_TAG = "6.3.20" + SITE_LABEL = "repository" + } + } + } + + assert { + condition = ( + length(keys(local.runtime.extra_env)) == 2 && + local.runtime.extra_env.ISLANDORA_TAG == "6.3.20" && + local.runtime.extra_env.SITE_LABEL == "repository" + ) + error_message = "Explicit application environment must override preset defaults without dropping additional values." } } @@ -114,7 +168,7 @@ run "explicit_package_versions_override_template_defaults" { assert { condition = local.sitectl.package_versions == { sitectl = "v0.40.1" - sitectl-drupal = "v0.12.0" + sitectl-drupal = "v1.0.0" sitectl-isle = "v0.19.1" } error_message = "Explicit per-package selectors must override only their matching template defaults." @@ -146,7 +200,7 @@ run "custom_package_set_filters_template_versions" { assert { condition = local.sitectl.package_versions == { - sitectl = "v0.40.0" + sitectl = "v1.0.0" sitectl-wp = "v0.6.1" } error_message = "Template selectors for packages omitted by a custom package set must not reach the runtime." @@ -175,7 +229,7 @@ run "explicit_core_only_package_set_disables_template_plugins" { assert { condition = local.sitectl.packages == tolist(["sitectl"]) && local.sitectl.package_versions == { - sitectl = "v0.40.0" + sitectl = "v1.0.0" } error_message = "An explicit core-only package set must not be mistaken for an omitted template package selection." } diff --git a/templates/apps.json b/templates/apps.json index 9d4ea5e..5a8600d 100644 --- a/templates/apps.json +++ b/templates/apps.json @@ -4,6 +4,7 @@ "branch": "main", "plugin": "core", "packages": ["sitectl"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0" } @@ -14,6 +15,7 @@ "branch": "v1.0.0", "plugin": "archivesspace", "packages": ["sitectl", "sitectl-archivesspace"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-archivesspace": "v1.0.0" @@ -24,6 +26,7 @@ "branch": "v1.0.0", "plugin": "ojs", "packages": ["sitectl", "sitectl-ojs"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-ojs": "v1.0.0" @@ -31,13 +34,16 @@ }, "isle": { "repo": "https://github.com/libops/isle", - "branch": "v1.0.0", + "branch": "v1.1.0", "plugin": "isle", "packages": ["sitectl", "sitectl-drupal", "sitectl-isle"], + "extra_env": { + "ISLANDORA_TAG": "6.3.19" + }, "package_versions": { - "sitectl": "v0.40.0", - "sitectl-drupal": "v0.12.0", - "sitectl-isle": "v0.19.0" + "sitectl": "v1.0.0", + "sitectl-drupal": "v1.0.0", + "sitectl-isle": "v1.0.0" } }, "drupal": { @@ -45,6 +51,7 @@ "branch": "v1.0.0", "plugin": "drupal", "packages": ["sitectl", "sitectl-drupal"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-drupal": "v1.0.0" @@ -55,6 +62,7 @@ "branch": "v1.0.0", "plugin": "wp", "packages": ["sitectl", "sitectl-wp"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-wp": "v1.0.0" @@ -65,6 +73,7 @@ "branch": "v1.0.0", "plugin": "omeka-s", "packages": ["sitectl", "sitectl-omeka-s"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-omeka-s": "v1.0.0" @@ -75,6 +84,7 @@ "branch": "v1.0.0", "plugin": "omeka-classic", "packages": ["sitectl", "sitectl-omeka-classic"], + "extra_env": {}, "package_versions": { "sitectl": "v1.0.0", "sitectl-omeka-classic": "v1.0.0" diff --git a/tests/config-management/ansible/smoke.yml b/tests/config-management/ansible/smoke.yml index 64a11ee..06761bf 100644 --- a/tests/config-management/ansible/smoke.yml +++ b/tests/config-management/ansible/smoke.yml @@ -47,9 +47,9 @@ sitectl: environment: production package_versions: - sitectl: v0.40.0 - sitectl-drupal: v0.12.0 - sitectl-isle: v0.19.0 + sitectl: v1.0.0 + sitectl-drupal: v1.0.0 + sitectl-isle: v1.0.0 managed_runtime: enabled: false internal_services_enabled: false @@ -119,7 +119,7 @@ - '(cloud_compose_application_env_file.content | b64decode | from_json).PORT == "9999"' - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].docker_compose_repo == "https://github.com/libops/isle"' - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].project_dir == "/mnt/disks/data/libops/isle/main"' - - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].compose_project_name == "libops-isle-v1-0-0"' + - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].compose_project_name == "libops-isle-v1-1-0"' - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].ingress.domain == "isle.example.edu"' - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].sitectl_plugin == "isle"' - '(cloud_compose_manifest_file.content | b64decode | from_json)["isle-prod"].init_commands == []' diff --git a/variables.tf b/variables.tf index 56be3f8..9905ee6 100644 --- a/variables.tf +++ b/variables.tf @@ -212,7 +212,7 @@ variable "runtime" { upload_timeout = optional(string, "") }), {}) repo = optional(string, "") - branch = optional(string, "main") + branch = optional(string, "") projects = optional(map(object({ docker_compose_repo = string docker_compose_branch = optional(string)