ignition-stack 0.6.1__tar.gz → 0.7.0__tar.gz

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.
Files changed (184) hide show
  1. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/PKG-INFO +4 -7
  2. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/README.md +3 -6
  3. ignition_stack-0.7.0/ignition_stack/__init__.py +1 -0
  4. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/base.py +4 -4
  5. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/cli.py +8 -234
  6. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/writer.py +10 -22
  7. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/config/io.py +6 -6
  8. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/config/schema.py +1 -1
  9. {ignition_stack-0.6.1/ignition_stack/lifecycle → ignition_stack-0.7.0/ignition_stack}/record.py +21 -26
  10. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/wizard_composer.py +1 -1
  11. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_architectures.py +9 -9
  12. ignition_stack-0.7.0/tests/test_create_standalone.py +217 -0
  13. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_declarative_io.py +11 -11
  14. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_disable_builtins.py +3 -12
  15. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_docs_cli_reference.py +0 -1
  16. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_registry.py +2 -2
  17. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_wizard_breadcrumb.py +14 -16
  18. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/verification/smoke/README.md +4 -4
  19. ignition_stack-0.6.1/ignition_stack/__init__.py +0 -1
  20. ignition_stack-0.6.1/ignition_stack/architectures/carry.py +0 -319
  21. ignition_stack-0.6.1/ignition_stack/lifecycle/__init__.py +0 -31
  22. ignition_stack-0.6.1/ignition_stack/lifecycle/cleanup.py +0 -72
  23. ignition_stack-0.6.1/ignition_stack/lifecycle/regenerate.py +0 -62
  24. ignition_stack-0.6.1/tests/test_init_standalone.py +0 -128
  25. ignition_stack-0.6.1/tests/test_lifecycle.py +0 -165
  26. ignition_stack-0.6.1/tests/test_switch_arch_registry.py +0 -345
  27. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/.gitignore +0 -0
  28. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/LICENSE +0 -0
  29. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/builtin_modules.yaml +0 -0
  30. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/__init__.py +0 -0
  31. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/advisory.py +0 -0
  32. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/basic.py +0 -0
  33. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/hub_and_spoke.py +0 -0
  34. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/architectures/scale_out.py +0 -0
  35. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/__init__.py +0 -0
  36. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/builtins.py +0 -0
  37. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/download.py +0 -0
  38. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/loader.py +0 -0
  39. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/schema.py +0 -0
  40. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/catalog/verify.py +0 -0
  41. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/commands/__init__.py +0 -0
  42. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/commands/modules.py +0 -0
  43. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/completion.py +0 -0
  44. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/__init__.py +0 -0
  45. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/engine.py +0 -0
  46. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/templates/footer.yaml.j2 +0 -0
  47. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/templates/header.yaml.j2 +0 -0
  48. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/templates/services/bootstrap.yaml.j2 +0 -0
  49. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/compose/templates/services/ignition.yaml.j2 +0 -0
  50. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/config/__init__.py +0 -0
  51. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/postsetup/__init__.py +0 -0
  52. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/postsetup/generator.py +0 -0
  53. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/services/__init__.py +0 -0
  54. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/services/loader.py +0 -0
  55. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/services/manifest.py +0 -0
  56. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/services/resolver.py +0 -0
  57. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/__init__.py +0 -0
  58. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/default-namespace/Sparkplug B/config.json +0 -0
  59. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/default-namespace/Sparkplug B/resource.json +0 -0
  60. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/general/config.json +0 -0
  61. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/general/resource.json +0 -0
  62. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/namespace-server-set/Sparkplug B-Default Set/config.json +0 -0
  63. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/namespace-server-set/Sparkplug B-Default Set/resource.json +0 -0
  64. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/server/Chariot SCADA/config.json.j2 +0 -0
  65. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/server/Chariot SCADA/resource.json +0 -0
  66. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/server-set/Default Set/config.json +0 -0
  67. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-engine/config/resources/core/com.cirruslink.mqtt.engine.gateway/server-set/Default Set/resource.json +0 -0
  68. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/general/config.json +0 -0
  69. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/general/resource.json +0 -0
  70. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/history-store/Default In-Memory Store/config.json +0 -0
  71. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/history-store/Default In-Memory Store/resource.json +0 -0
  72. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/server/Chariot SCADA/config.json.j2 +0 -0
  73. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/server/Chariot SCADA/resource.json +0 -0
  74. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/server-set/Default/config.json +0 -0
  75. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/server-set/Default/resource.json +0 -0
  76. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/transmitter/{{gateway}}/config.json.j2 +0 -0
  77. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/iiot/gateway-resources-mqtt-transmission/config/resources/core/com.cirruslink.mqtt.transmission.gateway/transmitter/{{gateway}}/resource.json +0 -0
  78. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/_default.md.j2 +0 -0
  79. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/connections.md.j2 +0 -0
  80. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/device-connection.md.j2 +0 -0
  81. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/gateway-network-link.md.j2 +0 -0
  82. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/identity-provider.md.j2 +0 -0
  83. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/kafka-connector.md.j2 +0 -0
  84. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/mcp-module.md.j2 +0 -0
  85. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/mqtt-engine-connection.md.j2 +0 -0
  86. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/opc-ua-connection.md.j2 +0 -0
  87. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/redundancy-pairing.md.j2 +0 -0
  88. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/reverse-proxy.md.j2 +0 -0
  89. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/redundancy/redundancy.xml.j2 +0 -0
  90. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/compose.yaml.j2 +0 -0
  91. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/manifest.yaml +0 -0
  92. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/seed/service/USAGE.md +0 -0
  93. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/seed/service/chariot-trial.sh +0 -0
  94. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/compose.yaml.j2 +0 -0
  95. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/manifest.yaml +0 -0
  96. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/seed/service/USAGE.md +0 -0
  97. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/compose.yaml.j2 +0 -0
  98. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/manifest.yaml +0 -0
  99. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/seed/service/USAGE.md +0 -0
  100. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/compose.yaml.j2 +0 -0
  101. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/manifest.yaml +0 -0
  102. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/seed/service/USAGE.md +0 -0
  103. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/compose.yaml.j2 +0 -0
  104. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/manifest.yaml +0 -0
  105. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/gateway-resources/config/resources/core/ignition/identity-provider/keycloak/config.json +0 -0
  106. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/gateway-resources/config/resources/core/ignition/identity-provider/keycloak/resource.json +0 -0
  107. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/service/import/ignition-realm.json +0 -0
  108. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/compose.yaml.j2 +0 -0
  109. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/manifest.yaml +0 -0
  110. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/seed/service/initdb/00-create-extra-databases.sh +0 -0
  111. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/compose.yaml.j2 +0 -0
  112. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/manifest.yaml +0 -0
  113. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/seed/service/USAGE.md +0 -0
  114. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/compose.yaml.j2 +0 -0
  115. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/manifest.yaml +0 -0
  116. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/seed/service/initdb/01-demo-collection.js +0 -0
  117. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/compose.yaml.j2 +0 -0
  118. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/manifest.yaml +0 -0
  119. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/seed/service/initdb/00-create-extra-databases.sh +0 -0
  120. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/compose.yaml.j2 +0 -0
  121. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/manifest.yaml +0 -0
  122. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/seed/service/USAGE.md +0 -0
  123. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/compose.yaml.j2 +0 -0
  124. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/manifest.yaml +0 -0
  125. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/seed/service/USAGE.md +0 -0
  126. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/compose.yaml.j2 +0 -0
  127. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/manifest.yaml +0 -0
  128. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/database-connection/db/config.json +0 -0
  129. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/database-connection/db/resource.json +0 -0
  130. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/secret-provider/internal-secret-provider/config.json +0 -0
  131. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/secret-provider/internal-secret-provider/resource.json +0 -0
  132. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/service/initdb/00-create-extra-databases.sh +0 -0
  133. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/compose.yaml.j2 +0 -0
  134. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/manifest.yaml +0 -0
  135. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/seed/service/enabled_plugins +0 -0
  136. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/docker-compose.yaml +0 -0
  137. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/scripts/docker-bootstrap.sh +0 -0
  138. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/config/resources/core/config-mode.json +0 -0
  139. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/config/resources/dev/config-mode.json +0 -0
  140. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/projects/.gitkeep +0 -0
  141. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/update_check.py +0 -0
  142. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/ignition_stack/wizard.py +0 -0
  143. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/modules.yaml +0 -0
  144. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/pyproject.toml +0 -0
  145. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/__init__.py +0 -0
  146. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/conftest.py +0 -0
  147. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/architectures/basic/docker-compose.yaml +0 -0
  148. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/architectures/hub-and-spoke/docker-compose.yaml +0 -0
  149. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/architectures/scale-out/docker-compose.yaml +0 -0
  150. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/architectures/scale-out-redundant/docker-compose.yaml +0 -0
  151. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/combos/hub-and-spoke-iiot-chariot/docker-compose.yaml +0 -0
  152. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/combos/network-split/docker-compose.yaml +0 -0
  153. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/combos/smoke-stack/docker-compose.yaml +0 -0
  154. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/scaleout-skeleton/docker-compose.yaml +0 -0
  155. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/chariot/docker-compose.yaml +0 -0
  156. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/db-mariadb/docker-compose.yaml +0 -0
  157. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/db-mongo/docker-compose.yaml +0 -0
  158. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/db-mysql/docker-compose.yaml +0 -0
  159. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/db-postgres/docker-compose.yaml +0 -0
  160. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/emqx/docker-compose.yaml +0 -0
  161. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/hivemq/docker-compose.yaml +0 -0
  162. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/kafka/docker-compose.yaml +0 -0
  163. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/keycloak/docker-compose.yaml +0 -0
  164. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/modbus-sim/docker-compose.yaml +0 -0
  165. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/n8n/docker-compose.yaml +0 -0
  166. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/opcua-sim/docker-compose.yaml +0 -0
  167. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/services/rabbitmq/docker-compose.yaml +0 -0
  168. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/golden/standalone-postgres/docker-compose.yaml +0 -0
  169. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_builtin_catalog_smoke.py +0 -0
  170. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_completion.py +0 -0
  171. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_compose_engine.py +0 -0
  172. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_iiot_overlay.py +0 -0
  173. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_manifest_invariants.py +0 -0
  174. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_modules_catalog.py +0 -0
  175. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_modules_cli.py +0 -0
  176. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_postsetup.py +0 -0
  177. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_redundancy.py +0 -0
  178. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_service_catalog.py +0 -0
  179. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_service_catalog_smoke.py +0 -0
  180. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_update_check.py +0 -0
  181. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_wizard_back_nav.py +0 -0
  182. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/tests/test_wizard_composer.py +0 -0
  183. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/verification/iiot-spike/README.md +0 -0
  184. {ignition_stack-0.6.1 → ignition_stack-0.7.0}/verification/redundancy-spike/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ignition-stack
3
- Version: 0.6.1
3
+ Version: 0.7.0
4
4
  Summary: CLI that generates ready-to-run Docker Compose stacks for Ignition 8.3 SCADA demos and SE engagements
5
5
  Author-email: Eric Knorr <etknorr@gmail.com>
6
6
  License: MIT
@@ -55,14 +55,14 @@ pipx install git+https://github.com/ia-eknorr/ignition-stack.git@<branch>
55
55
  Generate a project and bring it up:
56
56
 
57
57
  ```sh
58
- ignition-stack init demo --arch basic
58
+ ignition-stack create demo --arch basic
59
59
  cd demo
60
60
  docker compose up -d
61
61
  ```
62
62
 
63
63
  The gateway reaches RUNNING with no UI prompts. The admin user is `admin / password` and the gateway is at `http://localhost:9088`. The default Postgres credentials are `ignition / ignition` on the `db` service.
64
64
 
65
- Run `init` without `--arch` to walk the interactive wizard instead: it opens architecture-first, then layers database, edition, IIoT, services, and exposure on top, with a summary you can preview, tweak, or generate.
65
+ Run `create` without `--arch` to walk the interactive wizard instead: it opens architecture-first, then layers database, edition, IIoT, services, and exposure on top, with a summary you can preview, tweak, or generate.
66
66
 
