diff --git a/.gitignore b/.gitignore index d5ec74aca..b6d155b1c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ docs/wiki/_templates cfg/InOut/*.42 cfg/InOut/*.csv + +.DS_Store \ No newline at end of file diff --git a/deployments/.gitignore b/deployments/.gitignore new file mode 100644 index 000000000..d2fdb96a5 --- /dev/null +++ b/deployments/.gitignore @@ -0,0 +1,5 @@ +environments/* +.DS_Store +*.42 +.env +settings.xml diff --git a/deployments/Makefile b/deployments/Makefile new file mode 100644 index 000000000..124e9a9e9 --- /dev/null +++ b/deployments/Makefile @@ -0,0 +1,31 @@ +.DEFAULT_GOAL := help +.ONESHELL: + +SHELL=bash + +install-taskfile: ## USE TASK instead of Makefile: Install Taskfile CLI tool + @sh -c "$$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin && \ + chmod +x ~/.local/bin/task && export PATH="${HOME}/.local/bin:${PATH}" + @echo; echo "add: ${HOME}/.local/bin:${PATH} to your ~/.bashrc or ~/.zshrc"; echo + +install-lazydocker: ## Install lazydocker CLI tool (to view logs, etc) + @curl --silent https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash + @echo; echo "don't forget to add: ${HOME}/.local/bin:${PATH} to your ~/.bashrc or ~/.zshrc"; echo + @echo "watch a Lazydocker demo here: https://www.youtube.com/watch?v=NICqQPxwJWw"; echo + +RESET = \033[0m +PURPLE = \033[0;35m +GREEN = \033[0;32m +LINE = $(PURPLE)----------------------------------------------------------------------------------------$(RESET) + +help: + @echo + @printf "\033[37m%-30s\033[0m %s\n" "#----------------------------------------------------------------------------------------" + @printf "\033[37m%-30s\033[0m %s\n" "# Makefile targets " + @printf "\033[37m%-30s\033[0m %s\n" "#----------------------------------------------------------------------------------------" + @echo + @printf "\033[37m%-30s\033[0m %s\n" "#-target-----------------------description-----------------------------------------------" + @grep -E '^[a-zA-Z_-].+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + @echo + +print-% : ; @echo $* = $($*) diff --git a/deployments/README.md b/deployments/README.md new file mode 100644 index 000000000..e010a534f --- /dev/null +++ b/deployments/README.md @@ -0,0 +1,327 @@ +# How to use + +## Dependencies + +- `gnu make` +- `bash` +- `task` a contemporary version of `make` +- `lazydocker` + +Which can be installed via `make install-lazydocker install-taskfile` + +## prep - onetime run + +```bash +make install-lazydocker install-taskfile env-create + +``` + +## Run `task` after you've done `make install-taskfile`: + +```bash +task + +``` + +returns: + +```bash +task: Available tasks for this project: +* build: Build all containers +* build-fortytwo: Build fortytwo (42) +* build-fsw: Build nos3-base-local (fsw) +* build-openmct: Build openmct +* build-yamcs: Build yamcs +* check-docker-ps: check docker ps for any exited|unhealthy|created|error containers +* check-service-ready: wait for a service to be ready on a given port +* clean: clean nos3 configuration +* clean-containers: clean images, cache, volumes, and networks +* config: configure nos3 by running config.sh +* config-nos3-mission: configure nos3-mission.xml to set start-time +* default: Shows this help message +* down: Bring down nos3 +* env-create: Create .env file from env.sh script +* info-services: info on accessing various services +* install-lazydocker: Install lazydocker CLI tool (to view logs, etc) +* purge-containers: WARNING: purge docker/podman images, cache, volumes, and networks +* set-permissions: set filesystem permissions, needed for restricted accounts +* setup-maven: Setup maven settings.xml with proxy info-services +* sidecar: Run sidecar to enable output +* submodule-update: sync and update git submodules +* up: Bring up nos3 in detached state +* up-minimum: Bring up nos3 (minimum) in detached state +* k8s:apply:deployment: apply nos3 kubernetes deployment(s) +* k8s:apply:ingress:nginx: apply ingress-nginx for nos3 kubernetes +* k8s:apply:kustomization: Apply kustomization to the namespace +* k8s:convert:kompose: convert docker-compose to kubernetes manifests using kompose +* k8s:convert:kompose:helm: convert docker-compose to kubernetes manifests using kompose +* k8s:create:namespace: Create the Kubernetes namespace +* k8s:delete:deployment: delete nos3 kubernetes deployment(s) +* k8s:delete:kustomization: Delete kustomize and namespace +* k8s:delete:namespace: delete nos3 kubernetes namespace +* k8s:generate:all: Generate all kubernetes yamls for COMPONENT_NAME +* k8s:generate:configmap:args: Generate kubernetes configmaps yaml for COMPONENT_NAME +* k8s:generate:configmap:env: Generate kubernetes configmaps yaml for COMPONENT_NAME +* k8s:generate:configmap:volumes: Generate kubernetes volumes configmaps yaml for COMPONENT_NAME +* k8s:generate:configmaps:all: Generate all kubernetes yamls for COMPONENT_NAME +* k8s:generate:deployment: Generate kubernetes deployment yaml for COMPONENT_NAME +* k8s:generate:ingress: Generate kubernetes configmaps yaml for COMPONENT_NAME +* k8s:generate:kustomization: Generate Kustomization yaml for COMPONENT_NAME +* k8s:generate:service: Generate kubernetes service yaml for COMPONENT_NAME +* k8s:get:configmap: get a specific kubernetes configmaps defined in K8S_CONFIGMAP_NAME +* k8s:get:configmaps: get nos3 kubernetes configmaps +* k8s:get:pod-name: get the pod name for nos3 kubernetes deployment +* k8s:kill:port-forward: Kill port-forward +* k8s:path:yamls: generate kubernetes yamls for the deployment +* k8s:port-forward: Port forward to access services locally +* k8s:write:env: write k8s env file + + +``` + +## Run - which actually also runs `task submodule-update` + +```bash +task up + +``` + +### Taskfile + +more info on `task` can be found here https://taskfile.dev + +### Lazydocker + +more info on `lazydocker` can be found here https://github.com/jesseduffield/lazydocker +![lazydocker](https://raw.githubusercontent.com/jesseduffield/lazydocker/refs/heads/master/docs/resources/demo3.gif) + +## Test + +open http://localhost:8090/instance?c=nos3__realtime to access yamcs/gsw +open http://localhost:30090/vnc.html to access fortytwo (42) +open http://localhost:9000 to access openmct + +## Diagrams + +Ignore the below for now + +```mermaid +graph TD + A[ubuntu:jammy-20250126]-->|FROM| B + B[nasa-itc/deployments/] -->|build-->push| C(docker.io/ivvitc/nos3-64:dev) + C-->|FROM| D[haisamido/nos3-64/] + D-->|build-->push| E(ghcr.io/haisamido/nos3-64:dev) + +``` + +```mermaid +graph TD; + %% client([client])-. Ingress-managed
load balancer .->ingress[Ingress]; + %% ingress-->|routing rule|service[Service]; + + subgraph namespace + %% ingress; + %% gps-->|tcp:4245|fortytwo[fortytwo] + %% time-->message_bus + + rw0-->|rx:4278|fortytwo + fortytwo[fortytwo]-->|tx:4277|rw0 + %% rw0-->|uart:2|uart-bus + + rw1-->|rx:4378|fortytwo + fortytwo[fortytwo]-->|tx:4377|rw1 + %% rw1-->|uart:3|uart-bus + + rw2-->|rx:4478|fortytwo + fortytwo[fortytwo]-->|tx:4477|rw2 + %% rw2-->|uart:4|uart-bus + + torquer-->|rx:4279|fortytwo[fortytwo] + thruster-->|rx:4280|fortytwo[fortytwo] + %% thruster-->|uart:29|uart-bus + + fortytwo[fortytwo]-->|tx:4245|gps + gps-sim-->|s|gps-app-->cfs + css-sim-->|s|css-app-->cfs + gps-->|uart:1|uart-bus + + subgraph gps + gps-sim + end + + subgraph cfs + gps-app; + end + + fortytwo[fortytwo]-->|tx:4277|css + %% css-->|64|i2c:2 + + fortytwo[fortytwo]-->|tx:4279|mag + + fortytwo[fortytwo]-->|tx:9999|truth42sim + truth42sim-->|tx:5111|yamcs + + fortytwo[fortytwo]-->|tx:4284|fss + + fortytwo[fortytwo]-->|tx:4281|imu + + fortytwo[fortytwo]-->|tx:4282|star-tracker + + fortytwo[fortytwo]-->|tx:4283|eps + + radio-->|ci:5010|nos_fsw + radio-->|to:5011|nos_fsw + radio-->|radio:5015|nos_fsw + + yamcs-->|tc:6010|cryptolib-->radio + + nos_fsw-->|command:5014|radio + + radio-->|tm:6011|yamcs + yamcs-->|tc:8010|radio + + %% camsim-->|60|i2c:2 + %% camsim-->|0|spi + + nos_engine_server-->|tcp:12001|time-->gps + stdio-terminal-->|udp:5555|x + udp-terminal-->|udp:5556|x + %% sample-sim-->|uart:16|uart-bus + + %% actuators + %% sensors + + subgraph time_sync + time + +end + + + subgraph reaction_wheels + rw0; + rw1; + rw2; + end + + subgraph actuators + reaction_wheels + thruster; + torquer; + end + + subgraph ground_segment + yamcs; + terminals; + cryptolib; + end + + subgraph physics_engine + fortytwo + end + + subgraph terminals + stdio-terminal; + udp-terminal; + end + + subgraph fsw + actuators + mag + mag + fss + css + camsim + eps + gps + star-tracker + imu + thruster + torquer + radio + sample-sim + uart-bus + nos_fsw + end + + subgraph space_segment + physics_engine + fsw + truth42sim + end + %% subgraph sensors + %% start-tracker + %% end + + end + + classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; + classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; + classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; + classDef rw fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; + + class fortytwo,gps,stdio-terminal,udp-terminal,sample-sim,eps,torquer,thruster,camsim,yamcs,cryptolib,css,mag,fss,imu,eps,star-tracker k8s; + + class truth42sim k8s; + class nos_engine_server k8s; + class nos_fsw k8s; + + class rw0,rw1,rw2 rw; + + class client plain; + class cluster cluster; +``` + +## docker ps + +```bash +docker ps | grep -v 'CONTAINER ID' |wc -l +24 + +``` + +```bash +docker ps + +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +3a130fadaea9 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 41 seconds ago Up 40 seconds nos_time_driver +9661c0fa0ac8 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 49 seconds ago Up 47 seconds sc_1_torquer_sim +4ff3a142614a ivvitc/nos3-64:20250217 "./nos3-single-simul…" 50 seconds ago Up 47 seconds sc_1_thruster_sim +277b46405250 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 50 seconds ago Up 48 seconds sc_1_startrk_sim +44d1809986f5 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 50 seconds ago Up 48 seconds sc_1_sample_sim +dcde3f725275 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 51 seconds ago Up 47 seconds 0.0.0.0:16010->6010/tcp, 0.0.0.0:16010->6010/udp, 0.0.0.0:16011->6011/tcp, 0.0.0.0:16011->6011/udp sc_1_radio_sim +1e0a92b988c3 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 51 seconds ago Up 48 seconds sc_1_rw_sim2 +eb3bc34fcc2f ivvitc/nos3-64:20250217 "./nos3-single-simul…" 51 seconds ago Up 49 seconds sc_1_rw_sim1 +0c327e64ef4e ivvitc/nos3-64:20250217 "./nos3-single-simul…" 52 seconds ago Up 50 seconds sc_1_rw_sim0 +9c6166335f7f ivvitc/nos3-64:20250217 "./nos3-single-simul…" 52 seconds ago Up 50 seconds sc_1_mag_sim +523b92a28e7f ivvitc/nos3-64:20250217 "./nos3-single-simul…" 53 seconds ago Up 50 seconds sc_1_imu_sim +82dfa03e9c62 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 53 seconds ago Up 51 seconds sc_1_gps_sim +af58b5d09af2 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 53 seconds ago Up 51 seconds sc_1_fss_sim +42fe85609195 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 54 seconds ago Up 51 seconds sc_1_eps_sim +ac7787f9cf7a ivvitc/nos3-64:20250217 "./nos3-single-simul…" 54 seconds ago Up 51 seconds sc_1_css_sim +5aedf4c0a619 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 56 seconds ago Up 53 seconds sc_1_truth42sim +0282c8fb48e2 ivvitc/nos3-64:20250217 "/usr/bin/nos_engine…" 57 seconds ago Up 53 seconds sc_1_nos_engine_server +14e98992d60b ivvitc/nos3-64:20250217 "./support/standalone" 57 seconds ago Up 54 seconds sc_1_cryptolib +0c06e9b85d03 ivvitc/nos3-64:20250217 "/opt/neo/nos3/scrip…" 57 seconds ago Up 53 seconds sc_1_nos_fsw +1e84eafbabe1 ivvitc/nos3-64:20250217 "/opt/neo/nos3/scrip…" 58 seconds ago Up 54 seconds sc_1_onair +2365e959b0c6 ivvitc/nos3-64:20250217 "/home/neo/.nos3/42/…" 58 seconds ago Up 55 seconds sc_1_fortytwo +72c26bc3690a ivvitc/nos3-64:20250217 "./nos3-single-simul…" 59 seconds ago Up 58 seconds nos_udp_terminal +96c8948f8b01 ivvitc/nos3-64:20250217 "./nos3-single-simul…" 59 seconds ago Up 58 seconds nos_terminal +f78f9bda0e0a ivvitc/nos3-64:20250217 "mvn -Dmaven.repo.lo…" About a minute ago Up 58 seconds 0.0.0.0:5012->5012/tcp, 0.0.0.0:8090->8090/tcp cosmos_openc3-operator_1 + +``` + +## docker network list + +```bash + +docker network list + +NETWORK ID NAME DRIVER SCOPE +2a772b648d00 bridge bridge local +5fe825f9aaa9 docker_quickstart bridge local +6652439bc0af host host local +8cd5a6aac2de none null local +6c6e8d8284e4 nos3_core bridge local +cca8286b3dd6 nos3_sc_1 bridge local + +``` diff --git a/deployments/Taskfile.yaml b/deployments/Taskfile.yaml new file mode 100644 index 000000000..7758a24da --- /dev/null +++ b/deployments/Taskfile.yaml @@ -0,0 +1,869 @@ +version: '3' + +dotenv: + - ./.env + +vars: + PROJECT: '{{.PROJECT | default "nos3"}}' + FLEET: '{{.PROJECT | default "nos3"}}' + MISSION: '{{.MISSION | default "m01"}}' + SPACECRAFT: '{{.SPACECRAFT | default "sc01"}}' + + PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + PROJECT_MISSION: '{{.PROJECT}}-{{.MISSION}}' + + COMPOSE_PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + SC_ENVIRO: '{{.SC_ENVIRO | default "sim"}}' + + YAMCS_HOST_PORT: '{{.YAMCS_HOST_PORT | default "8090"}}' + OPENMCT_HOST_PORT: '{{.OPENMCT_HOST_PORT | default "9000"}}' + FORTYTWO_HOST_PORT: '{{.FORTYTWO_HOST_PORT | default "30090"}}' + + SERVICES_DIR: ./services + SCRIPTS_DIR: ./scripts + TEMPLATES_DIR: ./templates + BUILD_DIR: ./build + ENVIROS_DIR: '{{.BUILD_DIR}}/' + + CONTAINER_BIN: docker + CONTAINER_COMPOSE_BIN: ' {{.CONTAINER_BIN}} compose ' + + CONTAINER_DIR: '.' + COMPOSE_FILE: '{{.CONTAINER_DIR}}/compose.yaml' + +# Variables for configuring builds and deployments + DEPLOYMENT_ENVIRO: '{{.DEPLOYMENT_ENVIRO | default ""}}' + HTTP_PROXY: '{{.HTTP_PROXY | default ""}}' + HTTPS_PROXY: '{{.HTTPS_PROXY | default ""}}' + + ENVIRO_SCRIPT: '{{.SCRIPTS_DIR}}/env.sh' + ENVIRO_FILE: '{{.CONTAINER_DIR}}/.env' + ENVIRO_TEMPLATE: '{{.TEMPLATES_DIR}}/env.template' + + MAVEN_HTTPS_PROXY: '-s./settings.xml' + MAVEN_SETTINGS_FILE: '{{.MAVEN_SETTINGS_FILE | default ""}}' + + # NOS3 configuration path + NOS3_CFG_PATH: '{{.NOS3_CFG_PATH | default ".."}}' + + # Kubernetes variables + K8S_ENV_FILE: '{{.K8S_ENV_FILE | default "./targets/kubernetes/env/k8s.env"}}' + K8S_CONTEXT: '{{.K8S_CONTEXT | default "docker-desktop"}}' + K8S_CLUSTER: '{{.K8S_CLUSTER | default "docker-desktop"}}' + K8S_NAMESPACE: '{{.PROJECT}}-{{.MISSION}}' + K8S_USER: '{{.K8S_USER | default "docker-desktop"}}' + + # TODO: COMPONENT doesn't make sense here + K8S_APP_LABEL: "{{.PROJECT_NAME}}-fortytwo" + K8S_PORT_FORWARD_VNC: 8080 + K8S_KOMPOSE_OUTPUT: '{{.K8S_KOMPOSE_OUTPUT | default "./targets/kubernetes/kompose/"}}' + K8S_CONFIGMAP_NAME: '{{.K8S_APP_LABEL}}' + K8S_REPLICAS: 1 + + K8S_BUILD_PATH: './build/k8s/contexts/{{.K8S_CONTEXT}}/clusters/{{.K8S_CLUSTER}}/namespaces/{{.K8S_NAMESPACE}}/applications/{{.K8S_APP_LABEL}}' +# K8S_BUILD_PATH: './services/fortytwo/kubernetes' + +tasks: + default: + desc: Shows this help message + cmds: + - task --list-all + silent: true + + test: + env: + PROJECT: '{{.PROJECT}}' + FLEET: '{{.FLEET}}' + MISSION: '{{.MISSION}}' + SPACECRAFT: '{{.SPACECRAFT}}' + PROJECT_MISSION: '{{.PROJECT}}-{{.MISSION}}' + PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + COMPOSE_PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + + SC_ENVIRO: '{{.SC_ENVIRO}}' + + FORTYTWO_HOST: '{{.FORTYTWO_HOST}}' + FORTYTWO_PORT: '{{.FORTYTWO_PORT}}' + FORTYTWO_HOST_PORT: '{{.FORTYTWO_HOST_PORT}}' + + YAMCS_HOST: '{{.YAMCS_HOST}}' + YAMCS_PORT: '{{.YAMCS_PORT}}' + YAMCS_HOST_PORT: '{{.YAMCS_HOST_PORT}}' + + OPENMCT_HOST: '{{.OPENMCT_HOST}}' + OPENMCT_PORT: '{{.OPENMCT_PORT}}' + OPENMCT_HOST_PORT: '{{.OPENMCT_HOST_PORT}}' + + ENV_PATH: '{{.BUILD_DIR}}/docker/{{.PROJECT}}/{{.MISSION}}/{{.SPACECRAFT}}/' + ENV_SHELL: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}.sh' + + cmds: + - echo "project = ${PROJECT}" + - echo "fleet = ${FLEET}" + - echo "mission = ${MISSION}" + - echo "spacecraft = ${SPACECRAFT}" + - echo "compose project name = ${COMPOSE_PROJECT_NAME}"; echo + - echo "spacecraft enviro = ${SC_ENVIRO}"; echo + - echo "fortytwo host = ${FORTYTWO_HOST}" + - echo "fortytwo port = ${FORTYTWO_PORT}" + - echo "fortytwo host port = ${FORTYTWO_HOST_PORT}"; echo + - echo "yamcs host = ${YAMCS_HOST}" + - echo "yamcs port = ${YAMCS_PORT}" + - echo "yamcs host port = ${YAMCS_HOST_PORT}";echo + - echo "openmct host = ${OPENMCT_HOST}" + - echo "openmct port = ${OPENMCT_PORT}" + - echo "openmct host port = ${OPENMCT_HOST_PORT}";echo + - echo "env path = ${ENV_PATH}" + - echo "env shell = ${ENV_SHELL}"; echo + - | + mkdir -p ${ENV_PATH} + + {{.ENVIRO_SCRIPT}} > ${ENV_PATH}/${ENV_SHELL}.env + + cp ${ENV_PATH}/${ENV_SHELL}.env .env + - task: up + + silent: true + + build-fortytwo: + desc: Build fortytwo (42) + deps: + - env:create + - set-permissions + cmds: + - | + source {{.ENVIRO_FILE}} && \ + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} build --pull nos3-fortytwo + silent: true + + build-yamcs: + desc: Build yamcs + deps: + - env:create + - setup-maven + - set-permissions + cmds: + - | + source {{.ENVIRO_FILE}} && \ + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} build --pull nos3-gsw + silent: true + + build-openmct: + desc: Build openmct + deps: + - env:create + - set-permissions + cmds: + - '{{.CONTAINER_BIN}} pull docker.io/library/ubuntu:25.04' + - | + source {{.ENVIRO_FILE}} && \ + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} build --pull nos3-openmct + silent: true + + build-fsw: + desc: Build nos3-base-local (fsw) + deps: + - env:create + - set-permissions + cmds: + - | + source {{.ENVIRO_FILE}} && \ + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} build --pull nos3-fsw + silent: true + + build: + desc: Build all containers + deps: + - env:create + - set-permissions + - setup-maven + cmds: + - '{{.CONTAINER_BIN}} pull docker.io/library/ubuntu:25.04' + - | + source {{.ENVIRO_FILE}} && \ + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} build --pull nos3-fortytwo nos3-gsw nos3-openmct nos3-fsw + silent: true + + set-permissions: + desc: set filesystem permissions, needed for restricted accounts + cmds: + - mkdir -p ../cfg/build + - find . -type f -name '*.sh' -exec chmod 777 {} \; # Make sure all scripts are world executable + - find . -type f -name '*.py' -exec chmod 777 {} \; # Make sure all scripts are world executable + - find . -type f -name '*.json' -exec chmod 666 {} \; # Make sure all .json files are world readable + - find . -type f -name '*.xml' -exec chmod 666 {} \; # Make sure all .xml files are world readable + - find . -type f -name '*.c' -exec chmod 555 {} \; # Make sure all .xml files are world readable + - find . -type f -name '*.h' -exec chmod 555 {} \; # Make sure all .xml files are world readable + - find ../cfg/build -type f -name '*.sh' -exec chmod 777 {} \; # Make sure all scripts are world executable + - find ../cfg/build -type f -name '*.py' -exec chmod 777 {} \; # Make sure all scripts are world executable + - find ../cfg/build -type f -name '*.json' -exec chmod 666 {} \; # Make sure all .json files are world readable + - find ../cfg/build -type f -name '*.xml' -exec chmod 666 {} \; # Make sure all .xml files are world readable + - find ${HOME}/.nos3/ -type f -name '*.xml' -exec chmod 666 {} \; # Make sure all .xml files are world readable + silent: true + + up: + desc: Bring up nos3 in detached state + # env: + # PROJECT: '{{.PROJECT}}' + # FLEET: '{{.FLEET}}' + # MISSION: '{{.MISSION}}' + # SPACECRAFT: '{{.SPACECRAFT}}' + # PROJECT_MISSION: '{{.PROJECT}}-{{.MISSION}}' + # PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + # COMPOSE_PROJECT_NAME: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + + # SC_ENVIRO: '{{.SC_ENVIRO}}' + + # FORTYTWO_HOST: '{{.FORTYTWO_HOST}}' + # FORTYTWO_PORT: '{{.FORTYTWO_PORT}}' + # FORTYTWO_HOST_PORT: '{{.FORTYTWO_HOST_PORT}}' + + # YAMCS_HOST: '{{.YAMCS_HOST}}' + # YAMCS_PORT: '{{.YAMCS_PORT}}' + # YAMCS_HOST_PORT: '{{.YAMCS_HOST_PORT}}' + + # OPENMCT_HOST: '{{.OPENMCT_HOST}}' + # OPENMCT_PORT: '{{.OPENMCT_PORT}}' + # OPENMCT_HOST_PORT: '{{.OPENMCT_HOST_PORT}}' + + # ENV_PATH: '{{.BUILD_DIR}}/docker/${PROJECT}/${MISSION}/${SPACECRAFT}/' + # ENV_SHELL: '${PROJECT}-${MISSION}-${SPACECRAFT}.sh' + + cmds: + - task: submodule-update + - task: env:generate + - task: build + - task: config-nos3-mission + - task: nos3:config + - task: set-permissions + - | + source {{.ENVIRO_FILE}} && \ + export NOS3_CFG_PATH={{.NOS3_CFG_PATH}}; \ + {{.CONTAINER_COMPOSE_BIN}} --env-file {{.ENVIRO_FILE}} -f {{.COMPOSE_FILE}} --project-name {{.COMPOSE_PROJECT_NAME}} up -d --remove-orphans + - task check-service-ready SERVICE_HOST={{.YAMCS_HOST}} SERVICE_PORT={{.YAMCS_HOST_PORT}} + - sleep 5 + - task sidecar + - task info-services + - task check-docker-ps + silent: true + + down: + desc: Bring down nos3 + cmds: + - | + {{.CONTAINER_COMPOSE_BIN}} -f {{.COMPOSE_FILE}} --project-name {{.COMPOSE_PROJECT_NAME}} down --remove-orphans || true + silent: true + + up-minimum: + desc: Bring up nos3 (minimum) in detached state + deps: + - down + - env:create + - build + - config-nos3-mission + - nos3:config + - set-permissions + cmds: + - sleep 5 + - | + source {{.ENVIRO_FILE}} && \ + export NOS3_CFG_PATH={{.NOS3_CFG_PATH}} ; \ + {{.CONTAINER_COMPOSE_BIN}} \ + --env-file {{.ENVIRO_FILE}} \ + -f {{.COMPOSE_FILE}} --project-name {{.COMPOSE_PROJECT_NAME}} up -d \ + nos3-fortytwo \ + nos3-nos-engine-server \ + nos3-fsw \ + nos3-gps-sim \ + nos3-time \ + nos3-radio-sim-cryptolib \ + nos3-truth42sim \ + nos3-gsw \ + nos3-openmct \ + --force-recreate \ + --remove-orphans + - task check-service-ready SERVICE_HOST=${YAMCS_HOST} SERVICE_PORT=${YAMCS_HOST_PORT} + - task sidecar + - task info-services + - task check-docker-ps + silent: true + + sidecar: + desc: Run sidecar to enable output + cmds: + - '{{.SCRIPTS_DIR}}/sidecar.sh -s {{.YAMCS_HOST}} -p {{.YAMCS_HOST_PORT}} -c "/CFS/CMD/TO_ENABLE_OUTPUT"' + silent: true + + clean-containers: + desc: clean images, cache, volumes, and networks + deps: + - down + cmds: + - yes | {{.CONTAINER_BIN}} image prune --filter "dangling=true" + - yes | {{.CONTAINER_BIN}} system prune -a + - yes | {{.CONTAINER_BIN}} volume prune + - yes | {{.CONTAINER_BIN}} network prune + silent: true + + setup-maven: + desc: Setup maven settings.xml with proxy info-services + cmds: + - echo "" > {{.SERVICES_DIR}}/yamcs/settings.xml + - | + if [ "{{.DEPLOYMENT_ENVIRO}}" == "vmmoc" ]; then + cp -f {{.MAVEN_SETTINGS_FILE}} ${HOME}/.nos3/yamcs/ || true + cp -f {{.MAVEN_SETTINGS_FILE}} {{.SERVICES_DIR}}/yamcs/ || true + fi + silent: true + + check-docker-ps: + desc: check docker ps for any exited|unhealthy|created|error containers + cmds: + - | + {{.CONTAINER_BIN}} ps -a | egrep -i 'exited|unhealthy|created|error' | grep -v STATUS || true + silent: true + + check-service-ready: + env: + SERVICE_HOST: '{{.SERVICE_HOST | default "{{.YAMCS_HOST}}"}}' + SERVICE_PORT: '{{.SERVICE_PORT | default "{{.YAMCS_HOST_PORT}}"}}' + desc: wait for a service to be ready on a given port + cmds: + - | + echo "Waiting for service {{.SERVICE_HOST}}:{{.SERVICE_PORT}} to be ready..." + COUNT=0 + until nc -z {{.SERVICE_HOST}} {{.SERVICE_PORT}}; do + COUNT=$((COUNT + 1)) + if [ $COUNT -ge 60 ]; then + echo "Timeout waiting for port {{.SERVICE_PORT}} to open" + exit 1 + fi + sleep 1 + echo "Waiting for {{.SERVICE_HOST}}:{{.SERVICE_PORT}} to be ready... ($COUNT/60)" + done + echo "Port {{.SERVICE_HOST}}:{{.SERVICE_PORT}} is open, checking API..." + COUNT=0 + until curl -s "http://{{.SERVICE_HOST}}:{{.SERVICE_PORT}}/api" | grep -q '"yamcsVersion"'; do + COUNT=$((COUNT + 1)) + if [ $COUNT -ge 60 ]; then + echo "Timeout waiting for API to be ready" + exit 1 + fi + sleep 1 + echo "Waiting for API to be ready... ($COUNT/60)" + done + echo "Service http://{{.SERVICE_HOST}}:{{.SERVICE_PORT}}/api is ready!" + silent: true + + purge-containers: + desc: 'WARNING: purge docker/podman images, cache, volumes, and networks' + deps: + - down + cmds: + - yes | {{.CONTAINER_BIN}} image prune --filter "dangling=true" || true + - yes | {{.CONTAINER_BIN}} system prune -a || true + - yes | {{.CONTAINER_BIN}} volume prune || true + - yes | {{.CONTAINER_BIN}} network prune || true + - echo + silent: true + + info-services: + desc: info on accessing various services + cmds: + - task env:create + - | + source {{.ENVIRO_FILE}} + echo; echo "How to access various services:"; echo; \ + echo "open http://localhost:${YAMCS_HOST_PORT} to access yamcs/gsw"; \ + echo "open http://localhost:${FORTYTWO_HOST_PORT}/vnc.html to access fortytwo (42) and then click Connect"; \ + echo "FT: open http://localhost:${OPENMCT_HOST_PORT}/#/browse/taxonomy:spacecraft/taxonomy:~SIM_42_TRUTH/taxonomy:~SIM_42_TRUTH~SIM_42_TRUTH_DATA/taxonomy:~SIM_42_TRUTH~SIM_42_TRUTH_DATA~BVB_2?tc.mode=fixed&tc.timeSystem=utc&tc.startBound=${SIM_T0_EPOCH_MILLISECONDS}&tc.endBound=${SIM_TF_EPOCH_MILLISECONDS}&view=plot-single" + echo "RT: open http://localhost:${OPENMCT_HOST_PORT}/#/browse/taxonomy:spacecraft/taxonomy:~SIM_42_TRUTH/taxonomy:~SIM_42_TRUTH~SIM_42_TRUTH_DATA/taxonomy:~SIM_42_TRUTH~SIM_42_TRUTH_DATA~BVB_2?tc.mode=local&tc.timeSystem=utc&view=plot-single&tc.startDelta=60000&tc.endDelta=300000" + echo + silent: true + + env:create: + desc: Create .env file from env.sh script + # cmds: + # - | + # {{.ENVIRO_SCRIPT}} > {{.ENVIRO_FILE}} + cmds: + - task env:generate + silent: true + + install-lazydocker: + desc: Install lazydocker CLI tool (to view logs, etc) + cmds: + - | + curl --silent https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash + - | + echo; echo "don't forget to add: ${HOME}/.local/bin:${PATH} to your ~/.bashrc or ~/.zshrc"; echo + - | + echo "watch a Lazydocker demo here: https://www.youtube.com/watch?v=NICqQPxwJWw"; echo + silent: true + + config-nos3-mission: + desc: configure nos3-mission.xml to set start-time + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + sed -Ei 's/(\s*)(\).*(\)/\1\2>'${START_TIME}'<\/\3/g' ../cfg/nos3-mission.xml && \ + sed -Ei 's/(\s*)(\).*(\)/\1\2>'${GSW_SOFTWARE}'<\/\3/g' ../cfg/nos3-mission.xml && \ + sed -Ei 's/(\s*)(\).*(\)/\1\2>'${FSW_SOFTWARE}'<\/\3/g' ../cfg/nos3-mission.xml + silent: true + + submodule-update: + desc: sync and update git submodules + cmds: + - git submodule sync; git submodule update --init --recursive; git submodule sync + silent: true + + env:generate: + desc: generate env.sh file + cmds: + - | + export PROJECT={{.PROJECT}} + export FLEET={{.FLEET}} + export MISSION={{.MISSION}} + export SPACECRAFT={{.SPACECRAFT}} + + export PROJECT_MISSION={{.PROJECT}}-{{.MISSION}} + export PROJECT_NAME={{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}} + export COMPOSE_PROJECT_NAME={{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}} + + export SC_ENVIRO={{.SC_ENVIRO}} + + export FORTYTWO_HOST={{.FORTYTWO_HOST}} + export FORTYTWO_PORT={{.FORTYTWO_PORT}} + export FORTYTWO_HOST_PORT={{.FORTYTWO_HOST_PORT}} + + export YAMCS_HOST={{.YAMCS_HOST}} + export YAMCS_PORT={{.YAMCS_PORT}} + export YAMCS_HOST_PORT={{.YAMCS_HOST_PORT}} + + export OPENMCT_HOST={{.OPENMCT_HOST}} + export OPENMCT_PORT={{.OPENMCT_PORT}} + export OPENMCT_HOST_PORT={{.OPENMCT_HOST_PORT}} + + export ENV_PATH={{.BUILD_DIR}}/docker/${PROJECT}/${MISSION}/${SPACECRAFT}/ + export ENV_SHELL=${PROJECT}-${MISSION}-${SPACECRAFT}.sh + + mkdir -p ${ENV_PATH} + + {{.ENVIRO_SCRIPT}} > ${ENV_PATH}/${ENV_SHELL}.env + + cp ${ENV_PATH}/${ENV_SHELL}.env .env + + silent: true + +# nos3 native tasks + nos3:config: + desc: configure nos3 by running config.sh + cmds: + - cd ../ && ./scripts/cfg/config.sh + silent: true + + nos3:clean: + desc: clean nos3 configuration + deps: + - down + cmds: + - cd ../ && make clean + silent: true + + nos3:uninstall: + desc: uninstall nos3 items + deps: + - down + - nos3:clean + cmds: + - cd ../ && make uninstall + silent: true + +# K8S Kubernetes Tasks + k8s:create:namespace: + desc: Create the Kubernetes namespace + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl create namespace {{.K8S_NAMESPACE}} \ + --context {{.K8S_CONTEXT}} || \ + echo "Namespace {{.K8S_NAMESPACE}} in context {{.K8S_CONTEXT}} already exists" + - echo "Initiated creation of Namespace [{{.K8S_NAMESPACE}}] in context [{{.K8S_CONTEXT}}]" + silent: true + + k8s:apply:kustomization: + desc: Apply kustomization to the namespace + deps: + - k8s:create:namespace + - k8s:generate:all + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl apply -k {{.K8S_BUILD_PATH}} \ + --context {{.K8S_CONTEXT}} \ + --namespace {{.K8S_NAMESPACE}} + - echo "Initiated apply of Kustomization in path [{{.K8S_BUILD_PATH}}] for context [{{.K8S_CONTEXT}}] and namespace [{{.K8S_NAMESPACE}}]" + silent: true + + k8s:delete:kustomization: + desc: Delete kustomize and namespace + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl delete -k {{.K8S_BUILD_PATH}} \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}}|| true + - echo "Initiated deletion of Kustomization for context [{{.K8S_CONTEXT}}] and namespace [{{.K8S_NAMESPACE}}]" + - task: k8s:delete:namespace + silent: true + + k8s:convert:kompose: + desc: convert docker-compose to kubernetes manifests using kompose + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + mkdir -p {{.K8S_KOMPOSE_OUTPUT}} && \ + kompose convert -f {{.COMPOSE_FILE}} -o {{.K8S_KOMPOSE_OUTPUT}} + silent: true + + k8s:convert:kompose:helm: + desc: convert docker-compose to kubernetes manifests using kompose + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + mkdir -p {{.K8S_KOMPOSE_OUTPUT}} && \ + kompose convert -c -f {{.COMPOSE_FILE}} -o {{.K8S_KOMPOSE_OUTPUT}} + silent: true + + k8s:delete:namespace: + desc: delete nos3 kubernetes namespace + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl delete namespace {{.K8S_NAMESPACE}} --context {{.K8S_CONTEXT}} || true + silent: true + + k8s:apply:deployment: + desc: apply nos3 kubernetes deployment(s) + deps: + - env:create + - k8s:create:namespace + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl apply -f ./targets/kubernetes/kompose/ --context {{.K8S_CONTEXT}} --namespace={{.K8S_NAMESPACE}} + silent: true + + k8s:delete:deployment: + desc: delete nos3 kubernetes deployment(s) + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl delete --all deployments --context {{.K8S_CONTEXT}} --namespace={{.K8S_NAMESPACE}} || true + + k8s:get:configmaps: + desc: get nos3 kubernetes configmaps + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl get configmaps --context {{.K8S_CONTEXT}} --namespace={{.K8S_NAMESPACE}} || true + silent: true + + k8s:get:configmap: + desc: get a specific kubernetes configmaps defined in K8S_CONFIGMAP_NAME + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl get configmap --context {{.K8S_CONTEXT}} --namespace={{.K8S_NAMESPACE}} {{.K8S_CONFIGMAP_NAME}} -o yaml + silent: true + + k8s:apply:ingress:nginx: + desc: apply ingress-nginx for nos3 kubernetes + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.14.1/deploy/static/provider/cloud/deploy.yaml || true + silent: true + + k8s:get:pod-name: + desc: get the pod name for nos3 kubernetes deployment + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null); \ + echo $POD_NAME + silent: true + + k8s:port-forward: + desc: Port forward to access services locally + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + echo "Checking for pod availability..." + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) + + if [ -z "$POD_NAME" ]; then + echo "Error: No pod found with label app={{.K8S_APP_LABEL}}" + exit 1 + fi + + echo "Found pod: $POD_NAME" + echo "Waiting for pod to be ready..." + + kubectl wait --for=condition=ready pod/$POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --timeout=300s + + if [ $? -ne 0 ]; then + echo "Error: Pod did not become ready within timeout" + exit 1 + fi + + echo "Pod is ready!" + echo "Forwarding ports:" + echo " - VNC: http://localhost:{{.K8S_PORT_FORWARD_VNC}}" + kubectl port-forward ${POD_NAME} \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + {{.K8S_PORT_FORWARD_VNC}}:80 + silent: true + + k8s:kill:port-forward: + desc: Kill port-forward + deps: + - env:create + cmds: + - | + source {{.ENVIRO_FILE}} && \ + pkill -f 'kubectl port-forward' || true + silent: true + + k8s:write:env: + desc: write k8s env file + cmds: + - | + echo "HTTP_PROXY={{.HTTP_PROXY}}" > {{.K8S_ENV_FILE}} + echo "HTTPS_PROXY={{.HTTPS_PROXY}}" >> {{.K8S_ENV_FILE}} + echo "NO_PROXY={{.NO_PROXY}}" >> {{.K8S_ENV_FILE}} + silent: true + + k8s:generate:all: + desc: Generate all kubernetes yamls for COMPONENT_NAME + deps: + - k8s:path:yamls + - k8s:generate:configmaps:all + - k8s:generate:deployment + - k8s:generate:service + - k8s:generate:ingress + - k8s:generate:kustomization + silent: true + + k8s:path:yamls: + desc: generate kubernetes yamls for the deployment + cmds: + - mkdir -p {{.K8S_BUILD_PATH}} + silent: true + + k8s:generate:configmaps:all: + desc: Generate all kubernetes yamls for COMPONENT_NAME + deps: + - k8s:generate:configmap:env + - k8s:generate:configmap:volumes + - k8s:generate:configmap:args + silent: true + + k8s:generate:configmap:env: + desc: Generate kubernetes configmaps yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl create configmap \ + {{.K8S_CONFIGMAP_NAME}} \ + --from-env-file={{.ENVIRO_FILE}} --dry-run=client -o yaml > {{.K8S_BUILD_PATH}}/configmap-env.yaml + silent: true + + k8s:generate:configmap:volumes: + desc: Generate kubernetes volumes configmaps yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + kubectl create configmap {{.K8S_CONFIGMAP_NAME}}-volumes \ + --from-file=./services/fortytwo/entrypoint.sh \ + --dry-run=client \ + --output yaml > {{.K8S_BUILD_PATH}}/configmap-volumes.yaml + silent: true + + k8s:generate:configmap:args: + desc: Generate kubernetes configmaps yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + echo "" > {{.K8S_BUILD_PATH}}/configmap-args.yaml + silent: true + + k8s:generate:service: + desc: Generate kubernetes service yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + cat < {{.K8S_BUILD_PATH}}/service.yaml + --- + apiVersion: v1 + kind: Service + metadata: + name: {{.K8S_APP_LABEL}} + + spec: + selector: + app: {{.K8S_APP_LABEL}} + ports: + - name: x-vnc + protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP + EOF + silent: true + + k8s:generate:ingress: + desc: Generate kubernetes configmaps yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + echo "" > {{.K8S_BUILD_PATH}}/ingress.yaml + silent: true + + k8s:generate:deployment: + desc: Generate kubernetes deployment yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + cat < {{.K8S_BUILD_PATH}}/deployment.yaml + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: {{.K8S_APP_LABEL}} + namespace: {{.K8S_NAMESPACE}} + labels: + app: {{.K8S_APP_LABEL}} + spec: + replicas: {{.K8S_REPLICAS}} + selector: + matchLabels: + app: {{.K8S_APP_LABEL}} + template: + metadata: + labels: + app: {{.K8S_APP_LABEL}} + spec: + containers: + - args: + - /entrypoint.sh + env: + - name: COMPONENT_NAME + value: fortytwo + - name: DISPLAY + value: :1 + image: ghcr.io/haisamido/nos3-base-fortytwo:dev + workingDir: /42 + imagePullPolicy: Always + name: {{.K8S_APP_LABEL}} + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "3" + memory: "2048Mi" + requests: + cpu: "1" + memory: "2048Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /entrypoint.sh + name: {{.K8S_APP_LABEL}}-volumes + subPath: entrypoint.sh + hostname: {{.K8S_APP_LABEL}} + restartPolicy: Always + volumes: + - configMap: + items: + - key: entrypoint.sh + path: entrypoint.sh + name: {{.K8S_APP_LABEL}}-volumes + defaultMode: 0555 + name: "{{.K8S_APP_LABEL}}-volumes" + EOF + silent: true + + k8s:generate:kustomization: + desc: Generate Kustomization yaml for COMPONENT_NAME + deps: + - env:create + - k8s:path:yamls + cmds: + - | + source {{.ENVIRO_FILE}} && \ + cat < {{.K8S_BUILD_PATH}}/kustomization.yaml + --- + apiVersion: kustomize.config.k8s.io/v1beta1 + kind: Kustomization + resources: + - ./configmap-args.yaml + - ./configmap-env.yaml + - ./configmap-volumes.yaml + - ./deployment.yaml + - ./service.yaml + - ./ingress.yaml + + EOF + silent: true diff --git a/deployments/compose.yaml b/deployments/compose.yaml new file mode 100644 index 000000000..0016ac9f8 --- /dev/null +++ b/deployments/compose.yaml @@ -0,0 +1,937 @@ +name: ${COMPOSE_PROJECT_NAME} + +services: + nos3-fortytwo: + image: ghcr.io/haisamido/nos3-base-fortytwo:dev + env_file: + - ./.env + build: + context: ./services/fortytwo + dockerfile: Dockerfile + args: + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + MAVEN_HTTPS_PROXY: ${MAVEN_HTTPS_PROXY} + GIT_URL: ${FORTYTWO_GIT_URL} + GIT_COMMIT: ${FORTYTWO_GIT_COMMIT} + GIT_FOLDER: ${FORTYTWO_GIT_FOLDER:-42} + STARTUP_FOLDER: ${FORTYTWO_STARTUP_FOLDER} + RECOMPILE: ${FORTYTWO_RECOMPILE:-false} + BASE_DIR: ${FORTYTWO_BASE_DIR} + VNC_PASSWORD: ${FORTYTWO_VNC_PASSWORD} + healthcheck: + test: ["CMD-SHELL", "/usr/bin/pgrep -f 42 | grep -v xterm ; sleep 2"] + interval: 10s + timeout: 5s + retries: 7 + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-fortytwo + hostname: ${COMPOSE_PROJECT_NAME}-fortytwo + working_dir: "/opt/nasa-itc/" + command: '/entrypoint.sh' + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/InOut/:/opt/nasa-itc/42/NOS3InOut/ + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/InOut/Inp_IPC.txt:/opt/nasa-itc/42/NOS3InOut/Inp_IPC.txt + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/InOut/Inp_Sim.txt:/opt/nasa-itc/42/NOS3InOut/Inp_Sim.txt + - ${PWD}/services/fortytwo/entrypoint.sh:/entrypoint.sh + ports: + - "127.0.0.1:${FORTYTWO_HOST_PORT}:${FORTYTWO_PORT}" + environment: + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + MAVEN_HTTPS_PROXY: ${MAVEN_HTTPS_PROXY} + GIT_URL: ${FORTYTWO_GIT_URL} + GIT_COMMIT: ${FORTYTWO_GIT_COMMIT} + GIT_FOLDER: ${FORTYTWO_GIT_FOLDER:-42} + STARTUP_FOLDER: ${FORTYTWO_STARTUP_FOLDER} + RECOMPILE: ${FORTYTWO_RECOMPILE:-false} + BASE_DIR: ${FORTYTWO_BASE_DIR} + VNC_PASSWORD: ${FORTYTWO_VNC_PASSWORD} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + HOST_PORT: ${FORTYTWO_PORT} + networks: + mission-spacecraft-network: + aliases: + - fortytwo + mission-network: + + nos3-gsw: + image: ghcr.io/haisamido/nos3-base-yamcs:dev + env_file: + - ./.env + build: + context: ./services/yamcs + dockerfile: Dockerfile + args: + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + MAVEN_REPO_LOCAL: ${MAVEN_REPO_LOCAL} + MAVEN_HTTPS_PROXY: ${MAVEN_HTTPS_PROXY} + COMPONENT_DIR: ${COMPONENT_DIR} + YAMCS_DATA_DIR: ${YAMCS_DATA_DIR} + GSW_SOFTWARE: ${GSW_SOFTWARE} + GIT_URL: ${YAMCS_GIT_URL} + GIT_COMMIT: ${YAMCS_GIT_COMMIT} + healthcheck: + test: ["CMD-SHELL", "curl http://${YAMCS_HOST}:${YAMCS_PORT}/api"] + interval: 10s + timeout: 5s + retries: 10 + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-gsw + hostname: ${COMPOSE_PROJECT_NAME}-gsw + working_dir: "/home/nos3/.nos3/yamcs" + command: "/entrypoint.sh" + volumes: + - ${PWD}/services/yamcs/entrypoint.sh:/entrypoint.sh + - ${PWD}/services/yamcs/settings.xml:/home/nos3/.nos3/yamcs/settings.xml + ports: + - "127.0.0.1:${YAMCS_HOST_PORT}:${YAMCS_PORT}" + tty: true + stdin_open: true + privileged: true + environment: + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + MAVEN_REPO_LOCAL: ${MAVEN_REPO_LOCAL} + MAVEN_HTTPS_PROXY: ${MAVEN_HTTPS_PROXY} + COMPONENT_DIR: ${COMPONENT_DIR} + YAMCS_DATA_DIR: ${YAMCS_DATA_DIR} + GSW_SOFTWARE: ${GSW_SOFTWARE} + GIT_URL: ${YAMCS_GIT_URL} + GIT_COMMIT: ${YAMCS_GIT_COMMIT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - active-gs + - yamcs + - cosmos + mission-network: + + nos3-onair: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-onair + hostname: ${COMPOSE_PROJECT_NAME}-onair + working_dir: /home/nos3/builds/nos3/fsw/build/exe/cpu1 + command: "/home/nos3/builds/nos3/scripts/fsw/onair_launch.sh" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + BASE_DIR: /home/nos3/builds/nos3 + FSW_DIR: /home/nos3/builds/nos3/fsw/build/exe/cpu1 + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + SCRIPT_DIR: + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - onair + - sc01-onair + mission-network: + + nos3-fsw: + image: nos3-base-local:dev + env_file: + - ./.env + build: + context: ./services/fsw + dockerfile: Dockerfile + args: + + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + MAVEN_HTTPS_PROXY: ${MAVEN_HTTPS_PROXY} + + GIT_URL: ${NOS3_GIT_URL} + GIT_COMMIT: ${NOS3_GIT_COMMIT} + + NOS3_USER: ${NOS3_USER} + BASE_DIR: ${NOS3_BASE_DIR} + IMAGE_URI: ${NOS3_IMAGE_URI} + FSW_SOFTWARE: ${FSW_SOFTWARE} + GSW_SOFTWARE: ${GSW_SOFTWARE} + LD_LIBRARY_PATH: /usr/local/lib + GROUND_SOFTWARE: ${GSW_SOFTWARE} + + healthcheck: + test: ["CMD-SHELL", "/usr/bin/pgrep core-cpu1"] + interval: 10s + timeout: 5s + retries: 5 + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-nos-engine-server: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-fsw + hostname: ${COMPOSE_PROJECT_NAME}-fsw + working_dir: /home/nos3/builds/nos3/ + volumes: + - ${PWD}/services/fsw/entrypoint.sh:/entrypoint.sh + command: "/entrypoint.sh" + sysctls: + fs.mqueue.msg_max: 10000 + ulimits: + rtprio: 99 + cap_add: + - sys_nice + environment: + BASE_DIR: /home/nos3/builds/nos3 + FSW_DIR: /home/nos3/builds/nos3/fsw/build/exe/cpu1 + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - fsw + - sc01-fsw + mission-network: + + nos3-nos-engine-server: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "/usr/bin/nc -vz nos-engine-server 12000 && /usr/bin/nc -vz nos-engine-server 12001"] + interval: 10s + timeout: 5s + retries: 5 + container_name: ${COMPOSE_PROJECT_NAME}-nos-engine-server + hostname: ${COMPOSE_PROJECT_NAME}-nos-engine-server + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "/usr/bin/nos_engine_server_standalone -f ./nos_engine_server_config.json" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos_engine_server_config.json:/home/nos3/builds/nos3/sims/build/bin/nos_engine_server_config.json + tty: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: +# TODO: below is needed for some reason! + - sc01-nos-engine-server + - nos-engine-server + mission-network: + + nos3-truth42sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-gsw: + condition: service_healthy + nos3-nos-engine-server: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-truth42sim + hostname: ${COMPOSE_PROJECT_NAME}-truth42sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml truth42sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - truth42sim + mission-network: + + nos3-nos-terminal: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-nos-terminal + hostname: ${COMPOSE_PROJECT_NAME}-nos-terminal + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml stdio-terminal" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - nos-terminal + mission-network: + + nos3-nos-udp-terminal: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-nos-udp-terminal + hostname: ${COMPOSE_PROJECT_NAME}-nos-udp-terminal + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml udp-terminal" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - nos-udp-terminal + mission-network: + + nos3-nos-sim-bridge: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-nos-sim-bridge + hostname: ${COMPOSE_PROJECT_NAME}-nos-sim-bridge + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-sim-cmdbus-bridge -f ./nos3-simulator.xml" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - nos-sim-bridge + mission-network: + + nos3-camsim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-cam-sim + hostname: ${COMPOSE_PROJECT_NAME}-cam-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml camsim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - camsim +# TODO: needed? + - sc01-camsim + mission-network: + + nos3-css-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-css-sim + hostname: ${COMPOSE_PROJECT_NAME}-css-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-css-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - css + - css-sim + mission-network: + + nos3-eps-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-nos-engine-server: + condition: service_healthy + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-eps-sim + hostname: ${COMPOSE_PROJECT_NAME}-eps-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-eps-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - eps +# TODO: needed? + - sc01-eps-sim + mission-network: + + nos3-fss-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-fss-sim + hostname: ${COMPOSE_PROJECT_NAME}-fss-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-fss-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - fss +# TODO: needed? + - sc01-fss-sim + mission-network: + + nos3-gps-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-gps-sim + hostname: ${COMPOSE_PROJECT_NAME}-gps-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml gps" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - gps +# TODO: needed? + - sc01-gps-sims + mission-network: + + nos3-imu-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-imu-sim + hostname: ${COMPOSE_PROJECT_NAME}-imu-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-imu-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - imu +# TODO: needed? + - sc01-imu-sim + mission-network: + + nos3-mag-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-mag-sim + hostname: ${COMPOSE_PROJECT_NAME}-mag-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-mag-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - mag +# TODO: needed? + - sc01-mag-sim + mission-network: + + nos3-rw-sim0: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-rw-sim0 + hostname: ${COMPOSE_PROJECT_NAME}-rw-sim0 + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim0" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - rw0 +# TODO: needed? + - sc01-rw-sim0 + mission-network: + + nos3-rw-sim1: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-rw-sim1 + hostname: ${COMPOSE_PROJECT_NAME}-rw-sim1 + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim1" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - rw1 +# TODO: needed? + - sc01-rw-sim1 + mission-network: + + nos3-rw-sim2: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-rw-sim2 + hostname: ${COMPOSE_PROJECT_NAME}-rw-sim2 + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim2" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - rw2 +# TODO: needed? + - sc01-rw-sim2 + mission-network: + + # nos3-radio-sim: + # image: ghcr.io/haisamido/nos3-base:dev + # env_file: + # - ./.env + # attach: true + # healthcheck: + # test: [ "CMD-SHELL", "/usr/bin/pgrep -f nos3-single-simulator" ] + # interval: 10s + # timeout: 5s + # retries: 7 + # depends_on: + # nos3-cryptolib: + # condition: service_started + # container_name: sc01-radio-sim + # hostname: radio-sim + # working_dir: /home/nos3/builds/nos3/sims/build/bin + # command: "/entrypoint.sh" + # volumes: + # - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + # - ${PWD}/radio-sim/entrypoint.sh:/entrypoint.sh + # environment: + # HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + # networks: + # mission-spacecraft-network: + # # aliases: + # # - radio-sim + # mission-network: + +# nos3-cryptolib: +# image: nos3-base-local:dev +# env_file: +# - ./.env +# attach: true +# healthcheck: +# test: ["CMD-SHELL", "/usr/bin/pgrep -f ./support/standalone"] +# interval: 10s +# timeout: 5s +# retries: 5 +# depends_on: +# # nos3-radio-sim: +# # condition: service_started +# nos3-fsw: +# condition: service_healthy +# container_name: sc01_cryptolib-gsw +# # hostname: cryptolib +# working_dir: /home/nos3/builds/nos3/gsw/build +# command: "./support/standalone" +# volumes: +# - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml +# environment: +# HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} +# networks: +# mission-spacecraft-network: +# aliases: +# - cryptolib +# mission-network: + + nos3-radio-sim-cryptolib: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + healthcheck: + test: [ "CMD-SHELL", "/usr/bin/pgrep -f nos3-single-simulator && /usr/bin/pgrep -f ./support/standalone" ] + interval: 10s + timeout: 5s + retries: 7 + depends_on: + nos3-fsw: + condition: service_healthy + nos3-gsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-radio-sim-cryptolib + hostname: ${COMPOSE_PROJECT_NAME}- radio-sim-cryptolib + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "/entrypoint.sh" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + - ${PWD}/services/radio-sim/entrypoint2.sh:/entrypoint.sh + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - radio-sim + - cryptolib + mission-network: + + nos3-sample-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-sample-sim + hostname: ${COMPOSE_PROJECT_NAME}-sample-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml sample-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - sample-sim + mission-network: + + nos3-startrk-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-startrk-sim + hostname: ${COMPOSE_PROJECT_NAME}-startrk-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-star-tracker-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - startrk-sim + mission-network: + + nos3-thruster-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-thruster-sim + hostname: ${COMPOSE_PROJECT_NAME}-thruster-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-thruster-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - thruster-sim + mission-network: + + nos3-torquer-sim: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-fortytwo: + condition: service_healthy + nos3-fsw: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-torquer-sim + hostname: ${COMPOSE_PROJECT_NAME}-torquer-sim + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml generic-torquer-sim" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - torquer-sim + - trq-sim + mission-network: + + nos3-time: + image: nos3-base-local:dev + env_file: + - ./.env + attach: true + depends_on: + nos3-nos-engine-server: + condition: service_healthy + container_name: ${COMPOSE_PROJECT_NAME}-nos-time-driver + hostname: ${COMPOSE_PROJECT_NAME}-nos-time-driver + working_dir: /home/nos3/builds/nos3/sims/build/bin + command: "./nos3-single-simulator -f ./nos3-simulator.xml time" + volumes: + - ${PWD}/${NOS3_CFG_PATH}/cfg/build/sims/nos3-simulator.xml:/home/nos3/builds/nos3/sims/build/bin/nos3-simulator.xml + tty: true + stdin_open: true + privileged: true + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - ${COMPOSE_PROJECT_NAME}-nos-time-driver + mission-network: + + nos3-openmct: + env_file: + - ./.env + build: + context: ./services/openmct + dockerfile: Containerfile + args: + DEPLOYMENT_ENVIRO: ${DEPLOYMENT_ENVIRO} + HTTPS_PROXY: ${HTTPS_PROXY} + HTTP_PROXY: ${HTTP_PROXY} + NO_PROXY: ${NO_PROXY} + + IMAGE_URI: ${OPENMCT_IMAGE_URI} + NVM_VERSION: ${OPENMCT_NVM_VERSION} + NODE_VERSION: ${OPENMCT_NODE_VERSION} + + GIT_URL: ${OPENMCT_GIT_URL} + GIT_COMMIT: ${OPENMCT_GIT_COMMIT} + + attach: true + container_name: ${COMPOSE_PROJECT_NAME}-openmct + hostname: ${COMPOSE_PROJECT_NAME}-openmct + working_dir: "/opt/openmct" + volumes: + - "${PWD}/services/openmct/entrypoint.sh:/opt/openmct/entrypoint.sh" + - "${PWD}/services/openmct/webpack.dev.mjs:/opt/openmct/.webpack/webpack.dev.mjs" + - "${PWD}/services/openmct/example/index.js:/opt/openmct/example/index.js" + - "${PWD}/services/openmct/example/make-example-events.mjs:/opt/openmct/example/make-example-events.mjs" + command: '/opt/openmct/entrypoint.sh' + healthcheck: + test: ["CMD-SHELL", "curl http://localhost:${OPENMCT_PORT}/"] + interval: 10s + timeout: 5s + retries: 30 + start_period: 30s + depends_on: + nos3-gsw: + condition: service_healthy + ports: + - "127.0.0.1:${OPENMCT_HOST_PORT}:${OPENMCT_PORT}" + environment: + MISSION: ${MISSION} + SPACECRAFT: ${SPACECRAFT} + PROJECT_NAME: ${PROJECT_NAME} + networks: + mission-spacecraft-network: + aliases: + - openmct + mission-network: + fleet-network: + +networks: + fleet-network: + external: ${EXTERNAL_NETWORK_FLEET:-false} + name: ${FLEET}-fleet + mission-network: + external: ${EXTERNAL_NETWORK_MISSION:-false} + name: ${PROJECT_MISSION} + mission-spacecraft-network: + external: ${EXTERNAL_NETWORK_MISSION_SPACECRAFT:-false} + name: ${COMPOSE_PROJECT_NAME} diff --git a/deployments/docs/FlowDiagram.md b/deployments/docs/FlowDiagram.md new file mode 100644 index 000000000..082a8c85b --- /dev/null +++ b/deployments/docs/FlowDiagram.md @@ -0,0 +1,212 @@ +# NOS3 Data Flow Diagram + +```mermaid +flowchart TB + subgraph External["External Access"] + User["👤 User/Browser"] + end + + subgraph GroundSoftware["Ground Software"] + YAMCS["nos3-gsw
(YAMCS)
:8090, :5012"] + OpenMCT["nos3-openmct
:9000, :8080"] + end + + subgraph FlightSoftware["Flight Software"] + FSW["nos3-fsw
(cFS Flight Software)"] + OnAir["nos3-onair
(On-Air Launch)"] + end + + subgraph SimulationCore["Simulation Core"] + FortyTwo["nos3-fortytwo
(42 Simulator)
:30090"] + NosEngine["nos3-nos-engine-server
:12000, :12001"] + Time["nos3-time
(Time Driver)"] + Truth42["nos3-truth42sim"] + end + + subgraph Terminals["Terminals & Bridges"] + Terminal["nos3-nos-terminal
(STDIO Terminal)"] + UDPTerminal["nos3-nos-udp-terminal
(UDP Terminal)"] + SimBridge["nos3-nos-sim-bridge
(Command Bus Bridge)"] + end + + subgraph SensorSimulators["Sensor Simulators"] + CSS["nos3-css-sim
(Coarse Sun Sensor)"] + FSS["nos3-fss-sim
(Fine Sun Sensor)"] + GPS["nos3-gps-sim"] + IMU["nos3-imu-sim"] + MAG["nos3-mag-sim
(Magnetometer)"] + StarTrk["nos3-startrk-sim
(Star Tracker)"] + CAM["nos3-camsim
(Camera)"] + end + + subgraph ActuatorSimulators["Actuator Simulators"] + RW0["nos3-rw-sim0
(Reaction Wheel 0)"] + RW1["nos3-rw-sim1
(Reaction Wheel 1)"] + RW2["nos3-rw-sim2
(Reaction Wheel 2)"] + Thruster["nos3-thruster-sim"] + Torquer["nos3-torquer-sim"] + end + + subgraph OtherSims["Other Simulators"] + EPS["nos3-eps-sim
(Power System)"] + Sample["nos3-sample-sim"] + RadioCrypto["nos3-radio-sim-cryptolib
(Radio + CryptoLib)"] + end + + %% User Access + User -->|":8090 YAMCS Web"| YAMCS + User -->|":9000/:8080 OpenMCT"| OpenMCT + User -->|":30090 42 VNC"| FortyTwo + + %% Ground to Flight Communication + OpenMCT -->|"Telemetry API"| YAMCS + YAMCS <-->|"Commands/Telemetry
via RadioCrypto"| RadioCrypto + RadioCrypto <-->|"Encrypted Comms"| FSW + + %% Core Dependencies + FSW -->|"depends_on"| FortyTwo + FSW -->|"depends_on"| NosEngine + Time -->|"depends_on"| NosEngine + Truth42 -->|"depends_on"| NosEngine + + %% NOS Engine as central hub + NosEngine <-->|"Time Sync"| Time + NosEngine <-->|"Simulation Bus"| FSW + NosEngine <-->|"42 Data"| Truth42 + + %% 42 Simulator provides environment data + FortyTwo -->|"Spacecraft State
(Position, Attitude)"| Truth42 + FortyTwo -->|"Sun Vector"| CSS + FortyTwo -->|"Sun Vector"| FSS + FortyTwo -->|"Orbit/Position"| GPS + FortyTwo -->|"Angular Rates"| IMU + FortyTwo -->|"Magnetic Field"| MAG + FortyTwo -->|"Star Field"| StarTrk + FortyTwo -->|"Scene Data"| CAM + FortyTwo -->|"Solar Power"| EPS + + %% Sensor data to FSW + CSS -->|"Sensor Data"| FSW + FSS -->|"Sensor Data"| FSW + GPS -->|"Sensor Data"| FSW + IMU -->|"Sensor Data"| FSW + MAG -->|"Sensor Data"| FSW + StarTrk -->|"Sensor Data"| FSW + CAM -->|"Sensor Data"| FSW + EPS -->|"Power Status"| FSW + Sample -->|"Sample Data"| FSW + + %% FSW commands to actuators + FSW -->|"Wheel Commands"| RW0 + FSW -->|"Wheel Commands"| RW1 + FSW -->|"Wheel Commands"| RW2 + FSW -->|"Thrust Commands"| Thruster + FSW -->|"Torque Commands"| Torquer + + %% Actuator feedback to 42 + RW0 -->|"Torque Applied"| FortyTwo + RW1 -->|"Torque Applied"| FortyTwo + RW2 -->|"Torque Applied"| FortyTwo + Thruster -->|"Thrust Applied"| FortyTwo + Torquer -->|"Torque Applied"| FortyTwo + + %% Terminals + SimBridge <-->|"Command Bus"| FSW + Terminal <-->|"Debug I/O"| NosEngine + UDPTerminal <-->|"UDP Debug"| NosEngine + + %% Styling + classDef ground fill:#4a90d9,stroke:#2c5282,color:#fff + classDef flight fill:#48bb78,stroke:#276749,color:#fff + classDef simcore fill:#ed8936,stroke:#c05621,color:#fff + classDef sensor fill:#9f7aea,stroke:#6b46c1,color:#fff + classDef actuator fill:#f56565,stroke:#c53030,color:#fff + classDef terminal fill:#718096,stroke:#4a5568,color:#fff + classDef other fill:#38b2ac,stroke:#285e61,color:#fff + classDef external fill:#ecc94b,stroke:#b7791f,color:#000 + + class YAMCS,OpenMCT ground + class FSW,OnAir flight + class FortyTwo,NosEngine,Time,Truth42 simcore + class CSS,FSS,GPS,IMU,MAG,StarTrk,CAM sensor + class RW0,RW1,RW2,Thruster,Torquer actuator + class Terminal,UDPTerminal,SimBridge terminal + class EPS,Sample,RadioCrypto other + class User external +``` + +## NOS3 Architecture Overview + +The diagram shows the **NASA Operational Simulator for Small Satellites (NOS3)** system with these key data flows: + +### Core Components + +| Component | Purpose | Ports | +|-----------|---------|-------| +| **nos3-fortytwo** | 42 Spacecraft Dynamics Simulator | :30090 (VNC) | +| **nos3-nos-engine-server** | Central simulation bus | :12000, :12001 | +| **nos3-fsw** | cFS Flight Software | - | +| **nos3-gsw (YAMCS)** | Ground Software/Mission Control | :8090, :5012 | +| **nos3-openmct** | Web-based telemetry visualization | :9000, :8080 | + +### Data Flow Patterns + +1. **Environment → Sensors**: 42 Simulator provides spacecraft state data (sun vectors, magnetic field, star field, etc.) to sensor simulators + +2. **Sensors → FSW**: Sensor simulators send telemetry to the Flight Software + +3. **FSW → Actuators**: Flight Software sends commands to reaction wheels, thrusters, and torquers + +4. **Actuators → Environment**: Actuator responses feed back to 42 Simulator to update spacecraft dynamics + +5. **FSW ↔ Ground**: Radio simulator with CryptoLib handles encrypted communication between flight and ground software + +### Networks + +All services connect to both Docker networks: +- **nos3-core**: Core infrastructure network +- **nos3-sc01**: Spacecraft 01 network + +### Service Dependencies + +```mermaid +flowchart LR + subgraph StartupOrder["Startup Order"] + NE["nos-engine-server"] --> FSW["nos3-fsw"] + FT["nos3-fortytwo"] --> FSW + FSW --> Sims["Sensor/Actuator Sims"] + FSW --> Radio["radio-sim-cryptolib"] + YAMCS["nos3-gsw"] --> Radio + YAMCS --> OpenMCT["nos3-openmct"] + end +``` + +### Sensor Simulators + +| Simulator | Description | +|-----------|-------------| +| **nos3-css-sim** | Coarse Sun Sensor | +| **nos3-fss-sim** | Fine Sun Sensor | +| **nos3-gps-sim** | GPS Receiver | +| **nos3-imu-sim** | Inertial Measurement Unit | +| **nos3-mag-sim** | Magnetometer | +| **nos3-startrk-sim** | Star Tracker | +| **nos3-camsim** | Camera | + +### Actuator Simulators + +| Simulator | Description | +|-----------|-------------| +| **nos3-rw-sim0/1/2** | Reaction Wheels (3-axis control) | +| **nos3-thruster-sim** | Thruster | +| **nos3-torquer-sim** | Magnetic Torquer | + +### Other Simulators + +| Simulator | Description | +|-----------|-------------| +| **nos3-eps-sim** | Electrical Power System | +| **nos3-sample-sim** | Sample/Payload Simulator | +| **nos3-radio-sim-cryptolib** | Radio with encryption (CryptoLib) | +| **nos3-time** | Time synchronization driver | +| **nos3-truth42sim** | Ground truth from 42 | diff --git a/deployments/kustomization.yaml b/deployments/kustomization.yaml new file mode 100644 index 000000000..ca3f98015 --- /dev/null +++ b/deployments/kustomization.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./services/fortytwo/kubernetes/ diff --git a/deployments/nos3/cfg/InOut/Inp_IPC.txt b/deployments/nos3/cfg/InOut/Inp_IPC.txt new file mode 100644 index 000000000..fe1505fcd --- /dev/null +++ b/deployments/nos3/cfg/InOut/Inp_IPC.txt @@ -0,0 +1,21 @@ +<<<<<<<<<<<<<<< 42: InterProcess Comm Configuration File >>>>>>>>>>>>>>>> +2 ! Number of Sockets +********************************** GPS IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State03.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4245 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].GPS[0]" ! Prefix 0 +********************************** Truth data to sim to pass to COSMOS ******************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 9999 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +2 ! Number of TX prefixes +"SC" ! Prefix 0 +"Orb" ! Prefix 1 diff --git a/deployments/nos3/cfg/InOut/Inp_IPC.txt.orig b/deployments/nos3/cfg/InOut/Inp_IPC.txt.orig new file mode 100644 index 000000000..6dcb7b493 --- /dev/null +++ b/deployments/nos3/cfg/InOut/Inp_IPC.txt.orig @@ -0,0 +1,161 @@ +<<<<<<<<<<<<<<< 42: InterProcess Comm Configuration File >>>>>>>>>>>>>>>> +17 ! Number of Sockets +********************************** RW 0 to 42 ***************************** +RX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State01.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4278 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC" ! Prefix 0 +********************************** RW 0 from 42 ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State02.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4277 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].Whl[0].H" ! Prefix 0 +********************************** RW 1 to 42 ***************************** +RX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State01.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4378 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC" ! Prefix 0 +********************************** RW 1 from 42 ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State02.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4377 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].Whl[1].H" ! Prefix 0 +********************************** RW 2 to 42 ***************************** +RX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State01.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4478 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC" ! Prefix 0 +********************************** RW 2 from 42 ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State02.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4477 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].Whl[2].H" ! Prefix 0 +********************************** Torquer IPC ***************************** +RX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"Torquer.Rx" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4279 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC" ! Prefix 0 +********************************** Thruster IPC **************************** +RX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"Thruster.Rx" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4280 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC" ! Prefix 0 +********************************** GPS IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State03.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4245 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].GPS[0]" ! Prefix 0 +********************************** CSS IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State04.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4227 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].CSS" ! Prefix 0 +********************************** MAG IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State05.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4234 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].MAG" ! Prefix 0 +********************************** Truth data to sim to pass to COSMOS ******************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 9999 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +2 ! Number of TX prefixes +"SC" ! Prefix 0 +"Orb" ! Prefix 1 +********************************** Write to file for analysis ***************************** +WRITEFILE ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"State.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 6008 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +2 ! Number of TX prefixes +"SC" ! Prefix 0 +"Orb" ! Prefix 1 +********************************** FSS IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"FSS.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4284 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].FSS[0]" ! Prefix 0 +********************************** IMU IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"IMU.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4281 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +2 ! Number of TX prefixes +"SC[0].Accel" ! Prefix 0 +"SC[0].Gyro" ! Prefix 1 +********************************** Star Tracker IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"ST.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4282 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +1 ! Number of TX prefixes +"SC[0].ST" ! Prefix 0 +********************************** EPS IPC ***************************** +TX ! IPC Mode (OFF,TX,RX,TXRX,ACS,WRITEFILE,READFILE) +"EPS.42" ! File name for WRITE or READ +SERVER ! Socket Role (SERVER,CLIENT,GMSEC_CLIENT) +fortytwo 4283 ! Server Host Name, Port +FALSE ! Allow Blocking (i.e. wait on RX) +FALSE ! Echo to stdout +4 ! Number of TX prefixes +"SC[0].svb" ! Prefix 0 +"SC[0].PosR" ! Prefix 1 +"SC[0].qn" ! Prefix 2 +"Orb[0].PosN" ! Prefix 3 \ No newline at end of file diff --git a/deployments/nos3/cfg/nos3-mission.xml b/deployments/nos3/cfg/nos3-mission.xml new file mode 100644 index 000000000..221ecbf93 --- /dev/null +++ b/deployments/nos3/cfg/nos3-mission.xml @@ -0,0 +1,23 @@ + + 1767225600.0 + + + + + yamcs + + + + cfs + + + + 1 + + + + sc-full-config.xml + + + + diff --git a/deployments/nos3/cfg/sc-fprime-config.xml b/deployments/nos3/cfg/sc-fprime-config.xml new file mode 100644 index 000000000..b9b6eb4f6 --- /dev/null +++ b/deployments/nos3/cfg/sc-fprime-config.xml @@ -0,0 +1,84 @@ + + + + + false + + + false + + + false + + + false + + + false + + + false + + + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + true + + + false + + + true + + + true + + + false + + + false + + + false + + + + true + + + -5.0 + -5.0 + 5.0 + + + false + + \ No newline at end of file diff --git a/deployments/nos3/cfg/sc-full-config.xml b/deployments/nos3/cfg/sc-full-config.xml new file mode 100644 index 000000000..f3fd5ebbd --- /dev/null +++ b/deployments/nos3/cfg/sc-full-config.xml @@ -0,0 +1,84 @@ + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + true + + + 0.1 + 1.0 + -1.0 + + + true + + \ No newline at end of file diff --git a/deployments/nos3/cfg/sc-minimal-config.xml b/deployments/nos3/cfg/sc-minimal-config.xml new file mode 100644 index 000000000..e7bfe0919 --- /dev/null +++ b/deployments/nos3/cfg/sc-minimal-config.xml @@ -0,0 +1,84 @@ + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + true + + + false + + + false + + + false + + + false + + + + true + + + -5.0 + -5.0 + 5.0 + + + false + + \ No newline at end of file diff --git a/deployments/nos3/cfg/sims/nos3-simulator.xml b/deployments/nos3/cfg/sims/nos3-simulator.xml new file mode 100644 index 000000000..e2f293ae0 --- /dev/null +++ b/deployments/nos3/cfg/sims/nos3-simulator.xml @@ -0,0 +1,658 @@ + + + + + sim_log_config.xml + + + + + + 1767225600.0 + 10000 + 10000 + tcp://nos-engine-server:12001 + + + + + time + true + libnos_time_driver.so + + TimeDriver + + + time + tcp://sc01-nos-engine-server:12001 + command + sc1-time-driver + + + command + command + time-command + + + + + + + stdio-terminal + true + libsim_terminal.so + + SimTerminal + + STDIO + 5555 + false + + + + + + command + command + + stdio-terminal + sample-command + ASCII + ASCII + + + + + + + + udp-terminal + true + libsim_terminal.so + + SimTerminal + + UDP + 5556 + false + + + + + + command + command + + udp-terminal + sample-command + ASCII + ASCII + + + + + + + + cmdbus-bridge + true + + SIM_CMDBUS_BRIDGE + + + command + command + sim-cmdbus-bridge-node + + + + + + + + + + + sample-sim + true + libsample_sim.so + + SAMPLE + + command + command + sample-command + + usart + usart_16 + 16 + + + + SAMPLE_PROVIDER + + + + + + + gps + true + libgps_sim.so + + OEM615 + + + usart + usart_1 + 1 + + + + GPS42SOCKET + fortytwo + 4245 + 30 + 1 + 0 + 0 + 37 + + + + + + + camsim + true + libcam_sim.so + + ARDUCAM_OV5640 + + commandcommandcam-command-node + + + +
60
+ i2c_2 +
+ + spi_0 + 0 + +
+
+ + + generic-eps-sim + true + libgeneric_eps_sim.so + + GENERIC_EPS + + + command + command + eps-command + + + i2c + i2c_1 + 0x2B + 10 + + + + + GENERIC_EPS_42_PROVIDER + fortytwo + 4283 + 30 + 1 + 0 + + + + 24.0 + 30.0 + 1.0 + 32.0 + 80.0 + + + sample-command + 1.23 + 4.56 + 0000 + + + star-tracker-command + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 3.30 + 0.25 + 0000 + + + unknown-sim-command-node + 12.00 + 1.23 + 0000 + + + + + + + generic-reactionwheel-sim0 + true + libgeneric_rw_sim.so + + GENERICREACTIONWHEELHARDWARE + + commandcommandrw0-command + usart + usart_2 + 2 + + + + GENERICRWSIMDATA42SOCKETPROVIDER + fortytwo + 4277 + 4278 + 30 + 1 + 0 + 0 + + + + + + generic-reactionwheel-sim1 + true + libgeneric_rw_sim.so + + GENERICREACTIONWHEELHARDWARE + + commandcommandrw1-command + usart + usart_3 + 3 + + + + GENERICRWSIMDATA42SOCKETPROVIDER + fortytwo + 4377 + 4378 + 30 + 1 + 0 + 1 + + + + + + generic-reactionwheel-sim2 + true + libgeneric_rw_sim.so + + GENERICREACTIONWHEELHARDWARE + + commandcommandrw2-command + usart + usart_4 + 4 + + + + GENERICRWSIMDATA42SOCKETPROVIDER + fortytwo + 4477 + 4478 + 30 + 1 + 0 + 2 + + + + + + generic-css-sim + true + libgeneric_css_sim.so + + GENERIC_CSS + + + command + command + css-command + + + + GENERIC_CSS_42_PROVIDER + fortytwo + 4227 + 30 + 1 + 0 + <42-css-scale-factor>1.0 + + +
64
+ i2c_2 +
+
+
+ + + generic-torquer-sim + true + libgeneric_torquer_sim.so + + GENERIC_TORQUER + + + command + command + torquer-command + + + + GENERIC_TORQUER_42_PROVIDER + fortytwo + 4279 + 30 + 1 + + + 3 + + + 1.42 + 1.42 + 1.42 + + + + + + generic-thruster-sim + true + libgeneric_thruster_sim.so + + GENERIC_THRUSTER + + + command + command + thruster-command + + usart + usart_29 + 29 + + + + GENERIC_THRUSTER_42_PROVIDER + fortytwo + 4280 + 30 + 1 + + + + + + truth42sim + true + libtruth_42_sim.so + + TRUTH42 + cosmos + 5111 + 1.0 + 100 + + + commandcommandtruth42-sim-command-node + + + TRUTH42PROVIDER + fortytwo + 9999 + 30 + 1 + 0 + 0 + + + + + + generic-fss-sim + true + libgeneric_fss_sim.so + + GENERIC_FSS + + commandcommandfss-command + spi + spi_1 + 1 + + + + GENERIC_FSS_42_PROVIDER + fortytwo + 4284 + 30 + 1 + 0 + + + + + + generic-radio-sim + true + libgeneric_radio_sim.so + + GENERIC_RADIO + + + command + command + radio-sim-command-node + + + fsw + nos-fsw + 5010 + 5011 + 5015 + + + radio + radio-sim + 5014 + + + gsw + + + + + + cryptolib + 8010 + 8011 + + + prox + radio-sim + 7012 + 7010 + 7011 + 7012 + + + + GENERIC_RADIO_PROVIDER + + + + + + generic-imu-sim + true + libgeneric_imu_sim.so + + GENERIC_IMU + + command + command + imu-command + + can + can_0 + 15 + + + + GENERIC_IMU_42_PROVIDER + fortytwo + 4281 + 30 + 1 + 0 + + + + + + generic-mag-sim + true + libgeneric_mag_sim.so + + GENERIC_MAG + + command + command + mag-command + + spi + spi_2 + 2 + + + + GENERIC_MAG_42_PROVIDER + fortytwo + 4234 + 30 + 1 + 0 + + + + + + generic-star-tracker-sim + true + libgeneric_star_tracker_sim.so + + GENERIC_STAR_TRACKER + + command + command + star-tracker-command + + usart + usart_10 + 10 + + + + GENERIC_STAR_TRACKER_42_PROVIDER + fortytwo + 4282 + 30 + 1 + 0 + 0 + + + + +
+
diff --git a/deployments/nos3/cfg/sims/nos_engine_server_config.json b/deployments/nos3/cfg/sims/nos_engine_server_config.json new file mode 100644 index 000000000..aea5ced90 --- /dev/null +++ b/deployments/nos3/cfg/sims/nos_engine_server_config.json @@ -0,0 +1,17 @@ +{ + "plugins": [ + "uart" + ], + + "server_uris": [ + { + "name": "fsw", + "server_uri": "tcp://nos-engine-server:12000" + }, + { + "name": "nos3", + "server_uri": "tcp://nos-engine-server:12001" + } + ] +} + diff --git a/deployments/nos3/cfg/sims/sim_log_config.xml b/deployments/nos3/cfg/sims/sim_log_config.xml new file mode 100644 index 000000000..d1e5ea3d7 --- /dev/null +++ b/deployments/nos3/cfg/sims/sim_log_config.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/deployments/scripts/env.sh b/deployments/scripts/env.sh new file mode 100755 index 000000000..57feeb579 --- /dev/null +++ b/deployments/scripts/env.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash + +set -e + +# A script to generate .env file for container deployments + +# Simulation specific inputs +NOW=$(date -u +"%Y-%m-%d %H:%M:%S UTC") +SIM_T0_DATETIME="2026-01-01 00:00:00 UTC" +SIM_T0_DATETIME="${NOW}" + +TIME_INTERVAL=3600 # 1 hour in seconds +TIME_INTERVAL_MILLISECONDS=$( expr ${TIME_INTERVAL} \* 1000 ) + +#SIM_T0_DATETIME="${NOW}" +LEAP_SECONDS=37 + +GSW_SOFTWARE=yamcs +FSW_SOFTWARE=cfs + +# This is to define either the standard path, i.e. ${PWD}/nos3, or a local definition +NOS3_CFG_PATH=.. +NOS3_MISSION_CFG_FILE=../cfg/nos3-mission.xml + +NOS3_GIT_URL=https://github.com/nasa/nos3 +NOS3_GIT_COMMIT=dev + +NOS3_IMAGE_URI=docker.io/ivvitc/nos3-64:20251107 +NOS3_BASE_DIR=/home/nos3/.nos3 + +PROJECT=${PROJECT:-nos3} +MISSION=${MISSION:-m01} +SPACECRAFT=${SPACECRAFT:-sc01} +PROJECT_NAME=${PROJECT}-${MISSION}-${SPACECRAFT} +PROJECT_MISSION=${PROJECT}-${MISSION} +SC_ENVIRO=${SC_ENVIRO:-sim} + +FORTYTWO_HOST=${FORTYTWO_HOST:-localhost} +FORTYTWO_PORT=${FORTYTWO_PORT:-80} +FORTYTWO_HOST_PORT=${FORTYTWO_HOST_PORT:-30090} + +YAMCS_HOST=${YAMCS_HOST:-localhost} +YAMCS_PORT=${YAMCS_PORT:-8090} +YAMCS_HOST_PORT=${YAMCS_HOST_PORT:-8090} + +OPENMCT_HOST=${OPENMCT_HOST:-localhost} +OPENMCT_PORT=${OPENMCT_PORT:-9000} +OPENMCT_HOST_PORT=${OPENMCT_HOST_PORT:-9000} + +######################################################################## +# Avoid updating the below variables unless you know what you are doing +######################################################################## + +# Time specific derivations +TIME_OFFSET_SECONDS=+30 # to simulate 30 seconds into the future from SIM_T0_DATETIME +J2000_REFERENCE_DATETIME="2000-01-01 12:00:00 UTC" +SIM_T0_EPOCH_SECONDS=$(date -ud "${SIM_T0_DATETIME} ${TIME_OFFSET_SECONDS} seconds" +"%s") +SIM_T0_EPOCH_MILLISECONDS=$( expr ${SIM_T0_EPOCH_SECONDS} \* 1000 ) +SIM_TF_EPOCH_MILLISECONDS=$( expr ${SIM_T0_EPOCH_MILLISECONDS} + ${TIME_INTERVAL} \* 1000 ) +J2000_EPOCH_SECONDS=$(date -ud "${J2000_REFERENCE_DATETIME}" +"%s") + +cat << EOF +# +# Auto-generated by ${PWD}/$(basename $0) on $(date -u +"%Y-%m-%dT%H:%M:%S%z") +# + +PROJECT=${PROJECT} +FLEET=${PROJECT} +MISSION=${MISSION} +SPACECRAFT=${SPACECRAFT} +PROJECT_NAME=${PROJECT_NAME} +PROJECT_MISSION=${PROJECT_MISSION} +COMPOSE_PROJECT_NAME=${PROJECT_NAME} +SC_ENVIRO=${SC_ENVIRO} + +# nos3 specific configurations +NOS3_GIT_URL=${NOS3_GIT_URL} +NOS3_GIT_COMMIT=${NOS3_GIT_COMMIT} +NOS3_DIR=/home/nos3/.nos3 +NOS3_USER=nos3 +NOS3_IMAGE_URI=${NOS3_IMAGE_URI} +NOS3_BASE_DIR=${NOS3_BASE_DIR} + +# This is to define either the standard path, i.e. ${PWD}/nos3, or a local definition +NOS3_CFG_PATH=${NOS3_CFG_PATH} +NOS3_MISSION_CFG_FILE=${NOS3_MISSION_CFG_FILE} + +# Simulation specific configurations +SIM_T0_DATETIME="${SIM_T0_DATETIME}" +J2000_REFERENCE_DATETIME="${J2000_REFERENCE_DATETIME}" + +TIME_OFFSET_SECONDS=${TIME_OFFSET_SECONDS} +TIME_INTERVAL=${TIME_INTERVAL} +TIME_INTERVAL_MILLISECONDS=${TIME_INTERVAL_MILLISECONDS} + +# In epoch seconds +SIM_T0_EPOCH_SECONDS=${SIM_T0_EPOCH_SECONDS} +SIM_T0_EPOCH_MILLISECONDS=${SIM_T0_EPOCH_MILLISECONDS} +SIM_TF_EPOCH_MILLISECONDS=${SIM_TF_EPOCH_MILLISECONDS} +J2000_EPOCH_SECONDS=${J2000_EPOCH_SECONDS} + +# In J2000 seconds +START_TIME=$((${SIM_T0_EPOCH_SECONDS}-${J2000_EPOCH_SECONDS})) + +# Deployment specific configurations +DEPLOYMENT_ENVIRO=${DEPLOYMENT_ENVIRO} +HEALTHCHECK_PORT=${HEALTHCHECK_PORT} + +# Proxy configurations, the proxy values come for the environment, +# which is important for the vmmoc +HTTPS_PROXY=${HTTPS_PROXY} +HTTP_PROXY=${HTTP_PROXY} +NO_PROXY=${NO_PROXY} + +# Maven/Java specific configurations +MAVEN_REPO_LOCAL=/home/nos3/.nos3/.m2 +MAVEN_HTTPS_PROXY="--settings ./settings.xml" +MAVEN_SETTINGS_FILE=${MAVEN_SETTINGS_FILE} + +# 42 specific configurations +FORTYTWO_DISPLAY=:1 +FORTYTWO_GIT_URL=https://github.com/nasa-itc/42.git +FORTYTWO_GIT_COMMIT=nos3-main +FORTYTWO_GIT_FOLDER=42 +FORTYTWO_STARTUP_FOLDER=NOS3InOut +FORTYTWO_RECOMPILE=false +FORTYTWO_BASE_DIR=/opt/nasa-itc +FORTYTWO_VNC_PASSWORD=$(echo -n "foobar" | shasum -a 256 | cut -d" " -f1) + +FORTYTWO_HOST=${FORTYTWO_HOST} +FORTYTWO_PORT=${FORTYTWO_PORT} +FORTYTWO_HOST_PORT=${FORTYTWO_HOST_PORT} + +FORTYTWO_SIM_DATE="$(date -ud "@${SIM_T0_EPOCH_SECONDS}" +"%m %d %Y")" +FORTYTWO_SIM_TIME="$(date -ud "@${SIM_T0_EPOCH_SECONDS}" +"%H %M %S.%2N")" +FORTYTWO_LEAP_SECONDS=${LEAP_SECONDS} + +# gsw+fsw specific configurations +GSW_SOFTWARE=${GSW_SOFTWARE} +FSW_SOFTWARE=${FSW_SOFTWARE} + +COMPONENT_DIR=/home/nos3/builds/nos3/components + +# yamcs specific configurations +YAMCS_DATA_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yamcs-data +# YAMCS_ETC_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yamcs-etc + +# YAMCS_CACHE_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yam + +YAMCS_GIT_URL=https://github.com/nasa-itc/nos3_yamcs_master.git +YAMCS_GIT_COMMIT=nos3-dev + +YAMCS_INSTANCES=nos3 + +YAMCS_HOST=${YAMCS_HOST} +YAMCS_HOST_PORT=${YAMCS_HOST_PORT} +YAMCS_PORT=${YAMCS_PORT} + +# openmct specific configurations +OPENMCT_IMAGE_URI=docker.io/library/ubuntu:25.04 + +OPENMCT_GIT_URL=https://github.com/akhenry/openmct-yamcs.git +OPENMCT_GIT_COMMIT=master + +OPENMCT_NVM_VERSION=v0.40.1 +OPENMCT_NODE_VERSION=v21.7.3 + +OPENMCT_HOST=${OPENMCT_HOST} +OPENMCT_PORT=${OPENMCT_PORT} +OPENMCT_HOST_PORT=${OPENMCT_HOST_PORT} + +# nasa-itc specific configurations +BASE_DIR=/opt/nasa-itc + +EOF \ No newline at end of file diff --git a/deployments/scripts/generate-k8s.sh b/deployments/scripts/generate-k8s.sh new file mode 100755 index 000000000..bdd0a9b13 --- /dev/null +++ b/deployments/scripts/generate-k8s.sh @@ -0,0 +1,551 @@ +#!/bin/bash -e + +RECREATE=${1:-no} # recreate namespaces, pods, etc. +PROVIDER=${2:-podman} # + +MY_PWD=${PWD} + +#source ./scripts/functions/deployment.sh + +#------------------------------------------------------------------------------ +# A script to generate k8s deployment, service... yaml files and apply them +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# TODO: figure out podman and arm64 for nos3 +export KIND_EXPERIMENTAL_PROVIDER=${PROVIDER} + +K8S_CONTEXT=docker-desktop +NODE_SELECTOR=docker-desktop + +K8S_MODE='docker-desktop' # if this value is different from K8S_CONTEXT, target remote k8s on aws + +# kubectl --context kind-myorg-dev-missions-exp apply -k . +#------------------------------------------------------------------------------ +NOS3_CONFIG=$(cat ./scripts/nos3.yaml | yq 'explode(.)' | grep -iv '^null$') +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Mission/SC/Component Arrays +#------------------------------------------------------------------------------ +OU=$(echo "${NOS3_CONFIG}" | yq '.metadata.OU') +ENVIRO=$(echo "${NOS3_CONFIG}" | yq '.metadata.ENVIRO') +TENANT=$(echo "${NOS3_CONFIG}" | yq '.metadata.TENANT') +PURPOSE=$(echo "${NOS3_CONFIG}" | yq '.metadata.PURPOSE') +CONTEXT=$(echo "${NOS3_CONFIG}" | yq '.metadata.CONTEXT')${PURPOSE} # -exp must exist to match remote cluster system + +REALM=${OU}-${ENVIRO}-${CONTEXT} + +nodeSelector=$(echo "${NOS3_CONFIG}" | yq '.defaults.spec.nodes.nodeSelector') # will be overridden if target k8s is remote +imagePullPolicy=$(echo "${NOS3_CONFIG}" | yq '.defaults.spec.nodes.imagePullPolicy') +HEALTHCHECK_PORT=$(echo "${NOS3_CONFIG}" | yq '.defaults.spec.HEALTHCHECK_PORT') + +MISSIONS=($(echo "$NOS3_CONFIG" | yq '.missions[] | keys[]')) +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Creds +#------------------------------------------------------------------------------ +MISSION_GIT_USER=$(cat ~/.appdat/personal_access_token) +MISSION_GIT_TOKEN=$(cat ~/.appdat/personal_access_token) +MISSION_GIT_SERVER=appdat.jsc.nasa.gov + +K8S_LOCAL=true # to know if k8s is local +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# K8s local or remote +#------------------------------------------------------------------------------ +if [ "${K8S_MODE}" != "${K8S_CONTEXT}" ]; then + + AWS_CLUSTER_NAME=${OU}-${ENVIRO}-${CONTEXT} + + ENVIRO=$(echo ${AWS_CLUSTER_NAME} | cut -d- -f2) + + # All this is to capitalize the first letter! + ENVIRO_USE=`echo ${ENVIRO:0:1} | tr '[a-z]' '[A-Z]'`${ENVIRO:1} + + echo; echo "Cluster name: $AWS_CLUSTER_NAME" + + mkdir -p /tmp/${HOME}/development/APPDAT/appdat.jsc.nasa.gov/ssmo/SSMO-APPDAT/ + cd /tmp/${HOME}/development/APPDAT/appdat.jsc.nasa.gov/ssmo/SSMO-APPDAT/ + + git clone git@appdat.jsc.nasa.gov:ssmo/SSMO-APPDAT/sysconf.git || true + cd ./sysconf/admin + + make kubeconfig AWS_CLUSTER_NAME=${AWS_CLUSTER_NAME} + source /tmp/aws-credentials_SSMO-Appdat-Hybrid-Gov${ENVIRO_USE}.sh + + cd ${MY_PWD} # critical + + K8S_CONTEXT=arn:aws-us-gov:eks:${AWS_REGION}:${AWS_ACCOUNT}:cluster/${AWS_CLUSTER_NAME} + + imagePullPolicy=Always + K8S_LOCAL=false +fi + +echo; echo Using and setting context ${K8S_CONTEXT}... +kubectl config use-context ${K8S_CONTEXT} +kubectl config set-context ${K8S_CONTEXT} +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Image URI with its creds +#------------------------------------------------------------------------------ +# TODO: put these in one file +IMAGE_REGISTRY=registry.appdat.jsc.nasa.gov +#IMAGE_URI=${IMAGE_REGISTRY}/ssmo/images/ssmo/nos3/nos3-base:20250217 + +IMAGE_REGISTRY_USER=${USER} +IMAGE_REGISTRY_PASSWORD=$(cat ~/.appdat/images/SSMO_IMAGES) + +IMAGE_SECRET_NAME=appdat-registry + +cat <<-EOF > /tmp/config.json +{ + "auths": { + "${IMAGE_REGISTRY}": { + "auth": "$(echo -n ${IMAGE_REGISTRY_USER}:${IMAGE_REGISTRY_PASSWORD} | base64 | tr -d '\n')", + "username": "${IMAGE_REGISTRY_USER}", + "password": "${IMAGE_REGISTRY_PASSWORD}" + } + } +} +EOF + +#------------------------------------------------------------------------------ +# Missions Loop +#------------------------------------------------------------------------------ +for MISSION in "${MISSIONS[@]}" +do + + _MISSION_ENABLED=$(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.enabled" | grep -iv '^null$') + + if [ "${_MISSION_ENABLED}" != "true" ]; then + echo; echo MISSION ${MISSION} is not enabled, add enabled: true, skipping... + continue + else + echo; echo MISSION ${MISSION} is enabled continuing. + fi + + MISSION_PATH=./environments/${OU}/${ENVIRO}/${CONTEXT}/${MISSION} + mkdir -p ${MISSION_PATH} + + KUSTOMIZATION_FILE_MISSION=${MISSION_PATH}/kustomization.yaml + touch ${KUSTOMIZATION_FILE_MISSION} + + # Printout preamble of kustomization file + cat <<-EOF > ${KUSTOMIZATION_FILE_MISSION} +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +EOF + + SPACECRAFT=($(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[] | keys[]")) + + #------------------------------------------------------------------------------ + # Generate deployment and service yaml files + # run is below that + #------------------------------------------------------------------------------ + for SC in "${SPACECRAFT[@]}" + do + + _SPACECRAFT_ENABLED=$(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[].${SC}.enabled" | grep -iv '^null$') + + if [ "${_SPACECRAFT_ENABLED}" != "true" ]; then + echo " MISSION ${MISSION} is enabled, but SPACECRAFT ${SC} is not enabled, add enabled: true, skipping..." + continue + else + echo " MISSION ${MISSION} is enabled, and SPACECRAFT ${SC} is enabled continuing." + fi + + if [ "${K8S_LOCAL}" != "true" ]; then + nodeSelector=$( + cat <> ${KUSTOMIZATION_FILE_MISSION} + - ./${SC}/kubernetes +EOF +echo " Created ${KUSTOMIZATION_FILE_MISSION}" + + SPACECRAFT_PATH=${MISSION_PATH}/${SC} + mkdir -p ${SPACECRAFT_PATH} + + SPACECRAFT_PATH_K8S=${SPACECRAFT_PATH}/kubernetes + mkdir -p ${SPACECRAFT_PATH_K8S} + + KUSTOMIZATION_FILE_SC=${SPACECRAFT_PATH_K8S}/kustomization.yaml + rm -f ${KUSTOMIZATION_FILE_SC} + touch ${KUSTOMIZATION_FILE_SC} + + SPACECRAFT_PATH_DOCKER=${SPACECRAFT_PATH}/docker/${K8S_NAMESPACE} + mkdir -p ${SPACECRAFT_PATH_DOCKER} + + #------------------------------------------------------------------------------ + # docker-compose + #------------------------------------------------------------------------------ + DOCKER_COMPOSE_FILE=${SPACECRAFT_PATH_DOCKER}/${K8S_NAMESPACE}_docker-compose.yaml + + rm -rf ${DOCKER_COMPOSE_FILE} + touch ${DOCKER_COMPOSE_FILE} + + cat <<-EOF > ${DOCKER_COMPOSE_FILE} +# generated on $(date -u "+%YT%T") + +services: +EOF +echo " Created ${DOCKER_COMPOSE_FILE}" + #------------------------------------------------------------------------------ + + # create configMap per namespace TODO: how to use +CONFIGMAP_FILE=${SPACECRAFT_PATH_K8S}/${K8S_NAMESPACE}_configmap.yaml + + cat <<-EOF > ${CONFIGMAP_FILE} +apiVersion: v1 +kind: ConfigMap +metadata: + name: ${K8S_NAMESPACE}-configmap + namespace: ${K8S_NAMESPACE} +data: + key1: value1 +EOF +echo " Created ${CONFIGMAP_FILE}.yaml" + + # Print preamble of kustomization file + cat <<-EOF > ${KUSTOMIZATION_FILE_SC} +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +EOF +echo " Created blank ${KUSTOMIZATION_FILE_SC}" + + #------------------------------------------------------------------------------ + # By component + #------------------------------------------------------------------------------ + COMPONENTS=($(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[].${SC}.components" | grep -iv '^null$' | yq ' keys[]')) + + THINGS=(${COMPONENTS[@]}) + + _COMPONENTS=$(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[].${SC}.components" | grep -iv '^null$') + + for COMPONENT in "${THINGS[@]}" + do + + COMPONENTS=($(echo "${_COMPONENTS}" | yq ' keys[]')) + + _CONTAINER=$(echo "${_COMPONENTS}" | yq ".${COMPONENT}.container" | grep -iv '^null$') + + # TODO: get replicas: value +# REPLICAS=$(echo "${_COMPONENTS}" | yq ".${COMPONENT}.container.replicas" | grep -iv '^null$') + + REPLICAS=1 + CONTAINER_RESOURCES=$(echo "${_CONTAINER}" | yq ".resources" | grep -iv '^null$') + + CONTAINER_LIMITS_MEMORY=$(echo "${CONTAINER_RESOURCES}"| yq ".limits.memory" | grep -iv '^null$' ) + CONTAINER_LIMITS_CPU=$(echo "${CONTAINER_RESOURCES}"| yq ".limits.cpu" | grep -iv '^null$' ) + + CONTAINER_REQUESTS_MEMORY=$(echo "${CONTAINER_RESOURCES}"| yq ".requests.memory" | grep -iv '^null$' ) + CONTAINER_REQUESTS_CPU=$(echo "${CONTAINER_RESOURCES}"| yq ".requests.cpu" | grep -iv '^null$' ) + + _PATHS=$(echo "${_CONTAINER}" | yq ".PATHS" | grep -iv '^null$') + CONTAINER_PATHS=($(echo "${_PATHS}")) + + BASE_DIR=$(echo "${_PATHS}" | yq '.BASE_DIR') + SIM_BIN=$(echo "${_PATHS}" | yq '.SIM_BIN') + SIMULATOR_BIN=$(echo "${_PATHS}" | yq '.SIMULATOR_BIN') + LOG_CONFIG=$(echo "${_PATHS}" | yq '.LOG_CONFIG') + +# TODO: note SC_CFG_FILE below + CFG_FILE=$(echo "${_PATHS}" | yq '.SC_CFG_FILE') +# TODO: TBD wrt to GND + GND_CFG_FILE=$(echo "${_PATHS}" | yq '.GND_CFG_FILE') + + IMAGE_URI=$(echo "${_PATHS}" | yq '.IMAGE_URI') + + METADATA_NAME=${MISSION}-${SC}-${COMPONENT} + DEPLOYMENT=${MISSION}-${SC}-${COMPONENT} + + COMPONENT_PATH=${SPACECRAFT_PATH_K8S}/${COMPONENT} + mkdir -p ${COMPONENT_PATH} + + KUSTOMIZATION_FILE_COMPONENT=${COMPONENT_PATH}/kustomization.yaml + rm -f ${KUSTOMIZATION_FILE_COMPONENT} + + #------------------------------------------------------------------------------ + # Generate Kustomization files + #------------------------------------------------------------------------------ + cat <<-EOF >> ${KUSTOMIZATION_FILE_COMPONENT} +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./deployment.yaml + - ./service.yaml +EOF +echo " Created ${KUSTOMIZATION_FILE_COMPONENT}" + + SERVICE_FILE_COMPONENT=${COMPONENT_PATH}/service.yaml + rm -f ${SERVICE_FILE_COMPONENT} + + cat <<-EOF >> ${KUSTOMIZATION_FILE_SC} + - ./${COMPONENT} +EOF +echo " Added component ${COMPONENT} to ${SERVICE_FILE_COMPONENT}" + + DEPLOYMENT_FILE_COMPONENT=${COMPONENT_PATH}/deployment.yaml + rm -f ${DEPLOYMENT_FILE_COMPONENT} + + #------------------------------------------------------------------------------ + # Generate Deployment files + #------------------------------------------------------------------------------ + cat <<-EOF >> ${DEPLOYMENT_FILE_COMPONENT} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: ${K8S_NAMESPACE} + name: ${K8S_NAMESPACE}-${COMPONENT} + labels: + app: ${K8S_NAMESPACE}-${COMPONENT} +spec: + replicas: 0 + selector: + matchLabels: + app: ${K8S_NAMESPACE}-${COMPONENT} + template: + metadata: + labels: + app: ${K8S_NAMESPACE}-${COMPONENT} + spec: + imagePullSecrets: + - name: appdat-registry +${nodeSelector} + containers: + - name: ${K8S_NAMESPACE}-${COMPONENT} + image: ${IMAGE_URI} + imagePullPolicy: ${imagePullPolicy} + resources: + limits: + memory: ${CONTAINER_LIMITS_MEMORY} + cpu: ${CONTAINER_LIMITS_CPU} + requests: + memory: ${CONTAINER_REQUESTS_MEMORY} + cpu: ${CONTAINER_REQUESTS_CPU} + ports: + - containerPort: ${HEALTHCHECK_PORT} + env: + - name: HEALTHCHECK_PORT + value: "${HEALTHCHECK_PORT}" + - name: OU + value: ${OU} + - name: TENANT + value: ${TENANT} + - name: ENVIRO + value: ${ENVIRO} + - name: CONTEXT + value: missions + - name: MISSION + value: ${MISSION} + - name: SPACECRAFT + value: ${SC} + - name: MISSION_GIT_USER + value: ${MISSION_GIT_USER} + - name: MISSION_GIT_TOKEN + value: ${MISSION_GIT_TOKEN} + - name: MISSION_GIT_SERVER + value: ${MISSION_GIT_SERVER} + - name: BASE_DIR + value: ${BASE_DIR} + - name: SIM_BIN + value: ${SIM_BIN} + - name: SIMULATOR_BIN + value: ${SIMULATOR_BIN} + - name: LOG_CONFIG + value: ${LOG_CONFIG} + - name: CFG_FILE + value: ${CFG_FILE} + # - name: SC_CFG_FILE + # value: ${SC_CFG_FILE} + # - name: GND_CFG_FILE + # value: ${GND_CFG_FILE} + - name: NETWORK + value: ${K8S_NAMESPACE} + - name: COMPONENT_NAME + value: ${COMPONENT} +EOF +echo " Created ${DEPLOYMENT_FILE_COMPONENT}" + + #------------------------------------------------------------------------------ + # Generate Service files + #------------------------------------------------------------------------------ + cat <<-EOF >> ${SERVICE_FILE_COMPONENT} +--- +apiVersion: v1 +kind: Service +metadata: + name: ${COMPONENT} + namespace: ${K8S_NAMESPACE} +spec: + selector: + app: ${K8S_NAMESPACE}-${COMPONENT} + ports: + - name: healthcheck-tcp + protocol: TCP + port: ${HEALTHCHECK_PORT} + targetPort: ${HEALTHCHECK_PORT} + - name: healthcheck-udp + protocol: UDP + port: ${HEALTHCHECK_PORT} + targetPort: ${HEALTHCHECK_PORT} + type: ClusterIP + +EOF +echo " Created ${SERVICE_FILE_COMPONENT}" + + #------------------------------------------------------------------------------ + # docker-compose: services + #------------------------------------------------------------------------------ + SERVICE_NAME=${K8S_NAMESPACE}-${COMPONENT} + + cat <<-EOF >> ${DOCKER_COMPOSE_FILE} + ${SERVICE_NAME}: + image: ${IMAGE_URI} + container_name: ${SERVICE_NAME} + hostname: ${SERVICE_NAME} + environment: + HEALTHCHECK_PORT: ${HEALTHCHECK_PORT} + OU: ${OU} + TENANT: ${TENANT} + ENVIRO: ${ENVIRO} + CONTEXT: missions + MISSION: ${MISSION} + SPACECRAFT: ${SC} + MISSION_GIT_USER: ${MISSION_GIT_USER} + MISSION_GIT_TOKEN: ${MISSION_GIT_TOKEN} + MISSION_GIT_SERVER: ${MISSION_GIT_SERVER} + BASE_DIR: ${BASE_DIR} + SIM_BIN: ${SIM_BIN} + NOS3_SIMULATOR_BIN: ${SIMULATOR_BIN} + LOG_CONFIG: ${LOG_CONFIG} + CFG_FILE: ${CFG_FILE} + # SC_CFG_FILE: ${SC_CFG_FILE} + # GND_CFG_FILE: ${GND_CFG_FILE} + COMPONENT_NAME: ${COMPONENT} + privileged: true + networks: + - ${K8S_NAMESPACE} +EOF + + echo $MISSION $SC $COMPONENT ${SPACECRAFT[@]} + + done # COMPONENT loop + + #------------------------------------------------------------------------------ + # docker-compose completion for sc + #------------------------------------------------------------------------------ + cat <<-EOF >> ${DOCKER_COMPOSE_FILE} + +networks: + ${K8S_NAMESPACE}: + driver: bridge + +EOF + #------------------------------------------------------------------------------ + + done # SC loop + +done # MISSIONS loop + +#------------------------------------------------------------------------------ +# Run kubectl on created yaml files +#------------------------------------------------------------------------------ +# Missions Loop +for MISSION in "${MISSIONS[@]}" +do + + MISSION_PATH=./environments/${OU}/${ENVIRO}/${CONTEXT}/${MISSION} + + _MISSION_ENABLED=$(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.enabled" | grep -iv '^null$') + + if [ "${_MISSION_ENABLED}" != "true" ]; then + echo; echo MISSION ${MISSION} is not enabled, add enabled: true, skipping... + continue + else + echo; echo MISSION ${MISSION} is enabled continuing. + fi + + # resource names, to be used with context, cluster, namespace, pods, and services + RESOURCE_NAME=${REALM}-${MISSION} + + REALM=docker-desktop + + # contexts/clusters + K8S_CONTEXT=${REALM} + K8S_CLUSTER=${K8S_CONTEXT} + K8S_USER=${K8S_CONTEXT} + +# kind delete cluster --name ${K8S_CLUSTER} || true +# kind create cluster --name ${K8S_CLUSTER} || true + +# K8S_CONTEXT_PREFIX=kind- + K8S_CONTEXT=${K8S_CONTEXT_PREFIX}${K8S_CONTEXT} + + # set and use context + kubectl config set-context ${K8S_CONTEXT} + kubectl config use-context ${K8S_CONTEXT} + SPACECRAFT=($(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[] | keys[]")) + + for SC in "${SPACECRAFT[@]}" + do + + _SPACECRAFT_ENABLED=$(echo "${NOS3_CONFIG}" | yq ".missions[].${MISSION}.spacecraft[].${SC}.enabled" | grep -iv '^null$') + + if [ "${_SPACECRAFT_ENABLED}" != "true" ]; then + echo " MISSION ${MISSION} is enabled, but SPACECRAFT ${SC} is not enabled, add enabled: true, skipping..." + continue + else + echo " MISSION ${MISSION} is enabled, and SPACECRAFT ${SC} is enabled continuing." + fi + + K8S_NAMESPACE=${OU}-${ENVIRO}-${CONTEXT}-${MISSION}-${SC} + + if [ "${RECREATE}" == "yes" ]; then + echo; echo Deleting namespace ${K8S_NAMESPACE} in context ${K8S_CONTEXT}... + kubectl delete namespace ${K8S_NAMESPACE} --context ${K8S_CONTEXT} || true + fi + + echo; echo Creating namespace ${K8S_NAMESPACE} in context ${K8S_CONTEXT}... + kubectl create namespace ${K8S_NAMESPACE} --context ${K8S_CONTEXT} || true + + echo; echo Creating secret ${IMAGE_SECRET_NAME} in namespace ${K8S_NAMESPACE} in context ${K8S_CONTEXT}... + kubectl delete secret ${IMAGE_SECRET_NAME} -n ${K8S_NAMESPACE} || true + kubectl create secret generic ${IMAGE_SECRET_NAME} \ + --from-file=.dockerconfigjson=/tmp/config.json \ + --type=kubernetes.io/dockerconfigjson \ + -n ${K8S_NAMESPACE} + kubectl get secret ${IMAGE_SECRET_NAME} --output=yaml -n ${K8S_NAMESPACE} + + SPACECRAFT_PATH=${MISSION_PATH}/${SC} + SPACECRAFT_PATH_K8S=${SPACECRAFT_PATH}/kubernetes + + KUSTOMIZATION_FILE_SC=${SPACECRAFT_PATH_K8S} + + echo; echo Applying ${KUSTOMIZATION_FILE_SC} in context ${K8S_CONTEXT}... + kubectl apply -k ${KUSTOMIZATION_FILE_SC} + kubectl get deployments -n ${K8S_NAMESPACE} + + echo; echo Get pods in namespace ${K8S_NAMESPACE} in context ${K8S_CONTEXT}... + kubectl get pods -o wide -n ${K8S_NAMESPACE} + + done # SC + +done # MISSIONS diff --git a/deployments/scripts/nos3.yaml b/deployments/scripts/nos3.yaml new file mode 100644 index 000000000..40c627a63 --- /dev/null +++ b/deployments/scripts/nos3.yaml @@ -0,0 +1,249 @@ +metadata: + OU: myorg + ENVIRO: dev + TENANT: tenant + CONTEXT: missions # -exp must exist to match remote AWS EKS cluster + PURPOSE: -exp + +defaults: + spec: + HEALTHCHECK_PORT: &HEALTHCHECK_PORT + 60000 + PATHS: &PATHS + BASE_DIR: &BASE_DIR + /builds/nos3 + SIM_BIN: &SIM_BIN + /builds/nos3/sims/build/bin + SIMULATOR_BIN: &SIMULATOR_BIN + /builds/nos3/sims/build/bin/nos3-single-simulator + LOG_CONFIG: &LOG_CONFIG + /builds/nos3/sims/build/bin/sim_log_config.xml + # CFG_FILE: &CFG_FILE + # /builds/nos3/sims/build/bin/nos3-simulator.xml + SC_CFG_FILE: &SC_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + GND_CFG_FILE: &GND_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + IMAGE_REGISTRY: &IMAGE_REGISTRY + registry.appdat.jsc.nasa.gov + IMAGE_URI: &IMAGE_URI + registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + container: &container + PATHS: + << : *PATHS + resources: &resources + limits: &limits + memory: "128Mi" + cpu: "100m" + requests: &requests + memory: "128Mi" + cpu: "100m" + nodes: &nodes + min_size: 1 + max_size: 1 + desired_size: 1 + instance_types: m6i.xlarge + nodeSelector: "" + imagePullPolicy: IfNotPresent + components: &hw_components + camsim: + name: camsim + replicas: 1 + container: + << : *container + generic-css-sim: + name: css + replicas: 1 + container: + << : *container + generic-eps-sim: + name: eps + replicas: 1 + container: + << : *container + generic-fss-sim: + name: fss + replicas: 1 + container: + << : *container + gps: + name: gps + replicas: 1 + container: + << : *container + generic-imu-sim: + name: imu + replicas: 1 + container: + << : *container + generic-mag-sim: + name: mag + replicas: 1 + container: + << : *container + generic-reactionwheel-sim0: + name: rw0 + replicas: 1 + container: + << : *container + generic-reactionwheel-sim1: + name: rw1 + replicas: 1 + container: + << : *container + generic-reactionwheel-sim2: + name: rw2 + replicas: 1 + container: + << : *container + generic-radio-sim: + name: radio_sim + replicas: 1 + container: + PATHS: + << : *PATHS + resources: + limits: + memory: "128Mi" + cpu: "125m" + requests: + memory: "128Mi" + cpu: "125m" + host: radio_sim + network-alias: radio_sim + generic-star-tracker-sim: + name: start-tracker + replicas: 1 + container: + << : *container + generic-torquer-sim: + name: torquer + replicas: 1 + container: + << : *container + generic-thruster-sim: + name: thruster + replicas: 1 + container: + << : *container + time: + name: time + replicas: 1 + container: + << : *container + stdio-terminal: + name: stdio-terminal + replicas: 1 + container: + << : *container + udp-terminal: + replicas: 2 + name: udp-terminal + container: + << : *container + # nos_engine: & nos_engine + # container: + # << : *container + # truth42: &truth42 + # container: + # << : *container + # flight_dynamics: &flight_dynamics + # fortytwo: &fortytwo + # container: + # << : *container + # encryption: &encryption + # cryptolib: + # container: + # << : *container + +projects: + nos3: + missions: + m01: + enabled: true + spacecraft: + sc01: + enabled: true + components: + fortytwo: + port: 30090 + yamcs: + port: 8090 + openmct: + port: 9000 + sc02: + enabled: false + components: + fortytwo: + port: 30091 + yamcs: + port: 8091 + openmct: + port: 9001 + m02: + enabled: false + spacecraft: + sc01: + enabled: true + components: + fortytwo: + port: 30092 + yamcs: + port: 8092 + openmct: + port: 9002 + sc02: + enabled: false + components: + fortytwo: + port: 30093 + yamcs: + port: 8093 + openmct: + port: 9003 + +# projects: +# nos3: +# missions: +# - m01: +# enabled: true +# spacecraft: +# - sc01: +# enabled: true +# components: +# fortytwo: +# name: fsw +# replicas: 1 +# container: +# << : *container +# fsw: +# name: fsw +# replicas: 1 +# container: +# << : *container +# nos-engine-server: +# name: nos-engine-server +# replicas: 1 +# container: +# << : *container +# time: +# name: time +# replicas: 1 +# container: +# << : *container +# gps: +# name: gps +# replicas: 1 +# container: +# << : *container +# - m02: +# enabled: false +# spacecraft: +# - sc01: +# enabled: true +# components: +# << : *hw_components +# - sc02: +# enabled: false +# components: +# << : *hw_components \ No newline at end of file diff --git a/deployments/scripts/nos3_new.yml b/deployments/scripts/nos3_new.yml new file mode 100644 index 000000000..50b46ec2a --- /dev/null +++ b/deployments/scripts/nos3_new.yml @@ -0,0 +1,39 @@ +# cat /Users/hido/development//yaml_anchors_aliases.yml | yq '. | explode(.)' + +metadata: + OU: myorg + ENVIRO: dev + TENANT: tenant + CONTEXT: missions # -exp must exist to match remote AWS EKS cluster + PURPOSE: '-exp' + +defaults: + spec: + HEALTHCHECK_PORT: 60000 + env: &env + IMAGE_REGISTRY: registry.appdat.jsc.nasa.gov + IMAGE_URI: registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + resources: &resources + replicas: 1 + limits: + memory: 128Mi + cpu: 100m + requests: + memory: 128Mi + cpu: 100m + components: + camsim1: + name: camsim1 + resources: + <<: *resources + camsim2: + name: camsim2 + +# missions: +# - m01: +# enabled: true +# spacecraft: +# - sc1: +# enabled: true +# components: +# << : *components \ No newline at end of file diff --git a/deployments/scripts/sidecar.sh b/deployments/scripts/sidecar.sh new file mode 100755 index 000000000..b052b0994 --- /dev/null +++ b/deployments/scripts/sidecar.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash + +usage() { + cat <<-EOF + + Usage: $0 [-h] [-d] [-P] [-s] [-p] [-i] [-c] [-t] [-R] [-w] + + Purpose: a script to disable, enable links, and issue a command to a Yamcs server's instance on a specific processor. + + Eg.: + $0 -h + $0 -d + $0 -P http -s localhost -p 8090 -i nos3 + $0 -w + etc. + + Required Arguments: + + Options: + -h | --help help + -d | --defaults use default configurations. Other arguments will be ignored. + -P | --protocol , Default: http + -s | --server server's address, Default: localhost + -p | --port service's port, Default: 8090 + -i | --instance instance on server, Default: nos3 + -c | --command command to issue, Default: /CFS/CMD/CFE_ES_NOOP, invoke /CFS/CMD/TO_ENABLE_OUTPUT to enable telemetry outputs + -t | --tls_verify Default: False + -R | --processor Default: realtime + -w | --write Echo default values to stdout + +EOF +} + +params="$(getopt -o :h,d,P:s:p:i:c:t:R,w -l 'help,defaults,protocol:,server:,port:,instance:,command:,tls_verify:,processor,write' --name "$(basename $0)" -- "$@")" + +# Check if getopt encountered an error +if [ $? -ne 0 ]; then + echo + echo "ERROR: Invalid option or missing argument: $@" >&2 + usage + exit 1 +fi + +if [ $# -eq 0 ]; then + echo + echo "ERROR: no arguments provided: $@" >&2 + usage + exit 1 +fi + +eval set -- "$params" +unset params + +# Default values +PROTOCOL=http +SERVER=localhost +PORT=8090 +INSTANCE=nos3 +PROCESSOR=realtime +COMMAND="/CFS/CMD/TO_ENABLE_OUTPUT" +#COMMAND="/CFS/CMD/CFE_ES_NOOP" +TLS_VERIFY=False + +while true; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -d|--defaults) + echo; echo "[INFO] Will use default values. Other arguments will be ignored." + shift + break + ;; + -P|--protocol) + PROTOCOL="$2" + shift 2 + ;; + -s|--server) + SERVER="$2" + shift 2 + ;; + -p|--port) + PORT="$2" + shift 2 + ;; + -i|--instance) + INSTANCE="$2" + shift 2 + ;; + -c|--command) + COMMAND="$2" + shift 2 + ;; + -t|--tls_verify) + TLS_VERIFY="$2" + shift 2 + ;; + -w|--write) + echo + echo "[INFO] defaults are ${PROTOCOL}://${SERVER}:${PORT} on instance: $INSTANCE, with command: $COMMAND, using processor: $PROCESSOR" + echo + exit + ;; + --) + shift + break + ;; + *) + echo "Unrecognized option '$1'" + usage + exit + ;; + esac + +done + +echo +echo "Attempting to connect to yamcs on:" +echo " ${PROTOCOL}://${SERVER}:${PORT} on instance: $INSTANCE, with command: $COMMAND, using processor: $PROCESSOR" +echo + +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/radio-in:disable +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/radio-out:disable +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/truth42-in:disable + +sleep 5 + +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/radio-in:enable +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/radio-out:enable +curl -k -X POST ${PROTOCOL}://${SERVER}:${PORT}/api/links/nos3/truth42-in:enable + +pip3 install --break-system-packages --user --upgrade yamcs-client && \ + +python3 </etc/apt/trusted.gpg.d/TurboVNC.gpg +RUN wget -P /etc/apt/sources.list.d/ https://raw.githubusercontent.com/TurboVNC/repo/main/TurboVNC.list + +# virtualgl: https://virtualgl.org/ +RUN wget -q -O- https://packagecloud.io/dcommander/virtualgl/gpgkey | gpg --dearmor >/etc/apt/trusted.gpg.d/VirtualGL.gpg +RUN wget -P /etc/apt/sources.list.d/ https://raw.githubusercontent.com/VirtualGL/repo/main/VirtualGL.list + +# Install virtualgl and turbovnc +RUN apt-get update && \ + apt-get install -y \ + virtualgl \ + turbovnc && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Install and configure Display Manager(s) - https://fluxbox.org/ +RUN apt-get update && \ + apt-get install -y \ + fluxbox && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# TODO: need to figure out why this is needed +RUN ln -sf /usr/share/xsessions/fluxbox.desktop /usr/share/xsessions/gnome.desktop + +# Install tools for git cloning and development, etc. +RUN apt-get update && \ + apt install -y curl git build-essential vim jq tree tmux htop bash-completion dos2unix netcat-traditional iputils-ping && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Install https://taskfile.dev/ (Taskfile.yaml) +RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d + +# Install some useful .bashrc-isms +# COPY .bashrc.local /root/.bashrc.local +# RUN cat /root/.bashrc.local >> /root/.bashrc + +# VNC Config +RUN mkdir -p ~/.vnc/ +RUN echo ${VNC_PASSWORD} | vncpasswd -f > ~/.vnc/passwd +RUN chmod 0600 ~/.vnc/passwd +RUN openssl req -x509 -nodes -newkey rsa:2048 -keyout ~/novnc.pem -out ~/novnc.pem -days 3650 -subj "/C=US/ST=NY/L=NY/O=NY/OU=NY/CN=NY emailAddress=email@example.com" + +################################################################################ +FROM x-vnc AS fortytwo +################################################################################ +ARG GIT_URL +ARG GIT_COMMIT + +ENV GIT_URL=${GIT_URL} +ENV GIT_COMMIT=${GIT_COMMIT} + +# VNC Config +RUN mkdir -p ~/.vnc/ +RUN echo ${VNC_PASSWORD} | vncpasswd -f > ~/.vnc/passwd +RUN chmod 0600 ~/.vnc/passwd +RUN openssl req -x509 -nodes -newkey rsa:2048 -keyout ~/novnc.pem -out ~/novnc.pem -days 3650 -subj "/C=US/ST=NY/L=NY/O=NY/OU=NY/CN=NY emailAddress=email@example.com" + +# Install 42's dependencies +RUN apt-get update && \ + apt-get -y install libglu1-mesa-dev freeglut3-dev mesa-common-dev libglfw3-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# 42's MonteCarlo dependencies +RUN apt-get update && \ + apt-get -y install octave tshark && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# install Julia +RUN curl -fsSL https://install.julialang.org | sh -s -- --yes + +# Clone the 42 repo for a specific branch + +RUN mkdir -p /opt/nasa-itc && \ + cd /opt/nasa-itc && \ + git clone --recurse-submodules -b ${GIT_COMMIT} -j4 ${GIT_URL} && \ + cd ./42 &&\ + make clean && \ + make -j7 + +COPY entrypoint.sh /entrypoint.sh + +CMD ["/entrypoint.sh"] diff --git a/deployments/services/fortytwo/entrypoint.sh b/deployments/services/fortytwo/entrypoint.sh new file mode 100755 index 000000000..48057b74a --- /dev/null +++ b/deployments/services/fortytwo/entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +rm -f /tmp/.X1-lock || true +rm -f /tmp/.X11-unix/X1 || true + +pkill -9 -f vncserver || true +pkill -9 -f Xvnc || true +pkill -9 -f websockify || true + +/opt/TurboVNC/bin/vncserver -securitytypes tlsnone,x509none,none && \ + sleep 5 && \ + websockify -D \ + --web=/usr/share/novnc/ \ + --cert=~/novnc.pem 80 localhost:5901 + +export DISPLAY=${DISPLAY:-:1} +export DIR=/opt/nasa-itc +export GIT_FOLDER=${GIT_FOLDER} + +xterm & + +rm -rf /opt/nasa-itc/42/NO3InOut/{*.42,*.csv} + +if [ "$RECOMPILE" == "true" ]; then + cd /opt/nasa-itc/42 && \ + git fetch && \ + git checkout ${GIT_COMMIT} && \ + git pull origin && \ + git submodule update && \ + make clean && \ + make -j2 +fi + +STARTUP_FOLDER=${STARTUP_FOLDER:-NO3InOut} + +cd /opt/nasa-itc/42 && \ + xterm -e "./42 ${STARTUP_FOLDER}" & + +echo "Started 42 with PID $!" + +tail -f /dev/null diff --git a/deployments/services/fortytwo/kubernetes/configmap-args.yaml b/deployments/services/fortytwo/kubernetes/configmap-args.yaml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/configmap-args.yaml @@ -0,0 +1 @@ + diff --git a/deployments/services/fortytwo/kubernetes/configmap-env.yaml b/deployments/services/fortytwo/kubernetes/configmap-env.yaml new file mode 100644 index 000000000..9b46aba67 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/configmap-env.yaml @@ -0,0 +1,62 @@ +apiVersion: v1 +data: + BASE_DIR: /opt/nasa-itc + COMPONENT_DIR: /home/nos3/builds/nos3/components + COMPOSE_PROJECT_NAME: nos3-m01-sc01 + DEPLOYMENT_ENVIRO: "" + FORTYTWO_BASE_DIR: /opt/nasa-itc + FORTYTWO_DISPLAY: :1 + FORTYTWO_GIT_COMMIT: nos3-main + FORTYTWO_GIT_FOLDER: "42" + FORTYTWO_GIT_URL: https://github.com/nasa-itc/42.git + FORTYTWO_LEAP_SECONDS: "37" + FORTYTWO_PORT: "30090" + FORTYTWO_RECOMPILE: "false" + FORTYTWO_SIM_DATE: '"01 06 2026"' + FORTYTWO_SIM_TIME: '"18 46 59.00"' + FORTYTWO_STARTUP_FOLDER: NOS3InOut + FORTYTWO_VNC_PASSWORD: c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2 + FSW_SOFTWARE: cfs + GSW_SOFTWARE: yamcs + HEALTHCHECK_PORT: "" + HTTP_PROXY: "" + HTTPS_PROXY: "" + J2000_EPOCH_SECONDS: "946728000" + J2000_REFERENCE_DATETIME: '"2000-01-01 12:00:00 UTC"' + MAVEN_HTTPS_PROXY: '"--settings ./settings.xml"' + MAVEN_REPO_LOCAL: /home/nos3/.nos3/.m2 + MAVEN_SETTINGS_FILE: "" + MISSION: m01 + NO_PROXY: "" + NOS3_BASE_DIR: /home/nos3/.nos3 + NOS3_CFG_PATH: .. + NOS3_DIR: /home/nos3/.nos3 + NOS3_GIT_COMMIT: dev + NOS3_GIT_URL: https://github.com/nasa/nos3 + NOS3_IMAGE_URI: docker.io/ivvitc/nos3-64:20251107 + NOS3_MISSION_CFG_FILE: ../cfg/nos3-mission.xml + NOS3_USER: nos3 + OPENMCT_GIT_COMMIT: master + OPENMCT_GIT_URL: https://github.com/akhenry/openmct-yamcs.git + OPENMCT_IMAGE_URI: docker.io/library/ubuntu:25.04 + OPENMCT_NODE_VERSION: v21.7.3 + OPENMCT_NVM_VERSION: v0.40.1 + OPENMCT_PORT: "9000" + PROJECT_NAME: nos3-m01-sc01 + SIM_T0_DATETIME: '"2026-01-06 18:46:29 UTC"' + SIM_T0_EPOCH_MILLISECONDS: "1767725219000" + SIM_T0_EPOCH_SECONDS: "1767725219" + SIM_TF_EPOCH_MILLISECONDS: "1767728819000" + SPACECRAFT: sc01 + START_TIME: "820997219" + TIME_INTERVAL: "3600" + TIME_INTERVAL_MILLISECONDS: "3600000" + TIME_OFFSET_SECONDS: "+30" + YAMCS_DATA_DIR: /home/nos3/.nos3/yamcs/target/yamcs/yamcs-data + YAMCS_GIT_COMMIT: nos3-dev + YAMCS_GIT_URL: https://github.com/nasa-itc/nos3_yamcs_master.git + YAMCS_INSTANCES: nos3 + YAMCS_PORT: "8090" +kind: ConfigMap +metadata: + name: nos3-m01-sc01-fortytwo diff --git a/deployments/services/fortytwo/kubernetes/configmap-volumes.yaml b/deployments/services/fortytwo/kubernetes/configmap-volumes.yaml new file mode 100644 index 000000000..45ff864a1 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/configmap-volumes.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +data: + entrypoint.sh: "#!/bin/bash\n\nrm -f /tmp/.X1-lock || true\nrm -f /tmp/.X11-unix/X1 + || true\n\npkill -9 -f vncserver || true\npkill -9 -f Xvnc || true\npkill -9 -f + websockify || true\n\n/opt/TurboVNC/bin/vncserver -securitytypes tlsnone,x509none,none + && \\\n sleep 5 && \\\n websockify -D \\\n --web=/usr/share/novnc/ \\\n --cert=~/novnc.pem + 80 localhost:5901 \n \nexport DISPLAY=${DISPLAY:-:1}\nexport DIR=/opt/nasa-itc\nexport + GIT_FOLDER=${GIT_FOLDER}\n\nxterm &\n\nrm -rf /opt/nasa-itc/42/NO3InOut/{*.42,*.csv} + \n\nif [ \"$RECOMPILE\" == \"true\" ]; then\n cd /opt/nasa-itc/42 && \\\n git + fetch && \\\n git checkout ${GIT_COMMIT} && \\\n git pull origin && \\\n + \ git submodule update && \\\n make clean && \\\n make -j2\nfi\n\nSTARTUP_FOLDER=${STARTUP_FOLDER:-NO3InOut}\n\ncd + /opt/nasa-itc/42 && \\\n xterm -e \"./42 ${STARTUP_FOLDER}\" &\n\necho \"Started + 42 with PID $!\"\n\ntail -f /dev/null\n" +kind: ConfigMap +metadata: + name: nos3-m01-sc01-fortytwo-volumes diff --git a/deployments/services/fortytwo/kubernetes/deployment.yaml b/deployments/services/fortytwo/kubernetes/deployment.yaml new file mode 100644 index 000000000..e29eb0222 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/deployment.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nos3-m01-sc01-fortytwo + namespace: nos3-m01 + labels: + app: nos3-m01-sc01-fortytwo +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-fortytwo + template: + metadata: + labels: + app: nos3-m01-sc01-fortytwo + spec: + containers: + - args: + - /entrypoint.sh + env: + - name: COMPONENT_NAME + value: fortytwo + - name: DISPLAY + value: :1 + image: ghcr.io/haisamido/nos3-base-fortytwo:dev + workingDir: /42 + imagePullPolicy: Always + name: nos3-m01-sc01-fortytwo + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "3" + memory: "2048Mi" + requests: + cpu: "1" + memory: "2048Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /entrypoint.sh + name: nos3-m01-sc01-fortytwo-volumes + subPath: entrypoint.sh + hostname: nos3-m01-sc01-fortytwo + restartPolicy: Always + volumes: + - configMap: + items: + - key: entrypoint.sh + path: entrypoint.sh + name: nos3-m01-sc01-fortytwo-volumes + defaultMode: 0555 + name: "nos3-m01-sc01-fortytwo-volumes" diff --git a/deployments/services/fortytwo/kubernetes/ingress.yaml b/deployments/services/fortytwo/kubernetes/ingress.yaml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/ingress.yaml @@ -0,0 +1 @@ + diff --git a/deployments/services/fortytwo/kubernetes/kustomization.yaml b/deployments/services/fortytwo/kubernetes/kustomization.yaml new file mode 100644 index 000000000..64ba096b9 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/kustomization.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./configmap-args.yaml + - ./configmap-env.yaml + - ./configmap-volumes.yaml + - ./deployment.yaml + - ./service.yaml + - ./ingress.yaml + diff --git a/deployments/services/fortytwo/kubernetes/service.yaml b/deployments/services/fortytwo/kubernetes/service.yaml new file mode 100644 index 000000000..6a77faa15 --- /dev/null +++ b/deployments/services/fortytwo/kubernetes/service.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: nos3-m01-sc01-fortytwo + +spec: + selector: + app: nos3-m01-sc01-fortytwo + ports: + - name: x-vnc + protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP diff --git a/deployments/services/fortytwo/nos3.yaml b/deployments/services/fortytwo/nos3.yaml new file mode 100644 index 000000000..4d98248f1 --- /dev/null +++ b/deployments/services/fortytwo/nos3.yaml @@ -0,0 +1,101 @@ +metadata: + OU: myorg + ENVIRO: dev + TENANT: tenant + CONTEXT: missions # -exp must exist to match remote AWS EKS cluster + PURPOSE: -exp + +defaults: + spec: + HEALTHCHECK_PORT: &HEALTHCHECK_PORT + 60000 + PATHS: &PATHS + BASE_DIR: &BASE_DIR + /builds/nos3 + SIM_BIN: &SIM_BIN + /builds/nos3/sims/build/bin + SIMULATOR_BIN: &SIMULATOR_BIN + /builds/nos3/sims/build/bin/nos3-single-simulator + LOG_CONFIG: &LOG_CONFIG + /builds/nos3/sims/build/bin/sim_log_config.xml + # CFG_FILE: &CFG_FILE + # /builds/nos3/sims/build/bin/nos3-simulator.xml + SC_CFG_FILE: &SC_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + GND_CFG_FILE: &GND_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + IMAGE_REGISTRY: &IMAGE_REGISTRY + ghcr.io + IMAGE_URI: &IMAGE_URI + ghcr.io/ericstoneking/42:latest + container: &container + PATHS: + << : *PATHS + resources: &resources + limits: &limits + memory: "128Mi" + cpu: "100m" + requests: &requests + memory: "128Mi" + cpu: "100m" + nodes: &nodes + min_size: 1 + max_size: 1 + desired_size: 1 + instance_types: m6i.xlarge + nodeSelector: "" + imagePullPolicy: IfNotPresent + components: &hw_components + fortytwo: + name: fortytwo + host: fortytwo + replicas: 1 + container: + PATHS: + BASE_DIR: &BASE_DIR + /builds/nos3 + SIM_BIN: &SIM_BIN + /builds/nos3/sims/build/bin + SIMULATOR_BIN: &SIMULATOR_BIN + /builds/nos3/sims/build/bin/nos3-single-simulator + LOG_CONFIG: &LOG_CONFIG + /builds/nos3/sims/build/bin/sim_log_config.xml + # CFG_FILE: &CFG_FILE + # /builds/nos3/sims/build/bin/nos3-simulator.xml + SC_CFG_FILE: &SC_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + GND_CFG_FILE: &GND_CFG_FILE + /builds/nos3/sims/build/bin/nos3-simulator.xml + IMAGE_REGISTRY: &IMAGE_REGISTRY + ghcr.io + IMAGE_URI: &IMAGE_URI + ghcr.io/ericstoneking/42:latest + resources: &resources + limits: &limits + memory: "128Mi" + cpu: "100m" + requests: &requests + memory: "128Mi" + cpu: "100m" + + +missions: + - m01: + enabled: true + spacecraft: + - sc1: + enabled: true + components: + << : *hw_components + + - m02: + enabled: false + spacecraft: + - sc1: + enabled: true + components: + << : *hw_components + - sc2: + enabled: false + components: + << : *hw_components \ No newline at end of file diff --git a/deployments/services/fsw/Dockerfile b/deployments/services/fsw/Dockerfile new file mode 100644 index 000000000..270eda61f --- /dev/null +++ b/deployments/services/fsw/Dockerfile @@ -0,0 +1,119 @@ +ARG REGISTRY_HOST=ghcr.io +ARG IMAGE_USERNAME=haisamido +ARG IMAGE_NAME=nos3-64 +ARG IMAGE_TAG=dev +ARG IMAGE_URI=${REGISTRY_HOST}/${IMAGE_USERNAME}/${IMAGE_NAME}:${IMAGE_TAG} +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +ARG GIT_URL=https://github.com/nasa/nos3 +ARG GIT_COMMIT=dev + +ARG NOS3_USER=nos3 +ARG FSW_SOFTWARE=cfs +ARG GSW_SOFTWARE=yamcs + +#------------------------------------------------------------------------------ +FROM ${IMAGE_URI} AS nos3-base + +ARG DEBIAN_FRONTEND=noninteractive + +#------------------------------------------------------------------------------ +# Proxy configs +#------------------------------------------------------------------------------ +ARG MAVEN_HTTPS_PROXY +ARG HTTPS_PROXY +ARG HTTP_PROXY +ARG NO_PROXY +ARG DEPLOYMENT_ENVIRO + +ENV MAVEN_HTTPS_PROXY=${MAVEN_HTTPS_PROXY} +ENV HTTPS_PROXY=${HTTPS_PROXY} +ENV HTTP_PROXY=${HTTP_PROXY} +ENV NO_PROXY=${NO_PROXY} +ENV DEPLOYMENT_ENVIRO=${DEPLOYMENT_ENVIRO} + +#------------------------------------------------------------------------------ +# Git Configs +#------------------------------------------------------------------------------ +ARG GIT_URL +ARG GIT_COMMIT + +ENV GIT_URL=${GIT_URL} +ENV GIT_COMMIT=${GIT_COMMIT} + +#------------------------------------------------------------------------------ +# NOS3 Configs +#------------------------------------------------------------------------------ +ARG NOS3_USER +ARG FSW_SOFTWARE +ARG GSW_SOFTWARE +ARG GROUND_SOFTWARE +ARG LD_LIBRARY_PATH + +ENV NOS3_USER=${NOS3_USER} +ENV FSW_SOFTWARE=${FSW_SOFTWARE} +ENV GSW_SOFTWARE=${GSW_SOFTWARE} +ENV GROUND_SOFTWARE=${GSW_SOFTWARE} +ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH} + +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Tools +#------------------------------------------------------------------------------ +RUN apt-get update && \ + apt-get install -y sudo git curl vim make cmake tmux tree python3 pip && \ + apt-get install -y iputils-ping dnsutils lsof net-tools tshark jq && \ + apt-get install -y libgcrypt20-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +RUN git config --global http.sslVerify false + +#------------------------------------------------------------------------------ +# Create a new user named ${NOS3_USER} with a home directory +#------------------------------------------------------------------------------ +RUN useradd -m ${NOS3_USER} +RUN adduser ${NOS3_USER} sudo +RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +# Switch to the newly created user +USER ${NOS3_USER} + +# Create builds directory +RUN mkdir -p /home/${NOS3_USER}/builds/ + +WORKDIR /home/${NOS3_USER}/builds/ + +#------------------------------------------------------------------------------ +# Clone ${GIT_URL} +#------------------------------------------------------------------------------ +RUN git clone --recurse-submodules -b ${GIT_COMMIT} -j4 ${GIT_URL} + +WORKDIR /home/${NOS3_USER}/builds/nos3 + +RUN chown -R ${NOS3_USER}:${NOS3_USER} /home/${NOS3_USER} + +# commented printf(CRYPTO_PROMPT) because it fills up volume while the cryptolib is running +COPY components/cryptolib/standalone/standalone.h ./components/cryptolib/support/standalone/standalone.h +COPY components/cryptolib/standalone/standalone.c ./components/cryptolib/support/standalone/standalone.c +COPY scripts/cfg/prepare.sh ./scripts/cfg/prepare.sh + +RUN make -j6 clean +RUN make -j6 prep +RUN make -j6 config +RUN make -j6 build-cryptolib + +RUN make -j6 -e FSW_SOFTWARE=${FSW_SOFTWARE} build-fsw +RUN make -j6 build-sim +#RUN make -j6 build-test + +#------------------------------------------------------------------------------ +# Install the relevant GSW Software +#------------------------------------------------------------------------------ +RUN ./scripts/gsw/gsw_${GSW_SOFTWARE}_build.sh + +COPY entrypoint.sh /entrypoint.sh + +CMD ["/entrypoint.sh"] \ No newline at end of file diff --git a/deployments/services/fsw/components/cryptolib/standalone/standalone.c b/deployments/services/fsw/components/cryptolib/standalone/standalone.c new file mode 100755 index 000000000..b9b189d5a --- /dev/null +++ b/deployments/services/fsw/components/cryptolib/standalone/standalone.c @@ -0,0 +1,1072 @@ +/* Copyright (C) 2009 - 2022 National Aeronautics and Space Administration. + All Foreign Rights are Reserved to the U.S. Government. + + This software is provided "as is" without any warranty of any kind, either expressed, implied, or statutory, + including, but not limited to, any warranty that the software will conform to specifications, any implied warranties + of merchantability, fitness for a particular purpose, and freedom from infringement, and any warranty that the + documentation will conform to the program, or any warranty that the software will be error free. + + In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or + consequential damages, arising out of, resulting from, or in any way connected with the software or its + documentation, whether or not based upon warranty, contract, tort or otherwise, and whether or not loss was sustained + from, or arose out of the results of, or use of, the software, documentation or services provided hereunder. + + ITC Team + NASA IV&V + jstar-development-team@mail.nasa.gov +*/ + +/******************************************************************************* +** Standalone CryptoLib Implementation +** UDP interfaces to apply / process each frame type and return the result. +*******************************************************************************/ + +#include "standalone.h" + +/* +** Global Variables +*/ +#define DYNAMIC_LENGTHS 1 + +static volatile uint8_t keepRunning = CRYPTO_LIB_SUCCESS; +static volatile uint8_t tc_seq_num = 0; +static volatile uint8_t tc_vcid = CRYPTO_STANDALONE_FRAMING_VCID; +static volatile uint8_t tc_debug = 1; +static volatile uint8_t tm_debug = 0; +static volatile uint8_t crypto_use_tcp = STANDALONE_TCP ? 1 : 0; + +/* +** Functions +*/ +int32_t crypto_standalone_check_number_arguments(int actual, int expected) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + if (actual != expected) + { + status = CRYPTO_LIB_ERROR; + printf("Invalid command format or number of arguments, type 'help' for more info\n"); + } + return status; +} + +void crypto_standalone_to_lower(char *str) +{ + char *ptr = str; + while (*ptr) + { + *ptr = tolower((unsigned char)*ptr); + ptr++; + } + return; +} + +void crypto_standalone_print_help(void) +{ + printf(CRYPTO_PROMPT "command [args]\n" + "----------------------------------------------------------------------\n" + "exit - Exit app \n" + "help - Display help \n" + "noop - No operation command to device \n" + "reset - Reset CryptoLib \n" + "active - Displays all operational SAs \n" + "tc - Toggle TC debug prints \n" + "tm - Toggle TM debug prints \n" + "vcid # - Change active TC virtual channel \n" + "\n"); +} + +int32_t crypto_standalone_get_command(const char *str) +{ + int32_t status = CRYPTO_CMD_UNKNOWN; + char lcmd[CRYPTO_MAX_INPUT_TOKEN_SIZE]; + + strncpy(lcmd, str, CRYPTO_MAX_INPUT_TOKEN_SIZE); + crypto_standalone_to_lower(lcmd); + + if (strcmp(lcmd, "help") == 0) + { + status = CRYPTO_CMD_HELP; + } + else if (strcmp(lcmd, "exit") == 0) + { + status = CRYPTO_CMD_EXIT; + } + else if (strcmp(lcmd, "noop") == 0) + { + status = CRYPTO_CMD_NOOP; + } + else if (strcmp(lcmd, "reset") == 0) + { + status = CRYPTO_CMD_RESET; + } + else if (strcmp(lcmd, "vcid") == 0) + { + status = CRYPTO_CMD_VCID; + } + else if (strcmp(lcmd, "tc") == 0) + { + status = CRYPTO_CMD_TC_DEBUG; + } + else if (strcmp(lcmd, "tm") == 0) + { + status = CRYPTO_CMD_TM_DEBUG; + } + else if (strcmp(lcmd, "active") == 0) + { + status = CRYPTO_CMD_ACTIVE; + } + return status; +} + +int32_t crypto_standalone_process_command(int32_t cc, int32_t num_tokens, char *tokens) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + + /* Process command */ + switch (cc) + { + case CRYPTO_CMD_HELP: + crypto_standalone_print_help(); + break; + + case CRYPTO_CMD_EXIT: + keepRunning = CRYPTO_LIB_ERROR; + break; + + case CRYPTO_CMD_NOOP: + if (crypto_standalone_check_number_arguments(num_tokens, 0) == CRYPTO_LIB_SUCCESS) + { + printf("NOOP command success\n"); + } + break; + + case CRYPTO_CMD_RESET: + if (crypto_standalone_check_number_arguments(num_tokens, 0) == CRYPTO_LIB_SUCCESS) + { + status = crypto_reset(); + printf("Reset command received\n"); + } + break; + + case CRYPTO_CMD_VCID: + if (crypto_standalone_check_number_arguments(num_tokens, 1) == CRYPTO_LIB_SUCCESS) + { + uint8_t vcid = (uint8_t)atoi(&tokens[0]); + /* Confirm new VCID valid */ + if (vcid < 64) + { + SaInterface sa_if = get_sa_interface_inmemory(); + SecurityAssociation_t *test_association = NULL; + int32_t status = CRYPTO_LIB_SUCCESS; + + status = sa_if->sa_get_operational_sa_from_gvcid(0, SCID, vcid, 0, &test_association); + if (status == CRYPTO_LIB_SUCCESS) + { + Crypto_saPrint(test_association); + } + printf("Get_SA_Status: %d\n", status); + if ((status == CRYPTO_LIB_SUCCESS) && (test_association->sa_state == SA_OPERATIONAL) && + (test_association->gvcid_blk.mapid == TYPE_TC) && (test_association->gvcid_blk.scid == SCID)) + { + tc_vcid = vcid; + printf("Changed active virtual channel (VCID) to %d \n", tc_vcid); + } + else + { + printf("Error - virtual channel (VCID) %d is invalid! Sticking with prior vcid %d \n", vcid, + tc_vcid); + status = CRYPTO_LIB_SUCCESS; + } + } + else + { + printf("Error - virtual channel (VCID) %d must be less than 64! Sticking with prior vcid %d \n", + vcid, tc_vcid); + } + } + break; + + case CRYPTO_CMD_TC_DEBUG: + if (crypto_standalone_check_number_arguments(num_tokens, 0) == CRYPTO_LIB_SUCCESS) + { + if (tc_debug == 0) + { + tc_debug = 1; + printf("Enabled TC debug prints! \n"); + } + else + { + tc_debug = 0; + printf("Disabled TC debug prints! \n"); + } + } + break; + + case CRYPTO_CMD_TM_DEBUG: + if (crypto_standalone_check_number_arguments(num_tokens, 0) == CRYPTO_LIB_SUCCESS) + { + if (tm_debug == 0) + { + tm_debug = 1; + printf("Enabled TM debug prints! \n"); + } + else + { + tm_debug = 0; + printf("Disabled TM debug prints! \n"); + } + } + break; + + case CRYPTO_CMD_ACTIVE: + if (crypto_standalone_check_number_arguments(num_tokens, 0) == CRYPTO_LIB_SUCCESS) + { + SaInterface sa_if = get_sa_interface_inmemory(); + SecurityAssociation_t *test_association = NULL; + + printf("Active SAs: \n\t"); + for (int i = 0; i < NUM_SA; i++) + { + sa_if->sa_get_from_spi(i, &test_association); + if (test_association->sa_state == SA_OPERATIONAL) + { + if (i < 5) + { + printf("TC - "); + } + if (i > 4 && i < 9) + { + printf("TM - "); + } + if (i > 8 && i < 13) + { + printf("AOS - "); + } + if (i == 63) + { + printf("ExProc - "); + } + + printf("SPI %d - VCID %d - EST %d - AST %d\n\t", i, test_association->gvcid_blk.vcid, + test_association->est, test_association->ast); + } + } + printf("\n"); + } + break; + + default: + // printf("Invalid command format, type 'help' for more info\n"); + // status = CRYPTO_LIB_ERROR; + break; + } + + return status; +} + +int32_t crypto_host_to_ip(const char *hostname, char *ip) +{ + struct addrinfo hints, *res, *p; + int status; + void *addr; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; // Uses IPV4 only. AF_UNSPEC for IPV6 Support + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) + { + return 1; + } + + for (p = res; p != NULL; p = p->ai_next) + { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + addr = &(ipv4->sin_addr); + + // Convert IP to String + if (inet_ntop(p->ai_family, addr, ip, INET_ADDRSTRLEN) == NULL) + { + freeaddrinfo(res); + return 1; + } + + freeaddrinfo(res); + return 0; // IP Found + } + freeaddrinfo(res); + return 1; // IP NOT Found +} + +int32_t crypto_standalone_socket_init(udp_info_t *sock, int32_t port, uint8_t bind_sock, int connection) +{ + int status = CRYPTO_LIB_SUCCESS; + int optval; + socklen_t optlen; + + sock->port = port; + + if (connection == 1) + { + /* Creating TCP socket */ + sock->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (sock->sockfd == -1) + { + printf("tcp_init: Socket create error on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + + /* Determine IP */ + sock->saddr.sin_family = AF_INET; + if (inet_addr(sock->ip_address) != INADDR_NONE) + { + sock->saddr.sin_addr.s_addr = inet_addr(sock->ip_address); + } + else + { + char ip[16]; + int check = crypto_host_to_ip(sock->ip_address, ip); + if (check == 0) + { + sock->saddr.sin_addr.s_addr = inet_addr(ip); + } + else + { + printf("socket_init: Failed to resolve hostname '%s'\n", sock->ip_address); + return CRYPTO_LIB_ERROR; + } + } + sock->saddr.sin_port = htons(sock->port); + } + else + { + /* Create UDP socket */ + sock->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock->sockfd == -1) + { + printf("udp_init: Socket create error port %d \n", sock->port); + } + + /* Determine IP */ + sock->saddr.sin_family = AF_INET; + if (inet_addr(sock->ip_address) != INADDR_NONE) + { + sock->saddr.sin_addr.s_addr = inet_addr(sock->ip_address); + } + else + { + char ip[16]; + int check = crypto_host_to_ip(sock->ip_address, ip); + if (check == 0) + { + sock->saddr.sin_addr.s_addr = inet_addr(ip); + } + } + sock->saddr.sin_port = htons(sock->port); + } + + if (crypto_use_tcp && ((sock->port == TC_APPLY_FWD_PORT || sock->port == TM_PROCESS_PORT))) + { + if (bind_sock != 0) + { + // TCP server: bind, listen, accept + if (bind(sock->sockfd, (struct sockaddr *)&sock->saddr, sizeof(sock->saddr)) != 0) + { + printf("tcp_init: Bind failed on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + + if (listen(sock->sockfd, 1) != 0) + { + printf("tcp_init: Listen failed on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + + int clientfd = accept(sock->sockfd, NULL, NULL); + if (clientfd < 0) + { + printf("tcp_init: Accept failed on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + + // Replace listener with connected client socket + // close(sock->sockfd); //may be needed + sock->sockfd = clientfd; + } + else + { + // TCP client: connect + if (connect(sock->sockfd, (struct sockaddr *)&sock->saddr, sizeof(sock->saddr)) < 0) + { + printf("tcp_init: Connect failed to %s:%d\n", sock->ip_address, sock->port); + return CRYPTO_LIB_ERROR; + } + } + } + else + { + // UDP: bind only if needed + if (bind_sock == 0 && sock->port != TM_PROCESS_FWD_PORT && sock->port != TC_APPLY_FWD_PORT) + { + status = bind(sock->sockfd, (struct sockaddr *)&sock->saddr, sizeof(sock->saddr)); + if (status != 0) + { + perror("bind"); + + printf("udp_init: Bind failed on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + // } + } + else + { + if (crypto_use_tcp == 0 && bind_sock == 1 && sock->port == TM_PROCESS_PORT) + { + status = bind(sock->sockfd, (struct sockaddr *)&sock->saddr, sizeof(sock->saddr)); + if (status != 0) + { + perror("bind"); + + printf("udp_init: Bind failed on port %d\n", sock->port); + return CRYPTO_LIB_ERROR; + } + } + } + } + + // Keep-alive socket option (not harmful for UDP, useful for TCP) + optval = 1; + optlen = sizeof(optval); + setsockopt(sock->sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + + return status; +} + +int32_t crypto_reset(void) +{ + int32_t status; + + status = Crypto_Shutdown(); + if (status != CRYPTO_LIB_SUCCESS) + { + printf("CryptoLib initialization failed with error %d \n", status); + } + + status = Crypto_SC_Init(); + if (status != CRYPTO_LIB_SUCCESS) + { + printf("CryptoLib initialization failed with error %d \n", status); + } + + return status; +} + +void crypto_standalone_tc_frame(uint8_t *in_data, uint16_t in_length, uint8_t *out_data, uint16_t *out_length) +{ + /* TC Length */ + if (DYNAMIC_LENGTHS) + { + uint8_t segment_hdr_len = 1; + uint8_t fecf_len = tc_current_managed_parameters_struct.has_fecf ? 2 : 0; + + *out_length = TC_FRAME_HEADER_SIZE + segment_hdr_len + in_length + fecf_len; + } + else + { + *out_length = CRYPTO_STANDALONE_FRAMING_TC_DATA_LEN + 6; + } + + /* TC Header */ + out_data[0] = 0x20; + out_data[1] = CRYPTO_STANDALONE_FRAMING_SCID; + out_data[2] = ((tc_vcid << 2) & 0xFC) | (((*out_length - 1) >> 8) & 0x03); + out_data[3] = (*out_length - 1) & 0xFF; + out_data[4] = tc_seq_num++; + + /* Segement Header */ + out_data[5] = 0xC0; + + /* SDLS Header */ + + /* TC Data */ + memcpy(&out_data[6], in_data, in_length); + + /* SDLS Trailer */ +} + +void *crypto_standalone_tc_apply(void *socks) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + udp_interface_t *tc_socks = (udp_interface_t *)socks; + udp_info_t *tc_read_sock = &tc_socks->read; + udp_info_t *tc_write_sock = &tc_socks->write; + + uint8_t tc_apply_in[TC_MAX_FRAME_SIZE]; + uint16_t tc_in_len = 0; + uint8_t *tc_out_ptr; + uint16_t tc_out_len = 0; + +#ifdef CRYPTO_STANDALONE_HANDLE_FRAMING + uint8_t tc_framed[TC_MAX_FRAME_SIZE] = {0}; +#endif + + int sockaddr_size = sizeof(struct sockaddr_in); + + /* Prepare */ + memset(tc_apply_in, 0x00, sizeof(tc_apply_in)); + + while (keepRunning == CRYPTO_LIB_SUCCESS) + { + // /* Receive */ + status = recvfrom(tc_read_sock->sockfd, tc_apply_in, sizeof(tc_apply_in), 0, + (struct sockaddr *)&tc_read_sock->ip_address, (socklen_t *)&sockaddr_size); + if (status != -1) + { + tc_in_len = status; + if (tc_debug == 1) + { + printf("crypto_standalone_tc_apply - received[%d]: 0x", tc_in_len); + for (int i = 0; i < status; i++) + { + printf("%02x", tc_apply_in[i]); + } + printf("\n"); + } + +/* Frame */ +#ifdef CRYPTO_STANDALONE_HANDLE_FRAMING + crypto_standalone_tc_frame(tc_apply_in, tc_in_len, tc_framed, &tc_out_len); + memcpy(tc_apply_in, tc_framed, tc_out_len); + tc_in_len = tc_out_len; + tc_out_len = 0; + if (tc_debug == 1) + { + printf("crypto_standalone_tc_apply - framed[%d]: 0x", tc_in_len); + for (int i = 0; i < tc_in_len; i++) + { + printf("%02x", tc_apply_in[i]); + } + printf("\n"); + } +#endif + + /* Process */ + status = Crypto_TC_ApplySecurity(tc_apply_in, tc_in_len, &tc_out_ptr, &tc_out_len); + if (status == CRYPTO_LIB_SUCCESS) + { + if (tc_debug == 1) + { + printf("crypto_standalone_tc_apply - status = %d, encrypted[%d]: 0x", status, tc_out_len); + for (int i = 0; i < tc_out_len; i++) + { + printf("%02x", tc_out_ptr[i]); + } + printf("\n"); + } + // printf("About to write to port %d!\n", tc_write_sock->port); + /* Reply */ + if (crypto_use_tcp) + { + status = send(tc_write_sock->sockfd, tc_out_ptr, tc_out_len, 0); + } + else + { + status = sendto(tc_write_sock->sockfd, tc_out_ptr, tc_out_len, 0, + (struct sockaddr *)&tc_write_sock->saddr, sizeof(tc_write_sock->saddr)); + } + if ((status == -1) || (status != tc_out_len)) + { + printf("crypto_standalone_tc_apply - Reply error %d \n", status); + } + // printf("Allegedly wrote %d bytes to port %d!\n", tc_out_len, tc_write_sock->port); + } + else + { + printf("crypto_standalone_tc_apply - ApplySecurity error %d \n", status); + } + + /* Reset */ + memset(tc_apply_in, 0x00, sizeof(tc_apply_in)); + memset(tc_framed, 0x00, sizeof(tc_framed)); + tc_in_len = 0; + tc_out_len = 0; + if (!tc_out_ptr) + free(tc_out_ptr); + if (tc_debug == 1) + { +#ifdef CRYPTO_STANDALONE_TC_APPLY_DEBUG + printf("\n"); +#endif + } + } + + /* Delay */ + usleep(100); + } + close(tc_read_sock->sockfd); + close(tc_write_sock->sockfd); + return tc_read_sock; +} + +void crypto_standalone_tm_frame(uint8_t *in_data, uint16_t in_length, uint8_t *out_data, uint16_t *out_length, + uint16_t spi) +{ + SaInterface sa_if = get_sa_interface_inmemory(); + SecurityAssociation_t *sa_ptr = NULL; + int32_t status = CRYPTO_LIB_SUCCESS; + + status = sa_if->sa_get_from_spi(spi, &sa_ptr); + if (status != CRYPTO_LIB_SUCCESS) + { + printf("WARNING - SA IS NULL!\n"); + } + + // Calculate security headers and trailers + uint8_t header_length = + TM_PRI_HDR_LENGTH + SDLS_SPI_LENGTH + sa_ptr->shivf_len + sa_ptr->shplf_len + sa_ptr->shsnf_len; + + uint8_t trailer_length = sa_ptr->stmacf_len; + if (tm_current_managed_parameters_struct.has_fecf == TM_HAS_FECF) + { + trailer_length += 2; + } + if (tm_current_managed_parameters_struct.has_ocf == TM_HAS_OCF) + { + trailer_length += 4; + } + + /* TM Length */ + *out_length = (uint16_t)in_length - header_length - trailer_length; + + /* TM Header */ + memcpy(out_data, &in_data[header_length], in_length - header_length - trailer_length); +} + +void crypto_standalone_tm_debug_recv(int32_t status, int tm_process_len, uint8_t *tm_process_in) +{ + if (tm_debug == 1) + { + printf("crypto_standalone_tm_process - received[%d]: 0x", tm_process_len); + for (int i = 0; i < status; i++) + { + printf("%02x", tm_process_in[i]); + } + printf("\n"); + } +} + +void crypto_standalone_tm_debug_process(uint8_t *tm_process_in) +{ + if (tm_debug == 1) + { + printf("Printing first bytes of Tf Pri Hdr:\n\t"); + for (int i = 0; i < 6; i++) + { + printf("%02X", *(tm_process_in + 4 + i)); + } + printf("\n"); + printf("Processing frame WITH ASM...\n"); + } +} + +void crypto_standalone_spp_telem_or_idle(int32_t *status, uint8_t *tm_ptr, uint16_t *spp_len, udp_interface_t *tm_socks, + int *tm_process_len) +{ + udp_info_t *tm_write_sock = &tm_socks->write; + + if ((tm_ptr[0] == 0x08) || (tm_ptr[0] == 0x09) || ((tm_ptr[0] == 0x07) && (tm_ptr[1] == 0xff)) || + (tm_ptr[0] == 0x0F && tm_ptr[1] == 0xFD)) + { + *spp_len = (((0xFFFF & tm_ptr[4]) << 8) | tm_ptr[5]) + 7; +#ifdef CRYPTO_STANDALONE_TM_PROCESS_DEBUG + printf("crypto_standalone_tm_process - SPP[%d]: 0x", *spp_len); + for (int i = 0; i < *spp_len; i++) + { + printf("%02x", tm_ptr[i]); + } + printf("\n"); +#endif + // Send all SPP telemetry packets + // 0x09 for HK/Device TLM Packets (Generic Components) + // 0x0FFD = CFDP + if (tm_ptr[0] == 0x08 || tm_ptr[0] == 0x09 || (tm_ptr[0] == 0x0f && tm_ptr[1] == 0xfd)) + { + *status = sendto(tm_write_sock->sockfd, tm_ptr, *spp_len, 0, (struct sockaddr *)&tm_write_sock->saddr, + sizeof(tm_write_sock->saddr)); + } + // Only send idle packets if configured to do so + else + { +#ifdef CRYPTO_STANDALONE_DISCARD_IDLE_PACKETS + // Don't forward idle packets + *status = *spp_len; +#else + *status = sendto(tm_write_sock->sockfd, tm_ptr, *spp_len, 0, (struct sockaddr *)&tm_write_sock->saddr, + sizeof(tm_write_sock->saddr)); +#endif + } + + // Check status + if ((*status == -1) || (*status != *spp_len)) + { + printf("crypto_standalone_tm_process - Reply error %d \n", *status); + } + + *tm_process_len -= *spp_len; + } + else if ((tm_ptr[0] == 0xFF && tm_ptr[1] == 0x48) || (tm_ptr[0] == 0x00 && tm_ptr[1] == 0x00) || + (tm_ptr[0] == 0x02 && tm_ptr[1] == 0x00) || (tm_ptr[0] == 0xFF && tm_ptr[1] == 0xFF)) + { + // TODO: Why 0x0200? + // Idle Frame + // Idle Frame is entire length of remaining data +#ifdef CRYPTO_STANDALONE_DISCARD_IDLE_FRAMES + // Don't forward idle frame + *status = *spp_len; +#else + *status = sendto(tm_write_sock->sockfd, tm_ptr, *spp_len, 0, (struct sockaddr *)&tm_write_sock->saddr, + sizeof(tm_write_sock->saddr)); + if ((*status == -1) || (*status != *spp_len)) + { + printf("crypto_standalone_tm_process - Reply error %d \n", *status); + } +#endif + *tm_process_len = 0; + } + else + { + printf("crypto_standalone_tm_process - SPP loop error, expected idle packet or frame! tm_ptr = 0x%02x%02x \n", + tm_ptr[0], tm_ptr[1]); + *tm_process_len = 0; + } +} + +void *crypto_standalone_tm_process(void *socks) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + udp_interface_t *tm_socks = (udp_interface_t *)socks; + udp_info_t *tm_read_sock = &tm_socks->read; + udp_info_t *tm_write_sock = &tm_socks->write; + + uint8_t tm_process_in[TM_CADU_SIZE]; // Accounts for ASM automatically based on #def + int tm_process_len = 0; + uint16_t spp_len = 0; + uint8_t *tm_ptr; + uint16_t tm_out_len = 0; + +#ifdef CRYPTO_STANDALONE_HANDLE_FRAMING + uint8_t tm_framed[TM_CADU_SIZE]; + uint16_t tm_framed_len = 0; +#endif + + int sockaddr_size = sizeof(struct sockaddr_in); + + while (keepRunning == CRYPTO_LIB_SUCCESS) + { + /* Receive */ + if (crypto_use_tcp) + { + status = recv(tm_read_sock->sockfd, tm_process_in, sizeof(tm_process_in), 0); + if (status == -1) + { + printf(" Problem with recv TCP tm_proccess: status = %d \n", status); + } + } + else + { + status = recvfrom(tm_read_sock->sockfd, tm_process_in, sizeof(tm_process_in), 0, + (struct sockaddr *)&tm_read_sock->ip_address, (socklen_t *)&sockaddr_size); + } + if (status != -1) + { + tm_process_len = status; + /* Receive */ + crypto_standalone_tm_debug_recv(status, tm_process_len, tm_process_in); + /* Process */ +#ifdef TM_CADU_HAS_ASM + // Process Security skipping prepended ASM + crypto_standalone_tm_debug_process(tm_process_in); + // Account for ASM length + if (tm_process_in[4] == 0x40) + { + status = Crypto_AOS_ProcessSecurity(tm_process_in + 4, (const uint16_t)tm_process_len - 4, &tm_ptr, + &tm_out_len); + if (status != 0) + { + printf("Crypto_AOS_ProcessSecurity Failed with status = %d\n", status); + } + } + else + { + status = Crypto_TM_ProcessSecurity(tm_process_in + 4, (const uint16_t)tm_process_len - 4, &tm_ptr, + &tm_out_len); + if (status != 0) + { + printf("Crypto_TM_ProcessSecurity Failed with status = %d\n", status); + } + } +#else + if (tm_debug == 1) + { + printf("Processing frame without ASM...\n"); + } + status = Crypto_TM_ProcessSecurity(tm_process_in, (const uint16_t)tm_process_len, &tm_ptr, &tm_out_len); + if (status != 0) + { + printf("Crypto_TM_ProcessSecurity Failed with status = %d\n", status); + } +#endif + if (status == CRYPTO_LIB_SUCCESS) + { + if (tm_debug == 1) + { + if ((tm_ptr[4] == 0x07) && (tm_ptr[5] == 0xFF)) + { + // OID Frame + } + else + { + printf("crypto_standalone_tm_process: 1 - status = %d, decrypted[%d]: 0x", status, tm_out_len); + for (int i = 0; i < tm_out_len; i++) + { + printf("%02x", tm_ptr[i]); + } + printf("\n"); + } + } + +/* Frame */ +#ifdef CRYPTO_STANDALONE_HANDLE_FRAMING +#ifdef TM_CADU_HAS_ASM + uint16_t spi = (tm_process_in[10] << 8) | tm_process_in[11]; + crypto_standalone_tm_frame(tm_ptr, tm_out_len, tm_framed, &tm_framed_len, spi); +#else + uint16_t spi = (tm_process_in[6] << 8) | tm_process_in[7]; + crypto_standalone_tm_frame(tm_process_in, tm_process_len, tm_framed, &tm_framed_len, spi); +#endif + memcpy(tm_process_in, tm_framed, tm_framed_len); + tm_process_len = tm_framed_len; + tm_framed_len = 0; + + if (tm_debug == 1) + // Note: Need logic to allow broken packet assembly + { + printf("crypto_standalone_tm_process: 2 - beginning after first header pointer - deframed[%d]: 0x", + tm_process_len); + for (int i = 0; i < tm_process_len; i++) + { + printf("%02x", tm_framed[i]); + } + printf("\n"); + } +#endif + + /* Space Packet Protocol Loop */ + tm_ptr = &tm_process_in[0]; + while (tm_process_len > 5) + { + // SPP Telemetry OR SPP Idle Packet + crypto_standalone_spp_telem_or_idle(&status, tm_ptr, &spp_len, tm_socks, &tm_process_len); + tm_ptr = &tm_ptr[spp_len]; + } + } + else + { + printf("crypto_standalone_tm_process - ProcessSecurity error %d \n", status); + } + + /* Reset */ + memset(tm_process_in, 0x00, sizeof(tm_process_in)); + tm_process_len = 0; + memset(tm_ptr, 0x00, sizeof(tm_process_in)); +#ifdef CRYPTO_STANDALONE_TM_PROCESS_DEBUG + printf("\n"); +#endif + } + + /* Delay */ + usleep(10); + } + close(tm_read_sock->sockfd); + close(tm_write_sock->sockfd); + return tm_read_sock; +} + +void crypto_standalone_cleanup(const int signal) +{ + if (signal == SIGINT) + { + printf("\n"); + printf("Received CTRL+C, cleaning up... \n"); + } + /* Signal threads to stop */ + keepRunning = CRYPTO_LIB_ERROR; + exit(signal); + return; +} + +int main(int argc, char *argv[]) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + + // char input_buf[CRYPTO_MAX_INPUT_BUF]; + // char input_tokens[CRYPTO_MAX_INPUT_TOKENS][CRYPTO_MAX_INPUT_TOKEN_SIZE]; + // int num_input_tokens; + // int cmd; + // char *token_ptr; + + udp_interface_t tc_apply; + udp_interface_t tm_process; + + pthread_t tc_apply_thread; + pthread_t tm_process_thread; + + tc_apply.read.ip_address = CRYPTOLIB_HOSTNAME; + tc_apply.read.port = TC_APPLY_PORT; + tc_apply.write.ip_address = SC_HOSTNAME; + tc_apply.write.port = TC_APPLY_FWD_PORT; + tm_process.read.ip_address = CRYPTOLIB_HOSTNAME; + tm_process.read.port = TM_PROCESS_PORT; + tm_process.write.ip_address = GSW_HOSTNAME; + tm_process.write.port = TM_PROCESS_FWD_PORT; + + printf("Starting CryptoLib in standalone mode! \n"); + if (argc != 1) + { + printf("Invalid number of arguments! \n"); + printf(" Expected zero but received: %s \n", argv[1]); + } + printf("CryptoLib using %s sockets\n", crypto_use_tcp ? "TCP" : "UDP"); + + /* Catch CTRL+C */ + signal(SIGINT, crypto_standalone_cleanup); + + /* Startup delay */ + sleep(10); + + /* Initialize CryptoLib */ + status = crypto_reset(); + if (status != CRYPTO_LIB_SUCCESS) + { + printf("CryptoLib initialization failed with error %d \n", status); + keepRunning = CRYPTO_LIB_ERROR; + } + + /* Initialize sockets */ + if (keepRunning == CRYPTO_LIB_SUCCESS) + { + status = crypto_standalone_socket_init(&tc_apply.read, TC_APPLY_PORT, 0, 0); // udp 6010 + if (status != CRYPTO_LIB_SUCCESS) + { + printf("crypto_standalone_socket_init tc_apply.read failed with status %d \n", status); + keepRunning = CRYPTO_LIB_ERROR; + } + else + { + status = crypto_standalone_socket_init(&tc_apply.write, TC_APPLY_FWD_PORT, 0, + crypto_use_tcp); // tcp, connect() 8010 + if (status != CRYPTO_LIB_SUCCESS) + { + printf("crypto_standalone_socket_init tc_apply.write failed with status %d \n", status); + keepRunning = CRYPTO_LIB_ERROR; + } + } + } + + if (keepRunning == CRYPTO_LIB_SUCCESS) + { + status = + crypto_standalone_socket_init(&tm_process.read, TM_PROCESS_PORT, 1, crypto_use_tcp); // tcp, accept() 8011 + if (status != CRYPTO_LIB_SUCCESS) + { + printf("crypto_standalone_socket_init tm_apply.read failed with status %d \n", status); + keepRunning = CRYPTO_LIB_ERROR; + } + else + { + status = crypto_standalone_socket_init(&tm_process.write, TM_PROCESS_FWD_PORT, 0, 0); // udp 6011 + if (status != CRYPTO_LIB_SUCCESS) + { + printf("crypto_standalone_socket_init tm_process.write failed with status %d \n", status); + keepRunning = CRYPTO_LIB_ERROR; + } + } + } + + /* Start threads */ + if (keepRunning == CRYPTO_LIB_SUCCESS) + { + printf(" TC Apply \n"); + printf(" Read, UDP - %s : %d \n", tc_apply.read.ip_address, tc_apply.read.port); + printf(" Write, %s - %s : %d \n", crypto_use_tcp ? "TCP" : "UDP", tc_apply.write.ip_address, + tc_apply.write.port); + printf(" TM Process \n"); + printf(" Read, %s - %s : %d \n", crypto_use_tcp ? "TCP" : "UDP", tm_process.read.ip_address, + tm_process.read.port); + printf(" Write, UDP - %s : %d \n", tm_process.write.ip_address, tm_process.write.port); + printf("\n"); + + status = pthread_create(&tc_apply_thread, NULL, *crypto_standalone_tc_apply, &tc_apply); + if (status < 0) + { + perror("Failed to create tc_apply_thread thread"); + keepRunning = CRYPTO_LIB_ERROR; + } + else + { + status = pthread_create(&tm_process_thread, NULL, *crypto_standalone_tm_process, &tm_process); + if (status < 0) + { + perror("Failed to create tm_process_thread thread"); + keepRunning = CRYPTO_LIB_ERROR; + } + } + } + + /* Main loop */ + while (keepRunning == CRYPTO_LIB_SUCCESS) + { + // num_input_tokens = -1; + // cmd = CRYPTO_CMD_UNKNOWN; + + /* Read user input */ +/* commented this out because it fills up volume while the cryptolib container is running */ +/* printf(CRYPTO_PROMPT); */ + // fgets(input_buf, CRYPTO_MAX_INPUT_BUF, stdin); + + /* Tokenize line buffer */ + // token_ptr = strtok(input_buf, " \t\n"); + // while ((num_input_tokens < CRYPTO_MAX_INPUT_TOKENS) && (token_ptr != NULL)) + // { + // if (num_input_tokens == -1) + // { + // /* First token is command */ + // cmd = crypto_standalone_get_command(token_ptr); + // } + // else + // { + // strncpy(input_tokens[num_input_tokens], token_ptr, CRYPTO_MAX_INPUT_TOKEN_SIZE); + // } + // token_ptr = strtok(NULL, " \t\n"); + // num_input_tokens++; + // } + + /* Process command if valid */ + // if (num_input_tokens >= 0) + // { + // crypto_standalone_process_command(cmd, num_input_tokens, &input_tokens[0][0]); + // } + } + + /* Cleanup */ + close(tc_apply.read.sockfd); + close(tc_apply.write.sockfd); + close(tm_process.read.sockfd); + close(tm_process.write.sockfd); + + Crypto_Shutdown(); + + printf("\n"); + exit(status); +} diff --git a/deployments/services/fsw/components/cryptolib/standalone/standalone.h b/deployments/services/fsw/components/cryptolib/standalone/standalone.h new file mode 100755 index 000000000..c4857b5b3 --- /dev/null +++ b/deployments/services/fsw/components/cryptolib/standalone/standalone.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2009 - 2022 National Aeronautics and Space Administration. + All Foreign Rights are Reserved to the U.S. Government. + + This software is provided "as is" without any warranty of any kind, either expressed, implied, or statutory, + including, but not limited to, any warranty that the software will conform to specifications, any implied warranties + of merchantability, fitness for a particular purpose, and freedom from infringement, and any warranty that the + documentation will conform to the program, or any warranty that the software will be error free. + + In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or + consequential damages, arising out of, resulting from, or in any way connected with the software or its + documentation, whether or not based upon warranty, contract, tort or otherwise, and whether or not loss was sustained + from, or arose out of the results of, or use of, the software, documentation or services provided hereunder. + + ITC Team + NASA IV&V + jstar-development-team@mail.nasa.gov +*/ + +#ifndef CRYPTOLIB_STANDALONE_H +#define CRYPTOLIB_STANDALONE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* +** Includes +*/ +#include +#include +#include +#include +#include //hostent +#include +#include +#include +#include +#include +#include +#include + +#include "crypto.h" +#include "crypto_config.h" + +/* +** Configuration +*/ +#define CRYPTOLIB_HOSTNAME "cryptolib" +#define GSW_HOSTNAME "cosmos" +#define SC_HOSTNAME "radio-sim" + +#ifndef CRYPTO_RX_GROUND_PORT +#define TC_APPLY_PORT 6010 +#endif +#ifndef CRYPTO_RX_GROUND_PORT +#define TC_APPLY_FWD_PORT 8010 +#endif +#ifndef CRYPTO_RX_GROUND_PORT +#define TM_PROCESS_PORT 8011 +#endif +#ifndef CRYPTO_RX_GROUND_PORT +#define TM_PROCESS_FWD_PORT 6011 +#endif + +#define CRYPTO_STANDALONE_HANDLE_FRAMING +#define CRYPTO_STANDALONE_FRAMING_SCID 3 +#define CRYPTO_STANDALONE_FRAMING_VCID 0x00 +#define CRYPTO_STANDALONE_FRAMING_TC_DATA_LEN 512 + +/* +** Can be used to reduce ground system error messages +*/ +#define CRYPTO_STANDALONE_DISCARD_IDLE_PACKETS +#define CRYPTO_STANDALONE_DISCARD_IDLE_FRAMES + +/* +** Defines +*/ +#define CRYPTO_PROMPT "cryptolib> " +#define CRYPTO_MAX_INPUT_BUF 512 +#define CRYPTO_MAX_INPUT_TOKENS 32 +#define CRYPTO_MAX_INPUT_TOKEN_SIZE 64 + +#define TM_PRI_HDR_LENGTH 6 +#define TM_ASM_LENGTH 4 +#define SDLS_SPI_LENGTH 2 + +#define CRYPTO_CMD_UNKNOWN (-1) +#define CRYPTO_CMD_HELP 0 +#define CRYPTO_CMD_EXIT 1 +#define CRYPTO_CMD_NOOP 2 +#define CRYPTO_CMD_RESET 3 +#define CRYPTO_CMD_VCID 4 +#define CRYPTO_CMD_TC_DEBUG 5 +#define CRYPTO_CMD_TM_DEBUG 6 +#define CRYPTO_CMD_ACTIVE 7 + + /* + ** Structures + */ + typedef struct + { + int sockfd; + char *ip_address; + int port; + struct sockaddr_in saddr; + } udp_info_t; + + typedef struct + { + udp_info_t read; + udp_info_t write; + } udp_interface_t; + + /* + ** Prototypes + */ + int32_t crypto_standalone_check_number_arguments(int actual, int expected); + void crypto_standalone_to_lower(char *str); + void crypto_standalone_print_help(void); + int32_t crypto_standalone_get_command(const char *str); + int32_t crypto_standalone_process_command(int32_t cc, int32_t num_tokens, char *tokens); + int32_t crypto_host_to_ip(const char *hostname, char *ip); + int32_t crypto_standalone_udp_init(udp_info_t *sock, int32_t port, uint8_t bind_sock); + int32_t crypto_reset(void); + void crypto_standalone_tc_frame(uint8_t *in_data, uint16_t in_length, uint8_t *out_data, uint16_t *out_length); + void *crypto_standalone_tc_apply(void *socks); + void crypto_standalone_tm_frame(uint8_t *in_data, uint16_t in_length, uint8_t *out_data, uint16_t *out_length, + uint16_t spi); + void *crypto_standalone_tm_process(void *socks); + void crypto_standalone_cleanup(const int signal); + +#ifdef __cplusplus +} /* Close scope of 'extern "C"' declaration which encloses file. */ +#endif + +#endif // CRYPTOLIB_STANDALONE_H diff --git a/deployments/services/fsw/entrypoint.sh b/deployments/services/fsw/entrypoint.sh new file mode 100755 index 000000000..01030a8f4 --- /dev/null +++ b/deployments/services/fsw/entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# if [ -n "${HEALTHCHECK_PORT}" ]; then + +# if (( ${HEALTHCHECK_PORT} )); then # only if port is a number proceed +# pkill -f nc || +# while true; do (echo -e 'HTTP/1.1 200 OK\r\n'; echo -e "\n\tSuccess: health check port ${HEALTHCHECK_PORT}" ; echo -e "\t$(date -u +%FT%T)\n") | nc -lp ${HEALTHCHECK_PORT}; done & +# else +# echo "HEALTHCHECK_PORT variable is set but to a none number; therefore, not starting health check action" +# fi + +# else +# echo "HEALTHCHECK_PORT variable is not set; therefore, not starting health check action. Optional. Proceeding" +# fi + +pkill -f fsw_respawn.sh || true +pkill -f core-cpu1 || true + +export LD_LIBRARY_PATH=${FSW_DIR}/cf/:${LD_LIBRARY_PATH} + +mkdir -p $FSW_DIR/data +mkdir -p $FSW_DIR/data/cam +mkdir -p $FSW_DIR/data/evs +mkdir -p $FSW_DIR/data/hk +mkdir -p $FSW_DIR/data/inst +touch $FSW_DIR/data/dummy.txt +echo "1234567890" > $FSW_DIR/data/dummy.txt +truncate -s 1M $FSW_DIR/data/dummy.txt + +# +cd ${FSW_DIR} && \ + ./core-cpu1 -R PO 2>&1 | tee -a ${BASE_DIR}/core-cpu1.log & + +tail -f /dev/null diff --git a/deployments/services/fsw/libuart.c b/deployments/services/fsw/libuart.c new file mode 100755 index 000000000..495478abb --- /dev/null +++ b/deployments/services/fsw/libuart.c @@ -0,0 +1,230 @@ +/* Copyright (C) 2009 - 2018 National Aeronautics and Space Administration. All Foreign Rights are Reserved to the U.S. Government. + +This software is provided "as is" without any warranty of any, kind either express, implied, or statutory, including, but not +limited to, any warranty that the software will conform to, specifications any implied warranties of merchantability, fitness +for a particular purpose, and freedom from infringement, and any warranty that the documentation will conform to the program, or +any warranty that the software will be error free. + +In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or consequential damages, +arising out of, resulting from, or in any way connected with the software or its documentation. Whether or not based upon warranty, +contract, tort or otherwise, and whether or not loss was sustained from, or arose out of the results of, or use of, the software, +documentation or services provided hereunder + +ITC Team +NASA IV&V +ivv-itc@lists.nasa.gov +*/ + +#include "libuart.h" + +int32_t uart_init_port(uart_info_t* device) +{ + int32_t status = UART_SUCCESS; + speed_t speed; + + // Set the access flag. We default to O_RDWR if the specified access flag is + // out of range + int oflag = O_RDWR; + + if (device->access_option == uart_access_flag_RDONLY) + oflag = O_RDONLY; + else if (device->access_option == uart_access_flag_WRONLY) + oflag = O_WRONLY; + + device->handle = open(device->deviceString, oflag); + + if (device->handle >= 0) + { + // Set open flag + device->isOpen = PORT_OPEN; + + // Get current port options + if(tcgetattr(device->handle, &device->options)<0) + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 1\n"); + return status; + } + + // Set baud rate + switch(device->baud) + { + case 4800: + speed=B4800; + break; + case 9600: + speed=B9600; + break; + case 19200: + speed=B19200; + break; + case 38400: + speed=B38400; + break; + case 57600: + speed=B57600; + break; + case 115200: + speed=B115200; + break; + case 230400: + speed=B230400; + break; + case 460800: + speed=B460800; + break; + case 500000: + speed=B500000; + break; + case 576000: + speed=B576000; + break; + case 921600: + speed=B921600; + break; + case 1000000: + speed=B1000000; + break; + case 1152000: + speed=B1152000; + break; + case 2000000: + speed=B2000000; + break; + case 2500000: + speed=B2500000; + break; + case 3000000: + speed=B3000000; + break; + case 3500000: + speed=B3500000; + break; + case 4000000: + speed=B4000000; + break; + default: + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 2\n"); + return status; + } + if(cfsetispeed(&device->options,speed)<0) + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 3\n"); + return status; + } + if(cfsetospeed(&device->options,speed)<0) + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 4\n"); + return status; + } + + // Raw byte mode - no strings and no CRLF + device->options.c_iflag = IGNBRK | INPCK; + device->options.c_oflag = 0; + device->options.c_cflag = CREAD | CS8 | CLOCAL; + device->options.c_lflag = NOFLSH; + if(device->canonicalModeOn == 1) + { + device->options.c_lflag |= ICANON; + } + + // Set the port to blocking read with timeout of 0.1 sec + device->options.c_cc[VMIN] = 0; // min of bytes to read + device->options.c_cc[VTIME] = 1; // intra-byte time to wait - tenths of sec + fcntl(device->handle, F_SETFL, O_NONBLOCK); // Don't have serial port block + + // TODO - any other options needed like hw control? + tcflush(device->handle, TCIOFLUSH); + + // Set the options + if(tcsetattr(device->handle, TCSANOW, &device->options)<0) + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 5\n"); + return status; + } + } + else + { + printf("Oh no! Open \"%s\" failed and reported: %s \n", device->deviceString, strerror(device->handle)); + device->isOpen = PORT_CLOSED; + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 6\n"); + + } + + return status; +} + +int32_t uart_bytes_available(uart_info_t* device) +{ + int32_t bytes_available = 0; + + ioctl(device->handle, FIONREAD, &bytes_available); + + return bytes_available; +} + +int32_t uart_flush(uart_info_t* device) +{ + tcflush(device->handle,TCIOFLUSH); + + return UART_SUCCESS; +} + +int32_t uart_read_port(uart_info_t* device, uint8_t data[], const uint32_t numBytes) +{ + int32_t status = UART_SUCCESS; + + if (data != NULL) + { + // TODO - this read blocks forever if no serial data on the port. + // it should be timing out - need to look into this ASAP + status = read(device->handle, data, numBytes); + } + else + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 7\n"); + + } + + return status; +} + +int32_t uart_write_port(uart_info_t* device, uint8_t data[], const uint32_t numBytes) +{ + int32_t status = UART_SUCCESS; + + status = write(device->handle, data, numBytes); + + return status; +} + +int32_t uart_close_port(uart_info_t* device) +{ + int32_t status = UART_SUCCESS; + + if (device->handle >= 0) + { + status = close(device->handle); + if (0 == status) /* todo remove magic number */ + { + status = UART_SUCCESS; + } + else + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 8\n"); + } + } + else + { + status = OS_ERR_FILE; + fprintf(stderr, "***************** ERROR: Something went wrong: 9\n"); + } + return status; +} diff --git a/deployments/services/fsw/scripts/cfg/prepare.sh b/deployments/services/fsw/scripts/cfg/prepare.sh new file mode 100755 index 000000000..26a87143c --- /dev/null +++ b/deployments/services/fsw/scripts/cfg/prepare.sh @@ -0,0 +1,16 @@ +#!/bin/bash -i +# +# Convenience script for NOS3 development +# +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +source $SCRIPT_DIR/env.sh +echo "" + +echo "Create local user directory... ${USER_NOS3_DIR}" +mkdir -p $USER_NOS3_DIR +mkdir -p $USER_NOS3_DIR/42 +echo "" + +echo "Preparing Shared Folders for Fprime... ${$USER_FPRIME_PATH}" +mkdir -p $USER_FPRIME_PATH +echo "" \ No newline at end of file diff --git a/deployments/services/openmct/Containerfile b/deployments/services/openmct/Containerfile new file mode 100644 index 000000000..a2fe91136 --- /dev/null +++ b/deployments/services/openmct/Containerfile @@ -0,0 +1,65 @@ +ARG IMAGE_URI=docker.io/library/ubuntu:25.04 + +FROM ${IMAGE_URI} + +#--- PROXY CONFIG (if needed) +ARG HTTPS_PROXY +ARG HTTP_PROXY +ARG NO_PROXY +ARG DEPLOYMENT_ENVIRO + +ENV HTTPS_PROXY=${HTTPS_PROXY} +ENV HTTP_PROXY=${HTTP_PROXY} +ENV NO_PROXY=${NO_PROXY} +ENV DEPLOYMENT_ENVIRO=${DEPLOYMENT_ENVIRO} + +# Install dependencies +RUN apt-get update && \ + apt-get -y install \ + sudo git curl && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /opt + +# Install nvm and node +ARG NVM_VERSION +ARG NODE_VERSION + +ENV NVM_VERSION=${NVM_VERSION} +ENV NVM_URL=https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh +ENV NVM_DIR=/opt/nvm +RUN mkdir -p $NVM_DIR + +ENV NODE_VERSION=${NODE_VERSION} +ENV NODE_PATH=$NVM_DIR/versions/node/${NODE_VERSION}/bin +ENV PATH=${NVM_DIR}:${NODE_PATH}:${PATH} + +# Install nvm and node +WORKDIR /opt +RUN curl -o- ${NVM_URL} | bash +RUN . ${NVM_DIR}/nvm.sh && nvm install ${NODE_VERSION} + +# Clone openmct-yamcs repo +ARG GIT_URL +ARG GIT_COMMIT + +ENV GIT_URL=${GIT_URL} +ENV GIT_COMMIT=${GIT_COMMIT} + +RUN git clone --recurse-submodules -b ${GIT_COMMIT} -j2 ${GIT_URL} openmct + +# Set working directory to the cloned repo +WORKDIR /opt/openmct + +# Install dependencies and build openmct-yamcs +RUN ${NODE_PATH}/npm install -loglevel verbose +RUN ${NODE_PATH}/npm run build:example:master -loglevel verbose + +# Install dependencies +RUN apt-get update && \ + apt-get -y install \ + sudo iputils-ping vim netcat-traditional tmux tree && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* diff --git a/deployments/services/openmct/entrypoint.sh b/deployments/services/openmct/entrypoint.sh new file mode 100755 index 000000000..ba0d12884 --- /dev/null +++ b/deployments/services/openmct/entrypoint.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +pkill -f node +pkill -f npm + +npm start + +tail -f /dev/null diff --git a/deployments/services/openmct/example/index.js b/deployments/services/openmct/example/index.js new file mode 100644 index 000000000..257bfa154 --- /dev/null +++ b/deployments/services/openmct/example/index.js @@ -0,0 +1,229 @@ +import installYamcsPlugins from '../src/openmct-yamcs.js'; + +const config = { + yamcsDictionaryEndpoint: "http://localhost:9000/yamcs-proxy/", + yamcsHistoricalEndpoint: "http://localhost:9000/yamcs-proxy/", + yamcsWebsocketEndpoint: "ws://localhost:9000/yamcs-proxy-ws/", + yamcsUserEndpoint: "http://localhost:9000/yamcs-proxy/api/user/", + yamcsInstance: "nos3", + yamcsProcessor: "realtime", + yamcsFolder: "nos3", + throttleRate: 1000, + // Batch size is specified in characers as there is no performant way of calculating true + // memory usage of a string buffer in real-time. + // String characters can be 8 or 16 bits in JavaScript, depending on the code page used. + // Thus 500,000 characters requires up to 16MB of memory (1,000,000 * 16). + maxBufferSize: 1000000 +}; +const STATUS_STYLES = { + NO_STATUS: { + iconClass: "icon-question-mark", + iconClassPoll: "icon-status-poll-question-mark" + }, + GO: { + iconClass: "icon-check", + iconClassPoll: "icon-status-poll-question-mark", + statusClass: "s-status-ok", + statusBgColor: "#33cc33", + statusFgColor: "#000" + }, + MAYBE: { + iconClass: "icon-alert-triangle", + iconClassPoll: "icon-status-poll-question-mark", + statusClass: "s-status-warning", + statusBgColor: "#ffb66c", + statusFgColor: "#000" + }, + NO_GO: { + iconClass: "icon-circle-slash", + iconClassPoll: "icon-status-poll-question-mark", + statusClass: "s-status-error", + statusBgColor: "#9900cc", + statusFgColor: "#fff" + } +}; +const openmct = window.openmct; + +(() => { + const POLL_INTERVAL = 100; // ms + const MAX_POLL_TIME = 10000; // 10 seconds + const COMPOSITION_RETRY_DELAY = 250; // ms + const MAX_COMPOSITION_RETRIES = 20; // 5 seconds total with 250ms intervals + const ONE_SECOND = 1000; + const ONE_MINUTE = ONE_SECOND * 60; + const THIRTY_MINUTES = ONE_MINUTE * 30; + + openmct.setAssetPath("/node_modules/openmct/dist"); + + installDefaultPlugins(); + openmct.install(installYamcsPlugins(config)); + openmct.install( + openmct.plugins.OperatorStatus({ statusStyles: STATUS_STYLES }) + ); + + document.addEventListener("DOMContentLoaded", function () { + openmct.start(); + }); + openmct.install( + openmct.plugins.Conductor({ + menuOptions: [ + { + name: "Realtime", + timeSystem: "utc", + clock: "local", + clockOffsets: { + start: -THIRTY_MINUTES, + end: 0 + } + }, + { + name: "Fixed", + timeSystem: "utc", + bounds: { + start: Date.now() - THIRTY_MINUTES, + end: 0 + } + } + ] + }) + ); + + function installDefaultPlugins() { + openmct.install(openmct.plugins.LocalStorage()); + openmct.install(openmct.plugins.Espresso()); + openmct.install(openmct.plugins.MyItems()); + openmct.install(openmct.plugins.example.Generator()); + openmct.install(openmct.plugins.example.ExampleImagery()); + openmct.install(openmct.plugins.UTCTimeSystem()); + openmct.install(openmct.plugins.TelemetryMean()); + + openmct.install( + openmct.plugins.DisplayLayout({ + showAsView: ["summary-widget", "example.imagery", "yamcs.image"] + }) + ); + openmct.install(openmct.plugins.SummaryWidget()); + openmct.install(openmct.plugins.Notebook()); + openmct.install(openmct.plugins.LADTable()); + openmct.install( + openmct.plugins.ClearData([ + "table", + "telemetry.plot.overlay", + "telemetry.plot.stacked" + ]) + ); + + openmct.install(openmct.plugins.FaultManagement()); + openmct.install(openmct.plugins.BarChart()); + openmct.install(openmct.plugins.Timeline()); + openmct.install(openmct.plugins.EventTimestripPlugin()); + + // setup example display layout + openmct.on('start', async () => { + if (localStorage.getItem('exampleLayout') !== null) { + return; + } + + // try to import the example display layout, fail gracefully + try { + // Function to fetch JSON content as text + async function fetchJsonText(url) { + const response = await fetch(url); + const text = await response.text(); + + return text; + } + + async function getExampleLayoutPath() { + const objects = Object.values(JSON.parse(localStorage.getItem('mct'))); + const exampleLayout = objects.find(object => object.name === 'Example Flexible Layout'); + let path = await openmct.objects.getOriginalPath(exampleLayout.identifier); + + path.pop(); + path = path.reverse(); + path = path.reduce((prev, curr) => { + return prev + '/' + openmct.objects.makeKeyString(curr.identifier); + }, '#/browse'); + + return path; + } + + // poll for the localStorage item + function mctItemExists() { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + function checkItem() { + if (localStorage.getItem('mct') !== null) { + resolve(true); + + return; + } + + if (Date.now() - startTime > MAX_POLL_TIME) { + reject(new Error('Timeout waiting for mct localStorage item')); + + return; + } + + setTimeout(checkItem, POLL_INTERVAL); + } + + checkItem(); + }); + } + + // wait for the 'mct' item to exist + await mctItemExists(); + + // setup to use import as JSON action + const importAction = openmct.actions.getAction('import.JSON'); + const myItems = await openmct.objects.get('mine'); + const exampleDisplayText = await fetchJsonText('./example-display.json'); + const selectFile = { + body: exampleDisplayText + }; + + // import the example display layout + importAction.onSave(myItems, { selectFile }); + + // the importAction has asynchronous code, so we will need to check + // the composition of My Items to confirm the import was successful + const compositionCollection = openmct.composition.get(myItems); + let compositionLength = 0; + let composition; + + let retryCount = 0; + while (compositionLength === 0 && retryCount < MAX_COMPOSITION_RETRIES) { + composition = await compositionCollection.load(); + compositionLength = composition.length; + + if (compositionLength === 0) { + retryCount++; + await new Promise(resolve => setTimeout(resolve, COMPOSITION_RETRY_DELAY)); + } + } + + if (compositionLength === 0) { + throw new Error('Failed to load composition after maximum retries'); + } + + const exampleLayoutPath = await getExampleLayoutPath(); + + // give everything time to initialize + await new Promise(resolve => setTimeout(resolve, 250)); + + openmct.notifications.info('Navigated to Example Display Layout'); + + // navigate to the "Example Display Layout" + openmct.router.navigate(exampleLayoutPath); + + // set the localStorage item to prevent this from running again + localStorage.setItem('exampleLayout', 'true'); + } catch (error) { + console.error('Failed to set up example display layout:', error); + openmct.notifications.error('Failed to load example display layout: ' + error.message); + } + }); + } +})(); diff --git a/deployments/services/openmct/example/make-example-events.mjs b/deployments/services/openmct/example/make-example-events.mjs new file mode 100644 index 000000000..345a93c9f --- /dev/null +++ b/deployments/services/openmct/example/make-example-events.mjs @@ -0,0 +1,127 @@ +import process from 'process'; + +const INSTANCE = "nos3"; +const URL = `http://localhost:8090/api/archive/${INSTANCE}/events`; + +const events = [ + { + type: "PRESSURE_ALERT", + message: "Pressure threshold exceeded", + severity: "CRITICAL", + source: "PressureModule", + sequenceNumber: 1, + extra: { + pressure: "150 PSI", + location: "Hydraulic System" + } + }, + { + type: "PRESSURE_WARNING", + message: "Pressure nearing critical level", + severity: "WARNING", + source: "PressureModule", + sequenceNumber: 2, + extra: { + pressure: "140 PSI", + location: "Hydraulic System" + } + }, + { + type: "PRESSURE_INFO", + message: "Pressure system check completed", + severity: "INFO", + source: "PressureModule", + sequenceNumber: 3, + extra: { + checkType: "Routine Inspection", + duration: "10m" + } + }, + { + type: "TEMPERATURE_ALERT", + message: "Temperature threshold exceeded", + severity: "CRITICAL", + source: "TemperatureModule", + sequenceNumber: 4, + extra: { + temperature: "100°C", + location: "Engine Room" + } + }, + { + type: "TEMPERATURE_WARNING", + message: "Temperature nearing critical level", + severity: "WARNING", + source: "TemperatureModule", + sequenceNumber: 5, + extra: { + temperature: "95°C", + location: "Engine Room" + } + }, + { + type: "TEMPERATURE_INFO", + message: "Temperature nominal", + severity: "INFO", + source: "TemperatureModule", + sequenceNumber: 6, + extra: { + temperature: "35°C", + location: "Life Support" + } + }, + { + type: "TEMPERATURE_INFO", + message: "Temperature nominal", + severity: "INFO", + source: "TemperatureModule", + sequenceNumber: 7, + extra: { + temperature: "30°C", + location: "Life Support" + } + }, + { + type: "TEMPERATURE_SEVERE", + message: "Temperature nominal", + severity: "SEVERE", + source: "TemperatureModule", + sequenceNumber: 8, + extra: { + temperature: "200°C", + location: "Engine Room" + } + } +]; + +async function postEvent(event, delaySeconds) { + const eventTime = new Date(Date.now() + delaySeconds * 1000).toISOString(); + event.time = eventTime; + + try { + const response = await fetch(URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(event) + }); + + if (response.ok) { + console.log(`Event posted successfully: ${event.type}`); + } else { + console.error(`Failed to post event: ${event.type}. HTTP Status: ${response.status}`); + } + } catch (error) { + console.error(`Error posting event: ${event.type}.`, error); + } +} + +export async function postAllEvents() { + for (let i = 0; i < events.length; i++) { + await postEvent(events[i], i * 5); + } +} + +// If you still want to run it standalone +if (import.meta.url === `file://${process.argv[1]}`) { + postAllEvents(); +} diff --git a/deployments/services/openmct/webpack.dev.mjs b/deployments/services/openmct/webpack.dev.mjs new file mode 100644 index 000000000..2d21c4e55 --- /dev/null +++ b/deployments/services/openmct/webpack.dev.mjs @@ -0,0 +1,71 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2020, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ +// @ts-check +import path from "path"; +import { fileURLToPath } from "url"; +import { merge } from "webpack-merge"; +import commonConfig from "./webpack.common.mjs"; + +// Replicate __dirname functionality for ES modules +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +/** @type {import('webpack').Configuration} */ +const devConfig = { + mode: "development", + context: path.resolve(__dirname, "../"), + devtool: "eval-source-map", + entry: { + "openmct-yamcs-example": path.resolve(__dirname, "../example/index.js"), + }, + devServer: { + compress: true, + port: 9000, + static: [ + { + directory: path.join(__dirname, "../example"), + }, + { + directory: path.join(__dirname, "../node_modules/openmct/dist"), + publicPath: "/node_modules/openmct/dist", + }, + ], + proxy: [ + { + context: ["/yamcs-proxy/"], + target: "http://active-gs:8090/", + secure: false, + changeOrigin: true, + pathRewrite: { "^/yamcs-proxy/": "" }, + }, + { + context: ["/yamcs-proxy-ws/"], + target: "ws://active-gs:8090/api/websocket", + secure: false, + changeOrigin: true, + ws: true, + pathRewrite: { "^/yamcs-proxy-ws/": "" }, + }, + ], + }, +}; + +export default merge(commonConfig, devConfig); diff --git a/deployments/services/radio-sim/entrypoint.sh b/deployments/services/radio-sim/entrypoint.sh new file mode 100755 index 000000000..4b269fce4 --- /dev/null +++ b/deployments/services/radio-sim/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash -x + +cd /home/nos3/builds/nos3/sims/build/bin +pkill -f ./nos3-single-simulator +./nos3-single-simulator -f ./nos3-simulator.xml generic-radio-sim & + +tail -f /dev/null diff --git a/deployments/services/radio-sim/entrypoint2.sh b/deployments/services/radio-sim/entrypoint2.sh new file mode 100755 index 000000000..5b653d2e7 --- /dev/null +++ b/deployments/services/radio-sim/entrypoint2.sh @@ -0,0 +1,13 @@ +#!/bin/bash -x + +cd /home/nos3/builds/nos3/sims/build/bin +pkill -f ./nos3-single-simulator +./nos3-single-simulator -f ./nos3-simulator.xml generic-radio-sim & + +cd /home/nos3/builds/nos3/gsw/build +pkill -f ./support/standalone +./support/standalone & + +cd - + +tail -f /dev/null diff --git a/deployments/services/yamcs/Dockerfile b/deployments/services/yamcs/Dockerfile new file mode 100644 index 000000000..0817bd34d --- /dev/null +++ b/deployments/services/yamcs/Dockerfile @@ -0,0 +1,87 @@ +ARG REGISTRY_HOST=ghcr.io +ARG IMAGE_USERNAME=haisamido +ARG IMAGE_NAME=nos3-base +ARG IMAGE_TAG=dev + +ARG IMAGE_URI=${REGISTRY_HOST}/${IMAGE_USERNAME}/${IMAGE_NAME}:${IMAGE_TAG} + +#------------------------------------------------------------------------------ +ARG GIT_URL=https://github.com/nasa-itc/yamcs-nos3 +ARG GIT_COMMIT=dev + +#------------------------------------------------------------------------------ +ARG NOS3_USER=nos3 +ARG FLIGHT_SOFTWARE=cfs +ARG GSW_SOFTWARE=yamcs + +################################################################################ +FROM ${IMAGE_URI} AS nos3-yamcs +################################################################################ +USER root + +ARG DEBIAN_FRONTEND=noninteractive + +#------------------------------------------------------------------------------ +# Proxy configs +#------------------------------------------------------------------------------ +ARG MAVEN_HTTPS_PROXY +ARG MAVEN_REPO_LOCAL +ARG COMPONENT_DIR + +ARG HTTPS_PROXY +ARG HTTP_PROXY +ARG NO_PROXY +ARG DEPLOYMENT_ENVIRO + +# =/home/${NOS3_USER}/.m2/repository +ENV MAVEN_HTTPS_PROXY=${MAVEN_HTTPS_PROXY} +ENV MAVEN_REPO_LOCAL=${MAVEN_REPO_LOCAL} +ENV COMPONENT_DIR=${COMPONENT_DIR} + +ENV HTTPS_PROXY=${HTTPS_PROXY} +ENV HTTP_PROXY=${HTTP_PROXY} +ENV NO_PROXY=${NO_PROXY} +ENV DEPLOYMENT_ENVIRO=${DEPLOYMENT_ENVIRO} + +#------------------------------------------------------------------------------ +# Git Configs +#------------------------------------------------------------------------------ +ARG GIT_URL +ARG GIT_COMMIT + +ENV GIT_URL=${GIT_URL} +ENV GIT_COMMIT=${GIT_COMMIT} + +#------------------------------------------------------------------------------ +# NOS3 Configs +#------------------------------------------------------------------------------ +ARG FLIGHT_SOFTWARE +ARG GSW_SOFTWARE +ARG NOS3_USER +ARG YAMCS_PORT + +ENV NOS3_USER=${NOS3_USER} +ENV FLIGHT_SOFTWARE=${FLIGHT_SOFTWARE} +ENV GSW_SOFTWARE=${GSW_SOFTWARE} +ENV YAMCS_PORT=${YAMCS_PORT} +#------------------------------------------------------------------------------ + + # Switch to the newly created user +USER ${NOS3_USER} + +#------------------------------------------------------------------------------ +# Install the GSW Software +#------------------------------------------------------------------------------ +WORKDIR /home/${NOS3_USER}/.nos3 +RUN rm -rf /home/${NOS3_USER}/.nos3/${GSW_SOFTWARE} +RUN git clone --recurse-submodules -b ${GIT_COMMIT} -j4 ${GIT_URL} ${GSW_SOFTWARE} && \ + cd ./${GSW_SOFTWARE} && \ + git fetch && \ + git pull origin + +WORKDIR /home/${NOS3_USER}/.nos3/${GSW_SOFTWARE} +COPY settings.xml ./settings.xml + +RUN mvn -X ${MAVEN_HTTPS_PROXY} -DskipTests -Dmaven.repo.local=${MAVEN_REPO_LOCAL} -DCOMPONENT_DIR=${COMPONENT_DIR} install + +#------------------------------------------------------------------------------ diff --git a/deployments/services/yamcs/display.par b/deployments/services/yamcs/display.par new file mode 100644 index 000000000..db878b48f --- /dev/null +++ b/deployments/services/yamcs/display.par @@ -0,0 +1,25 @@ +{ + "$schema": "https://yamcs.org/schema/parameter-table.schema.json", + "scroll": false, + "bufferSize": 18, + "parameters": [ + "/CFS/CFE_EVS_PACKET/MESSAGE", + "/CFS/CFE_EVS_TLMPKT/MESSAGESENDCOUNTER", + "/CFS/CFE_TBL_HKPACKET/LASTUPDATETIME_SUBSECONDS", + "/CFS/DS_HKPACKET/FILEWRITECOUNTER", + "/NOVATEL_OEM615/NOVATEL_OEM615_DATA_TLM/GPS_FRAC_SECS", + "/SIM_42_TRUTH/SIM_42_TRUTH_DATA/BVB_1", + "/GENERIC_TORQUER/GENERIC_TORQUER_HK_TLM_T/TORQUER_DIRECTION_0", + "/GENERIC_EPS/GENERIC_EPS_HK_TLM/RAW_BATTERY_VOLTAGE", + "/GENERIC_ADCS/GENERIC_ADCS_DI/FSS_SVB_X", + "/GENERIC_ADCS/GENERIC_ADCS_DI/IMU_ACC_X", + "/GENERIC_MAG/GENERIC_MAG_DATA_TLM/RAW_MAG_X", + "/GENERIC_REACTION_WHEEL/GENRW_HK_TLM_T/MOMENTUM_NMS_0", + "/GENERIC_REACTION_WHEEL/GENRW_HK_TLM_T/MOMENTUM_NMS_1", + "/GENERIC_REACTION_WHEEL/GENRW_HK_TLM_T/MOMENTUM_NMS_2", + "/GENERIC_RADIO/GENERIC_RADIO_HK_TLM/FORWARD_COUNT", + "/yamcs/cosmos/links/radio-in/dataInCount", + "/yamcs/cosmos/links/radio-out/dataInCount", + "/SAMPLE/SAMPLE_HK_TLM/DEVICE_ENABLED" + ] +} diff --git a/deployments/services/yamcs/entrypoint.sh b/deployments/services/yamcs/entrypoint.sh new file mode 100755 index 000000000..ea5aefd4b --- /dev/null +++ b/deployments/services/yamcs/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +pkill -9 java +rm -rf ${YAMCS_DATA_DIR}/_global.rdb/LOCK +rm -rf ${YAMCS_DATA_DIR}/nos3.rdb/LOCK + +mkdir -p /tmp/nos3 +mkdir -p /tmp/nos3/data +mkdir -p /tmp/nos3/data/cam +mkdir -p /tmp/nos3/data/evs +mkdir -p /tmp/nos3/data/hk +mkdir -p /tmp/nos3/data/inst +mkdir -p /tmp/nos3/uplink + +# Start YAMCS server +mvn -X ${MAVEN_HTTPS_PROXY} -Dmaven.repo.local=${MAVEN_REPO_LOCAL} -DCOMPONENT_DIR=${COMPONENT_DIR} yamcs:run + +tail -f /dev/null diff --git a/deployments/targets/docker/entrypoint_nos_engine_server.sh b/deployments/targets/docker/entrypoint_nos_engine_server.sh new file mode 100755 index 000000000..c28a9182e --- /dev/null +++ b/deployments/targets/docker/entrypoint_nos_engine_server.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +pkill -f nos_engine_server_standalone || true + +/usr/bin/nos_engine_server_standalone /builds/nos3/sims/build/bin/nos_engine_server_config.json + +tail -f /dev/null diff --git a/deployments/targets/docker/hw-components/entrypoint.sh b/deployments/targets/docker/hw-components/entrypoint.sh new file mode 100755 index 000000000..547c35fa0 --- /dev/null +++ b/deployments/targets/docker/hw-components/entrypoint.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +DIR=/home/nos3 + +pkill -f ./nos3-single-simulator +pkill -f ./support/standalone + +# Radio Sim and Cryptolib +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-radio-sim 2>&1 \ + | tee -a ${DIR}/radio-sim.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/gsw/build && \ + ./support/standalone 2>&1 \ + | tee -a ${DIR}/cryptolib.log | tee -a ${DIR}/hw-components.log & + +# HW Components +cd /home/nos3/builds/nos3/fsw/build/exe/cpu1 && \ + /home/nos3/builds/nos3/scripts/fsw/onair_launch.sh 2>&1 \ + | tee -a ${DIR}/onair_launch.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml camsim 2>&1 \ + | tee -a ${DIR}/camsim.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-css-sim 2>&1 \ + | tee -a ${DIR}/css.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-eps-sim 2>&1 \ + | tee -a ${DIR}/eps.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-fss-sim 2>&1 \ + | tee -a ${DIR}/fss.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml gps 2>&1 \ + | tee -a ${DIR}/gps.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-imu-sim 2>&1 \ + | tee -a ${DIR}/imu.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-mag-sim 2>&1 \ + | tee -a ${DIR}/mag.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim0 2>&1 \ + | tee -a ${DIR}/rw0.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim1 2>&1 \ + | tee -a ${DIR}/rw1.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-reactionwheel-sim2 2>&1 \ + | tee -a ${DIR}/rw2.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml sample-sim 2>&1 \ + | tee -a ${DIR}/sample-sim.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-star-tracker-sim 2>&1 \ + | tee -a ${DIR}/star-tracker.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-thruster-sim 2>&1 \ + | tee -a ${DIR}/thruster.log | tee -a ${DIR}/hw-components.log & + +cd /home/nos3/builds/nos3/sims/build/bin && \ + ./nos3-single-simulator -f ./nos3-simulator.xml generic-torquer-sim 2>&1 \ + | tee -a ${DIR}/torquer.log | tee -a ${DIR}/hw-components.log & + +# cd /home/nos3/builds/nos3/sims/build/bin && \ +# ./nos3-single-simulator -f ./nos3-simulator.xml truth42sim 2>&1 \ +# | tee -a ${DIR}/truth42.log | tee -a ${DIR}/hw-components.log & + +tail -f /dev/null diff --git a/deployments/targets/kubernetes/Taskfile.yaml b/deployments/targets/kubernetes/Taskfile.yaml new file mode 100644 index 000000000..7ee253871 --- /dev/null +++ b/deployments/targets/kubernetes/Taskfile.yaml @@ -0,0 +1,678 @@ +--- +version: '3' + +dotenv: + - ../../../targets/docker/.env + +# kind delete cluster --name ${K8S_CLUSTER} || true +# kind create cluster --name ${K8S_CLUSTER} || true + +env: + KIND_EXPERIMENTAL_PROVIDER: '{{.KIND_EXPERIMENTAL_PROVIDER | default "docker"}}' + +vars: + TARGETS_DIR: ../../targets + SERVICES_DIR: ../../services + SCRIPTS_DIR: ../../scripts + + CONTAINER_DIR: '{{.TARGETS_DIR}}/docker/' + + PROJECT: 'nos3' + MISSION: 'm01' + SPACECRAFT: 'sc01' + SC_ENVIRO: 'sim' + COMPONENT: 'fortytwo' + + ENVIRO_SCRIPT: '{{.SCRIPTS_DIR}}/env.sh' + ENVIRO_FILE: '{{.CONTAINER_DIR}}/.env' + + DEFAULT_NAMESPACE: '{{.PROJECT}}-{{.MISSION}}-{{.SPACECRAFT}}' + + APP_LABEL: '{{.DEFAULT_NAMESPACE}}-{{.COMPONENT}}' + + # Context defaults - support both Docker Desktop and Podman + K8S_CONTEXT: '{{.K8S_CONTEXT | default "docker-desktop"}}' + K8S_CLUSTER: '{{.K8S_CLUSTER | default "docker-desktop"}}' + K8S_USER: '{{.K8S_USER | default "docker-desktop"}}' + + # KIND provider - set to 'podman' to use Podman runtime with KIND + KIND_EXPERIMENTAL_PROVIDER: '{{.KIND_EXPERIMENTAL_PROVIDER | default "docker"}}' + + K8S_APP_LABEL: '{{.APP_LABEL}}' + K8S_NAMESPACE: '{{.K8S_NAMESPACE | default .DEFAULT_NAMESPACE}}' + + K8S_KUSTOMIZE_DIR: '{{.K8S_KUSTOMIZE_DIR | default "."}}' + K8S_PORT_FORWARD_VNC: '8080' + K8S_DEPLOYMENT_NAME: 'nos3-{{.COMPONENT}}' + +tasks: + default: + desc: Shows available tasks + cmds: + - task --list-all + silent: true + + detect-runtime: + desc: Detect which container runtime is being used (docker or podman) + cmds: + - | + CURRENT_CONTEXT=$(kubectl config current-context 2>/dev/null || echo "none") + echo "Current kubectl context: $CURRENT_CONTEXT" + echo "KIND provider: {{.KIND_EXPERIMENTAL_PROVIDER}}" + echo "" + + if echo "$CURRENT_CONTEXT" | grep -qi "podman"; then + echo "Detected runtime: Podman" + echo "To use Podman with all tasks, set: KIND_EXPERIMENTAL_PROVIDER=podman" + elif echo "$CURRENT_CONTEXT" | grep -qi "docker"; then + echo "Detected runtime: Docker Desktop" + echo "To use Docker with all tasks, set: KIND_EXPERIMENTAL_PROVIDER=docker (default)" + else + echo "Unknown runtime from context: $CURRENT_CONTEXT" + echo "Available runtimes:" + which docker 2>/dev/null && echo " - docker (installed)" + which podman 2>/dev/null && echo " - podman (installed)" + fi + echo "" + echo "Current KIND_EXPERIMENTAL_PROVIDER: {{.KIND_EXPERIMENTAL_PROVIDER}}" + silent: false + + check-podman: + desc: Check if Podman Kubernetes is available and running + cmds: + - | + echo "Checking Podman Kubernetes setup..." + + # Check if podman machine exists + if ! podman machine list 2>/dev/null | grep -q "Currently running"; then + echo "Warning: Podman machine is not running" + echo "Start it with: podman machine start" + exit 1 + fi + + echo "Podman machine is running" + + # Check if podman-desktop context exists + if ! kubectl config get-contexts podman-desktop &>/dev/null; then + echo "Warning: podman-desktop context not found" + echo "Please ensure Kubernetes is enabled in Podman Desktop" + echo "Or manually create a context pointing to your Podman cluster" + exit 1 + fi + + echo "Podman Kubernetes context is available" + silent: false + + get-contexts: + desc: List all available Kubernetes contexts + cmds: + - | + kubectl config get-contexts + silent: false + + get-current-context: + desc: Show the current Kubernetes context + cmds: + - | + echo "Current context:" + kubectl config current-context + silent: false + + set-context: + desc: Set the current Kubernetes context (use K8S_CONTEXT variable) + cmds: + - | + kubectl config use-context {{.K8S_CONTEXT}} + echo "Switched to context: {{.K8S_CONTEXT}}" + echo "" + echo "Common contexts:" + echo " - docker-desktop (Docker Desktop Kubernetes)" + echo " - podman-desktop (Podman Desktop Kubernetes)" + echo " - minikube (Minikube)" + echo "" + echo "Verify cluster: kubectl cluster-info" + silent: false + + create-context: + desc: Create a new Kubernetes context + cmds: + - | + kubectl config set-context {{.K8S_CONTEXT}} \ + --cluster={{.K8S_CLUSTER}} \ + --user={{.K8S_USER}} \ + --namespace={{.K8S_NAMESPACE}} + echo "Context {{.K8S_CONTEXT}} created/updated with:" + echo " Cluster: {{.K8S_CLUSTER}}" + echo " User: {{.K8S_USER}}" + echo " Namespace: {{.K8S_NAMESPACE}}" + - | + echo "To use this context, run: task set-context K8S_CONTEXT={{.K8S_CONTEXT}}" + silent: false + + create-user-certs: + desc: Generate client certificates for a new user + vars: + NEW_USER: '{{.NEW_USER | default "myuser"}}' + CERT_DIR: '{{.CERT_DIR | default "/tmp/k8s-certs"}}' + ORG: '{{.ORG | default "system:masters"}}' + cmds: + - | + mkdir -p {{.CERT_DIR}} + echo "Generating private key for user: {{.NEW_USER}}" + openssl genrsa -out {{.CERT_DIR}}/{{.NEW_USER}}.key 2048 + - | + echo "Generating certificate signing request (CSR)" + openssl req -new \ + -key {{.CERT_DIR}}/{{.NEW_USER}}.key \ + -out {{.CERT_DIR}}/{{.NEW_USER}}.csr \ + -subj "/CN={{.NEW_USER}}/O={{.ORG}}" + - | + echo "Certificates generated in {{.CERT_DIR}}" + echo " Private key: {{.CERT_DIR}}/{{.NEW_USER}}.key" + echo " CSR: {{.CERT_DIR}}/{{.NEW_USER}}.csr" + echo "" + echo "Next steps:" + echo " 1. Get the CSR signed by the cluster CA" + echo " 2. Run: task create-user-kubeconfig NEW_USER={{.NEW_USER}} CERT_DIR={{.CERT_DIR}}" + silent: false + + create-user-k8s-csr: + desc: Create and approve Kubernetes CertificateSigningRequest for user (may not work on Docker Desktop) + vars: + NEW_USER: '{{.NEW_USER | default "myuser"}}' + CERT_DIR: '{{.CERT_DIR | default "/tmp/k8s-certs"}}' + ORG: '{{.ORG | default "developers"}}' + cmds: + - | + echo "Creating Kubernetes CertificateSigningRequest for {{.NEW_USER}}" + cat < {{.CERT_DIR}}/{{.NEW_USER}}.crt + - | + echo "Certificate signed and saved to {{.CERT_DIR}}/{{.NEW_USER}}.crt" + echo "" + echo "Next step:" + echo " Run: task create-user-kubeconfig NEW_USER={{.NEW_USER}} CERT_DIR={{.CERT_DIR}}" + silent: false + + create-user-manual-sign: + desc: Sign user certificate using cluster CA directly (for Docker Desktop) + vars: + NEW_USER: '{{.NEW_USER | default "myuser"}}' + CERT_DIR: '{{.CERT_DIR | default "/tmp/k8s-certs"}}' + CA_CERT: '{{.CA_CERT | default "$HOME/.minikube/ca.crt"}}' + CA_KEY: '{{.CA_KEY | default "$HOME/.minikube/ca.key"}}' + cmds: + - | + echo "Signing certificate for {{.NEW_USER}} using cluster CA" + echo "Note: This requires access to the cluster CA certificate and key" + echo "" + + # For Docker Desktop, try to find CA files + if [ -f "$HOME/.docker/run/config/ca.pem" ]; then + CA_CERT="$HOME/.docker/run/config/ca.pem" + CA_KEY="$HOME/.docker/run/config/ca-key.pem" + fi + + if [ ! -f "{{.CA_CERT}}" ]; then + echo "ERROR: CA certificate not found at {{.CA_CERT}}" + echo "" + echo "For Docker Desktop, CA files are typically not accessible." + echo "Recommended: Use the docker-desktop user instead, or:" + echo " 1. Use a cluster that supports CSR API (minikube, EKS, GKE, etc.)" + echo " 2. Manually copy CA files from the Docker Desktop VM" + exit 1 + fi + + openssl x509 -req \ + -in {{.CERT_DIR}}/{{.NEW_USER}}.csr \ + -CA {{.CA_CERT}} \ + -CAkey {{.CA_KEY}} \ + -CAcreateserial \ + -out {{.CERT_DIR}}/{{.NEW_USER}}.crt \ + -days 365 + - | + echo "Certificate signed and saved to {{.CERT_DIR}}/{{.NEW_USER}}.crt" + echo "" + echo "Next step:" + echo " Run: task create-user-kubeconfig NEW_USER={{.NEW_USER}} CERT_DIR={{.CERT_DIR}}" + silent: false + + create-user-kubeconfig: + desc: Add user credentials to kubeconfig + vars: + NEW_USER: '{{.NEW_USER | default "myuser"}}' + CERT_DIR: '{{.CERT_DIR | default "/tmp/k8s-certs"}}' + cmds: + - | + echo "Adding user {{.NEW_USER}} to kubeconfig" + kubectl config set-credentials {{.NEW_USER}} \ + --client-certificate={{.CERT_DIR}}/{{.NEW_USER}}.crt \ + --client-key={{.CERT_DIR}}/{{.NEW_USER}}.key \ + --embed-certs=true + - | + echo "User {{.NEW_USER}} added to kubeconfig" + echo "" + echo "Create a context for this user:" + echo " task create-context K8S_USER={{.NEW_USER}} K8S_CONTEXT={{.NEW_USER}}-context" + echo "" + echo "Or use with existing context:" + echo " kubectl config set-context docker-desktop --user={{.NEW_USER}}" + silent: false + + create-user: + desc: Complete workflow to create a new user (generates certs, signs via K8s CSR, adds to kubeconfig) + vars: + NEW_USER: '{{.NEW_USER | default "myuser"}}' + CERT_DIR: '{{.CERT_DIR | default "/tmp/k8s-certs"}}' + ORG: '{{.ORG | default "developers"}}' + cmds: + - task: create-user-certs + vars: + NEW_USER: '{{.NEW_USER}}' + CERT_DIR: '{{.CERT_DIR}}' + ORG: '{{.ORG}}' + - task: create-user-k8s-csr + vars: + NEW_USER: '{{.NEW_USER}}' + CERT_DIR: '{{.CERT_DIR}}' + ORG: '{{.ORG}}' + - task: create-user-kubeconfig + vars: + NEW_USER: '{{.NEW_USER}}' + CERT_DIR: '{{.CERT_DIR}}' + - | + echo "" + echo "User {{.NEW_USER}} created successfully with organization: {{.ORG}}" + echo "" + echo "IMPORTANT: The user has been created but has NO permissions yet." + echo "You need to create a RoleBinding or ClusterRoleBinding to grant permissions." + echo "" + echo "Example - Grant admin in a namespace:" + echo " kubectl create rolebinding {{.NEW_USER}}-admin --clusterrole=admin --user={{.NEW_USER}} -n {{.K8S_NAMESPACE}}" + echo "" + echo "Example - Grant cluster-wide view:" + echo " kubectl create clusterrolebinding {{.NEW_USER}}-view --clusterrole=view --user={{.NEW_USER}}" + echo "" + echo "To create a context for this user:" + echo " task create-context K8S_USER={{.NEW_USER}} K8S_CONTEXT={{.NEW_USER}}-context" + silent: false + + list-users: + desc: List all users in kubeconfig + cmds: + - | + echo "Users in kubeconfig:" + kubectl config view -o jsonpath='{.users[*].name}' | tr ' ' '\n' + silent: false + + delete-user: + desc: Remove user from kubeconfig + vars: + USER_TO_DELETE: '{{.USER_TO_DELETE | default "myuser"}}' + cmds: + - | + kubectl config unset users.{{.USER_TO_DELETE}} + echo "User {{.USER_TO_DELETE}} removed from kubeconfig" + - rm -rf /tmp/k8s-certs/{{.USER_TO_DELETE}}* + silent: false + + create-namespace: + desc: Create the Kubernetes namespace + cmds: + - | + kubectl create namespace {{.K8S_NAMESPACE}} \ + --context {{.K8S_CONTEXT}} || \ + echo "Namespace {{.K8S_NAMESPACE}} already exists" + silent: false + + create-configmap-from-env: + desc: Create a ConfigMap from the .env file + deps: + - create-namespace + vars: + CONFIGMAP_NAME: '{{.CONFIGMAP_NAME | default "env-configmap"}}' + cmds: + - | + echo "Creating ConfigMap {{.CONFIGMAP_NAME}} from {{.ENVIRO_FILE}}" + kubectl create configmap {{.CONFIGMAP_NAME}} \ + --from-env-file={{.ENVIRO_FILE}} \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --dry-run=client -o yaml > {{.CONFIGMAP_NAME}}.yaml + - echo "ConfigMap {{.CONFIGMAP_NAME}} created/updated successfully" + silent: false + + apply-configmaps: + desc: Apply configmaps to the namespace + deps: + - create-namespace + cmds: + - | + kubectl apply -f configmap.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - echo "ConfigMaps applied successfully" + silent: false + + apply-service: + desc: Apply service to the namespace + deps: + - create-namespace + cmds: + - | + kubectl apply -f service.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - echo "Service applied successfully" + silent: false + + apply-kustomize: + desc: Apply kustomize to the namespace + deps: + - create-namespace + # - apply-configmaps + cmds: + - | + kubectl apply -k . \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - echo "Kustomization applied successfully" + silent: false + + apply-deployment: + desc: Apply deployment to the namespace + deps: + - create-namespace + - apply-configmaps + cmds: + - | + kubectl apply -f deployment.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - echo "Deployment applied successfully" + silent: false + + apply-all: + desc: Apply all Kubernetes resources (recommended) + deps: + - create-namespace + cmds: + - | + kubectl apply -k {{.K8S_KUSTOMIZE_DIR}} \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - task: port-forward + - echo "All resources applied successfully via kustomize" + silent: false + + delete-deployment: + desc: Delete the deployment + cmds: + - | + kubectl delete -f deployment.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} || true + - echo "Deployment deleted" + silent: false + + delete-namespace: + desc: Delete Namespace + cmds: + - | + kubectl delete namespace {{.K8S_NAMESPACE}} \ + --context {{.K8S_CONTEXT}} || true + - echo "Namespace deleted" + silent: false + + delete-service: + desc: Delete the service + cmds: + - | + kubectl delete -f service.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} || true + - echo "Service deleted" + silent: false + + delete-configmaps: + desc: Delete the configmaps + cmds: + - | + kubectl delete -f configmap.yaml \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} || true + - echo "ConfigMaps deleted" + silent: false + + delete-all: + desc: Delete all resources + deps: + - delete-deployment + - delete-service + - delete-configmaps + - delete-namespace + cmds: + - | + kubectl delete -k {{.K8S_KUSTOMIZE_DIR}} \ + --context {{.K8S_CONTEXT}} || true + - echo "All resources deleted via kustomize" + silent: false + + restart-deployment: + desc: Restart the deployment (rollout restart) + cmds: + - | + kubectl rollout restart deployment/nos3-fortytwo \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + - echo "Deployment restarted" + silent: false + + get-pods: + desc: Get pods in the namespace + cmds: + - | + kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} + silent: false + + get-all: + desc: Get all resources in the namespace + cmds: + - | + kubectl get all \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} + silent: false + + describe-pod: + desc: Describe the fortytwo pod (useful for debugging) + cmds: + - | + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}') + kubectl describe pod $POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} + silent: false + + logs: + desc: Get logs from the fortytwo pod + cmds: + - | + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}') + kubectl logs $POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --tail=100 \ + --follow + silent: false + + logs-previous: + desc: Get logs from the previous container instance (useful after crash) + cmds: + - | + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}') + kubectl logs $POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --previous + silent: false + + exec: + desc: Execute a shell in the fortytwo pod + cmds: + - | + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}') + kubectl exec -it $POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -- /bin/bash + silent: false + + port-forward: + desc: Port forward to access services locally + cmds: + - | + echo "Checking for pod availability..." + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) + + if [ -z "$POD_NAME" ]; then + echo "Error: No pod found with label app={{.K8S_APP_LABEL}}" + exit 1 + fi + + echo "Found pod: $POD_NAME" + echo "Waiting for pod to be ready..." + + kubectl wait --for=condition=ready pod/$POD_NAME \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --timeout=300s + + if [ $? -ne 0 ]; then + echo "Error: Pod did not become ready within timeout" + exit 1 + fi + + echo "Pod is ready!" + echo "Forwarding ports:" + echo " - VNC: http://localhost:{{.K8S_PORT_FORWARD_VNC}}" + kubectl port-forward ${POD_NAME} \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + {{.K8S_PORT_FORWARD_VNC}}:80 + silent: false + + status: + desc: Show status of all resources + cmds: + - echo "Namespace {{.K8S_NAMESPACE}} status:" + - echo "" + - echo "=== ConfigMaps ===" + - | + kubectl get configmaps \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} || echo "No configmaps found" + - echo "" + - echo "=== Services ===" + - | + kubectl get services \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + fortytwo || echo "No services found" + - echo "" + - echo "=== Deployments ===" + - | + kubectl get deployments \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} || echo "No deployments found" + - echo "" + - echo "=== Pods ===" + - | + kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} || echo "No pods found" + silent: false + + redeploy: + desc: Delete and recreate all resources (full redeploy) + cmds: + - task: delete-all + - sleep 3 + - task: apply-all + - task: get-pods + silent: false + + troubleshoot: + desc: Run troubleshooting diagnostics + cmds: + - echo "=== Checking namespace ===" + - | + kubectl get namespace {{.K8S_NAMESPACE}} \ + --context {{.K8S_CONTEXT}} || echo "Namespace does not exist!" + - echo "" + - echo "=== Checking configmaps ===" + - | + kubectl get configmaps nos3-fortytwo-cm0 \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} || echo "ConfigMaps not found!" + - echo "" + - echo "=== Checking pod events ===" + - | + POD_NAME=$(kubectl get pods \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + -l app={{.K8S_APP_LABEL}} \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) + if [ -n "$POD_NAME" ]; then + kubectl get events \ + --context {{.K8S_CONTEXT}} \ + --namespace={{.K8S_NAMESPACE}} \ + --field-selector involvedObject.name=$POD_NAME \ + --sort-by='.lastTimestamp' + else + echo "No pods found" + fi + silent: false diff --git a/deployments/targets/kubernetes/fortytwo/configmaps/args-configmap.yaml b/deployments/targets/kubernetes/fortytwo/configmaps/args-configmap.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/deployments/targets/kubernetes/fortytwo/configmaps/env-configmap.yaml b/deployments/targets/kubernetes/fortytwo/configmaps/env-configmap.yaml new file mode 100644 index 000000000..5b7e71ef5 --- /dev/null +++ b/deployments/targets/kubernetes/fortytwo/configmaps/env-configmap.yaml @@ -0,0 +1,65 @@ +apiVersion: v1 + +kind: ConfigMap + +metadata: + name: nos3-m01-sc01-fortytwo-env + +data: + BASE_DIR: /opt/nasa-itc + COMPONENT_DIR: /home/nos3/builds/nos3/components + COMPOSE_PROJECT_NAME: nos3-m01-sc01 + DEPLOYMENT_ENVIRO: "" + FORTYTWO_BASE_DIR: /opt/nasa-itc + FORTYTWO_DISPLAY: :1 + FORTYTWO_GIT_COMMIT: nos3-main + FORTYTWO_GIT_FOLDER: "42" + FORTYTWO_GIT_URL: https://github.com/nasa-itc/42.git + FORTYTWO_LEAP_SECONDS: "37" + FORTYTWO_PORT: "30090" + FORTYTWO_RECOMPILE: "false" + FORTYTWO_SIM_DATE: '"12 29 2025"' + FORTYTWO_SIM_TIME: '"15 57 13.00"' + FORTYTWO_STARTUP_FOLDER: NOS3InOut + FORTYTWO_VNC_PASSWORD: c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2 + FSW_SOFTWARE: cfs + GSW_SOFTWARE: yamcs + HEALTHCHECK_PORT: "" + HTTP_PROXY: "" + HTTPS_PROXY: "" + J2000_EPOCH_SECONDS: "946728000" + J2000_REFERENCE_DATETIME: '"2000-01-01 12:00:00 UTC"' + MAVEN_HTTPS_PROXY: '"--settings ./settings.xml"' + MAVEN_REPO_LOCAL: /home/nos3/.nos3/.m2 + MAVEN_SETTINGS_FILE: "" + MISSION: m01 + NO_PROXY: "" + NOS3_BASE_DIR: /home/nos3/.nos3 + NOS3_CFG_PATH: .. + NOS3_DIR: /home/nos3/.nos3 + NOS3_GIT_COMMIT: dev + NOS3_GIT_URL: https://github.com/nasa/nos3 + NOS3_IMAGE_URI: docker.io/ivvitc/nos3-64:20251107 + NOS3_MISSION_CFG_FILE: ../cfg/nos3-mission.xml + NOS3_USER: nos3 + OPENMCT_GIT_COMMIT: master + OPENMCT_GIT_URL: https://github.com/akhenry/openmct-yamcs.git + OPENMCT_IMAGE_URI: docker.io/library/ubuntu:25.04 + OPENMCT_NODE_VERSION: v21.7.3 + OPENMCT_NVM_VERSION: v0.40.1 + OPENMCT_PORT: "9000" + PROJECT_NAME: nos3-m01-sc01 + SIM_T0_DATETIME: '"2025-12-29 15:56:43 UTC"' + SIM_T0_EPOCH_MILLISECONDS: "1767023833000" + SIM_T0_EPOCH_SECONDS: "1767023833" + SIM_TF_EPOCH_MILLISECONDS: "1767027433000" + SPACECRAFT: sc01 + START_TIME: "820295833" + TIME_INTERVAL: "3600" + TIME_INTERVAL_MILLISECONDS: "3600000" + TIME_OFFSET_SECONDS: "+30" + YAMCS_DATA_DIR: /home/nos3/.nos3/yamcs/target/yamcs/yamcs-data + YAMCS_GIT_COMMIT: nos3-dev + YAMCS_GIT_URL: https://github.com/nasa-itc/nos3_yamcs_master.git + YAMCS_INSTANCES: nos3 + YAMCS_PORT: "8090" diff --git a/deployments/targets/kubernetes/fortytwo/configmaps/volumes-configmap.yaml b/deployments/targets/kubernetes/fortytwo/configmaps/volumes-configmap.yaml new file mode 100644 index 000000000..e82b4932f --- /dev/null +++ b/deployments/targets/kubernetes/fortytwo/configmaps/volumes-configmap.yaml @@ -0,0 +1,53 @@ +--- +apiVersion: v1 + +kind: ConfigMap +metadata: + annotations: + use-subpath: "true" + name: nos3-m01-sc01-fortytwo-volumes + +data: + entrypoint.sh: | + #!/bin/bash + + rm -f /tmp/.X1-lock || true + rm -f /tmp/.X11-unix/X1 || true + + pkill -9 -f vncserver || true + pkill -9 -f Xvnc || true + pkill -9 -f websockify || true + + /opt/TurboVNC/bin/vncserver -securitytypes tlsnone,x509none,none && \ + sleep 5 && \ + websockify -D \ + --web=/usr/share/novnc/ \ + --cert=~/novnc.pem 80 localhost:5901 + + export DISPLAY=${DISPLAY:-:1} + export DIR=/opt/nasa-itc + export GIT_FOLDER=${GIT_FOLDER} + + xterm & + + rm -rf /opt/nasa-itc/42/NO3InOut/{*.42,*.csv} + + if [ "$RECOMPILE" == "true" ]; then + cd /opt/nasa-itc/42 && \ + git fetch && \ + git checkout ${GIT_COMMIT} && \ + git pull origin && \ + git submodule update && \ + make clean && \ + make -j2 + fi + + STARTUP_FOLDER=${STARTUP_FOLDER:-NO3InOut} + + cd /opt/nasa-itc/42 && \ + xterm -e "./42 ${STARTUP_FOLDER}" & + + echo "Started 42 with PID $!" + + tail -f /dev/null + diff --git a/deployments/targets/kubernetes/fortytwo/deployment.yaml b/deployments/targets/kubernetes/fortytwo/deployment.yaml new file mode 100644 index 000000000..35bea97d1 --- /dev/null +++ b/deployments/targets/kubernetes/fortytwo/deployment.yaml @@ -0,0 +1,58 @@ +--- +apiVersion: apps/v1 + +kind: Deployment + +metadata: + name: nos3-m01-sc01-fortytwo + labels: + app: nos3-m01-sc01-fortytwo + +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-fortytwo + template: + metadata: + labels: + app: nos3-m01-sc01-fortytwo + spec: + containers: + - args: + - /entrypoint.sh + env: + - name: COMPONENT_NAME + value: fortytwo + - name: DISPLAY + value: :1 + image: ghcr.io/haisamido/nos3-base-fortytwo:dev + workingDir: /42 + imagePullPolicy: Always + name: nos3-m01-sc01-fortytwo + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "3" + memory: "2048Mi" + requests: + cpu: "1" + memory: "2048Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /entrypoint.sh + name: nos3-m01-sc01-fortytwo-volumes + subPath: entrypoint.sh + hostname: fortytwo + restartPolicy: Always + volumes: + - configMap: + items: + - key: entrypoint.sh + path: entrypoint.sh + name: nos3-m01-sc01-fortytwo-volumes + defaultMode: 0555 + name: nos3-m01-sc01-fortytwo-volumes diff --git a/deployments/targets/kubernetes/fortytwo/ingress.yaml b/deployments/targets/kubernetes/fortytwo/ingress.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/deployments/targets/kubernetes/fortytwo/kustomization.yaml b/deployments/targets/kubernetes/fortytwo/kustomization.yaml new file mode 100644 index 000000000..3d7dc0f0e --- /dev/null +++ b/deployments/targets/kubernetes/fortytwo/kustomization.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./configmaps/args-configmap.yaml + - ./configmaps/env-configmap.yaml + - ./configmaps/volumes-configmap.yaml + - ./deployment.yaml + - ./service.yaml + - ./ingress.yaml diff --git a/deployments/targets/kubernetes/fortytwo/service.yaml b/deployments/targets/kubernetes/fortytwo/service.yaml new file mode 100644 index 000000000..234314595 --- /dev/null +++ b/deployments/targets/kubernetes/fortytwo/service.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v1 + +kind: Service + +metadata: + name: nos3-m01-sc01-fortytwo + +spec: + selector: + app: nos3-m01-sc01-fortytwo + ports: + - name: x-vnc + protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP diff --git a/deployments/targets/kubernetes/fsw/configmap.yaml b/deployments/targets/kubernetes/fsw/configmap.yaml new file mode 100644 index 000000000..020855f91 --- /dev/null +++ b/deployments/targets/kubernetes/fsw/configmap.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: v1 +data: + entrypoint_fsw.sh: | + #!/bin/bash + pkill -f fsw_respawn.sh || true + pkill -f core-cpu1 || true + $SCRIPT_DIR/fsw/fsw_respawn.sh +kind: ConfigMap +metadata: + annotations: + use-subpath: "true" + labels: + io.kompose.service: nos3-fsw + name: nos3-fsw-cm0 diff --git a/deployments/targets/kubernetes/fsw/deployment.yaml b/deployments/targets/kubernetes/fsw/deployment.yaml new file mode 100644 index 000000000..43b18399c --- /dev/null +++ b/deployments/targets/kubernetes/fsw/deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: nos3-m01-sc01 + name: nos3-fsw + labels: + app: nos3-m01-sc01-fsw +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-fsw + template: + metadata: + labels: + app: nos3-m01-sc01-fsw + spec: + containers: + - args: + - /entrypoint.sh + env: + - name: BASE_DIR + value: /builds/nos3 + - name: CFG_FILE + value: /builds/nos3/sims/build/bin/nos_engine_server_config.json + - name: COMPONENT_NAME + value: fsw + - name: HEALTHCHECK_PORT + value: "60000" + - name: LOG_CONFIG + value: /builds/nos3/sims/build/bin/sim_log_config.xml + - name: SCRIPT_DIR + value: /builds/nos3/scripts + - name: SIMULATOR_BIN + value: /usr/bin/nos_engine_server_standalone + - name: SIM_BIN + value: /builds/nos3/sims/build/bin + image: registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + imagePullPolicy: IfNotPresent + name: 01-sc01-nos-fsw + resources: + limits: + cpu: 100m + memory: "128Mi" + requests: + cpu: 100m + memory: "128Mi" + securityContext: + capabilities: + add: + - sys_nice + privileged: true + volumeMounts: + - mountPath: /entrypoint.sh + name: nos3-fsw-cm0 + subPath: entrypoint.sh + workingDir: /builds/nos3/fsw/build/exe/cpu1 + hostname: fsw + restartPolicy: Always + volumes: + - configMap: + items: + - key: entrypoint_fsw.sh + path: entrypoint.sh + name: nos3-fsw-cm0 + defaultMode: 0555 + name: nos3-fsw-cm0 diff --git a/deployments/targets/kubernetes/fsw/kustomization.yaml b/deployments/targets/kubernetes/fsw/kustomization.yaml new file mode 100644 index 000000000..164db37ac --- /dev/null +++ b/deployments/targets/kubernetes/fsw/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./configmap.yaml + - ./deployment.yaml + - ./service.yaml diff --git a/deployments/targets/kubernetes/fsw/service.yaml b/deployments/targets/kubernetes/fsw/service.yaml new file mode 100644 index 000000000..38a3f4928 --- /dev/null +++ b/deployments/targets/kubernetes/fsw/service.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: fsw + namespace: nos3-m01-sc01 +spec: + selector: + app: nos3-m01-sc01-fsw + ports: + - name: healthcheck-tcp + protocol: TCP + port: 60000 + targetPort: 60000 + - name: healthcheck-udp + protocol: UDP + port: 60000 + targetPort: 60000 + type: ClusterIP diff --git a/deployments/targets/kubernetes/gps/deployment.yaml b/deployments/targets/kubernetes/gps/deployment.yaml new file mode 100644 index 000000000..651d55ef8 --- /dev/null +++ b/deployments/targets/kubernetes/gps/deployment.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: nos3-m01-sc01 + name: nos3-gps + labels: + app: nos3-m01-sc01-gps +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-gps + template: + metadata: + labels: + app: nos3-m01-sc01-gps + spec: + containers: + - env: + - name: BASE_DIR + value: /builds/nos3 + - name: CFG_FILE + value: /builds/nos3/sims/build/bin/nos3-simulator.xml + - name: COMPONENT_NAME + value: gps + - name: HEALTHCHECK_PORT + value: "60000" + - name: LOG_CONFIG + value: /builds/nos3/sims/build/bin/sim_log_config.xml + - name: SIMULATOR_BIN + value: /builds/nos3/sims/build/bin/nos3-single-simulator + - name: SIM_BIN + value: /builds/nos3/sims/build/bin + image: registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + name: 03-sc01-gps-sim + resources: + limits: + cpu: 100m + memory: "128Mi" + requests: + cpu: 100m + memory: "Mi" + securityContext: + privileged: true + hostname: gps + restartPolicy: Always diff --git a/deployments/targets/kubernetes/gps/kustomization.yaml b/deployments/targets/kubernetes/gps/kustomization.yaml new file mode 100644 index 000000000..318bab171 --- /dev/null +++ b/deployments/targets/kubernetes/gps/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +# - ./configmap.yaml + - ./deployment.yaml + - ./service.yaml diff --git a/deployments/targets/kubernetes/gps/service.yaml b/deployments/targets/kubernetes/gps/service.yaml new file mode 100644 index 000000000..338bbb405 --- /dev/null +++ b/deployments/targets/kubernetes/gps/service.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: gps + namespace: nos3-m01-sc01 +spec: + selector: + app: nos3-m01-sc01-gps + ports: + - name: healthcheck-tcp + protocol: TCP + port: 60000 + targetPort: 60000 + - name: healthcheck-udp + protocol: UDP + port: 60000 + targetPort: 60000 + type: ClusterIP diff --git a/deployments/targets/kubernetes/kubernetes.sh b/deployments/targets/kubernetes/kubernetes.sh new file mode 100755 index 000000000..37bceb796 --- /dev/null +++ b/deployments/targets/kubernetes/kubernetes.sh @@ -0,0 +1,29 @@ + +REALM=nos3 +#K8S_CONTEXT=kind-${REALM} + +# kompose convert --file ../../docker/docker-compose.yaml + +export K8S_CONTEXT=docker-desktop +export K8S_NAMESPACE=${REALM}-m01-sc01 + +COMPONENT=fortytwo + +echo; echo Creating namespace ${K8S_NAMESPACE} in context ${K8S_CONTEXT}... +kubectl create namespace ${K8S_NAMESPACE} --context ${K8S_CONTEXT} || true + +kubectl --context ${K8S_CONTEXT} --namespace ${K8S_NAMESPACE} apply -k . + +echo +echo "Waiting on fortytwo pod to be ready" +echo +sleep 10 + +K8S_POD=$(kubectl get pods --context ${K8S_CONTEXT} --namespace ${K8S_NAMESPACE} | grep ${COMPONENT} | cut -d' ' -f1) + +x=${HOME}/development/github.com/haisamido/nos3/cfg/InOut + +kubectl --context ${K8S_CONTEXT} --namespace ${K8S_NAMESPACE} cp ${x} ${K8S_POD}:/opt/nasa-itc/42/X + +sleep 10 +kubectl port-forward pod/${K8S_POD} 30003:80 --context ${K8S_CONTEXT} --namespace ${K8S_NAMESPACE} diff --git a/deployments/targets/kubernetes/kustomization.yaml b/deployments/targets/kubernetes/kustomization.yaml new file mode 100644 index 000000000..58106a6c3 --- /dev/null +++ b/deployments/targets/kubernetes/kustomization.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./fortytwo + # - ./fsw + # - ./nos-engine-server + # - ./gps + # - ./time + \ No newline at end of file diff --git a/deployments/targets/kubernetes/nos-engine-server/configmap.yaml b/deployments/targets/kubernetes/nos-engine-server/configmap.yaml new file mode 100644 index 000000000..05ae714ef --- /dev/null +++ b/deployments/targets/kubernetes/nos-engine-server/configmap.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: v1 +data: + entrypoint_nos_engine_server.sh: | + #!/bin/bash + pkill -f nos_engine_server_standalone || true + /usr/bin/nos_engine_server_standalone /builds/nos3/sims/build/bin/nos_engine_server_config.json +kind: ConfigMap +metadata: + annotations: + use-subpath: "true" + labels: + io.kompose.service: nos3-nos-engine-server + name: nos3-nos-engine-server-cm0 diff --git a/deployments/targets/kubernetes/nos-engine-server/deployment.yaml b/deployments/targets/kubernetes/nos-engine-server/deployment.yaml new file mode 100644 index 000000000..2b3e4e464 --- /dev/null +++ b/deployments/targets/kubernetes/nos-engine-server/deployment.yaml @@ -0,0 +1,68 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: nos3-m01-sc01 + name: nos3-nos-engine-server + labels: + app: nos3-m01-sc01-nos-engine-server +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-nos-engine-server + template: + metadata: + labels: + app: nos3-m01-sc01-nos-engine-server + spec: + containers: + - args: + - /entrypoint.sh + env: + - name: BASE_DIR + value: /builds/nos3 + - name: CFG_FILE + value: /builds/nos3/sims/build/bin/nos_engine_server_config.json + - name: HEALTHCHECK_PORT + value: "60000" + - name: LOG_CONFIG + value: /builds/nos3/sims/build/bin/sim_log_config.xml + - name: SIMULATOR_BIN + value: /usr/bin/nos_engine_server_standalone + - name: SIM_BIN + value: /builds/nos3/sims/build/bin + image: registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + imagePullPolicy: IfNotPresent + name: 02-sc01-nos-engine-server + ports: + - containerPort: 12000 + protocol: TCP + - containerPort: 12001 + protocol: TCP + resources: + limits: + cpu: 100m + memory: "128Mi" + requests: + cpu: 100m + memory: "128Mi" + securityContext: + privileged: true + stdin: true + tty: true + volumeMounts: + - mountPath: /entrypoint.sh + name: nos3-nos-engine-server-cm0 + subPath: entrypoint.sh + workingDir: /builds/nos3/sims/build/bin + hostname: nos-engine-server + restartPolicy: Always + volumes: + - configMap: + items: + - key: entrypoint_nos_engine_server.sh + path: entrypoint.sh + defaultMode: 0555 + name: nos3-nos-engine-server-cm0 + name: nos3-nos-engine-server-cm0 diff --git a/deployments/targets/kubernetes/nos-engine-server/kustomization.yaml b/deployments/targets/kubernetes/nos-engine-server/kustomization.yaml new file mode 100644 index 000000000..164db37ac --- /dev/null +++ b/deployments/targets/kubernetes/nos-engine-server/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./configmap.yaml + - ./deployment.yaml + - ./service.yaml diff --git a/deployments/targets/kubernetes/nos-engine-server/service.yaml b/deployments/targets/kubernetes/nos-engine-server/service.yaml new file mode 100644 index 000000000..dd2ed634b --- /dev/null +++ b/deployments/targets/kubernetes/nos-engine-server/service.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: nos-engine-server + namespace: nos3-m01-sc01 +spec: + selector: + app: nos3-m01-sc01-nos-engine-server + ports: + - name: fsw-tcp + protocol: TCP + port: 12000 + targetPort: 12000 + - name: nos3-tcp + protocol: TCP + port: 12001 + targetPort: 12001 + - name: healthcheck-tcp + protocol: TCP + port: 60000 + targetPort: 60000 + - name: healthcheck-udp + protocol: UDP + port: 60000 + targetPort: 60000 + type: ClusterIP + diff --git a/deployments/targets/kubernetes/time/deployment.yaml b/deployments/targets/kubernetes/time/deployment.yaml new file mode 100644 index 000000000..dabe9a4a0 --- /dev/null +++ b/deployments/targets/kubernetes/time/deployment.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert --file ../../docker/docker-compose.yaml + kompose.version: 1.36.0 (HEAD) + labels: + io.kompose.service: nos3-time + name: nos3-time +spec: + replicas: 1 + selector: + matchLabels: + app: nos3-m01-sc01-time + template: + metadata: + labels: + app: nos3-m01-sc01-time + spec: + containers: + - env: + - name: BASE_DIR + value: /builds/nos3 + - name: CFG_FILE + value: /builds/nos3/sims/build/bin/nos3-simulator.xml + - name: COMPONENT_NAME + value: time + - name: HEALTHCHECK_PORT + value: "60000" + - name: LOG_CONFIG + value: /builds/nos3/sims/build/bin/sim_log_config.xml + - name: SIMULATOR_BIN + value: /builds/nos3/sims/build/bin/nos3-single-simulator + - name: SIM_BIN + value: /builds/nos3/sims/build/bin + image: registry.appdat.jsc.nasa.gov/ssmo/images/ssmo/nos3/nos3-base:20250217 + name: 04-nos-time-driver + resources: + limits: + cpu: 100m + memory: "128Mi" + requests: + cpu: 100m + memory: "128Mi" + securityContext: + privileged: true + stdin: true + tty: true + hostname: time + restartPolicy: Always diff --git a/deployments/targets/kubernetes/time/kustomization.yaml b/deployments/targets/kubernetes/time/kustomization.yaml new file mode 100644 index 000000000..318bab171 --- /dev/null +++ b/deployments/targets/kubernetes/time/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +# - ./configmap.yaml + - ./deployment.yaml + - ./service.yaml diff --git a/deployments/targets/kubernetes/time/service.yaml b/deployments/targets/kubernetes/time/service.yaml new file mode 100644 index 000000000..81953c575 --- /dev/null +++ b/deployments/targets/kubernetes/time/service.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: time + namespace: nos3-m01-sc01 +spec: + selector: + app: nos3-m01-sc01-time + ports: + - name: healthcheck-tcp + protocol: TCP + port: 60000 + targetPort: 60000 + - name: healthcheck-udp + protocol: UDP + port: 60000 + targetPort: 60000 + type: ClusterIP diff --git a/deployments/templates/env.template b/deployments/templates/env.template new file mode 100755 index 000000000..29cf7a242 --- /dev/null +++ b/deployments/templates/env.template @@ -0,0 +1,158 @@ +#!/usr/bin/env bash + +set -e + +# A script to generate .env file for container deployments + +# Simulation specific inputs +NOW=$(date -u +"%Y-%m-%d %H:%M:%S UTC") +SIM_T0_DATETIME="2026-01-01 00:00:00 UTC" +SIM_T0_DATETIME="${NOW}" + +TIME_INTERVAL=3600 # 1 hour in seconds +TIME_INTERVAL_MILLISECONDS=$( expr ${TIME_INTERVAL} \* 1000 ) + +#SIM_T0_DATETIME="${NOW}" +LEAP_SECONDS=37 + +GSW_SOFTWARE=yamcs +FSW_SOFTWARE=cfs + +# This is to define either the standard path, i.e. ${PWD}/nos3, or a local definition +NOS3_CFG_PATH=.. +NOS3_MISSION_CFG_FILE=../cfg/nos3-mission.xml + +NOS3_GIT_URL=https://github.com/nasa/nos3 +NOS3_GIT_COMMIT=dev + +NOS3_IMAGE_URI=docker.io/ivvitc/nos3-64:20251107 +NOS3_BASE_DIR=/home/nos3/.nos3 + +######################################################################## +# Avoid updating the below variables unless you know what you are doing +######################################################################## + +# Time specific derivations +TIME_OFFSET_SECONDS=+30 # to simulate 30 seconds into the future from SIM_T0_DATETIME +J2000_REFERENCE_DATETIME="2000-01-01 12:00:00 UTC" +SIM_T0_EPOCH_SECONDS=$(date -ud "${SIM_T0_DATETIME} ${TIME_OFFSET_SECONDS} seconds" +"%s") +SIM_T0_EPOCH_MILLISECONDS=$( expr ${SIM_T0_EPOCH_SECONDS} \* 1000 ) +SIM_TF_EPOCH_MILLISECONDS=$( expr ${SIM_T0_EPOCH_MILLISECONDS} + ${TIME_INTERVAL} \* 1000 ) +J2000_EPOCH_SECONDS=$(date -ud "${J2000_REFERENCE_DATETIME}" +"%s") + +cat << EOF +# +# Auto-generated by ${PWD}/$(basename $0) on $(date -u +"%Y-%m-%dT%H:%M:%S%z") +# + +PROJECT=${PROJECT} +FLEET=${FLEET} +MISSION=${MISSION} +SPACECRAFT=$SPACECRAFT + +PROJECT_NAME=${PROJECT_NAME} +PROJECT_MISSION=${PROJECT_MISSION} +COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} + +SC_ENVIRO=${SC_ENVIRO} + +# nos3 specific configurations +NOS3_GIT_URL=${NOS3_GIT_URL} +NOS3_GIT_COMMIT=${NOS3_GIT_COMMIT} +NOS3_DIR=/home/nos3/.nos3 +NOS3_USER=nos3 +NOS3_IMAGE_URI=${NOS3_IMAGE_URI} +NOS3_BASE_DIR=${NOS3_BASE_DIR} + +# This is to define either the standard path, i.e. ${PWD}/nos3, or a local definition +NOS3_CFG_PATH=${NOS3_CFG_PATH} +NOS3_MISSION_CFG_FILE=${NOS3_MISSION_CFG_FILE} + +# Simulation specific configurations +SIM_T0_DATETIME="${SIM_T0_DATETIME}" +J2000_REFERENCE_DATETIME="${J2000_REFERENCE_DATETIME}" + +TIME_OFFSET_SECONDS=${TIME_OFFSET_SECONDS} +TIME_INTERVAL=${TIME_INTERVAL} +TIME_INTERVAL_MILLISECONDS=${TIME_INTERVAL_MILLISECONDS} + +# In epoch seconds +SIM_T0_EPOCH_SECONDS=${SIM_T0_EPOCH_SECONDS} +SIM_T0_EPOCH_MILLISECONDS=${SIM_T0_EPOCH_MILLISECONDS} +SIM_TF_EPOCH_MILLISECONDS=${SIM_TF_EPOCH_MILLISECONDS} +J2000_EPOCH_SECONDS=${J2000_EPOCH_SECONDS} + +# In J2000 seconds +START_TIME=$((${SIM_T0_EPOCH_SECONDS}-${J2000_EPOCH_SECONDS})) + +# Deployment specific configurations +DEPLOYMENT_ENVIRO=${DEPLOYMENT_ENVIRO} +HEALTHCHECK_PORT=${HEALTHCHECK_PORT} + +# Proxy configurations, the proxy values come for the environment, +# which is important for the vmmoc +HTTPS_PROXY=${HTTPS_PROXY} +HTTP_PROXY=${HTTP_PROXY} +NO_PROXY=${NO_PROXY} + +# Maven/Java specific configurations +MAVEN_REPO_LOCAL=/home/nos3/.nos3/.m2 +MAVEN_HTTPS_PROXY="--settings ./settings.xml" +MAVEN_SETTINGS_FILE=${MAVEN_SETTINGS_FILE} + +# 42 specific configurations +FORTYTWO_DISPLAY=:1 +FORTYTWO_GIT_URL=https://github.com/nasa-itc/42.git +FORTYTWO_GIT_COMMIT=nos3-main +FORTYTWO_GIT_FOLDER=42 +FORTYTWO_STARTUP_FOLDER=NOS3InOut +FORTYTWO_RECOMPILE=false +FORTYTWO_BASE_DIR=/opt/nasa-itc +FORTYTWO_VNC_PASSWORD=$(echo -n "foobar" | shasum -a 256 | cut -d" " -f1) + +FORTYTWO_HOST=${FORTYTWO_HOST} +FORTYTWO_PORT=${FORTYTWO_PORT} +FORTYTWO_HOST_PORT=${FORTYTWO_HOST_PORT} + +FORTYTWO_SIM_DATE="$(date -ud "@${SIM_T0_EPOCH_SECONDS}" +"%m %d %Y")" +FORTYTWO_SIM_TIME="$(date -ud "@${SIM_T0_EPOCH_SECONDS}" +"%H %M %S.%2N")" +FORTYTWO_LEAP_SECONDS=${LEAP_SECONDS} + +# gsw+fsw specific configurations +GSW_SOFTWARE=${GSW_SOFTWARE} +FSW_SOFTWARE=${FSW_SOFTWARE} + +COMPONENT_DIR=/home/nos3/builds/nos3/components + +# yamcs specific configurations +YAMCS_DATA_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yamcs-data +# YAMCS_ETC_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yamcs-etc + +# YAMCS_CACHE_DIR=/home/nos3/.nos3/yamcs/target/yamcs/yam + +YAMCS_GIT_URL=https://github.com/nasa-itc/nos3_yamcs_master.git +YAMCS_GIT_COMMIT=nos3-dev + +YAMCS_INSTANCES=nos3 + +YAMCS_HOST=${YAMCS_HOST} +YAMCS_HOST_PORT=${YAMCS_HOST_PORT} +YAMCS_PORT=${YAMCS_PORT} + +# openmct specific configurations +OPENMCT_IMAGE_URI=docker.io/library/ubuntu:25.04 + +OPENMCT_GIT_URL=https://github.com/akhenry/openmct-yamcs.git +OPENMCT_GIT_COMMIT=master + +OPENMCT_NVM_VERSION=v0.40.1 +OPENMCT_NODE_VERSION=v21.7.3 + +OPENMCT_HOST=${OPENMCT_HOST} +OPENMCT_PORT=${OPENMCT_PORT} +OPENMCT_HOST_PORT=${OPENMCT_HOST_PORT} + +# nasa-itc specific configurations +BASE_DIR=/opt/nasa-itc + +EOF \ No newline at end of file