hopeless-masquerade: birbs
Assisted-by: Claude Opus 5 via Claude Code
diff --git a/dns.tf b/dns.tf
index 6f8ff12..83f52d8 100644
--- a/dns.tf
+++ b/dns.tf
@@ -15,10 +15,10 @@ resource "dnsimple_zone" "zones" {
resource "dnsimple_zone_record" "chislan_family_subdomains" {
for_each = {
- auth = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
- birdnetpi = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
- docs = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
- files = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
+ auth = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
+ birbs = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
+ docs = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
+ files = { zone = dnsimple_zone.zones["chislan_family"], ip = local.lotus_land_story.ip_address }
}
zone_name = each.value.zone.name
diff --git a/hopeless-masquerade/README.md b/hopeless-masquerade/README.md
new file mode 100644
index 0000000..117b41e
--- /dev/null
+++ b/hopeless-masquerade/README.md
@@ -0,0 +1,11 @@
+# hopeless-masquerade
+
+A Raspberry Pi 4 Model B running [BirdNET-Pi][birdnet-pi].
+
+## setup
+
+```sh
+ansible-playbook -l hopeless-masquerade -e ansible_host=ANSIBLE_HOST --ask-become-pass hopeless-masquerade/main.yml
+```
+
+[birdnet-pi]: https://github.com/zach7036/BirdNET-Pi
diff --git a/hopeless-masquerade/main.yml b/hopeless-masquerade/main.yml
index 8f789f6..5482505 100644
--- a/hopeless-masquerade/main.yml
+++ b/hopeless-masquerade/main.yml
@@ -16,7 +16,7 @@
# TODO Standardize these into a shared playbook
- name: Secure the system
- hosts: legacy-of-lunatic-kingdom
+ hosts: hopeless-masquerade
become: true
tasks:
@@ -47,74 +47,106 @@
# TODO disallow network access from non-tailscale interfaces
- import_playbook: ../playbooks/tailscale.yml # noqa: name[play]
-- import_playbook: vector.yml # noqa: name[play]
-
+# https://setup.vector.dev
# https://grafana.com/blog/2024/07/12/obirdability-how-to-build-an-observability-system-for-bird-songs/
-- name: Ship birdnet logs
- tags: birdnet_o11y
+- name: Vector
+ tags: vector
hosts: hopeless-masquerade
become: true
tasks:
- - name: Create Vector configuration
+ - name: Install required dependencies
+ ansible.builtin.apt:
+ pkg:
+ - apt-transport-https
+ - curl
+ - gnupg
+ - python3-debian # for ansible.builtin.deb822_repository
+ state: present
+ update_cache: true
+
+ - name: Create keyrings directory
+ ansible.builtin.file:
+ path: /usr/share/keyrings
+ state: directory
+ mode: '0755'
+
+ - name: Download Vector GPG key
+ ansible.builtin.get_url:
+ url: https://keys.datadoghq.com/DATADOG_APT_KEY_CURRENT.public
+ dest: /tmp/vector_key.public
+ mode: '0644'
+
+ - name: Import Vector GPG key
+ ansible.builtin.command: gpg --dearmor --output /usr/share/keyrings/datadog-archive-keyring.gpg /tmp/vector_key.public
+ args:
+ creates: /usr/share/keyrings/datadog-archive-keyring.gpg
+
+ # Left behind by ansible.builtin.apt_repository; apt reads both formats, so
+ # leaving it would configure the repository twice.
+ - name: Remove one-line Vector repository
+ ansible.builtin.file:
+ path: /etc/apt/sources.list.d/vector.list
+ state: absent
+
+ - name: Add Vector repository
+ ansible.builtin.deb822_repository:
+ name: vector
+ types: deb
+ uris: https://apt.vector.dev/
+ suites: stable
+ components: vector-0
+ signed_by: /usr/share/keyrings/datadog-archive-keyring.gpg
+ state: present
+
+ - name: Install Vector
+ ansible.builtin.apt:
+ name: vector
+ state: present
+ update_cache: true
+
+ - name: Configure Vector
ansible.builtin.copy:
- content: |
- sources:
- journald:
- type: journald
-
- transforms:
- birdnet:
- type: remap
- inputs:
- - journald
- source: |
- if ._SYSTEMD_UNIT != "birdnet_analysis.service" {
- abort
- }
-
- parsed, err = parse_regex(.message, r'.+\((\'|")(?P<species_latin>.+?)_(?P<species>.+?)(\'|"), (?P<confidence>.+?)\)')
- if err != null {
- abort
- }
-
- . |= parsed
-
- if includes(["Engine", "Human"], .species) {
- abort
- }
-
- # actually probably unnecessary?
- .confidence_interval = round(to_float!(.confidence), precision: 1)
-
- sinks:
- console:
- type: console
- inputs:
- - birdnet
- encoding:
- codec: json
- vlogs:
- inputs:
- - birdnet
- type: http
- uri: http://lotus-land-story:9428/insert/jsonline?_stream_fields=host&_msg_field=message&_time_field=timestamp
- compression: gzip
- encoding:
- codec: json
- framing:
- method: newline_delimited
- healthcheck:
- enabled: false
+ src: templates/vector.yml
dest: /etc/vector/vector.yaml
mode: '0644'
backup: true
notify: Restart Vector
+ - name: Enable and start Vector service
+ ansible.builtin.systemd:
+ name: vector
+ enabled: true
+ state: started
+ daemon_reload: true
+
+ - name: Clean up temporary key file
+ ansible.builtin.file:
+ path: /tmp/vector_key.public
+ state: absent
+
handlers:
- name: Restart Vector
ansible.builtin.systemd:
name: vector
state: restarted
+# - name: birbnet
+# tags: birbnet
+# hosts: hopeless-masquerade
+# tasks:
+#
+# - name: Install pipx
+# become: true
+# ansible.builtin.apt:
+# pkg:
+# - pipx
+# state: present
+# update_cache: true
+#
+# - name: Install uv
+# ansible.builtin.command: pipx install uv
+# args:
+# creates: /home/alpha/.local/bin/uv
+
# vim: ft=yaml.ansible
diff --git a/hopeless-masquerade/templates/vector.yml b/hopeless-masquerade/templates/vector.yml
new file mode 100644
index 0000000..2b71fef
--- /dev/null
+++ b/hopeless-masquerade/templates/vector.yml
@@ -0,0 +1,80 @@
+sources:
+ journald:
+ type: journald
+ bird_db_txt:
+ type: file
+ include:
+ - "/home/alpha/BirdNET-Pi/BirdDB.txt"
+
+transforms:
+ birdnet:
+ type: remap
+ inputs:
+ - journald
+ source: |
+ if ._SYSTEMD_UNIT != "birdnet_analysis.service" {
+ abort
+ }
+
+ parsed, err = parse_regex(.message, r'.+\((\'|")(?P<species_latin>.+?)_(?P<species>.+?)(\'|"), (?P<confidence>.+?)\)')
+ if err != null {
+ abort
+ }
+
+ . |= parsed
+
+ if includes(["Engine", "Human"], .species) {
+ abort
+ }
+
+ # actually probably unnecessary?
+ .confidence_interval = round(to_float!(.confidence), precision: 1)
+ bird_db:
+ type: remap
+ inputs:
+ - bird_db_txt
+ source: |
+ keys = split("Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap", ";")
+ parsed = object_from_array(
+ split!(.message, ";"),
+ keys: keys,
+ )
+
+ # handle headers
+ if parsed.Date == "Date" {
+ abort
+ }
+
+ date = string!(parsed.Date)
+ time = string!(parsed.Time)
+ ts = "{{date}}T{{time}}"
+ .timestamp = parse_timestamp!(
+ ts,
+ format: "%Y-%m-%dT%H:%M:%S",
+ timezone: "America/Los_Angeles",
+ )
+
+ .com_name = parsed.Com_Name
+ .sci_name = parsed.Sci_Name
+ .confidence = parsed.Confidence
+
+sinks:
+ console:
+ type: console
+ inputs:
+ - bird_db
+ - bird_db_txt
+ encoding:
+ codec: json
+ vlogs:
+ inputs:
+ - birdnet
+ type: http
+ uri: http://lotus-land-story:9428/insert/jsonline?_stream_fields=host&_msg_field=message&_time_field=timestamp
+ compression: gzip
+ encoding:
+ codec: json
+ framing:
+ method: newline_delimited
+ healthcheck:
+ enabled: false
diff --git a/hopeless-masquerade/vector.yml b/hopeless-masquerade/vector.yml
deleted file mode 100644
index 0305637..0000000
--- a/hopeless-masquerade/vector.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-# https://setup.vector.dev
-
-- name: Install Vector on Debian
- tags: vector
- hosts: hopeless-masquerade
- become: true
- tasks:
-
- - name: Install required dependencies
- ansible.builtin.apt:
- pkg:
- - apt-transport-https
- - curl
- - gnupg
- state: present
- update_cache: true
-
- - name: Create keyrings directory
- ansible.builtin.file:
- path: /usr/share/keyrings
- state: directory
- mode: '0755'
-
- - name: Download Vector GPG key
- ansible.builtin.get_url:
- url: https://keys.datadoghq.com/DATADOG_APT_KEY_CURRENT.public
- dest: /tmp/vector_key.public
- mode: '0644'
-
- - name: Import Vector GPG key
- ansible.builtin.command: gpg --dearmor --output /usr/share/keyrings/datadog-archive-keyring.gpg /tmp/vector_key.public
- args:
- creates: /usr/share/keyrings/datadog-archive-keyring.gpg
-
- - name: Add Vector repository
- ansible.builtin.apt_repository:
- repo: deb [signed-by=/usr/share/keyrings/datadog-archive-keyring.gpg] https://apt.vector.dev/ stable vector-0
- filename: vector
- state: present
- update_cache: true
-
- - name: Install Vector
- ansible.builtin.apt:
- name: vector
- state: present
- update_cache: true
-
- - name: Enable and start Vector service
- ansible.builtin.systemd:
- name: vector
- enabled: true
- state: started
- daemon_reload: true
-
- - name: Clean up temporary key file
- ansible.builtin.file:
- path: /tmp/vector_key.public
- state: absent
-
diff --git a/lotus-land-story/templates/Caddyfile b/lotus-land-story/templates/Caddyfile
index 2f0d6a9..112bd90 100644
--- a/lotus-land-story/templates/Caddyfile
+++ b/lotus-land-story/templates/Caddyfile
@@ -197,7 +197,7 @@ gists.kejadlen.dev {
}
}
-birdnetpi.chislan.family {
+birbs.chislan.family {
log
reverse_proxy hopeless-masquerade:80
diff --git a/lotus-land-story/templates/scrape.yml b/lotus-land-story/templates/scrape.yml
index 2ea8d4f..289d0a2 100644
--- a/lotus-land-story/templates/scrape.yml
+++ b/lotus-land-story/templates/scrape.yml
@@ -44,7 +44,7 @@ scrape_configs:
# personal
- https://auth.chislan.family
- https://auth.kejadlen.dev
- - https://birdnetpi.chislan.family
+ - https://birbs.chislan.family
- https://git.kejadlen.dev
- https://hey.kejadlen.dev
relabel_configs: