diff --git a/tailscale/DOCS.md b/tailscale/DOCS.md index b214eecee..a3aa01718 100644 --- a/tailscale/DOCS.md +++ b/tailscale/DOCS.md @@ -83,6 +83,14 @@ stateful_filtering: false tags: - tag:example - tag:homeassistant +taildrive: + addons: false + addon_configs: false + backup: false + config: false + media: false + share: false + ssl: false taildrop: true userspace_networking: true ``` @@ -348,6 +356,17 @@ They need to start with `tag:`. More information: [Tags][tailscale_info_tags] +### Option: `taildrive` + +This option allows you to specify which Home Assistant directories you want to +share with other Tailscale nodes using Taildrive. + +Only the listed directories are available. + +These options are disabled by default. + +More information: [Taildrive][tailscale_info_taildrive] + ### Option: `taildrop` This app supports [Tailscale's Taildrop][tailscale_info_taildrop] feature, @@ -535,6 +554,7 @@ SOFTWARE. [tailscale_info_site_to_site]: https://tailscale.com/kb/1214/site-to-site [tailscale_info_subnets]: https://tailscale.com/kb/1019/subnets [tailscale_info_tags]: https://tailscale.com/kb/1068/tags +[tailscale_info_taildrive]: https://tailscale.com/kb/1369/taildrive [tailscale_info_taildrop]: https://tailscale.com/kb/1106/taildrop [tailscale_info_userspace_networking]: https://tailscale.com/kb/1112/userspace-networking [tailscale_machines]: https://login.tailscale.com/admin/machines diff --git a/tailscale/config.yaml b/tailscale/config.yaml index 5c018a4fe..885de6ef1 100644 --- a/tailscale/config.yaml +++ b/tailscale/config.yaml @@ -23,7 +23,21 @@ privileged: devices: - /dev/net/tun map: - - share:rw + - type: addons + read_only: false + - type: all_addon_configs + read_only: false + - type: backup + read_only: false + - type: homeassistant_config + read_only: false + path: /config + - type: media + read_only: false + - type: share + read_only: false + - type: ssl + read_only: false ports: 41641/udp: null options: @@ -41,6 +55,14 @@ options: snat_subnet_routes: true stateful_filtering: false tags: [] + taildrive: + addons: false + addon_configs: false + backup: false + config: false + media: false + share: false + ssl: false taildrop: true userspace_networking: true schema: @@ -60,5 +82,13 @@ schema: stateful_filtering: bool tags: - "match(^tag:[a-zA-Z][a-zA-Z0-9-]*$)" + taildrive: + addons: bool + addon_configs: bool + backup: bool + config: bool + media: bool + share: bool + ssl: bool taildrop: bool userspace_networking: bool diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/dependencies.d/post-tailscaled b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/dependencies.d/post-tailscaled new file mode 100644 index 000000000..e69de29bb diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/run b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/run new file mode 100755 index 000000000..78b2398d3 --- /dev/null +++ b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/run @@ -0,0 +1,72 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash +export LOG_FD +# ============================================================================== +# Home Assistant Community App: Tailscale +# Exposes Home Assistant directories over Taildrive +# ============================================================================== + +# These are not arrays, but newline separated lists (single strings) +declare all_share_names +declare configured_share_names +declare active_share_names + +declare share_name + +# Read all possible and configured directories from the app configuration. +if ! all_share_names=$(bashio::config 'taildrive' | jq -rc 'keys_unsorted[]') || \ + ! configured_share_names=$(bashio::config 'taildrive' | jq -rc 'to_entries[] | select(.value) | .key') +then + bashio::exit.nok "Error reading configured Taildrive directories from app configuration." +fi + +# Check if Taildrive is available +if ! /opt/tailscale status --self=true --peers=false --json \ + | jq -rce '.Self.CapMap | has("drive:share")' > /dev/null; +then + # If Taildrive is not available but any share is configured, that is an error + if (( 0 < $(wc -w <<< "${configured_share_names}") )); then + bashio::exit.nok \ + "Tailscale's Taildrive feature is not available, but directories are configured" \ + "for sharing. Please check your Tailscale plan and ACL settings." + fi +else + # Read currently shared directories into an array from tailscale drive list. + # The output of which looks like: + # name path as + # ------ ------- ---- + # config /config root + if ! active_share_names=$(/opt/tailscale drive list | tail -n +3 | awk '{print $1}'); then + bashio::exit.nok "Error reading shared Taildrive directories from Tailscale." + fi + + # If a directory is configured but not shared, share it. + # Note: do not quote configured_share_names in the for loop, + # as we want to iterate over words (lines), this is not an array + for share_name in ${configured_share_names}; do + if ! grep -Fxq -- "${share_name}" <<< "${active_share_names}"; then + bashio::log.info "Taildrive: sharing /${share_name}" + if ! /opt/tailscale drive share "${share_name}" "/${share_name}"; then + bashio::exit.nok "Failed to share /${share_name}" + fi + else + bashio::log.info "Taildrive: /${share_name} is already shared" + fi + done + + # If a directory is shared but not configured, and managed by this app, unshare it. + # Note: do not quote active_share_names in the for loop, + # as we want to iterate over words (lines), this is not an array + for share_name in ${active_share_names}; do + if ! grep -Fxq -- "${share_name}" <<< "${configured_share_names}"; then + if grep -Fxq -- "${share_name}" <<< "${all_share_names}"; then + bashio::log.info "Taildrive: unsharing /${share_name}" + if ! /opt/tailscale drive unshare "${share_name}"; then + bashio::exit.nok "Failed to unshare /${share_name}" + fi + else + bashio::log.info "Taildrive: skipping unshare of '${share_name}' (not managed by this app)" + fi + fi + done +fi diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/type b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/type new file mode 100644 index 000000000..bdd22a185 --- /dev/null +++ b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/type @@ -0,0 +1 @@ +oneshot diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/up b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/up new file mode 100644 index 000000000..5f15bb532 --- /dev/null +++ b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/taildrive/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/taildrive/run \ No newline at end of file diff --git a/tailscale/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/taildrive b/tailscale/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/taildrive new file mode 100644 index 000000000..e69de29bb diff --git a/tailscale/translations/en.yaml b/tailscale/translations/en.yaml index d7bbffc5c..ee6e14bd8 100644 --- a/tailscale/translations/en.yaml +++ b/tailscale/translations/en.yaml @@ -94,6 +94,13 @@ configuration: description: >- This option allows you to specify specific ACL tags for this Tailscale instance. They need to start with `tag:`. + taildrive: + name: Taildrive shares + description: >- + This option allows you to specify which Home Assistant directories you want to + share with other Tailscale nodes using Taildrive. + Only the listed directories are available. + These options are disabled by default. taildrop: name: Taildrop description: >-