FastDeploy Service Registration Role¶
Register a service runner with FastDeploy so the FastDeploy UI/API can trigger a narrowly scoped
ops-control deployment flow through a controlled fastdeploy -> deploy -> root privilege chain.
What The Role Does¶
fastdeploy_register_service currently:
creates the
deployuser/group and its runner workspace under/home/deploy/optionally installs an age key at
/home/deploy/.config/sops/age/keys.txtprepares
ops-controlfor the runner:rsync: syncs to/home/deploy/ops-controlgit: clones or refreshes/home/deploy/_workspace/ops-control
renders an owner-only runner to
/home/deploy/runners/<service>/deploy.pyoptionally writes a deploy-user-only runner config payload to
/home/deploy/runners/<service>/deploy-config.jsonoptionally writes a separate deploy-user-only secret runner payload to
/home/deploy/runners/<service>/deploy-secrets.jsoncopies that runner into
/home/fastdeploy/site/services/<service>/deploy.pywith owner-only permissionswrites
/home/fastdeploy/site/services/<service>/config.jsoninstalls
/etc/sudoers.d/fastdeploy_<service>optionally calls
POST <fd_api_base>/services/sync
The role does not generate deploy.sh or playbook.yml. Those belong to other FastDeploy
registration patterns such as apt_upgrade_register.
Requirements¶
FastDeploy must already be installed, including the
fastdeployuser/group.Run the role with
become: true.For the default
rsyncmethod, the controller must provide a readable localops-controlcheckout viafd_ops_control_local_path.rsyncmust be available on the controller and target when usingfd_ops_control_method: rsync.
Default Paths¶
/home/fastdeploy/site/services/<service>/
├── config.json
└── deploy.py
/home/deploy/
├── .config/sops/age/keys.txt
├── ops-control/
├── runners/<service>/deploy-config.json
├── runners/<service>/deploy-secrets.json
├── runners/<service>/deploy.py
└── _workspace/
/etc/sudoers.d/fastdeploy_<service>
Security notes:
/home/deploy/runners/<service>/deploy.pyis written0700and owned bydeploy./home/deploy/runners/<service>/deploy-config.jsonis written0600and owned bydeploywhenfd_runner_configis provided./home/deploy/runners/<service>/deploy-secrets.jsonis written0600and owned bydeploywhenfd_runner_secret_configis provided./home/fastdeploy/site/services/<service>/deploy.pyis written0700and owned byfastdeploy./home/deploy/runners/<service>/and/home/deploy/.ssh/are created0700.Keep
fd_runner_confignon-secret when possible. The default runner reads that private payload at execution time, merges it withfd_runner_secret_configif present, and writes anyansible.extra_varsvalues to a transient0600temp file instead of embedding them in the runner source oransible-playbookargv.Prefer
ansible.extra_vars_from_sopsinsidefd_runner_configwhen the runner can decrypt staged SOPS files at execution time. That keeps decrypted values out of long-lived runner config files while still feeding them to Ansible through the same transient temp file path.
Key Variables¶
service_name: nyxmon
fd_service_name: "{{ service_name | mandatory }}"
fd_service_description: "Deploy {{ fd_service_name }} via ops-control"
fd_fastdeploy_root: /home/fastdeploy/site
fd_fastdeploy_user: fastdeploy
fd_service_config_dir: "{{ fd_fastdeploy_root }}/services/{{ fd_service_name }}"
fd_deploy_user: deploy
fd_deploy_home: "/home/{{ fd_deploy_user }}"
fd_runner_script: "{{ fd_deploy_home }}/runners/{{ fd_service_name }}/deploy.py"
fd_runner_config_path: "{{ fd_deploy_home }}/runners/{{ fd_service_name }}/deploy-config.json"
fd_runner_secret_config_path: "{{ fd_deploy_home }}/runners/{{ fd_service_name }}/deploy-secrets.json"
fd_sudoers_file: "/etc/sudoers.d/fastdeploy_{{ fd_service_name }}"
fd_ops_control_method: rsync
fd_ops_control_local_path: /path/to/ops-control
fd_ops_control_remote_path: "{{ fd_deploy_home }}/ops-control"
fd_api_base: http://localhost:8000
fd_api_token: ""
fd_sync_services: true
fd_sops_age_key_contents: ""
fd_runner_content: ""
fd_runner_config: {}
fd_runner_secret_config: {}
Notes:
fd_service_namedefaults toservice_nameand is required.fd_runner_contentoverrides the defaultdeploy.py.j2template.fd_runner_configwrites a deploy-user-only JSON payload next to the runner. The default template merges that static payload withfd_runner_secret_configand any runtimeDEPLOY_CONFIG_FILE/--configdata from FastDeploy.fd_runner_secret_configwrites a separate deploy-user-only JSON payload for secrets that must stay out ofdeploy-config.jsonbut still need to persist across deployments.fd_runner_config.ansible.extra_vars_from_sopsaccepts a list of runtime secret sources. Each entry must definepathplus avarsmap of destination extra-var names to SOPS key paths. A mapping value can be either a string key path or an object withpathand optionaldefault.fd_ops_control_local_pathis required whenfd_ops_control_method == "rsync".If
fd_api_tokenis empty, the service sync call is skipped.
Example¶
- name: Register Nyxmon with FastDeploy
hosts: fastdeploy_host
become: true
roles:
- role: local.ops_library.fastdeploy_register_service
vars:
service_name: nyxmon
fd_service_description: "Deploy nyxmon via ops-control"
fd_ops_control_method: rsync
fd_ops_control_local_path: "{{ playbook_dir }}/../ops-control"
fd_sops_age_key_contents: "{{ lookup('file', lookup('env', 'HOME') ~ '/.config/sops/age/keys.txt') }}"
fd_runner_config:
ansible:
extra_vars:
release_channel: stable
extra_vars_from_sops:
- path: secrets/prod/nyxmon.yml
vars:
nyxmon_secret_key: django_secret_key
verify:
systemd_service: nyxmon
fd_runner_secret_config:
ansible:
extra_vars:
nyxmon_runtime_secret: "{{ nyxmon_runtime_secret }}"
fd_api_token: "{{ fastdeploy_api_token }}"
Execution Flow¶
FastDeploy starts
/home/fastdeploy/site/services/<service>/deploy.py.The sudoers rule allows that runner to execute as
deploy.The runner prepares
ops-control:rsync: uses the pre-synced checkout already placed at/home/deploy/ops-controlgit: clones or refreshes a checkout in/home/deploy/_workspace/ops-control
The runner installs Ansible collections when
collections/requirements.ymlexists.The runner merges
deploy-config.json,deploy-secrets.json, and any runtime FastDeploy config file, if present.The runner resolves any
ansible.extra_vars_from_sopsentries at execution time usingsops -d --output-type json, relative to the stagedops-controlworkspace unless absolute paths are provided.The runner executes:
ansible-playbook -i inventories/prod/hosts.yml playbooks/site.yml -l localhost --extra-vars filter=<service> --become --become-user root
Progress is emitted as NDJSON on stdout. If FastDeploy supplied callback URLs and a token, the runner also sends best-effort HTTP updates.
Validation¶
Focused Molecule coverage for this role lives under:
just molecule-test fastdeploy_register_service