67
67
  Everything that ships in the generated project is hand-readable: `docker-compose.yaml`, `.env`, `scripts/docker-bootstrap.sh`, and a `services/ignition/` resources tree the gateway reads on first boot.
68
68
 
@@ -70,11 +70,8 @@ Everything that ships in the generated project is hand-readable: `docker-compose
70
70
 
71
71
  | Command | What it does |
72
72
  | --- | --- |
73
- | `init <name>` | Generate a project at `./<name>/` from an architecture and a few prompts. |
73
+ | `create <name>` | Generate a project at `./<name>/` from an architecture and a few prompts. |
74
74
  | `modules` | Download, verify, and manage the `.modl` / JDBC catalog. |
75
- | `reset` | Re-run generation from an SE-demo project's recorded config. |
76
- | `switch-arch` | Reshape an SE-demo project under a different architecture. |
77
- | `wipe` | Remove this project's containers and volumes only. |
78
75
 
79
76
  See the [CLI reference](docs/docs/reference/cli.md) for every command, argument, and option.
80
77
 
@@ -26,14 +26,14 @@ pipx install git+https://github.com/ia-eknorr/ignition-stack.git@<branch>
26
26
  Generate a project and bring it up:
27
27
 
28
28
  ```sh
29
- ignition-stack init demo --arch basic
29
+ ignition-stack create demo --arch basic
30
30
  cd demo
31
31
  docker compose up -d
32
32
  ```
33
33
 
34
34
  The gateway reaches RUNNING with no UI prompts. The admin user is `admin / password` and the gateway is at `http://localhost:9088`. The default Postgres credentials are `ignition / ignition` on the `db` service.
35
35
 
36
- Run `init` without `--arch` to walk the interactive wizard instead: it opens architecture-first, then layers database, edition, IIoT, services, and exposure on top, with a summary you can preview, tweak, or generate.
36
+ Run `create` without `--arch` to walk the interactive wizard instead: it opens architecture-first, then layers database, edition, IIoT, services, and exposure on top, with a summary you can preview, tweak, or generate.
37
37
 
38
38
  Everything that ships in the generated project is hand-readable: `docker-compose.yaml`, `.env`, `scripts/docker-bootstrap.sh`, and a `services/ignition/` resources tree the gateway reads on first boot.
39
39
 
