<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Deevnet Software on Deevnet IoTaaS</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/</link><description>Recent content in Deevnet Software on Deevnet IoTaaS</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/index.xml" rel="self" type="application/rss+xml"/><item><title>Deevnet API</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/deevnet-api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/deevnet-api/</guid><description>&lt;h1 id="deevnet-api">
 Deevnet API
 &lt;a class="anchor" href="#deevnet-api">#&lt;/a>
&lt;/h1>
&lt;p>Fills the &lt;strong>provisioning API&lt;/strong> role at the

 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/tenant/boundary/">substrate–tenant boundary&lt;/a>: the one interface a tenant uses,
which builds on the substrate what the tenant declares
(
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012&lt;/a>,

 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015&lt;/a>). It is
provisioning-only: nothing at runtime depends on it being up.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Repository&lt;/strong>&lt;/td>
 &lt;td>&lt;code>deevnet-provisioning-api&lt;/code>, Go (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/software-catalog/#deevnets-own-software">version&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Runs on&lt;/strong>&lt;/td>
 &lt;td>&lt;code>dv02prv001v01&lt;/code>, 10.20.25.20, as two podman containers under systemd: &lt;code>deevnet-api&lt;/code> (on the host&amp;rsquo;s loopback address; tenants reach it at &lt;code>https://api.mobile.deevnet.net&lt;/code> through the host&amp;rsquo;s 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/management-plane/substrate-service-vms/#the-service-proxy">service proxy&lt;/a>) and &lt;code>deevnet-api-db&lt;/code> (PostgreSQL, on a private podman network, no published port)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Deployed by&lt;/strong>&lt;/td>
 &lt;td>&lt;code>deevnet.mgmt&lt;/code> role &lt;code>deevnet_api&lt;/code>: &lt;code>ansible-playbook playbooks/site.yml --limit deevnet_api&lt;/code>. The image is built and staged on the Builder (&lt;code>make stage&lt;/code>) and pushed to the host, never pulled. The role ends by checking &lt;code>/readyz&lt;/code> and that &lt;code>/version&lt;/code> is the pinned version&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Contract&lt;/strong>&lt;/td>
 &lt;td>&lt;code>api/openapi.yaml&lt;/code> in the repository (OpenAPI 3.1), published as the 
 &lt;a href="https://deevnet.github.io/deevnet-provisioning-api/docs/reference/">API reference&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Documentation&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-provisioning-api/">deevnet.github.io/deevnet-provisioning-api&lt;/a>, with 
 &lt;a href="https://deevnet.github.io/deevnet-provisioning-api/docs/release-notes/">release notes&lt;/a> for every version&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="what-it-exposes">
 What it exposes
 &lt;a class="anchor" href="#what-it-exposes">#&lt;/a>
&lt;/h2>
&lt;p>&lt;strong>The API has its own documentation site, 
 &lt;a href="https://deevnet.github.io/deevnet-provisioning-api/">Deevnet API&lt;/a>.&lt;/strong> Its

 &lt;a href="https://deevnet.github.io/deevnet-provisioning-api/docs/reference/">reference&lt;/a> lists every route, request and response, and is rendered from the
OpenAPI specification in the repository, which a test holds to the code.&lt;/p></description></item><item><title>Terraform Provider</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/terraform-provider/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/terraform-provider/</guid><description>&lt;h1 id="terraform-provider">
 Terraform Provider
 &lt;a class="anchor" href="#terraform-provider">#&lt;/a>
&lt;/h1>
&lt;p>&lt;code>deevnet/deevnet&lt;/code>: how a tenant declares itself to the 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/deevnet-software/deevnet-api/">Deevnet API&lt;/a>.
It is the tenant side of the 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/tenant/boundary/">substrate–tenant boundary&lt;/a>.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Repository&lt;/strong>&lt;/td>
 &lt;td>&lt;code>terraform-provider-deevnet&lt;/code>, Go, terraform-plugin-framework (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/software-catalog/#deevnets-own-software">version&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Runs on&lt;/strong>&lt;/td>
 &lt;td>Tenant laptops and the Builder. It is not in the public registry&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Distributed by&lt;/strong>&lt;/td>
 &lt;td>&lt;code>make release-build&lt;/code>: zips for macOS and Linux on amd64 and arm64, with &lt;code>SHA256SUMS&lt;/code>, &lt;code>install-provider.sh&lt;/code> and &lt;code>tenant-check.sh&lt;/code>. &lt;code>make stage&lt;/code> puts them on 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/runbook/tenant/getting-started/before-you-start/#getting-the-provider">tenant downloads&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Configuration&lt;/strong>&lt;/td>
 &lt;td>&lt;code>DEEVNET_API_ENDPOINT&lt;/code>, &lt;code>DEEVNET_API_TOKEN&lt;/code>, &lt;code>DEEVNET_API_CACERT&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Documentation&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/terraform-provider-deevnet/">deevnet.github.io/terraform-provider-deevnet&lt;/a>, with 
 &lt;a href="https://deevnet.github.io/terraform-provider-deevnet/docs/release-notes/">release notes&lt;/a> for every version&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="why-terraform-for-tenants">
 Why Terraform for tenants
 &lt;a class="anchor" href="#why-terraform-for-tenants">#&lt;/a>
&lt;/h2>
&lt;p>The substrate is configured by procedural automation; tenants use Terraform. A tenant is created and
destroyed often, so its tooling has to track what it owns, plan a change before making it, and
destroy cleanly. Terraform does all three, and it is what a tenant developer is likely to know
already. The substrate is configured rather than created, and gains nothing from state it would then
have to guard.&lt;/p></description></item><item><title>Log Bridge</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/log-bridge/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/log-bridge/</guid><description>&lt;h1 id="log-bridge">
 Log Bridge
 &lt;a class="anchor" href="#log-bridge">#&lt;/a>
&lt;/h1>
&lt;p>Carries device log lines from the MQTT broker into each tenant&amp;rsquo;s device-log partition, &lt;code>(index, 2)&lt;/code>,
in the tenant log store (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0027-tenant-log-store/">ADR-0027&lt;/a> §4,

 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0021-mqtt-log-bridge/">CHG-0021&lt;/a>). A device publishes; it never talks to the log
store.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Repository&lt;/strong>&lt;/td>
 &lt;td>&lt;code>deevnet-log-bridge&lt;/code>, Go (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/software-catalog/#deevnets-own-software">version&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Runs on&lt;/strong>&lt;/td>
 &lt;td>&lt;code>dv02msg001v01&lt;/code>, beside the broker, as the &lt;code>deevnet-log-bridge&lt;/code> container; &lt;code>deevnet.mgmt&lt;/code> role &lt;code>log_bridge&lt;/code>. Also on the Pi backend image&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Reads&lt;/strong>&lt;/td>
 &lt;td>MQTT &lt;code>+/log/#&lt;/code> (&lt;code>&amp;lt;tenant&amp;gt;/log/&amp;lt;device&amp;gt;&lt;/code>), QoS 1, persistent session, as the subscribe-only account &lt;code>substrate-log-bridge&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Writes&lt;/strong>&lt;/td>
 &lt;td>vmauth on the log store, with the tenant named in &lt;code>X-Deevnet-Tenant&lt;/code>, under one store token&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Health&lt;/strong>&lt;/td>
 &lt;td>&lt;code>/healthz&lt;/code> on &lt;code>127.0.0.1:9099&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>It keeps no state. Its queue holds 10,000 lines and drops the oldest when full, logging the loss.
Failed batches are retried with backoff; batches the store refuses are not. It is in no device&amp;rsquo;s
path: if it stops, devices keep publishing, and their lines queue in its persistent broker session
up to the broker&amp;rsquo;s limits.&lt;/p></description></item><item><title>Tenant Egress Agent</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/egress-agent/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/egress-agent/</guid><description>&lt;h1 id="tenant-egress-agent">
 Tenant Egress Agent
 &lt;a class="anchor" href="#tenant-egress-agent">#&lt;/a>
&lt;/h1>
&lt;p>Keeps a default route inside every tenant VRF on the fabric exit node, so each tenant&amp;rsquo;s internet
traffic leaves through the perimeter (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015&lt;/a> §7).
Proxmox does not model that route, and the alternative was to give the API root on a hypervisor.
Instead the node pulls the tenant list and renders the route itself.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Source&lt;/strong>&lt;/td>
 &lt;td>&lt;code>ansible-collection-deevnet.net&lt;/code>, role &lt;code>tenant_egress_agent&lt;/code>: a Bash script with embedded Python&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Runs on&lt;/strong>&lt;/td>
 &lt;td>&lt;code>dv02hyp002p02&lt;/code>: &lt;code>/usr/local/sbin/deevnet-egress-agent&lt;/code>, run by &lt;code>deevnet-egress-agent.timer&lt;/code> two minutes after boot and every five minutes after that&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Deployed by&lt;/strong>&lt;/td>
 &lt;td>&lt;code>ansible-playbook playbooks/tenant-egress-agent.yml&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Reads&lt;/strong>&lt;/td>
 &lt;td>&lt;code>GET /v1/fabric/egress&lt;/code> from the API, with a token that can read that route and nothing else&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Writes&lt;/strong>&lt;/td>
 &lt;td>&lt;code>/etc/frr/frr.conf.local&lt;/code>. Only when it changes: &lt;code>pvesh set /cluster/sdn&lt;/code> and a reload of FRR&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>A failed fetch leaves the file as it is, so an API outage withdraws no route. A deleted tenant loses
its route on the next run.&lt;/p></description></item><item><title>deevnet-kit</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/deevnet-kit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/deevnet-kit/</guid><description>&lt;h1 id="deevnet-kit">
 deevnet-kit
 &lt;a class="anchor" href="#deevnet-kit">#&lt;/a>
&lt;/h1>
&lt;p>The Deevnet API&amp;rsquo;s stand-in on a Raspberry Pi. On the take-home Pi backend image it does, for one
tenant and on the Pi itself, what the API does for a tenant on the site: broker accounts, log users,
the card&amp;rsquo;s own CA and certificates, and a Grafana organization. It is built from the API&amp;rsquo;s own
packages, so the same rules apply in both places.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Source&lt;/strong>&lt;/td>
 &lt;td>&lt;code>deevnet-provisioning-api&lt;/code>, &lt;code>cmd/deevnet-kit&lt;/code>; it shares the API&amp;rsquo;s tag&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Built by&lt;/strong>&lt;/td>
 &lt;td>&lt;code>make build-pi&lt;/code> and &lt;code>make stage-pi&lt;/code> in the API repository (linux/arm64), baked into the image by &lt;code>make pi-backend&lt;/code> in &lt;code>deevnet-image-factory&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Runs as&lt;/strong>&lt;/td>
 &lt;td>A CLI and three systemd units on the Pi: first boot, dashboards, and a self-test on every boot&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Commands&lt;/strong>&lt;/td>
 &lt;td>&lt;code>init&lt;/code>, &lt;code>status&lt;/code>, &lt;code>env&lt;/code>, &lt;code>export&lt;/code>, &lt;code>account add|list|rm&lt;/code>, &lt;code>regen-certs&lt;/code>, &lt;code>render&lt;/code>, &lt;code>dashboards&lt;/code>, &lt;code>selftest&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>State&lt;/strong>&lt;/td>
 &lt;td>&lt;code>/etc/deevnet-kit/&lt;/code> (the tenant and its tokens, accounts, TLS, Grafana settings); input from &lt;code>/boot/firmware/deevnet-kit.txt&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>It is not part of the deployed API. How a tenant uses the image is

 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/runbook/tenant/tenant-to-pi-image/">Tenant to Pi Image&lt;/a>.&lt;/p></description></item><item><title>Image Factories</title><link>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/image-factories/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/platforms/deevnet-software/image-factories/</guid><description>&lt;h1 id="image-factories">
 Image Factories
 &lt;a class="anchor" href="#image-factories">#&lt;/a>
&lt;/h1>
&lt;p>Two repositories that build what the site installs from. Both run on the Builder, and stage their
output on the artifact server.&lt;/p>
&lt;h2 id="deevnet-image-factory-os-images">
 &lt;code>deevnet-image-factory&lt;/code>: OS images
 &lt;a class="anchor" href="#deevnet-image-factory-os-images">#&lt;/a>
&lt;/h2>
&lt;p>Packer and Ansible builds of:&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Image&lt;/th>
 &lt;th>Target&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Fedora VM templates&lt;/td>
 &lt;td>Built straight onto each hypervisor: &lt;code>make proxmox-fedora-pve1&lt;/code>, &lt;code>make proxmox-fedora-pve2&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Raspberry Pi images&lt;/td>
 &lt;td>&lt;code>make pi-sdr&lt;/code>, &lt;code>make pi-pidp11&lt;/code>, and &lt;code>make pi-backend&lt;/code> (the take-home tenant backend, with 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/platforms/deevnet-software/deevnet-kit/">deevnet-kit&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Proxmox VE install ISO and PXE artifacts&lt;/td>
 &lt;td>&lt;code>make proxmox-pve-iso-ext4&lt;/code> and related targets. &lt;strong>Unfinished&lt;/strong>: neither hypervisor has been installed from it (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/roadmap/infrastructure/mobile/builder/">Builder roadmap&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Its &lt;code>scripts/pve-creds&lt;/code> fetches a hypervisor&amp;rsquo;s Proxmox token per run, from OpenBao or the inventory
vault, and never writes it to disk; the tenant fabric&amp;rsquo;s Terraform uses it too
(
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/runbook/substrate/building-recovery/build-secrets/">Build-Time Secrets&lt;/a>).&lt;/p></description></item></channel></rss>