ignition-stack 0.6.0__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.
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/PKG-INFO +4 -7
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/README.md +3 -6
- ignition_stack-0.7.0/ignition_stack/__init__.py +1 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/base.py +4 -4
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/cli.py +8 -234
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/writer.py +10 -22
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/config/io.py +6 -6
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/config/schema.py +1 -1
- {ignition_stack-0.6.0/ignition_stack/lifecycle → ignition_stack-0.7.0/ignition_stack}/record.py +21 -26
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/wizard_composer.py +1 -1
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_architectures.py +9 -9
- ignition_stack-0.7.0/tests/test_create_standalone.py +217 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_declarative_io.py +11 -11
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_disable_builtins.py +3 -12
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_docs_cli_reference.py +0 -1
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_registry.py +2 -2
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_wizard_breadcrumb.py +14 -16
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/verification/smoke/README.md +4 -4
- ignition_stack-0.6.0/ignition_stack/__init__.py +0 -1
- ignition_stack-0.6.0/ignition_stack/architectures/carry.py +0 -319
- ignition_stack-0.6.0/ignition_stack/lifecycle/__init__.py +0 -31
- ignition_stack-0.6.0/ignition_stack/lifecycle/cleanup.py +0 -72
- ignition_stack-0.6.0/ignition_stack/lifecycle/regenerate.py +0 -62
- ignition_stack-0.6.0/tests/test_init_standalone.py +0 -128
- ignition_stack-0.6.0/tests/test_lifecycle.py +0 -165
- ignition_stack-0.6.0/tests/test_switch_arch_registry.py +0 -345
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/.gitignore +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/LICENSE +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/builtin_modules.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/advisory.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/basic.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/hub_and_spoke.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/architectures/scale_out.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/builtins.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/download.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/loader.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/schema.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/catalog/verify.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/commands/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/commands/modules.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/completion.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/engine.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/templates/footer.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/templates/header.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/templates/services/bootstrap.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/compose/templates/services/ignition.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/config/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/postsetup/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/postsetup/generator.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/services/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/services/loader.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/services/manifest.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/services/resolver.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/__init__.py +0 -0
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/_default.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/connections.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/device-connection.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/gateway-network-link.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/identity-provider.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/kafka-connector.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/mcp-module.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/mqtt-engine-connection.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/opc-ua-connection.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/redundancy-pairing.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/post-setup/reverse-proxy.md.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/redundancy/redundancy.xml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/chariot/seed/service/chariot-trial.sh +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/emqx/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/hivemq/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/kafka/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/gateway-resources/config/resources/core/ignition/identity-provider/keycloak/config.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/gateway-resources/config/resources/core/ignition/identity-provider/keycloak/resource.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/keycloak/seed/service/import/ignition-realm.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mariadb/seed/service/initdb/00-create-extra-databases.sh +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/modbus-sim/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mongo/seed/service/initdb/01-demo-collection.js +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/mysql/seed/service/initdb/00-create-extra-databases.sh +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/n8n/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/opcua-sim/seed/service/USAGE.md +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/database-connection/db/config.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/gateway-resources/config/resources/core/ignition/database-connection/db/resource.json +0 -0
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → 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
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/postgres/seed/service/initdb/00-create-extra-databases.sh +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/compose.yaml.j2 +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/manifest.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/services/rabbitmq/seed/service/enabled_plugins +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/scripts/docker-bootstrap.sh +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/config/resources/core/config-mode.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/config/resources/dev/config-mode.json +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/templates/standalone-postgres/services/ignition/projects/.gitkeep +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/update_check.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/ignition_stack/wizard.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/modules.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/pyproject.toml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/__init__.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/conftest.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/architectures/basic/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/architectures/hub-and-spoke/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/architectures/scale-out/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/architectures/scale-out-redundant/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/combos/hub-and-spoke-iiot-chariot/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/combos/network-split/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/combos/smoke-stack/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/scaleout-skeleton/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/chariot/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/db-mariadb/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/db-mongo/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/db-mysql/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/db-postgres/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/emqx/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/hivemq/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/kafka/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/keycloak/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/modbus-sim/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/n8n/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/opcua-sim/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/services/rabbitmq/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/golden/standalone-postgres/docker-compose.yaml +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_builtin_catalog_smoke.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_completion.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_compose_engine.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_iiot_overlay.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_manifest_invariants.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_modules_catalog.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_modules_cli.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_postsetup.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_redundancy.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_service_catalog.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_service_catalog_smoke.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_update_check.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_wizard_back_nav.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/tests/test_wizard_composer.py +0 -0
- {ignition_stack-0.6.0 → ignition_stack-0.7.0}/verification/iiot-spike/README.md +0 -0
- {ignition_stack-0.6.0 → 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.
|
|
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
|
|
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 `
|
|
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
|
-
| `
|
|
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
|
|
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 `
|
|
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
|
-
| `
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
80
|
-
same artifact can be dumped with ``
|
|
81
|
-
``
|
|
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
|
|
80
|
+
has files.
|
|
90
81
|
"""
|
|
91
82
|
target_dir = Path(target_dir).resolve()
|
|
92
|
-
if
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5
|
-
``ignition-stack
|
|
6
|
-
artifact is what the
|
|
7
|
-
|
|
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
|
|
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
|
|
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,
|
|
560
|
+
"comment, config records) name the architecture they came from."
|
|
561
561
|
),
|
|
562
562
|
)
|
|
563
563
|
|
{ignition_stack-0.6.0/ignition_stack/lifecycle → ignition_stack-0.7.0/ignition_stack}/record.py
RENAMED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
:class:`~ignition_stack.config.schema.ProjectConfig`
|
|
5
|
-
``.ignition-stack/config.json``. That
|
|
6
|
-
``
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
25
|
+
RECORD_DIR = ".ignition-stack"
|
|
27
26
|
RECORD_NAME = "config.json"
|
|
28
27
|
|
|
29
28
|
|
|
30
|
-
class
|
|
31
|
-
"""Raised when a
|
|
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) /
|
|
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
|
|
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:`
|
|
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
|
|
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
|
|
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
|
-
|
|
87
|
+
config record and tests.
|
|
88
88
|
"""
|
|
89
89
|
|
|
90
90
|
config: ProjectConfig
|