@@ -41,11 +41,8 @@ Everything that ships in the generated project is hand-readable: `docker-compose
41
41
 
42
42
  | Command | What it does |
43
43
  | --- | --- |
44
- | `init <name>` | Generate a project at `./<name>/` from an architecture and a few prompts. |
44
+ | `create <name>` | Generate a project at `./<name>/` from an architecture and a few prompts. |
45
45
  | `modules` | Download, verify, and manage the `.modl` / JDBC catalog. |
46
- | `reset` | Re-run generation from an SE-demo project's recorded config. |
47
- | `switch-arch` | Reshape an SE-demo project under a different architecture. |
48
- | `wipe` | Remove this project's containers and volumes only. |
49
46
 
50
47
  See the [CLI reference](docs/docs/reference/cli.md) for every command, argument, and option.
51
48
 
@@ -0,0 +1 @@
1
+ __version__ = "0.7.0"
@@ -173,10 +173,10 @@ def _matching_gateways(config: ProjectConfig, redundant_role: str) -> list:
173
173
  def can_host_redundant_role(config: ProjectConfig, redundant_role: str) -> bool:
174
174
  """True when ``config`` has exactly one gateway that can be paired as master.
175
175
 
176
- ``switch-arch`` uses this to decide whether redundancy intent recovered from
177
- the old stack can carry to the target architecture, without raising the way
178
- :func:`mark_redundant` does - an architecture-specific role (e.g. basic's
179
- ``gateway``) simply may not exist in the destination.
176
+ Used to check whether a redundancy role from a recorded config could carry
177
+ to a target architecture, without raising the way :func:`mark_redundant`
178
+ does - an architecture-specific role (e.g. basic's ``gateway``) simply may
179
+ not exist in the destination.
180
180
  """
181
181
  if redundant_role in _NON_REDUNDANT_ROLES:
182
182
  return False
@@ -1,19 +1,12 @@
1
1
  """Top-level Typer application.
2
2
 
3
- Phase 2 implements ``init`` for the standalone+Postgres walking skeleton.
4
- Phase 3 wires the real ``modules`` sub-app (catalog list/validate/download);
5
- ``reset`` and ``wipe`` remain visible placeholders so the command surface
6
- is stable from day one, with later phases filling them in.
7
-
8
- Phase 6 widens ``init`` with ``--arch``, ``--spokes``, ``--force``, and
9
- ``--edge-role`` for the system architectures, and falls into the interactive
10
- wizard when no architecture is named.
3
+ The CLI surface is intentionally narrow: ``create`` generates a new named
4
+ stack, and the ``modules`` sub-app manages the module catalog. Stacks are
5
+ short-lived; recreate with the recorded config rather than reshape in place.
11
6
  """
12
7
 
13
8
  from __future__ import annotations
14
9
 
15
- import subprocess
16
- from dataclasses import replace
17
10
  from pathlib import Path
18
11
 
19
12
  import typer
@@ -24,16 +17,9 @@ from ignition_stack.architectures import (
24
17
  ArchitectureError,
25
18
  ArchOptions,
26
19
  build_architecture,
27
- can_host_redundant_role,
28
20
  get_architecture,
29
21
  list_architectures,
30
22
  )
31
- from ignition_stack.architectures.carry import (
32
- carry_registry,
33
- database_carried_by_kind,
34
- detect_iiot_broker,
35
- is_default_representable,
36
- )
37
23
  from ignition_stack.commands.modules import modules_app
38
24
  from ignition_stack.completion import (
39
25
  complete_architecture,
@@ -52,17 +38,7 @@ from ignition_stack.config import (
52
38
  dump_config,
53
39
  load_config,
54
40
  )
55
- from ignition_stack.lifecycle import (
56
- LIFECYCLE_DIR,
57
- RECORD_NAME,
58
- CleanupError,
59
- LifecycleError,
60
- project_name,
61
- read_record,
62
- wipe_command,
63
- )
64
- from ignition_stack.lifecycle.regenerate import regenerate
65
- from ignition_stack.services.loader import load_all_services
41
+ from ignition_stack.record import RECORD_DIR, RECORD_NAME
66
42
  from ignition_stack.services.resolver import resolve
67
43
  from ignition_stack.update_check import (
68
44
  check_for_update,
@@ -133,7 +109,7 @@ def _arch_help() -> str:
133
109
 
134
110
 
135
111
  @app.command()
136
- def init(
112
+ def create(
137
113
  name: str = typer.Argument(
138
114
  ...,
139
115
  help="Project name. Becomes the directory, the compose project, and the gateway name.",
@@ -283,7 +259,7 @@ def init(
283
259
  """
284
260
  target = ((output_dir or Path.cwd()) / name).resolve()
285
261
 
286
- _validate_init_flags(arch=arch, from_file=from_file, dry_run=dry_run, fmt=output_format)
262
+ _validate_create_flags(arch=arch, from_file=from_file, dry_run=dry_run, fmt=output_format)
287
263
 
288
264
  # Name validation runs before either the wizard or the architecture build so
289
265
  # invalid names fail fast with a clear exit code (2), instead of bubbling
@@ -337,7 +313,7 @@ def init(
337
313
  console.print(" docker compose up -d")
338
314
  console.print(f" open {_gateway_open_url(config)} (admin / {config.admin_password})")
339
315
  console.print()
340
- console.print(f" config recorded in {LIFECYCLE_DIR}/ - run `ignition-stack reset` to " "regenerate or `switch-arch <name>` to reshape this stack.")
316
+ console.print(f" config recorded in {RECORD_DIR}/{RECORD_NAME} - pass it to" " `ignition-stack create <name> -f` to recreate or clone this stack")
341
317
 
342
318
 
343
319
  def _gateway_open_url(config: ProjectConfig) -> str:
@@ -353,7 +329,7 @@ def _gateway_open_url(config: ProjectConfig) -> str:
353
329
  return f"http://localhost:{config.gateways[0].http_port}"
354
330
 
355
331
 
356
- def _validate_init_flags(*, arch: str | None, from_file: Path | None, dry_run: bool, fmt: str | None) -> None:
332
+ def _validate_create_flags(*, arch: str | None, from_file: Path | None, dry_run: bool, fmt: str | None) -> None:
357
333
  """Enforce the mutual-exclusion + flag-applicability rules, or exit code 2.
358
334
 
359
335
  ``--from-file`` already fully specifies the topology, so combining it with
@@ -459,207 +435,5 @@ def _run_wizard_or_exit(name: str) -> ProjectConfig:
459
435
  raise typer.Exit(code=130) from exc
460
436
 
461
437
 
462
- @app.command()
463
- def reset(
464
- project_dir: Path = typer.Option( # noqa: B008 - Typer pattern
465
- Path("."),
466
- "--project-dir",
467
- "-C",
468
- help="The generated project to reset. Defaults to the current directory.",
469
- ),
470
- ) -> None:
471
- """Regenerate a project from its recorded config.
472
-
473
- Reads ``.ignition-stack/config.json``, clears the generated tree (keeping the
474
- record and the modules cache), and re-runs generation. Works on any project
475
- generated by this CLI; a directory without a record can't be reset.
476
- """
477
- project_dir = project_dir.resolve()
478
- try:
479
- config = read_record(project_dir)
480
- except LifecycleError as exc:
481
- console.print(f"[red]error[/red]: {exc}")
482
- raise typer.Exit(code=2) from exc
483
-
484
- files = regenerate(project_dir, config)
485
- console.print(f"[green]reset[/green] {project_dir}")
486
- console.print(f" {len(files)} file(s) regenerated from {LIFECYCLE_DIR}/{RECORD_NAME}")
487
-
488
-
489
- @app.command(name="switch-arch")
490
- def switch_arch(
491
- arch: str = typer.Argument(
492
- ...,
493
- help="System architecture to switch this stack to.",
494
- autocompletion=complete_architecture,
495
- ),
496
- project_dir: Path = typer.Option( # noqa: B008 - Typer pattern
497
- Path("."),
498
- "--project-dir",
499
- "-C",
500
- help="The generated project to reshape. Defaults to the current directory.",
501
- ),
502
- ) -> None:
503
- """Reshape a project under a different system architecture.
504
-
505
- Carries the recorded database, services, reverse-proxy, and edge intent over
506
- to the new architecture, then regenerates in place and re-records the result.
507
- """
508
- project_dir = project_dir.resolve()
509
- try:
510
- current = read_record(project_dir)
511
- except LifecycleError as exc:
512
- console.print(f"[red]error[/red]: {exc}")
513
- raise typer.Exit(code=2) from exc
514
-
515
- try:
516
- get_architecture(arch)
517
- except KeyError as exc:
518
- console.print(f"[red]error[/red]: {exc}")
519
- raise typer.Exit(code=2) from exc
520
-
521
- options = _options_from_config(current)
522
- # Redundancy is pinned to an architecture-specific role (e.g. basic's
523
- # 'gateway'), which the target architecture may not have. Building its base
524
- # topology lets us check before build_architecture's mark_redundant would
525
- # reject it - drop the intent with an advisory rather than failing the reshape.
526
- if options.redundant_role is not None and not can_host_redundant_role(get_architecture(arch).build(current.name, options), options.redundant_role):
527
- console.print(
528
- f"[yellow]note[/yellow]: redundancy on '{options.redundant_role}' was not "
529
- f"carried to {arch} (no matching gateway); re-apply with --redundant "
530
- "if the new topology has a role to pair"
531
- )
532
- options = replace(options, redundant_role=None)
533
- try:
534
- new_config = build_architecture(arch, current.name, options)
535
- except ArchitectureError as exc:
536
- console.print(f"[red]advisory[/red]: {exc}")
537
- raise typer.Exit(code=3) from exc
538
- except ValueError as exc:
539
- console.print(f"[red]error[/red]: {exc}")
540
- raise typer.Exit(code=2) from exc
541
-
542
- # Re-graft the richer registry shapes ArchOptions can't express (custom
543
- # ids, per-instance overrides, partial attachment sets, a second database),
544
- # re-mapping their attachments by role and dropping any that the new topology
545
- # can't host - each with a printed advisory. Resolve first so the
546
- # architecture's legacy database is already lowered into per-gateway
547
- # attachments; the carry's one-database-per-gateway guard then sees them and
548
- # won't over-attach. The carry's output is resolved again by regenerate
549
- # (resolve is idempotent).
550
- new_config = carry_registry(resolve(new_config), current, console)
551
-
552
- files = regenerate(project_dir, new_config)
553
- console.print(f"[green]switched[/green] {current.architecture or 'custom'} -> {arch}")
554
- console.print(f" {len(files)} file(s) regenerated")
555
-
556
-
557
- def _options_from_config(config: ProjectConfig) -> ArchOptions:
558
- """Recover the architecture inputs a switch should carry over from a recorded config.
559
-
560
- Edge intent is recovered from whichever gateway runs the Edge edition (or
561
- 'none' to keep the new architecture from re-introducing its edge default); the
562
- spoke count from the number of spoke-role gateways, the frontend count from
563
- the number of frontend-role gateways, and the network split is carried over
564
- verbatim so a reshape preserves the user's topology choice. Disabled
565
- built-in modules are carried over too (see below) so a reshape doesn't
566
- silently re-enable Vision/SFC/etc.
567
- """
568
- edge_roles = [gw.role or gw.name for gw in config.gateways if gw.ignition_edition == "edge"]
569
- spoke_count = sum(1 for gw in config.gateways if (gw.role or "") == "spoke")
570
- frontend_count = sum(1 for gw in config.gateways if (gw.role or "") == "frontend")
571
- # Redundancy intent is carried by the master node (the backup is re-derived
572
- # by the resolver), so recover the role/name of whichever gateway is the
573
- # master and let the new architecture re-expand the pair.
574
- redundant_role = next(
575
- (gw.role or gw.name for gw in config.gateways if gw.redundancy is not None and gw.redundancy.mode == "master"),
576
- None,
577
- )
578
- # Disabled built-ins are applied stack-wide, so carry over the slugs disabled
579
- # on EVERY gateway (the intersection) - that is the stack-wide intent, and it
580
- # won't over-disable a module that a hand-authored config turned off on only
581
- # one node. The target architecture re-applies it uniformly.
582
- disabled_sets = [set(gw.disable_builtins) for gw in config.gateways]
583
- disable_builtins = tuple(sorted(set.intersection(*disabled_sets))) if disabled_sets else ()
584
- # A recorded config is resolved: its database + services live in the
585
- # registry, not the legacy fields. Recover the architecture inputs from the
586
- # registry. The primary database rides database_kind (see below); the
587
- # non-database instances that are default-representable ride `services`.
588
- # IIoT intent is recovered from the attachment roles: a stack with any
589
- # mqtt-transmission/mqtt-engine attachment was built with apply_iiot, so set
590
- # iiot=True and the broker slug. build_architecture re-runs the overlay in the new
591
- # topology, re-mapping Transmission/Engine onto the new roles naturally; the
592
- # broker instance is therefore excluded from `services` below to avoid a
593
- # double-add. Anything richer than `services` can express (custom ids,
594
- # per-instance overrides, partial/role-specific attachments, a second
595
- # database) is carried after build_architecture by carry_registry.
596
- iiot_broker = detect_iiot_broker(config)
597
- catalog = load_all_services()
598
- representable = tuple(inst.service for inst in config.non_database_instances() if inst.service != iiot_broker and is_default_representable(inst, config, catalog))
599
- # The primary database rides database_kind only when it has the clean
600
- # canonical shape (id "db", default image/credentials, consumer on every
601
- # non-Edge gateway). A custom primary database - or any second database - is
602
- # left for carry_registry to re-graft, so database_kind stays None and the
603
- # architecture does not also lay down a colliding default DB.
604
- carried_db = database_carried_by_kind(config, catalog)
605
- return ArchOptions(
606
- spokes=spoke_count or 3,
607
- frontends=frontend_count or 1,
608
- edge_role=edge_roles[0] if edge_roles else "none",
609
- network_split=config.network_split,
610
- reverse_proxy=config.reverse_proxy,
611
- database_kind=carried_db.service if carried_db is not None else None,
612
- services=representable,
613
- redundant_role=redundant_role,
614
- disable_builtins=disable_builtins,
615
- iiot=iiot_broker is not None,
616
- iiot_broker=iiot_broker,
617
- )
618
-
619
-
620
- @app.command()
621
- def wipe(
622
- project_dir: Path = typer.Option( # noqa: B008 - Typer pattern
623
- Path("."),
624
- "--project-dir",
625
- "-C",
626
- help="The generated project to wipe. Defaults to the current directory.",
627
- ),
628
- dry_run: bool = typer.Option(
629
- False,
630
- "--dry-run",
631
- help="Print the scoped teardown command without running it.",
632
- ),
633
- ) -> None:
634
- """Remove only this project's containers, networks, and volumes.
635
-
636
- Runs ``docker compose -p <project> down -v --remove-orphans``; the ``-p``
637
- pin scopes the teardown to resources labelled with this compose project, so
638
- unrelated Docker resources on the host are never touched.
639
- """
640
- project_dir = project_dir.resolve()
641
- try:
642
- name = project_name(project_dir)
643
- except CleanupError as exc:
644
- console.print(f"[red]error[/red]: {exc}")
645
- raise typer.Exit(code=2) from exc
646
-
647
- command = wipe_command(name)
648
- if dry_run:
649
- console.print(" ".join(command))
650
- return
651
-
652
- try:
653
- completed = subprocess.run(command, cwd=project_dir, check=False)
654
- except FileNotFoundError as exc:
655
- console.print("[red]error[/red]: docker not found on PATH; cannot wipe.")
656
- raise typer.Exit(code=1) from exc
657
-
658
- if completed.returncode != 0:
659
- console.print(f"[red]error[/red]: `{' '.join(command)}` exited {completed.returncode}")
660
- raise typer.Exit(code=completed.returncode)
661
- console.print(f"[green]wiped[/green] project '{name}'")
662
-
663
-
664
438
  if __name__ == "__main__": # pragma: no cover
665
439
  app()
@@ -30,8 +30,8 @@ from ignition_stack.catalog.loader import CatalogLoadError, load_catalog
30
30
  from ignition_stack.catalog.schema import Catalog
31
31
  from ignition_stack.compose.engine import render_compose
32
32
  from ignition_stack.config.schema import ProjectConfig, ServiceInstance
33
- from ignition_stack.lifecycle.record import write_record
34
33
  from ignition_stack.postsetup import generate_post_setup
34
+ from ignition_stack.record import write_record
35
35
  from ignition_stack.services.loader import load_all_services, service_dir
36
36
  from ignition_stack.services.resolver import resolve
37
37
 
@@ -63,12 +63,7 @@ _IIOT_VERIFIED_BROKERS = frozenset({"chariot"})
63
63
  _BROKER_MQTT_USER: dict[str, str] = {"chariot": "admin"}
64
64
 
65
65
 
66
- def write_project(
67
- config: ProjectConfig,
68
- target_dir: Path,
69
- *,
70
- overwrite: bool = False,
71
- ) -> list[Path]:
66
+ def write_project(config: ProjectConfig, target_dir: Path) -> list[Path]:
72
67
  """Generate the project tree at ``target_dir``.
73
68
 
74
69
  The config is resolved first (implicit dependencies expanded - see
@@ -76,20 +71,16 @@ def write_project(
76
71
  the on-disk seeds agree on the same fully-expanded stack.
77
72
 
78
73
  Every project records its resolved config under ``.ignition-stack/`` so
79
- ``reset`` / ``switch-arch`` can regenerate or reshape it in place; the
80
- same artifact can be dumped with ``init --dry-run`` and rebuilt with
81
- ``init -f``.
82
-
83
- ``overwrite`` lets ``reset`` / ``switch-arch`` write into a directory
84
- that still holds the preserved ``.ignition-stack/`` record; normal ``init``
85
- leaves it ``False`` so a stray non-empty directory still refuses to clobber.
74
+ the same stack can be recreated or cloned with ``create <name> -f``; the
75
+ same artifact can be dumped with ``create --dry-run`` and rebuilt with
76
+ ``create -f``.
86
77
 
87
78
  Returns the list of files written (absolute paths), in the order they
88
79
  were written. Raises :class:`FileExistsError` if ``target_dir`` already
89
- has files and ``overwrite`` is ``False``.
80
+ has files.
90
81
  """
91
82
  target_dir = Path(target_dir).resolve()
92
- if not overwrite and target_dir.exists() and any(target_dir.iterdir()):
83
+ if target_dir.exists() and any(target_dir.iterdir()):
93
84
  raise FileExistsError(f"target directory '{target_dir}' is not empty; refusing to overwrite")
94
85
  target_dir.mkdir(parents=True, exist_ok=True)
95
86
 
@@ -520,7 +511,7 @@ COMPOSE := docker compose
520
511
  PROJECT := @@PROJECT@@
521
512
 
522
513
  .DEFAULT_GOAL := help
523
- .PHONY: help up down logs wipe reset
514
+ .PHONY: help up down logs wipe
524
515
 
525
516
  help: ## List available targets.
526
517
  \t@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) \\
@@ -537,17 +528,14 @@ logs: ## Follow logs for every service.
537
528
 
538
529
  wipe: ## Remove ONLY this project's containers, networks, and volumes.
539
530
  \t$(COMPOSE) -p $(PROJECT) down -v --remove-orphans
540
-
541
- reset: ## Regenerate this project from its recorded config.
542
- \tignition-stack reset
543
531
  """
544
532
 
545
533
 
546
534
  def _write_makefile(config: ProjectConfig, target_dir: Path) -> Path:
547
- """Write the project ``Makefile`` (up/down/logs/wipe/reset).
535
+ """Write the project ``Makefile`` (up/down/logs/wipe).
548
536
 
549
537
  ``wipe`` is scoped to the compose project name so it cannot reach unrelated
550
- Docker resources; that scoping is the Phase-7 cleanup contract.
538
+ Docker resources on the host.
551
539
  """
552
540
  body = _MAKEFILE.replace("@@PROJECT@@", config.name)
553
541
  dst = target_dir / "Makefile"
@@ -1,12 +1,12 @@
1
1
  """Serialize and load a resolved :class:`ProjectConfig` as YAML or JSON.
2
2
 
3
3
  The resolved config is the CLI's full build input - project name, gateways,
4
- networks, database, services, env. ``ignition-stack init --dry-run`` dumps it;
5
- ``ignition-stack init -f <file>`` loads it back and builds from it. The same
6
- artifact is what the lifecycle record (:mod:`ignition_stack.lifecycle.record`)
7
- persists, so dump/edit/rebuild and reset/switch-arch share one schema.
4
+ networks, database, services, env. ``ignition-stack create --dry-run`` dumps it;
5
+ ``ignition-stack create -f <file>`` loads it back and builds from it. The same
6
+ artifact is what the record module (:mod:`ignition_stack.record`) persists, so
7
+ dump/edit/rebuild share one schema.
8
8
 
9
- JSON dumps reuse pydantic's ``model_dump_json`` so the on-disk lifecycle record
9
+ JSON dumps reuse pydantic's ``model_dump_json`` so the on-disk config record
10
10
  stays byte-identical to what it was before this module existed. YAML dumps go
11
11
  through ruamel (already the compose engine's YAML library) in safe mode, which
12
12
  emits block-style, alias-free output suitable for hand-editing by a person or
@@ -55,7 +55,7 @@ def _yaml() -> YAML:
55
55
  def dump_config(config: ProjectConfig, fmt: Format = "yaml") -> str:
56
56
  """Serialize ``config`` to a string in ``fmt`` ('yaml' or 'json').
57
57
 
58
- The JSON form matches the lifecycle record exactly (2-space indent, trailing
58
+ The JSON form matches the config record exactly (2-space indent, trailing
59
59
  newline). The YAML form is the hand-authorable artifact: block style, keys in
60
60
  schema declaration order, no anchors.
61
61
  """
@@ -557,7 +557,7 @@ class ProjectConfig(BaseModel):
557
557
  "('basic', 'scale-out', 'hub-and-spoke'). "
558
558
  "Informational - the compose engine reads from the resolved "
559
559
  "fields, not this slug - but lets generated files (header "
560
- "comment, lifecycle records) name the architecture they came from."
560
+ "comment, config records) name the architecture they came from."
561
561
  ),
562
562
  )
563
563
 
@@ -1,17 +1,16 @@
1
- """Lifecycle record: every generated project's serialized resolved config.
2
-
3
- Each project keeps a copy of its resolved
4
- :class:`~ignition_stack.config.schema.ProjectConfig` under
5
- ``.ignition-stack/config.json``. That record is the one primitive ``reset`` and
6
- ``switch-arch`` need: they read it back, optionally reshape it, and re-run
7
- generation - no second trip through the wizard.
8
-
9
- The record is just the declarative config artifact (see
10
- :mod:`ignition_stack.config.io`) written to a known path; ``init -f <file>``
11
- consumes the identical format. ``read_record`` is a thin wrapper over
12
- ``load_config`` that reports a missing record as a :class:`LifecycleError` so
13
- ``reset`` / ``switch-arch`` can fail cleanly on a directory that was never
14
- generated by this CLI.
1
+ """The resolved config record every generated project writes.
2
+
3
+ Every generation pass writes the fully-resolved
4
+ :class:`~ignition_stack.config.schema.ProjectConfig` to
5
+ ``.ignition-stack/config.json``. That file is the only artifact
6
+ ``ignition-stack create`` needs to recreate or clone the stack:
7
+
8
+ ignition-stack create <name> -f .ignition-stack/config.json
9
+
10
+ The positional name overrides the recorded one, so the same file clones
11
+ a stack under a new name. Editing the file before re-running is a
12
+ supported workflow - it is the same YAML/JSON schema that ``--dry-run``
13
+ dumps and ``-f`` rebuilds from.
15
14
  """
16
15
 
17
16
  from __future__ import annotations
@@ -23,21 +22,21 @@ from ignition_stack.config.schema import ProjectConfig
23
22
 
24
23
  # The directory the record lives in, at the project root. Dot-prefixed so it
25
24
  # stays out of the way of the hand-readable compose/.env/Makefile tree.
26
- LIFECYCLE_DIR = ".ignition-stack"
25
+ RECORD_DIR = ".ignition-stack"
27
26
  RECORD_NAME = "config.json"
28
27
 
29
28
 
30
- class LifecycleError(Exception):
31
- """Raised when a lifecycle operation can't find or read its record."""
29
+ class RecordError(Exception):
30
+ """Raised when a project's config record can't be found or read."""
32
31
 
33
32
 
34
33
  def record_path(project_dir: Path) -> Path:
35
34
  """Where the recorded config lives for a project rooted at ``project_dir``."""
36
- return Path(project_dir) / LIFECYCLE_DIR / RECORD_NAME
35
+ return Path(project_dir) / RECORD_DIR / RECORD_NAME
37
36
 
38
37
 
39
38
  def has_record(project_dir: Path) -> bool:
40
- """True when ``project_dir`` carries a lifecycle record."""
39
+ """True when ``project_dir`` carries a config record."""
41
40
  return record_path(project_dir).is_file()
42
41
 
43
42
 
@@ -56,18 +55,14 @@ def write_record(config: ProjectConfig, project_dir: Path) -> Path:
56
55
  def read_record(project_dir: Path) -> ProjectConfig:
57
56
  """Load the recorded config for a project.
58
57
 
59
- Raises :class:`LifecycleError` when the project has no record (a directory
58
+ Raises :class:`RecordError` when the project has no record (a directory
60
59
  that was never generated by this CLI, or one whose record was removed) or
61
60
  when the record can't be parsed or validated.
62
61
  """
63
62
  src = record_path(project_dir)
64
63
  if not src.is_file():
65
- raise LifecycleError(
66
- f"no lifecycle record at {src}. This directory was not generated by "
67
- "ignition-stack (or its record was removed); reset/switch-arch "
68
- "need a project with a recorded config."
69
- )
64
+ raise RecordError(f"no config record at {src}. This directory was not generated by " "ignition-stack (or its record was removed).")
70
65
  try:
71
66
  return load_config(src)
72
67
  except ConfigIOError as exc:
73
- raise LifecycleError(str(exc)) from exc
68
+ raise RecordError(str(exc)) from exc
@@ -84,7 +84,7 @@ class ComposerResult:
84
84
  the same exit-130 path the architecture flow uses). ``architecture``/
85
85
  ``options`` carry the originating architecture so the
86
86
  :class:`~ignition_stack.wizard.WizardOutcome` stays populated for the
87
- lifecycle record and tests.
87
+ config record and tests.
88
88
  """
89
89
 
90
90
  config: ProjectConfig