Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0bca64e7b | |||
| aa0257308b | |||
| 87f6839423 | |||
| eb0d52295b | |||
| 7ede2d12fe | |||
| 88e9cfe684 | |||
| 618909ad4b | |||
| 39eeb029ae | |||
| 0c7a84690f | |||
| 20cecfdaf4 | |||
| 118f1edc02 | |||
| 75d9486e2d | |||
| 7b47835749 | |||
| 854ed976db | |||
| 9bd2815f64 | |||
| f239b37126 | |||
| b4c29a693b | |||
| 0b74444e76 | |||
| 1425bf4efa | |||
| 3205a4a1e2 | |||
| 8377ba7cc6 | |||
| 90bc869b3d | |||
| 87218e5be7 | |||
| 3ae80ef3bb | |||
| a85f7f50e9 | |||
| 2ce3900c47 | |||
| 4aa0bdc783 | |||
| badadef12a | |||
| 04afce167a | |||
| 8ab2c8bb1b | |||
| e3c9344517 | |||
| 45d57a4585 | |||
| 56a3e5473e | |||
| b32340700b | |||
| f96b1131c0 | |||
| 42bb6ed218 | |||
| ed1fa33bf7 | |||
| a358f9c953 | |||
| ded7865e89 | |||
| 127aa27530 | |||
| 82637347b5 | |||
| 89886d0c9b | |||
| fc75831f12 | |||
| 2d6ff36a4f | |||
| 5c23f4cbea | |||
| 7ad9d1ed7d | |||
| 9ab66a7be1 | |||
| 44d706b891 | |||
| 160bca4f50 | |||
| 4d6d6b4b38 | |||
| eed76199b1 | |||
| 08b5295427 | |||
| 8b04252c1c | |||
| d46d109c20 | |||
| 094a0d2d41 |
@@ -22,7 +22,7 @@ jobs:
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
run: pip install hvac
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
|
||||
- name: Gotify Notification
|
||||
if: steps.validate-dags.outputs.exit_code == '0'
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
|
||||
- name: Gotify Notification
|
||||
if: steps.validate-dags.outputs.exit_code != '0'
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
|
||||
@@ -22,7 +22,7 @@ on:
|
||||
- "!renovate.json"
|
||||
|
||||
env:
|
||||
TEA_VERSION: "0.10.1"
|
||||
TEA_VERSION: "0.14.0"
|
||||
VAULT_VERSION: "1.21.0"
|
||||
VAULT_ADDR: ${{ secrets.TREZ_VAULT_ADDR }}
|
||||
VAULT_TOKEN: ${{ secrets.VAULT_GITEA_TOKEN }}
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
assignee: ${{ github.actor }}
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
host: [rinoa, rikku, benedikta]
|
||||
host: [aranea, lunafreya, rinoa, rikku, ultima]
|
||||
env:
|
||||
VAULT_ADDR: ${{ secrets.TREZ_VAULT_ADDR }}
|
||||
VAULT_TOKEN: ${{ secrets.VAULT_GITEA_TOKEN }}
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
run: pip install hvac
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
--check
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
echo "pr_index=${pr_index}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -174,7 +174,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
host: [rinoa, rikku, benedikta]
|
||||
host: [aranea, lunafreya, rinoa, rikku, ultima]
|
||||
env:
|
||||
VAULT_ADDR: ${{ secrets.TREZ_VAULT_ADDR }}
|
||||
VAULT_TOKEN: ${{ secrets.VAULT_GITEA_TOKEN }}
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
run: pip install hvac
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -234,7 +234,7 @@ jobs:
|
||||
--limit ${{ matrix.host }}
|
||||
|
||||
- name: Gotify Notification
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Gotify Notification (start check)
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: ${{ secrets.RUNNER_GOTIFY_URL }}
|
||||
gotify_app_token: ${{ secrets.RUNNER_GOTIFY_TOKEN }}
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
version: "stable"
|
||||
|
||||
- name: Gotify Notification (done)
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: ${{ secrets.RUNNER_GOTIFY_URL }}
|
||||
gotify_app_token: ${{ secrets.RUNNER_GOTIFY_TOKEN }}
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
VAULT_NAMESPACE: ""
|
||||
steps:
|
||||
- name: Vault Unseal Start
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Vault Unseal Completion
|
||||
uses: eikendev/gotify-action@master
|
||||
uses: eikendev/gotify-action@0.0.3
|
||||
with:
|
||||
gotify_api_base: "${{ secrets.RUNNER_GOTIFY_URL }}"
|
||||
gotify_app_token: "${{ secrets.RUNNER_GOTIFY_TOKEN }}"
|
||||
|
||||
@@ -3,3 +3,4 @@ inventory = inventory/hosts.yml
|
||||
collections_path = ./collections
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
strategy_plugins = plugins/mitogen-0.3.44/ansible_mitogen/plugins/strategy
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false,
|
||||
"type": "ovos_common_play",
|
||||
"preferred_audio_services": [
|
||||
"mpv",
|
||||
"vlc",
|
||||
"simple"
|
||||
],
|
||||
"disable_mpris": true,
|
||||
"dbus_type": "session",
|
||||
"manage_external_players": false,
|
||||
"active": true,
|
||||
"mode": "auto"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"first_boot": false
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"speak_alarm": false,
|
||||
"speak_timer": true,
|
||||
"sound_alarm": "constant_beep.mp3",
|
||||
"sound_timer": "beep4.mp3",
|
||||
"snooze_mins": 15,
|
||||
"timeout_min": 1,
|
||||
"play_volume": 90,
|
||||
"escalate_volume": true,
|
||||
"priority_cutoff": 8,
|
||||
"services": "",
|
||||
"frequency": 15,
|
||||
"sync_ask": false,
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"play_sound": true,
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"log_level": "WARNING",
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"gender": "male",
|
||||
"haunted": false,
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"apiv3": "8a2e8882b465b1cf7cce9ff6b35bdd7e",
|
||||
"search_depth": 5,
|
||||
"match_confidence": 0.8,
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"__mycroft_skill_firstrun": false
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"log_level": "INFO",
|
||||
"logs": { "path": "stdout" },
|
||||
"listener": {
|
||||
"continuous_listen": true,
|
||||
"microphone": {
|
||||
"module": "ovos-microphone-plugin-socket"
|
||||
},
|
||||
"VAD": {
|
||||
"module": "ovos-vad-plugin-silero"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
# otel_collector.yaml
|
||||
|
||||
receivers:
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
# 1) Host log collection
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
filelog:
|
||||
# Optional: give the receiver a human‑readable name
|
||||
name: host_logs
|
||||
# Paths to monitor – adjust glob patterns as needed
|
||||
include:
|
||||
- /var/log/*.log
|
||||
- /var/log/syslog
|
||||
- /var/log/messages
|
||||
# Optional: skip log files that match these patterns
|
||||
exclude: []
|
||||
# Optional: start reading from the beginning of the file
|
||||
start_at: beginning
|
||||
# Optional: decode JSON logs if they are JSON‑formatted
|
||||
# json:
|
||||
# keys: [timestamp, level, msg]
|
||||
# timestamp_key: timestamp
|
||||
# timestamp_format: RFC3339
|
||||
# Optional: throttle log ingestion
|
||||
# throttle:
|
||||
# max_per_second: 1000
|
||||
# Optional: keep track of processed offsets
|
||||
# cache:
|
||||
# file: /var/log/filelog_cache.json
|
||||
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
# 2) Docker container log collection
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
docker:
|
||||
# Connect to the local Docker daemon
|
||||
host: unix:///var/run/docker.sock
|
||||
# By default, the Docker receiver pulls container metrics, logs, and health‑checks.
|
||||
# If you only need logs, set the following to true (enabled by default):
|
||||
logs: true
|
||||
# Optional: enable or disable container log collection for specific containers
|
||||
# include: [ "my-app", "api-service" ]
|
||||
# exclude: [ "debug-container" ]
|
||||
# Optional: set the maximum number of log files to keep open
|
||||
# max_open_files: 100
|
||||
|
||||
processors:
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
# 1) Batch processor (recommended for all pipelines)
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
batch:
|
||||
timeout: 5s
|
||||
send_batch_size: 5000
|
||||
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
# 2) Optional resource processor – add host name to every log record
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
resource:
|
||||
attributes:
|
||||
- key: host.name
|
||||
from_env: HOSTNAME
|
||||
action: upsert
|
||||
- key: service.namespace
|
||||
value: host-logs
|
||||
action: upsert
|
||||
|
||||
exporters:
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
# 1) OTLP exporter – sends logs to the central collector
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
otlp:
|
||||
endpoint: "centralized-collector:4317"
|
||||
# If you want insecure connections (e.g., local dev), set insecure true
|
||||
tls:
|
||||
insecure: true
|
||||
# Optional: use HTTP instead of gRPC
|
||||
# http:
|
||||
# path: "/v1/logs"
|
||||
|
||||
service:
|
||||
pipelines:
|
||||
logs:
|
||||
receivers: [filelog, docker]
|
||||
processors: [batch, resource]
|
||||
exporters: [otlp]
|
||||
@@ -1,404 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Agent globals
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
local.file "endpoints" {
|
||||
// The endpoints file is used to define the endpoints, credentials and options
|
||||
// for the Agent export to.
|
||||
filename = "/etc/alloy/endpoints.json"
|
||||
}
|
||||
|
||||
discovery.docker "rinoadocker" {
|
||||
host = env("DOCKER_HOST")
|
||||
}
|
||||
|
||||
tracing {
|
||||
write_to = [otelcol.exporter.otlp.tempo.input]
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Metrics
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
prometheus.remote_write "mimir" {
|
||||
endpoint {
|
||||
url = json_path(local.file.endpoints.content, ".metrics.url")[0]
|
||||
basic_auth {
|
||||
username = json_path(local.file.endpoints.content, ".metrics.basicAuth.username")[0]
|
||||
password = json_path(local.file.endpoints.content, ".metrics.basicAuth.password")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prometheus.scrape "prometheus" {
|
||||
targets = [{
|
||||
__address__ = "localhost:12345",
|
||||
}]
|
||||
forward_to = [prometheus.remote_write.mimir.receiver]
|
||||
job_name = "prometheus"
|
||||
}
|
||||
|
||||
prometheus.exporter.unix "rinoa" {
|
||||
procfs_path = "/host/proc"
|
||||
sysfs_path = "/host/sys"
|
||||
rootfs_path = "/rootfs"
|
||||
}
|
||||
|
||||
prometheus.scrape "rinoa" {
|
||||
targets = prometheus.exporter.unix.rinoa.targets
|
||||
forward_to = [prometheus.remote_write.mimir.receiver]
|
||||
job_name = "rinoa_host"
|
||||
}
|
||||
|
||||
prometheus.exporter.cadvisor "docker" {
|
||||
docker_host = env("DOCKER_HOST")
|
||||
storage_duration = "5m"
|
||||
}
|
||||
|
||||
prometheus.scrape "docker" {
|
||||
targets = prometheus.exporter.cadvisor.docker.targets
|
||||
forward_to = [prometheus.remote_write.mimir.receiver]
|
||||
job_name = "docker_stats"
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Logging
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
loki.write "loki" {
|
||||
endpoint {
|
||||
url = json_path(local.file.endpoints.content, ".logs.url")[0]
|
||||
basic_auth {
|
||||
username = json_path(local.file.endpoints.content, ".logs.basicAuth.username")[0]
|
||||
password = json_path(local.file.endpoints.content, ".logs.basicAuth.password")[0]
|
||||
}
|
||||
}
|
||||
external_labels = {}
|
||||
}
|
||||
|
||||
loki.source.journal "hostjournal" {
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
max_age = "24h"
|
||||
path = "/rootfs/var/log/journal/"
|
||||
labels = {
|
||||
job = "host-journal",
|
||||
}
|
||||
}
|
||||
|
||||
local.file_match "system" {
|
||||
path_targets = [{
|
||||
__address__ = "localhost",
|
||||
__path__ = "/rootfs/var/log/*log",
|
||||
job = "varlogs",
|
||||
}]
|
||||
}
|
||||
|
||||
loki.source.file "system" {
|
||||
targets = local.file_match.system.targets
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
}
|
||||
|
||||
loki.source.docker "containers" {
|
||||
host = env("DOCKER_HOST")
|
||||
targets = discovery.docker.rinoadocker.targets
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
labels = {
|
||||
job = "containerlogs",
|
||||
}
|
||||
}
|
||||
|
||||
loki.process "containers" {
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
// stage.docker {}
|
||||
stage.json {
|
||||
expressions = {
|
||||
attrs = "",
|
||||
output = "log",
|
||||
stream = "stream",
|
||||
}
|
||||
}
|
||||
|
||||
stage.json {
|
||||
expressions = {
|
||||
tag = "",
|
||||
}
|
||||
source = "attrs"
|
||||
}
|
||||
|
||||
stage.regex {
|
||||
expression = "(?P<image_name>(?:[^|]*[^|])).(?P<container_name>(?:[^|]*[^|])).(?P<image_id>(?:[^|]*[^|])).(?P<container_id>(?:[^|]*[^|]))"
|
||||
source = "tag"
|
||||
}
|
||||
|
||||
stage.timestamp {
|
||||
source = "time"
|
||||
format = "RFC3339Nano"
|
||||
}
|
||||
|
||||
stage.labels {
|
||||
values = {
|
||||
container_id = null,
|
||||
container_name = null,
|
||||
image_id = null,
|
||||
image_name = null,
|
||||
stream = null,
|
||||
tag = null,
|
||||
}
|
||||
}
|
||||
|
||||
stage.output {
|
||||
source = "output"
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Traces
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
beyla.ebpf "rinoadocker" {
|
||||
open_port = "80-65535"
|
||||
routes {
|
||||
unmatched = "heauristic"
|
||||
}
|
||||
output {
|
||||
traces = [
|
||||
otelcol.connector.servicegraph.tracemetrics.input,
|
||||
otelcol.connector.spanmetrics.tracemetrics.input,
|
||||
otelcol.processor.batch.default.input,
|
||||
otelcol.connector.spanlogs.autologging.input,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
prometheus.scrape "beyla" {
|
||||
targets = beyla.ebpf.rinoadocker.targets
|
||||
forward_to = [prometheus.remote_write.mimir.receiver]
|
||||
}
|
||||
|
||||
otelcol.auth.headers "tempo" {
|
||||
header {
|
||||
key = "Authorization"
|
||||
value = join(["Basic ", json_path(local.file.endpoints.content, ".traces.basicAuthToken")[0]], "")
|
||||
}
|
||||
}
|
||||
|
||||
otelcol.processor.batch "default" {
|
||||
// Wait until we've received 16K of data.
|
||||
send_batch_size = 16384
|
||||
send_batch_max_size = 16384
|
||||
// Or until 2 seconds have elapsed.
|
||||
timeout = "2s"
|
||||
// When the Agent has enough batched data, send it to the OpenTelemetry exporter named 'tempo'.
|
||||
output {
|
||||
traces = [otelcol.exporter.otlp.tempo.input]
|
||||
}
|
||||
}
|
||||
|
||||
otelcol.exporter.otlp "tempo" {
|
||||
// Define the client for exporting.
|
||||
client {
|
||||
// Authentication block.
|
||||
auth = otelcol.auth.headers.tempo.handler
|
||||
|
||||
// Send to the locally running Tempo instance, on port 4317 (OTLP gRPC).
|
||||
endpoint = json_path(local.file.endpoints.content, ".traces.url")[0]
|
||||
|
||||
// Configure TLS settings for communicating with the endpoint.
|
||||
tls {
|
||||
// The connection is insecure.
|
||||
insecure = json_path(local.file.endpoints.content, ".traces.tls.insecure")[0]
|
||||
// Do not verify TLS certificates when connecting.
|
||||
insecure_skip_verify = json_path(local.file.endpoints.content, ".traces.tls.insecureSkipVerify")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
otelcol.connector.spanlogs "autologging" {
|
||||
// We only want to output a line for each root span (ie. every single trace), and not for every
|
||||
// process or span (outputting a line for every span would be extremely verbose).
|
||||
spans = false
|
||||
roots = true
|
||||
processes = false
|
||||
// We want to ensure that the following three span attributes are included in the log line, if
|
||||
// present.
|
||||
span_attributes = [ "http.method", "http.target", "http.status_code" ]
|
||||
|
||||
// Overrides the default key in the log line to be `traceId`, which is then used by Grafana to
|
||||
// identify the trace ID for correlation with the Tempo datasource.
|
||||
overrides {
|
||||
trace_id_key = "traceId"
|
||||
}
|
||||
// Send to the OpenTelemetry Loki exporter.
|
||||
output {
|
||||
logs = [otelcol.exporter.loki.autologging.input]
|
||||
}
|
||||
}
|
||||
|
||||
// Simply forwards the incoming OpenTelemetry log format out as a Loki log.
|
||||
// We need this stage to ensure we can then process the logline as a Loki object.
|
||||
otelcol.exporter.loki "autologging" {
|
||||
forward_to = [loki.process.autologging.receiver]
|
||||
}
|
||||
|
||||
// The Loki processor allows us to accept a correctly formatted Loki log and mutate it into
|
||||
// a set of fields for output.
|
||||
loki.process "autologging" {
|
||||
// The JSON stage simply extracts the `body` (the actual logline) from the Loki log, ignoring
|
||||
// all other fields.
|
||||
stage.json {
|
||||
expressions = { "body" = "" }
|
||||
}
|
||||
// The output stage takes the body (the main logline) and uses this as the source for the output
|
||||
// logline. In this case, it essentially turns it into logfmt.
|
||||
stage.output {
|
||||
source = "body"
|
||||
}
|
||||
|
||||
// Finally send the processed logline onto the Loki exporter.
|
||||
forward_to = [loki.write.autologging.receiver]
|
||||
}
|
||||
|
||||
// The Loki writer receives a processed Loki log and then writes it to a Loki instance.
|
||||
loki.write "autologging" {
|
||||
// Add the `agent` value to the `job` label, so we can identify it as having been generated
|
||||
// by Grafana Agent when querying.
|
||||
external_labels = {
|
||||
job = "agent",
|
||||
}
|
||||
|
||||
// Output the Loki log to the local Loki instance.
|
||||
endpoint {
|
||||
url = json_path(local.file.endpoints.content, ".logs.url")[0]
|
||||
|
||||
// The basic auth credentials for the Loki instance.
|
||||
basic_auth {
|
||||
username = json_path(local.file.endpoints.content, ".logs.basicAuth.username")[0]
|
||||
password = json_path(local.file.endpoints.content, ".logs.basicAuth.password")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The Tail Sampling processor will use a set of policies to determine which received traces to keep
|
||||
// and send to Tempo.
|
||||
otelcol.processor.tail_sampling "errors" {
|
||||
// Total wait time from the start of a trace before making a sampling decision. Note that smaller time
|
||||
// periods can potentially cause a decision to be made before the end of a trace has occurred.
|
||||
decision_wait = "30s"
|
||||
|
||||
// The following policies follow a logical OR pattern, meaning that if any of the policies match,
|
||||
// the trace will be kept. For logical AND, you can use the `and` policy. Every span of a trace is
|
||||
// examined by each policy in turn. A match will cause a short-circuit.
|
||||
|
||||
// This policy defines that traces that contain errors should be kept.
|
||||
policy {
|
||||
// The name of the policy can be used for logging purposes.
|
||||
name = "sample-erroring-traces"
|
||||
// The type must match the type of policy to be used, in this case examing the status code
|
||||
// of every span in the trace.
|
||||
type = "status_code"
|
||||
// This block determines the error codes that should match in order to keep the trace,
|
||||
// in this case the OpenTelemetry 'ERROR' code.
|
||||
status_code {
|
||||
status_codes = [ "ERROR" ]
|
||||
}
|
||||
}
|
||||
|
||||
// This policy defines that only traces that are longer than 200ms in total should be kept.
|
||||
policy {
|
||||
// The name of the policy can be used for logging purposes.
|
||||
name = "sample-long-traces"
|
||||
// The type must match the policy to be used, in this case the total latency of the trace.
|
||||
type = "latency"
|
||||
// This block determines the total length of the trace in milliseconds.
|
||||
latency {
|
||||
threshold_ms = 200
|
||||
}
|
||||
}
|
||||
|
||||
// The output block forwards the kept traces onto the batch processor, which will marshall them
|
||||
// for exporting to Tempo.
|
||||
output {
|
||||
traces = [otelcol.processor.batch.default.input]
|
||||
}
|
||||
}
|
||||
|
||||
// The Spanmetrics Connector will generate RED metrics based on the incoming trace span data.
|
||||
otelcol.connector.spanmetrics "tracemetrics" {
|
||||
// The namespace explicit adds a prefix to all the generated span metrics names.
|
||||
// In this case, we'll ensure they match as closely as possible those generated by Tempo.
|
||||
namespace = "traces.spanmetrics"
|
||||
|
||||
// Each extra dimension (metrics label) to be added to the generated metrics from matching span attributes. These
|
||||
// need to be defined with a name and optionally a default value (in the following cases, we do not want a default
|
||||
// value if the span attribute is not present).
|
||||
dimension {
|
||||
name = "http.method"
|
||||
}
|
||||
dimension {
|
||||
name = "http.target"
|
||||
}
|
||||
dimension {
|
||||
name = "http.status_code"
|
||||
}
|
||||
dimension {
|
||||
name = "service.version"
|
||||
}
|
||||
|
||||
// A histogram block must be present, either explicitly defining bucket values or via an exponential block.
|
||||
// We do the latter here.
|
||||
histogram {
|
||||
explicit {
|
||||
}
|
||||
}
|
||||
|
||||
// The exemplar block is added to ensure we generate exemplars for traces on relevant metric values.
|
||||
exemplars {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
// Generated metrics data is in OTLP format. We send this data to the OpenTelemetry Prometheus exporter to ensure
|
||||
// it gets transformed into Prometheus format data.
|
||||
output {
|
||||
metrics = [otelcol.exporter.prometheus.tracemetrics.input]
|
||||
}
|
||||
}
|
||||
|
||||
// The Servicegraph Connector will generate service graph metrics (edges and nodes) based on incoming trace spans.
|
||||
otelcol.connector.servicegraph "tracemetrics" {
|
||||
// Extra dimensions (metrics labels) to be added to the generated metrics from matching span attributes.
|
||||
// For this component, this is defined as an array. There are no default values and the labels will not be generated
|
||||
// for missing span attributes.
|
||||
dimensions = [
|
||||
"http.method",
|
||||
"http.target",
|
||||
"http.status_code",
|
||||
"service.version",
|
||||
]
|
||||
|
||||
// Generated metrics data is in OTLP format. We send this data to the OpenTelemetry Prometheus exporter to ensure
|
||||
// it gets transformed into Prometheus format data.
|
||||
output {
|
||||
metrics = [otelcol.exporter.prometheus.tracemetrics.input]
|
||||
}
|
||||
}
|
||||
|
||||
otelcol.exporter.prometheus "tracemetrics" {
|
||||
// Forward to our local Prometheus remote writer which will send the metrics to Mimir.
|
||||
forward_to = [prometheus.remote_write.mimir.receiver]
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Profiling
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pyroscope.write "pyroscope" {
|
||||
endpoint {
|
||||
url = json_path(local.file.endpoints.content, ".profiles.url")[0]
|
||||
basic_auth {
|
||||
username = json_path(local.file.endpoints.content, ".profiles.basicAuth.username")[0]
|
||||
password = json_path(local.file.endpoints.content, ".profiles.basicAuth.password")[0]
|
||||
}
|
||||
}
|
||||
external_labels = {}
|
||||
}
|
||||
|
||||
pyroscope.ebpf "rinoadocker" {
|
||||
forward_to = [pyroscope.write.pyroscope.receiver]
|
||||
targets = discovery.docker.rinoadocker.targets
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
{
|
||||
"metrics": {
|
||||
"url": "http://grafana-mimir:9009/api/v1/push",
|
||||
"basicAuth": {
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
},
|
||||
"logs": {
|
||||
"url": "http://grafana-loki:3100/loki/api/v1/push",
|
||||
"basicAuth": {
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
},
|
||||
"traces": {
|
||||
"url": "http://grafana-tempo:4317",
|
||||
"basicAuthToken": "",
|
||||
"tls": {
|
||||
"insecure": true,
|
||||
"insecureSkipVerify": true
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"url": "http://grafana-pyroscope:4040",
|
||||
"basicAuth": {
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
routes:
|
||||
patterns:
|
||||
- /*
|
||||
unmatched: heuristic
|
||||
@@ -1,77 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
multitenancy_enabled: false
|
||||
no_auth_tenant: rinoa_mimir
|
||||
# target: query-frontend
|
||||
# api:
|
||||
# prometheus_http_prefix: '/prometheus'
|
||||
server:
|
||||
http_listen_port: 9009
|
||||
# frontend:
|
||||
# split_queries_by_interval: 24h
|
||||
# align_queries_with_step: true
|
||||
# cache_results: true
|
||||
# results_cache:
|
||||
# backend: "memcached"
|
||||
# memcached:
|
||||
# addresses: "memcached-mimir:11211"
|
||||
# downstream_url: http://grafana-agent:12345
|
||||
|
||||
common:
|
||||
storage:
|
||||
backend: s3
|
||||
s3:
|
||||
endpoint: minio:9000
|
||||
access_key_id: "Q8KAihuXtGgmretKNh7C"
|
||||
secret_access_key: "hOlRODtnvFlNlL26Bj3GizZG6Ys3rlpG8p6Vo3NX"
|
||||
bucket_name: "mimir"
|
||||
insecure: true
|
||||
|
||||
blocks_storage:
|
||||
storage_prefix: rinoa
|
||||
tsdb:
|
||||
dir: /tmp/mimir/tsdb
|
||||
|
||||
memberlist:
|
||||
tls_enabled: false
|
||||
|
||||
compactor:
|
||||
# Directory to temporarily store blocks underdoing compaction.
|
||||
data_dir: /tmp/mimir/compactor
|
||||
# The sharding ring type used to share the hashed ring for the compactor.
|
||||
sharding_ring:
|
||||
# Use memberlist backend store (the default).
|
||||
kvstore:
|
||||
store: memberlist
|
||||
|
||||
# The distributor receives incoming metrics data for the system.
|
||||
distributor:
|
||||
# The ring to share hash ring data across instances.
|
||||
ring:
|
||||
# The address advertised in the ring. Localhost.
|
||||
instance_addr: 127.0.0.1
|
||||
# Use memberlist backend store (the default).
|
||||
kvstore:
|
||||
store: memberlist
|
||||
|
||||
# The ingester receives data from the distributor and processes it into indices and blocks.
|
||||
ingester:
|
||||
# The ring to share hash ring data across instances.
|
||||
ring:
|
||||
# The address advertised in the ring. Localhost.
|
||||
instance_addr: 127.0.0.1
|
||||
# Use memberlist backend store (the default).
|
||||
kvstore:
|
||||
store: memberlist
|
||||
# Only run one instance of the ingesters.
|
||||
# Note: It is highly recommended to run more than one ingester in production, the default is an RF of 3.
|
||||
replication_factor: 1
|
||||
|
||||
# The store gateway block configures gateway storage.
|
||||
store_gateway:
|
||||
# Configuration for the hash ring.
|
||||
sharding_ring:
|
||||
# Only run a single instance. In production setups, the replication factor must
|
||||
# be set on the querier and ruler as well.
|
||||
replication_factor: 1
|
||||
@@ -1,12 +0,0 @@
|
||||
storage:
|
||||
backend: s3
|
||||
s3:
|
||||
bucket_name: pyroscope
|
||||
endpoint: minio:9000
|
||||
region: us-east-fh-pln
|
||||
access_key_id: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['MINIO_PYROSCOPE_STORAGE_ACCESS_KEY'] }}
|
||||
secret_access_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['MINIO_PYROSCOPE_STORAGE_SECRET_KEY'] }}
|
||||
insecure: true
|
||||
|
||||
analytics:
|
||||
reporting_enabled: false
|
||||
@@ -1,787 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
target: all
|
||||
http_api_prefix: ""
|
||||
autocomplete_filtering_enabled: true
|
||||
server:
|
||||
http_listen_network: tcp
|
||||
http_listen_address: ""
|
||||
http_listen_port: 80
|
||||
http_listen_conn_limit: 0
|
||||
grpc_listen_network: tcp
|
||||
grpc_listen_address: ""
|
||||
grpc_listen_port: 9095
|
||||
grpc_listen_conn_limit: 0
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
http_tls_config:
|
||||
cert: ""
|
||||
key: null
|
||||
client_ca: ""
|
||||
cert_file: ""
|
||||
key_file: ""
|
||||
client_auth_type: ""
|
||||
client_ca_file: ""
|
||||
grpc_tls_config:
|
||||
cert: ""
|
||||
key: null
|
||||
client_ca: ""
|
||||
cert_file: ""
|
||||
key_file: ""
|
||||
client_auth_type: ""
|
||||
client_ca_file: ""
|
||||
register_instrumentation: true
|
||||
report_grpc_codes_in_instrumentation_label_enabled: false
|
||||
graceful_shutdown_timeout: 30s
|
||||
http_server_read_timeout: 30s
|
||||
http_server_read_header_timeout: 0s
|
||||
http_server_write_timeout: 30s
|
||||
http_server_idle_timeout: 2m0s
|
||||
http_log_closed_connections_without_response_enabled: false
|
||||
grpc_server_max_recv_msg_size: 16777216
|
||||
grpc_server_max_send_msg_size: 16777216
|
||||
grpc_server_max_concurrent_streams: 100
|
||||
grpc_server_max_connection_idle: 2562047h47m16.854775807s
|
||||
grpc_server_max_connection_age: 2562047h47m16.854775807s
|
||||
grpc_server_max_connection_age_grace: 2562047h47m16.854775807s
|
||||
grpc_server_keepalive_time: 2h0m0s
|
||||
grpc_server_keepalive_timeout: 20s
|
||||
grpc_server_min_time_between_pings: 10s
|
||||
grpc_server_ping_without_stream_allowed: true
|
||||
grpc_server_num_workers: 0
|
||||
log_format: logfmt
|
||||
log_level: info
|
||||
log_source_ips_enabled: false
|
||||
log_source_ips_header: ""
|
||||
log_source_ips_regex: ""
|
||||
log_request_headers: false
|
||||
log_request_at_info_level_enabled: false
|
||||
log_request_exclude_headers_list: ""
|
||||
http_path_prefix: ""
|
||||
internal_server:
|
||||
http_listen_network: tcp
|
||||
http_listen_address: ""
|
||||
http_listen_port: 3101
|
||||
http_listen_conn_limit: 0
|
||||
grpc_listen_network: ""
|
||||
grpc_listen_address: ""
|
||||
grpc_listen_port: 0
|
||||
grpc_listen_conn_limit: 0
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
http_tls_config:
|
||||
cert: ""
|
||||
key: null
|
||||
client_ca: ""
|
||||
cert_file: ""
|
||||
key_file: ""
|
||||
client_auth_type: ""
|
||||
client_ca_file: ""
|
||||
grpc_tls_config:
|
||||
cert: ""
|
||||
key: null
|
||||
client_ca: ""
|
||||
cert_file: ""
|
||||
key_file: ""
|
||||
client_auth_type: ""
|
||||
client_ca_file: ""
|
||||
register_instrumentation: false
|
||||
report_grpc_codes_in_instrumentation_label_enabled: false
|
||||
graceful_shutdown_timeout: 30s
|
||||
http_server_read_timeout: 30s
|
||||
http_server_read_header_timeout: 0s
|
||||
http_server_write_timeout: 30s
|
||||
http_server_idle_timeout: 2m0s
|
||||
http_log_closed_connections_without_response_enabled: false
|
||||
grpc_server_max_recv_msg_size: 0
|
||||
grpc_server_max_send_msg_size: 0
|
||||
grpc_server_max_concurrent_streams: 0
|
||||
grpc_server_max_connection_idle: 0s
|
||||
grpc_server_max_connection_age: 0s
|
||||
grpc_server_max_connection_age_grace: 0s
|
||||
grpc_server_keepalive_time: 0s
|
||||
grpc_server_keepalive_timeout: 0s
|
||||
grpc_server_min_time_between_pings: 0s
|
||||
grpc_server_ping_without_stream_allowed: false
|
||||
grpc_server_num_workers: 0
|
||||
log_format: logfmt
|
||||
log_level: info
|
||||
log_source_ips_enabled: false
|
||||
log_source_ips_header: ""
|
||||
log_source_ips_regex: ""
|
||||
log_request_headers: false
|
||||
log_request_at_info_level_enabled: false
|
||||
log_request_exclude_headers_list: ""
|
||||
http_path_prefix: ""
|
||||
enable: false
|
||||
distributor:
|
||||
ring:
|
||||
kvstore:
|
||||
store: memberlist
|
||||
prefix: collectors/
|
||||
consul:
|
||||
host: localhost:8500
|
||||
acl_token: ""
|
||||
http_client_timeout: 20s
|
||||
consistent_reads: false
|
||||
watch_rate_limit: 1
|
||||
watch_burst_size: 1
|
||||
cas_retry_delay: 1s
|
||||
etcd:
|
||||
endpoints: []
|
||||
dial_timeout: 10s
|
||||
max_retries: 10
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
username: ""
|
||||
password: ""
|
||||
multi:
|
||||
primary: ""
|
||||
secondary: ""
|
||||
mirror_enabled: false
|
||||
mirror_timeout: 2s
|
||||
heartbeat_period: 5s
|
||||
heartbeat_timeout: 5m0s
|
||||
instance_id: local-instance
|
||||
instance_interface_names:
|
||||
- eth0
|
||||
- en0
|
||||
instance_port: 0
|
||||
instance_addr: ""
|
||||
receivers: {}
|
||||
override_ring_key: distributor
|
||||
forwarders: []
|
||||
extend_writes: true
|
||||
retry_after_on_resource_exhausted: 0s
|
||||
ingester_client:
|
||||
pool_config:
|
||||
checkinterval: 15s
|
||||
healthcheckenabled: true
|
||||
healthchecktimeout: 1s
|
||||
maxconcurrenthealthchecks: 0
|
||||
remote_timeout: 5s
|
||||
grpc_client_config:
|
||||
max_recv_msg_size: 104857600
|
||||
max_send_msg_size: 104857600
|
||||
grpc_compression: snappy
|
||||
rate_limit: 0
|
||||
rate_limit_burst: 0
|
||||
backoff_on_ratelimits: false
|
||||
backoff_config:
|
||||
min_period: 100ms
|
||||
max_period: 10s
|
||||
max_retries: 10
|
||||
initial_stream_window_size: 63KiB1023B
|
||||
initial_connection_window_size: 63KiB1023B
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
connect_timeout: 5s
|
||||
connect_backoff_base_delay: 1s
|
||||
connect_backoff_max_delay: 5s
|
||||
metrics_generator_client:
|
||||
pool_config:
|
||||
checkinterval: 15s
|
||||
healthcheckenabled: true
|
||||
healthchecktimeout: 1s
|
||||
maxconcurrenthealthchecks: 0
|
||||
remote_timeout: 5s
|
||||
grpc_client_config:
|
||||
max_recv_msg_size: 104857600
|
||||
max_send_msg_size: 104857600
|
||||
grpc_compression: snappy
|
||||
rate_limit: 0
|
||||
rate_limit_burst: 0
|
||||
backoff_on_ratelimits: false
|
||||
backoff_config:
|
||||
min_period: 100ms
|
||||
max_period: 10s
|
||||
max_retries: 10
|
||||
initial_stream_window_size: 63KiB1023B
|
||||
initial_connection_window_size: 63KiB1023B
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
connect_timeout: 5s
|
||||
connect_backoff_base_delay: 1s
|
||||
connect_backoff_max_delay: 5s
|
||||
querier:
|
||||
search:
|
||||
query_timeout: 30s
|
||||
prefer_self: 10
|
||||
external_hedge_requests_at: 8s
|
||||
external_hedge_requests_up_to: 2
|
||||
external_backend: ""
|
||||
google_cloud_run: null
|
||||
external_endpoints: []
|
||||
trace_by_id:
|
||||
query_timeout: 10s
|
||||
max_concurrent_queries: 20
|
||||
frontend_worker:
|
||||
frontend_address: 127.0.0.1:9095
|
||||
dns_lookup_duration: 10s
|
||||
parallelism: 2
|
||||
match_max_concurrent: true
|
||||
id: ""
|
||||
grpc_client_config:
|
||||
max_recv_msg_size: 104857600
|
||||
max_send_msg_size: 16777216
|
||||
grpc_compression: gzip
|
||||
rate_limit: 0
|
||||
rate_limit_burst: 0
|
||||
backoff_on_ratelimits: false
|
||||
backoff_config:
|
||||
min_period: 100ms
|
||||
max_period: 1s
|
||||
max_retries: 5
|
||||
initial_stream_window_size: 0B
|
||||
initial_connection_window_size: 0B
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
connect_timeout: 0s
|
||||
connect_backoff_base_delay: 0s
|
||||
connect_backoff_max_delay: 0s
|
||||
query_relevant_ingesters: false
|
||||
query_frontend:
|
||||
max_outstanding_per_tenant: 2000
|
||||
querier_forget_delay: 0s
|
||||
max_batch_size: 5
|
||||
max_retries: 2
|
||||
search:
|
||||
concurrent_jobs: 1000
|
||||
target_bytes_per_job: 104857600
|
||||
default_result_limit: 20
|
||||
max_result_limit: 0
|
||||
max_duration: 168h0m0s
|
||||
query_backend_after: 15m0s
|
||||
query_ingesters_until: 30m0s
|
||||
trace_by_id:
|
||||
query_shards: 50
|
||||
hedge_requests_at: 2s
|
||||
hedge_requests_up_to: 2
|
||||
metrics:
|
||||
concurrent_jobs: 1000
|
||||
target_bytes_per_job: 104857600
|
||||
max_duration: 0s
|
||||
query_backend_after: 1h0m0s
|
||||
interval: 5m0s
|
||||
multi_tenant_queries_enabled: true
|
||||
compactor:
|
||||
ring:
|
||||
kvstore:
|
||||
store: ""
|
||||
prefix: collectors/
|
||||
consul:
|
||||
host: localhost:8500
|
||||
acl_token: ""
|
||||
http_client_timeout: 20s
|
||||
consistent_reads: false
|
||||
watch_rate_limit: 1
|
||||
watch_burst_size: 1
|
||||
cas_retry_delay: 1s
|
||||
etcd:
|
||||
endpoints: []
|
||||
dial_timeout: 10s
|
||||
max_retries: 10
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
username: ""
|
||||
password: ""
|
||||
multi:
|
||||
primary: ""
|
||||
secondary: ""
|
||||
mirror_enabled: false
|
||||
mirror_timeout: 2s
|
||||
heartbeat_period: 5s
|
||||
heartbeat_timeout: 1m0s
|
||||
wait_stability_min_duration: 1m0s
|
||||
wait_stability_max_duration: 5m0s
|
||||
instance_id: local-instance
|
||||
instance_interface_names:
|
||||
- eth0
|
||||
- en0
|
||||
instance_port: 0
|
||||
instance_addr: ""
|
||||
enable_inet6: false
|
||||
wait_active_instance_timeout: 10m0s
|
||||
compaction:
|
||||
v2_in_buffer_bytes: 5242880
|
||||
v2_out_buffer_bytes: 20971520
|
||||
v2_prefetch_traces_count: 1000
|
||||
compaction_window: 1h0m0s
|
||||
max_compaction_objects: 6000000
|
||||
max_block_bytes: 107374182400
|
||||
block_retention: 336h0m0s
|
||||
compacted_block_retention: 1h0m0s
|
||||
retention_concurrency: 10
|
||||
max_time_per_tenant: 5m0s
|
||||
compaction_cycle: 30s
|
||||
override_ring_key: compactor
|
||||
ingester:
|
||||
lifecycler:
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
prefix: collectors/
|
||||
consul:
|
||||
host: localhost:8500
|
||||
acl_token: ""
|
||||
http_client_timeout: 20s
|
||||
consistent_reads: false
|
||||
watch_rate_limit: 1
|
||||
watch_burst_size: 1
|
||||
cas_retry_delay: 1s
|
||||
etcd:
|
||||
endpoints: []
|
||||
dial_timeout: 10s
|
||||
max_retries: 10
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
username: ""
|
||||
password: ""
|
||||
multi:
|
||||
primary: ""
|
||||
secondary: ""
|
||||
mirror_enabled: false
|
||||
mirror_timeout: 2s
|
||||
heartbeat_timeout: 5m0s
|
||||
replication_factor: 1
|
||||
zone_awareness_enabled: false
|
||||
excluded_zones: ""
|
||||
num_tokens: 128
|
||||
heartbeat_period: 5s
|
||||
heartbeat_timeout: 1m0s
|
||||
observe_period: 0s
|
||||
join_after: 0s
|
||||
min_ready_duration: 15s
|
||||
interface_names:
|
||||
- en0
|
||||
- bridge100
|
||||
enable_inet6: false
|
||||
final_sleep: 0s
|
||||
tokens_file_path: ""
|
||||
availability_zone: ""
|
||||
unregister_on_shutdown: true
|
||||
readiness_check_ring_health: true
|
||||
address: 127.0.0.1
|
||||
port: 0
|
||||
id: local-instance
|
||||
concurrent_flushes: 4
|
||||
flush_check_period: 10s
|
||||
flush_op_timeout: 5m0s
|
||||
trace_idle_period: 10s
|
||||
max_block_duration: 30m0s
|
||||
max_block_bytes: 524288000
|
||||
complete_block_timeout: 15m0s
|
||||
override_ring_key: ring
|
||||
flush_all_on_shutdown: false
|
||||
metrics_generator:
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
prefix: collectors/
|
||||
consul:
|
||||
host: localhost:8500
|
||||
acl_token: ""
|
||||
http_client_timeout: 20s
|
||||
consistent_reads: false
|
||||
watch_rate_limit: 1
|
||||
watch_burst_size: 1
|
||||
cas_retry_delay: 1s
|
||||
etcd:
|
||||
endpoints: []
|
||||
dial_timeout: 10s
|
||||
max_retries: 10
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
username: ""
|
||||
password: ""
|
||||
multi:
|
||||
primary: ""
|
||||
secondary: ""
|
||||
mirror_enabled: false
|
||||
mirror_timeout: 2s
|
||||
heartbeat_period: 5s
|
||||
heartbeat_timeout: 1m0s
|
||||
instance_id: local-instance
|
||||
instance_interface_names:
|
||||
- eth0
|
||||
- en0
|
||||
instance_addr: 127.0.0.1
|
||||
instance_port: 0
|
||||
enable_inet6: false
|
||||
processor:
|
||||
service_graphs:
|
||||
wait: 10s
|
||||
max_items: 10000
|
||||
workers: 10
|
||||
histogram_buckets:
|
||||
- 0.1
|
||||
- 0.2
|
||||
- 0.4
|
||||
- 0.8
|
||||
- 1.6
|
||||
- 3.2
|
||||
- 6.4
|
||||
- 12.8
|
||||
dimensions: []
|
||||
enable_client_server_prefix: false
|
||||
peer_attributes:
|
||||
- peer.service
|
||||
- db.name
|
||||
- db.system
|
||||
span_multiplier_key: ""
|
||||
span_metrics:
|
||||
histogram_buckets:
|
||||
- 0.002
|
||||
- 0.004
|
||||
- 0.008
|
||||
- 0.016
|
||||
- 0.032
|
||||
- 0.064
|
||||
- 0.128
|
||||
- 0.256
|
||||
- 0.512
|
||||
- 1.024
|
||||
- 2.048
|
||||
- 4.096
|
||||
- 8.192
|
||||
- 16.384
|
||||
intrinsic_dimensions:
|
||||
service: true
|
||||
span_name: true
|
||||
span_kind: true
|
||||
status_code: true
|
||||
dimensions: []
|
||||
dimension_mappings: []
|
||||
enable_target_info: false
|
||||
span_multiplier_key: ""
|
||||
subprocessors:
|
||||
0: true
|
||||
1: true
|
||||
2: true
|
||||
filter_policies: []
|
||||
target_info_excluded_dimensions: []
|
||||
local_blocks:
|
||||
block:
|
||||
bloom_filter_false_positive: 0.01
|
||||
bloom_filter_shard_size_bytes: 102400
|
||||
version: vParquet3
|
||||
search_encoding: snappy
|
||||
search_page_size_bytes: 1048576
|
||||
v2_index_downsample_bytes: 1048576
|
||||
v2_index_page_size_bytes: 256000
|
||||
v2_encoding: zstd
|
||||
parquet_row_group_size_bytes: 100000000
|
||||
parquet_dedicated_columns: []
|
||||
search:
|
||||
chunk_size_bytes: 1000000
|
||||
prefetch_trace_count: 1000
|
||||
read_buffer_count: 32
|
||||
read_buffer_size_bytes: 1048576
|
||||
cache_control:
|
||||
footer: false
|
||||
column_index: false
|
||||
offset_index: false
|
||||
flush_check_period: 10s
|
||||
trace_idle_period: 10s
|
||||
max_block_duration: 1m0s
|
||||
max_block_bytes: 500000000
|
||||
complete_block_timeout: 1h0m0s
|
||||
max_live_traces: 0
|
||||
concurrent_blocks: 10
|
||||
filter_server_spans: true
|
||||
registry:
|
||||
collection_interval: 15s
|
||||
stale_duration: 15m0s
|
||||
max_label_name_length: 1024
|
||||
max_label_value_length: 2048
|
||||
storage:
|
||||
path: ""
|
||||
wal:
|
||||
wal_segment_size: 134217728
|
||||
wal_compression: none
|
||||
stripe_size: 16384
|
||||
truncate_frequency: 2h0m0s
|
||||
min_wal_time: 300000
|
||||
max_wal_time: 14400000
|
||||
no_lockfile: false
|
||||
remote_write_flush_deadline: 1m0s
|
||||
remote_write_add_org_id_header: true
|
||||
traces_storage:
|
||||
path: ""
|
||||
completedfilepath: ""
|
||||
blocksfilepath: ""
|
||||
v2_encoding: none
|
||||
search_encoding: none
|
||||
ingestion_time_range_slack: 0s
|
||||
version: vParquet3
|
||||
metrics_ingestion_time_range_slack: 30s
|
||||
query_timeout: 30s
|
||||
override_ring_key: metrics-generator
|
||||
storage:
|
||||
trace:
|
||||
pool:
|
||||
max_workers: 400
|
||||
queue_depth: 20000
|
||||
wal:
|
||||
path: /tmp/tempo/wal
|
||||
completedfilepath: /tmp/tempo/wal/completed
|
||||
blocksfilepath: /tmp/tempo/wal/blocks
|
||||
v2_encoding: snappy
|
||||
search_encoding: none
|
||||
ingestion_time_range_slack: 2m0s
|
||||
version: vParquet3
|
||||
block:
|
||||
bloom_filter_false_positive: 0.01
|
||||
bloom_filter_shard_size_bytes: 102400
|
||||
version: vParquet3
|
||||
search_encoding: snappy
|
||||
search_page_size_bytes: 1048576
|
||||
v2_index_downsample_bytes: 1048576
|
||||
v2_index_page_size_bytes: 256000
|
||||
v2_encoding: zstd
|
||||
parquet_row_group_size_bytes: 100000000
|
||||
parquet_dedicated_columns: []
|
||||
search:
|
||||
chunk_size_bytes: 1000000
|
||||
prefetch_trace_count: 1000
|
||||
read_buffer_count: 32
|
||||
read_buffer_size_bytes: 1048576
|
||||
cache_control:
|
||||
footer: false
|
||||
column_index: false
|
||||
offset_index: false
|
||||
blocklist_poll: 5m0s
|
||||
blocklist_poll_concurrency: 50
|
||||
blocklist_poll_fallback: true
|
||||
blocklist_poll_tenant_index_builders: 2
|
||||
blocklist_poll_stale_tenant_index: 0s
|
||||
blocklist_poll_jitter_ms: 0
|
||||
blocklist_poll_tolerate_consecutive_errors: 1
|
||||
backend: local
|
||||
local:
|
||||
path: /tmp/tempo/traces
|
||||
gcs:
|
||||
bucket_name: ""
|
||||
prefix: ""
|
||||
chunk_buffer_size: 10485760
|
||||
endpoint: ""
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
insecure: false
|
||||
object_cache_control: ""
|
||||
object_metadata: {}
|
||||
list_blocks_concurrency: 3
|
||||
s3:
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: VersionTLS12
|
||||
bucket: ""
|
||||
prefix: ""
|
||||
endpoint: ""
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
session_token: ""
|
||||
insecure: false
|
||||
part_size: 0
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
signature_v2: false
|
||||
forcepathstyle: false
|
||||
bucket_lookup_type: 0
|
||||
tags: {}
|
||||
storage_class: ""
|
||||
metadata: {}
|
||||
native_aws_auth_enabled: false
|
||||
list_blocks_concurrency: 3
|
||||
azure:
|
||||
storage_account_name: ""
|
||||
storage_account_key: ""
|
||||
use_managed_identity: false
|
||||
use_federated_token: false
|
||||
user_assigned_id: ""
|
||||
container_name: ""
|
||||
prefix: ""
|
||||
endpoint_suffix: blob.core.windows.net
|
||||
max_buffers: 4
|
||||
buffer_size: 3145728
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
use_v2_sdk: false
|
||||
cache: ""
|
||||
background_cache:
|
||||
writeback_goroutines: 10
|
||||
writeback_buffer: 10000
|
||||
memcached: null
|
||||
redis: null
|
||||
cache_min_compaction_level: 0
|
||||
cache_max_block_age: 0s
|
||||
overrides:
|
||||
defaults:
|
||||
ingestion:
|
||||
rate_strategy: local
|
||||
rate_limit_bytes: 15000000
|
||||
burst_size_bytes: 20000000
|
||||
max_traces_per_user: 10000
|
||||
read:
|
||||
max_bytes_per_tag_values_query: 5000000
|
||||
global:
|
||||
max_bytes_per_trace: 5000000
|
||||
per_tenant_override_config: ""
|
||||
per_tenant_override_period: 10s
|
||||
user_configurable_overrides:
|
||||
enabled: false
|
||||
poll_interval: 1m0s
|
||||
client:
|
||||
backend: ""
|
||||
confirm_versioning: true
|
||||
local:
|
||||
path: ""
|
||||
gcs:
|
||||
bucket_name: ""
|
||||
prefix: ""
|
||||
chunk_buffer_size: 10485760
|
||||
endpoint: ""
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
insecure: false
|
||||
object_cache_control: ""
|
||||
object_metadata: {}
|
||||
list_blocks_concurrency: 3
|
||||
s3:
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: VersionTLS12
|
||||
bucket: ""
|
||||
prefix: ""
|
||||
endpoint: ""
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
session_token: ""
|
||||
insecure: false
|
||||
part_size: 0
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
signature_v2: false
|
||||
forcepathstyle: false
|
||||
bucket_lookup_type: 0
|
||||
tags: {}
|
||||
storage_class: ""
|
||||
metadata: {}
|
||||
native_aws_auth_enabled: false
|
||||
list_blocks_concurrency: 3
|
||||
azure:
|
||||
storage_account_name: ""
|
||||
storage_account_key: ""
|
||||
use_managed_identity: false
|
||||
use_federated_token: false
|
||||
user_assigned_id: ""
|
||||
container_name: ""
|
||||
prefix: ""
|
||||
endpoint_suffix: blob.core.windows.net
|
||||
max_buffers: 4
|
||||
buffer_size: 3145728
|
||||
hedge_requests_at: 0s
|
||||
hedge_requests_up_to: 2
|
||||
use_v2_sdk: false
|
||||
api:
|
||||
check_for_conflicting_runtime_overrides: false
|
||||
memberlist:
|
||||
node_name: ""
|
||||
randomize_node_name: true
|
||||
stream_timeout: 2s
|
||||
retransmit_factor: 2
|
||||
pull_push_interval: 30s
|
||||
gossip_interval: 1s
|
||||
gossip_nodes: 2
|
||||
gossip_to_dead_nodes_time: 30s
|
||||
dead_node_reclaim_time: 0s
|
||||
compression_enabled: false
|
||||
advertise_addr: ""
|
||||
advertise_port: 7946
|
||||
cluster_label: ""
|
||||
cluster_label_verification_disabled: false
|
||||
join_members: []
|
||||
min_join_backoff: 1s
|
||||
max_join_backoff: 1m0s
|
||||
max_join_retries: 10
|
||||
abort_if_cluster_join_fails: false
|
||||
rejoin_interval: 0s
|
||||
left_ingesters_timeout: 5m0s
|
||||
leave_timeout: 20s
|
||||
message_history_buffer_bytes: 0
|
||||
bind_addr: []
|
||||
bind_port: 7946
|
||||
packet_dial_timeout: 2s
|
||||
packet_write_timeout: 5s
|
||||
tls_enabled: false
|
||||
tls_cert_path: ""
|
||||
tls_key_path: ""
|
||||
tls_ca_path: ""
|
||||
tls_server_name: ""
|
||||
tls_insecure_skip_verify: false
|
||||
tls_cipher_suites: ""
|
||||
tls_min_version: ""
|
||||
usage_report:
|
||||
reporting_enabled: true
|
||||
backoff:
|
||||
min_period: 100ms
|
||||
max_period: 10s
|
||||
max_retries: 0
|
||||
cache:
|
||||
background:
|
||||
writeback_goroutines: 10
|
||||
writeback_buffer: 10000
|
||||
caches: []
|
||||
@@ -1,54 +0,0 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
|
||||
server:
|
||||
http_listen_port: 3200
|
||||
|
||||
distributor:
|
||||
receivers: # this configuration will listen on all ports and protocols that tempo is capable of.
|
||||
jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can
|
||||
protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver
|
||||
thrift_http: #
|
||||
grpc: # for a production deployment you should only enable the receivers you need!
|
||||
thrift_binary:
|
||||
thrift_compact:
|
||||
zipkin:
|
||||
otlp:
|
||||
protocols:
|
||||
http:
|
||||
grpc:
|
||||
opencensus:
|
||||
|
||||
ingester:
|
||||
max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally
|
||||
|
||||
compactor:
|
||||
compaction:
|
||||
block_retention: 1h # overall Tempo trace retention. set for demo purposes
|
||||
|
||||
# metrics_generator:
|
||||
# registry:
|
||||
# external_labels:
|
||||
# source: tempo
|
||||
# cluster: docker-compose
|
||||
# storage:
|
||||
# path: /tmp/tempo/generator/wal
|
||||
# remote_write:
|
||||
# - url: http://grafana-alloy:12345/api/v1/write
|
||||
# send_exemplars: true
|
||||
|
||||
storage:
|
||||
trace:
|
||||
backend: s3 # backend configuration to use
|
||||
wal:
|
||||
path: /tmp/tempo/wal # where to store the the wal locally
|
||||
s3:
|
||||
bucket: tempo # how to store data in s3
|
||||
endpoint: minio:9000
|
||||
access_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['MINIO_TEMPO_STORAGE_ACCESS_KEY'] }}
|
||||
secret_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['MINIO_TEMPO_STORAGE_SECRET_KEY'] }}
|
||||
insecure: true
|
||||
|
||||
usage_report:
|
||||
reporting_enabled: false
|
||||
@@ -31,3 +31,9 @@
|
||||
url: http://192.168.1.252:8123
|
||||
key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['HOMEPAGE_HOME_ASSISTANT_API_KEY'] }}
|
||||
|
||||
- Media Library:
|
||||
- Audiomuse:
|
||||
href: https://muse.trez.wtf
|
||||
description: Automatic playlist generation using AI
|
||||
icon: /icons/audiomuseai.png
|
||||
weight: 0
|
||||
@@ -1,10 +1,10 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
containers:
|
||||
adguard:
|
||||
action_keywords:
|
||||
- restart:
|
||||
regex: '\[error\] dnsproxy.*timeout'
|
||||
# adguard:
|
||||
# action_keywords:
|
||||
# - restart:
|
||||
# regex: '\[error\] dnsproxy.*timeout'
|
||||
ghost_blog:
|
||||
action_keywords:
|
||||
- restart:
|
||||
|
||||
@@ -26,17 +26,6 @@
|
||||
},
|
||||
|
||||
"sources": [
|
||||
{
|
||||
"type": "spotify",
|
||||
"enabled": true,
|
||||
"name": "spotifySource",
|
||||
"clients": ["lastFmClient", "ListenBrainzClient", "malojaClient"],
|
||||
"data": {
|
||||
"clientId": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['YOUR_SPOTIFY_ID'] }}",
|
||||
"clientSecret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['YOUR_SPOTIFY_SECRET'] }}",
|
||||
"redirectUri": "https://scrobble.trez.wtf/callback"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lastfm",
|
||||
"enabled": true,
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
[botdetection]
|
||||
|
||||
# The prefix defines the number of leading bits in an address that are compared
|
||||
# to determine whether or not an address is part of a (client) network.
|
||||
|
||||
ipv4_prefix = 32
|
||||
ipv6_prefix = 48
|
||||
|
||||
# If the request IP is in trusted_proxies list, the client IP address is
|
||||
# extracted from the X-Forwarded-For and X-Real-IP headers. This should be
|
||||
# used if SearXNG is behind a reverse proxy or load balancer.
|
||||
|
||||
trusted_proxies = [
|
||||
'127.0.0.0/8',
|
||||
'::1',
|
||||
'192.168.0.0/16',
|
||||
'172.16.0.0/12',
|
||||
'172.17.0.0/12',
|
||||
'172.18.0.0/12'
|
||||
# '10.0.0.0/8',
|
||||
# 'fd00::/8',
|
||||
]
|
||||
|
||||
[botdetection.ip_limit]
|
||||
|
||||
# To get unlimited access in a local network, by default link-local addresses
|
||||
# (networks) are not monitored by the ip_limit
|
||||
filter_link_local = false
|
||||
|
||||
# activate link_token method in the ip_limit method
|
||||
link_token = false
|
||||
|
||||
[botdetection.ip_lists]
|
||||
|
||||
# In the limiter, the ip_lists method has priority over all other methods -> if
|
||||
# an IP is in the pass_ip list, it has unrestricted access and it is also not
|
||||
# checked if e.g. the "user agent" suggests a bot (e.g. curl).
|
||||
|
||||
block_ip = [
|
||||
# '93.184.216.34', # IPv4 of example.org
|
||||
# '257.1.1.1', # invalid IP --> will be ignored, logged in ERROR class
|
||||
]
|
||||
|
||||
pass_ip = [
|
||||
# '192.168.0.0/16', # IPv4 private network
|
||||
# 'fe80::/10' # IPv6 linklocal / wins over botdetection.ip_limit.filter_link_local
|
||||
'192.168.0.0/16',
|
||||
'172.16.0.0/12',
|
||||
'172.17.0.0/12',
|
||||
'172.18.0.0/12'
|
||||
]
|
||||
|
||||
# Activate passlist of (hardcoded) IPs from the SearXNG organization,
|
||||
# e.g. `check.searx.space`.
|
||||
pass_searxng_org = true
|
||||
@@ -1,5 +1,6 @@
|
||||
{% set vault_addr = 'https://vault.trez.wtf' %}
|
||||
{% set secrets_path = 'rinoa-docker/env' %}
|
||||
|
||||
general:
|
||||
# Debug mode, only for development. Is overwritten by ${SEARXNG_DEBUG}
|
||||
debug: false
|
||||
@@ -16,7 +17,6 @@ general:
|
||||
enable_metrics: true
|
||||
# expose stats in open metrics format at /metrics
|
||||
# leave empty to disable (no password set)
|
||||
# open_metrics: <password>
|
||||
open_metrics: ''
|
||||
|
||||
brand:
|
||||
@@ -25,87 +25,35 @@ brand:
|
||||
public_instances: https://searx.space
|
||||
wiki_url: https://github.com/searxng/searxng/wiki
|
||||
issue_url: https://github.com/searxng/searxng/issues
|
||||
# custom:
|
||||
# maintainer: "Jon Doe"
|
||||
# # Custom entries in the footer: [title]: [link]
|
||||
# links:
|
||||
# Uptime: https://uptime.searxng.org/history/darmarit-org
|
||||
# About: "https://searxng.org"
|
||||
|
||||
search:
|
||||
# Filter results. 0: None, 1: Moderate, 2: Strict
|
||||
safe_search: 0
|
||||
# Existing autocomplete backends: "360search", "baidu", "brave", "dbpedia", "duckduckgo", "google", "yandex",
|
||||
# "mwmbl", "naver", "seznam", "sogou", "startpage", "stract", "swisscows", "quark", "qwant", "wikipedia" -
|
||||
# leave blank to turn it off by default.
|
||||
autocomplete: ""
|
||||
# minimun characters to type before autocompleter starts
|
||||
autocomplete_min: 4
|
||||
# backend for the favicon near URL in search results.
|
||||
# Available resolvers: "allesedv", "duckduckgo", "google", "yandex" - leave blank to turn it off by default.
|
||||
favicon_resolver: ""
|
||||
# Default search language - leave blank to detect from browser information or
|
||||
# use codes from 'languages.py'
|
||||
default_lang: "auto"
|
||||
# max_page: 0 # if engine supports paging, 0 means unlimited numbers of pages
|
||||
# Available languages
|
||||
# languages:
|
||||
# - all
|
||||
# - en
|
||||
# - en-US
|
||||
# - de
|
||||
# - it-IT
|
||||
# - fr
|
||||
# - fr-BE
|
||||
# ban time in seconds after engine errors
|
||||
ban_time_on_fail: 5
|
||||
# max ban time in seconds after engine errors
|
||||
max_ban_time_on_fail: 120
|
||||
suspended_times:
|
||||
# Engine suspension time after error (in seconds; set to 0 to disable)
|
||||
# For error "Access denied" and "HTTP error [402, 403]"
|
||||
SearxEngineAccessDenied: 86400
|
||||
# For error "CAPTCHA"
|
||||
SearxEngineCaptcha: 86400
|
||||
# For error "Too many request" and "HTTP error 429"
|
||||
SearxEngineTooManyRequests: 3600
|
||||
# Cloudflare CAPTCHA
|
||||
cf_SearxEngineCaptcha: 1296000
|
||||
cf_SearxEngineAccessDenied: 86400
|
||||
# ReCAPTCHA
|
||||
recaptcha_SearxEngineCaptcha: 604800
|
||||
|
||||
# remove format to deny access, use lower case.
|
||||
# formats: [html, csv, json, rss]
|
||||
formats:
|
||||
- html
|
||||
|
||||
server:
|
||||
# Is overwritten by ${SEARXNG_PORT} and ${SEARXNG_BIND_ADDRESS}
|
||||
port: 8888
|
||||
bind_address: "127.0.0.1"
|
||||
# public URL of the instance, to ensure correct inbound links. Is overwritten
|
||||
# by ${SEARXNG_BASE_URL}.
|
||||
base_url: false # "http://example.com/location"
|
||||
# rate limit the number of request on the instance, block some bots.
|
||||
# Is overwritten by ${SEARXNG_LIMITER}
|
||||
base_url: false
|
||||
limiter: false
|
||||
# enable features designed only for public instances.
|
||||
# Is overwritten by ${SEARXNG_PUBLIC_INSTANCE}
|
||||
public_instance: false
|
||||
|
||||
# If your instance owns a /etc/searxng/settings.yml file, then set the following
|
||||
# values there.
|
||||
|
||||
secret_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token)['secret']['SEARXNG_SECRET_KEY'] }} # Is overwritten by ${SEARXNG_SECRET}
|
||||
# Proxy image results through SearXNG. Is overwritten by ${SEARXNG_IMAGE_PROXY}
|
||||
image_proxy: true
|
||||
# 1.0 and 1.1 are supported
|
||||
http_protocol_version: "1.0"
|
||||
# POST queries are "more secure!" but are also the source of hard-to-locate
|
||||
# annoyances, which is why GET may be better for end users and their browsers.
|
||||
# see https://github.com/searxng/searxng/pull/3619
|
||||
# Is overwritten by ${SEARXNG_METHOD}
|
||||
method: "POST"
|
||||
default_http_headers:
|
||||
X-Content-Type-Options: nosniff
|
||||
@@ -114,41 +62,20 @@ server:
|
||||
Referrer-Policy: no-referrer
|
||||
|
||||
valkey:
|
||||
# URL to connect valkey database. Is overwritten by ${SEARXNG_VALKEY_URL}.
|
||||
# https://docs.searxng.org/admin/settings/settings_valkey.html#settings-valkey
|
||||
# url: valkey://localhost:6379/0
|
||||
url: redis://searxng-valkey:6379/0
|
||||
|
||||
ui:
|
||||
# Custom static path - leave it blank if you didn't change
|
||||
static_path: ""
|
||||
# Custom templates path - leave it blank if you didn't change
|
||||
templates_path: ""
|
||||
# query_in_title: When true, the result page's titles contains the query
|
||||
# it decreases the privacy, since the browser can records the page titles.
|
||||
query_in_title: true
|
||||
# infinite_scroll: When true, automatically loads the next page when scrolling to bottom of the current page.
|
||||
infinite_scroll: true
|
||||
# ui theme
|
||||
default_theme: simple
|
||||
# center the results ?
|
||||
center_alignment: false
|
||||
# URL prefix of the internet archive, don't forget trailing slash (if needed).
|
||||
# cache_url: "https://webcache.googleusercontent.com/search?q=cache:"
|
||||
# Default interface locale - leave blank to detect from browser information or
|
||||
# use codes from the 'locales' config section
|
||||
default_locale: ""
|
||||
# Open result links in a new tab by default
|
||||
# results_on_new_tab: false
|
||||
theme_args:
|
||||
# style of simple theme: auto, light, dark
|
||||
simple_style: auto
|
||||
# Perform search immediately if a category selected.
|
||||
# Disable to select multiple categories at once and start the search manually.
|
||||
search_on_category_select: true
|
||||
# Hotkeys: default or vim
|
||||
hotkeys: default
|
||||
# URL formatting: pretty, full or host
|
||||
url_formatting: pretty
|
||||
|
||||
# Lock arbitrary settings on the preferences page.
|
||||
@@ -165,7 +92,6 @@ ui:
|
||||
# - locale
|
||||
# - theme
|
||||
# - results_on_new_tab
|
||||
# - infinite_scroll
|
||||
# - search_on_category_select
|
||||
# - method
|
||||
# - image_proxy
|
||||
@@ -177,7 +103,7 @@ outgoing:
|
||||
# default timeout in seconds, can be override by engine
|
||||
request_timeout: 3.0
|
||||
# the maximum timeout in seconds
|
||||
# max_request_timeout: 10.0
|
||||
max_request_timeout: 10.0
|
||||
# suffix of searxng_useragent, could contain information like an email address
|
||||
# to the administrator
|
||||
useragent_suffix: ""
|
||||
@@ -217,6 +143,7 @@ outgoing:
|
||||
# - 1.1.1.2
|
||||
# - fe80::/126
|
||||
|
||||
|
||||
# Plugin configuration, for more details see
|
||||
# https://docs.searxng.org/admin/settings/settings_plugins.html
|
||||
#
|
||||
@@ -225,6 +152,9 @@ plugins:
|
||||
searx.plugins.calculator.SXNGPlugin:
|
||||
active: true
|
||||
|
||||
searx.plugins.infinite_scroll.SXNGPlugin:
|
||||
active: true
|
||||
|
||||
searx.plugins.hash_plugin.SXNGPlugin:
|
||||
active: true
|
||||
|
||||
@@ -390,25 +320,6 @@ engines:
|
||||
timeout: 6
|
||||
disabled: true
|
||||
|
||||
- name: alexandria
|
||||
engine: json_engine
|
||||
shortcut: alx
|
||||
categories: general
|
||||
paging: true
|
||||
search_url: https://api.alexandria.org/?a=1&q={query}&p={pageno}
|
||||
results_query: results
|
||||
title_query: title
|
||||
url_query: url
|
||||
content_query: snippet
|
||||
timeout: 1.5
|
||||
disabled: true
|
||||
about:
|
||||
website: https://alexandria.org/
|
||||
official_api_documentation: https://github.com/alexandria-org/alexandria-api/raw/master/README.md
|
||||
use_official_api: true
|
||||
require_api_key: false
|
||||
results: JSON
|
||||
|
||||
- name: astrophysics data system
|
||||
engine: astrophysics_data_system
|
||||
shortcut: ads
|
||||
@@ -498,6 +409,15 @@ engines:
|
||||
shortcut: ask
|
||||
disabled: true
|
||||
|
||||
# - name: azure
|
||||
# engine: azure
|
||||
# shortcut: az
|
||||
# categories: [it, cloud]
|
||||
# azure_tenant_id: "your_tenant_id"
|
||||
# azure_client_id: "your_client_id"
|
||||
# azure_client_secret: "your_client_secret"
|
||||
# disabled: true
|
||||
|
||||
# tmp suspended: dh key too small
|
||||
# - name: base
|
||||
# engine: base
|
||||
@@ -667,12 +587,6 @@ engines:
|
||||
api_key: ""
|
||||
inactive: true
|
||||
|
||||
# - name: cppreference
|
||||
# engine: cppreference
|
||||
# shortcut: cpp
|
||||
# paging: false
|
||||
# disabled: true
|
||||
|
||||
- name: crossref
|
||||
engine: crossref
|
||||
shortcut: cr
|
||||
@@ -736,6 +650,11 @@ engines:
|
||||
shortcut: da
|
||||
timeout: 3.0
|
||||
|
||||
- name: devicons
|
||||
engine: devicons
|
||||
shortcut: di
|
||||
timeout: 3.0
|
||||
|
||||
- name: ddg definitions
|
||||
engine: duckduckgo_definitions
|
||||
shortcut: ddd
|
||||
@@ -1072,6 +991,12 @@ engines:
|
||||
play_categ: movies
|
||||
disabled: true
|
||||
|
||||
- name: grokipedia
|
||||
engine: grokipedia
|
||||
shortcut: gp
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: material icons
|
||||
engine: material_icons
|
||||
shortcut: mi
|
||||
@@ -1300,6 +1225,11 @@ engines:
|
||||
require_api_key: false
|
||||
results: HTML
|
||||
|
||||
- name: lucide
|
||||
engine: lucide
|
||||
shortcut: luc
|
||||
timeout: 3.0
|
||||
|
||||
- name: marginalia
|
||||
engine: marginalia
|
||||
shortcut: mar
|
||||
@@ -1434,22 +1364,6 @@ engines:
|
||||
require_api_key: false
|
||||
results: JSON
|
||||
|
||||
# https://docs.searxng.org/dev/engines/online/mullvad_leta.html
|
||||
- name: mullvadleta
|
||||
engine: mullvad_leta
|
||||
disabled: true
|
||||
leta_engine: google
|
||||
categories: [general, web]
|
||||
shortcut: ml
|
||||
|
||||
- name: mullvadleta brave
|
||||
engine: mullvad_leta
|
||||
network: mullvadleta
|
||||
disabled: true
|
||||
leta_engine: brave
|
||||
categories: [general, web]
|
||||
shortcut: mlb
|
||||
|
||||
- name: odysee
|
||||
engine: odysee
|
||||
shortcut: od
|
||||
@@ -1640,6 +1554,7 @@ engines:
|
||||
engine: pixiv
|
||||
disabled: true
|
||||
inactive: true
|
||||
remove_ai_images: false
|
||||
pixiv_image_proxies:
|
||||
- https://pximg.example.org
|
||||
# A proxy is required to load the images. Hosting an image proxy server
|
||||
@@ -2134,22 +2049,21 @@ engines:
|
||||
search_type: web
|
||||
shortcut: yd
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: yandex images
|
||||
engine: yandex
|
||||
network: yandex
|
||||
categories: images
|
||||
search_type: images
|
||||
shortcut: ydi
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: yandex music
|
||||
engine: yandex_music
|
||||
network: yandex
|
||||
shortcut: ydm
|
||||
disabled: true
|
||||
# https://yandex.com/support/music/access.html
|
||||
inactive: true
|
||||
|
||||
- name: yahoo
|
||||
engine: yahoo
|
||||
@@ -2298,31 +2212,27 @@ engines:
|
||||
|
||||
- name: wikicommons.images
|
||||
engine: wikicommons
|
||||
shortcut: wc
|
||||
shortcut: wci
|
||||
categories: images
|
||||
search_type: images
|
||||
number_of_results: 10
|
||||
wc_search_type: image
|
||||
|
||||
- name: wikicommons.videos
|
||||
engine: wikicommons
|
||||
shortcut: wcv
|
||||
categories: videos
|
||||
search_type: videos
|
||||
number_of_results: 10
|
||||
wc_search_type: video
|
||||
|
||||
- name: wikicommons.audio
|
||||
engine: wikicommons
|
||||
shortcut: wca
|
||||
categories: music
|
||||
search_type: audio
|
||||
number_of_results: 10
|
||||
wc_search_type: audio
|
||||
|
||||
- name: wikicommons.files
|
||||
engine: wikicommons
|
||||
shortcut: wcf
|
||||
categories: files
|
||||
search_type: files
|
||||
number_of_results: 10
|
||||
wc_search_type: file
|
||||
|
||||
- name: wolframalpha
|
||||
shortcut: wa
|
||||
@@ -2681,43 +2591,10 @@ engines:
|
||||
|
||||
- name: sourcehut
|
||||
shortcut: srht
|
||||
engine: xpath
|
||||
paging: true
|
||||
search_url: https://sr.ht/projects?page={pageno}&search={query}
|
||||
results_xpath: (//div[@class="event-list"])[1]/div[@class="event"]
|
||||
url_xpath: ./h4/a[2]/@href
|
||||
title_xpath: ./h4/a[2]
|
||||
content_xpath: ./p
|
||||
first_page_num: 1
|
||||
categories: [it, repos]
|
||||
engine: sourcehut
|
||||
# https://docs.searxng.org/dev/engines/online/sourcehut.html
|
||||
# sourcehut_sort_order: longest-active
|
||||
disabled: true
|
||||
about:
|
||||
website: https://sr.ht
|
||||
wikidata_id: Q78514485
|
||||
official_api_documentation: https://man.sr.ht/
|
||||
use_official_api: false
|
||||
require_api_key: false
|
||||
results: HTML
|
||||
|
||||
- name: goo
|
||||
shortcut: goo
|
||||
engine: xpath
|
||||
paging: true
|
||||
search_url: https://search.goo.ne.jp/web.jsp?MT={query}&FR={pageno}0
|
||||
url_xpath: //div[@class="result"]/p[@class='title fsL1']/a/@href
|
||||
title_xpath: //div[@class="result"]/p[@class='title fsL1']/a
|
||||
content_xpath: //p[contains(@class,'url fsM')]/following-sibling::p
|
||||
first_page_num: 0
|
||||
categories: [general, web]
|
||||
disabled: true
|
||||
timeout: 4.0
|
||||
about:
|
||||
website: https://search.goo.ne.jp
|
||||
wikidata_id: Q249044
|
||||
use_official_api: false
|
||||
require_api_key: false
|
||||
results: HTML
|
||||
language: ja
|
||||
|
||||
- name: bt4g
|
||||
engine: bt4g
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
## Version 2025/07/18
|
||||
# make sure that your <container_name> container is named <container_name>
|
||||
# make sure that your dns has a cname set for <container_name>
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
# listen 443 quic;
|
||||
listen [::]:443 ssl;
|
||||
# listen [::]:443 quic;
|
||||
|
||||
server_name muse.*;
|
||||
|
||||
include /config/nginx/ssl.conf;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
# enable for ldap auth (requires ldap-location.conf in the location block)
|
||||
#include /config/nginx/ldap-server.conf;
|
||||
|
||||
# enable for Authelia (requires authelia-location.conf in the location block)
|
||||
#include /config/nginx/authelia-server.conf;
|
||||
# enable for Authentik (requires authentik-location.conf in the location block)
|
||||
#include /config/nginx/authentik-server.conf;
|
||||
# enable for Tinyauth (requires tinyauth-location.conf in the location block)
|
||||
#include /config/nginx/tinyauth-server.conf;
|
||||
location / {
|
||||
# enable the next two lines for http auth
|
||||
#auth_basic "Restricted";
|
||||
#auth_basic_user_file /config/nginx/.htpasswd;
|
||||
|
||||
# enable for ldap auth (requires ldap-server.conf in the server block)
|
||||
#include /config/nginx/ldap-location.conf;
|
||||
|
||||
# enable for Authelia (requires authelia-server.conf in the server block)
|
||||
#include /config/nginx/authelia-location.conf;
|
||||
# enable for Authentik (requires authentik-server.conf in the server block)
|
||||
#include /config/nginx/authentik-location.conf;
|
||||
# enable for Tinyauth (requires tinyauth-server.conf in the server block)
|
||||
#include /config/nginx/tinyauth-location.conf;
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
set $upstream_app 192.168.1.248;
|
||||
set $upstream_port 8000;
|
||||
set $upstream_proto http;
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
## Version 2025/07/18
|
||||
# make sure that your <container_name> container is named <container_name>
|
||||
# make sure that your dns has a cname set for <container_name>
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
# listen 443 quic;
|
||||
listen [::]:443 ssl;
|
||||
# listen [::]:443 quic;
|
||||
|
||||
server_name cron.*;
|
||||
|
||||
include /config/nginx/ssl.conf;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
# enable for ldap auth (requires ldap-location.conf in the location block)
|
||||
#include /config/nginx/ldap-server.conf;
|
||||
|
||||
# enable for Authelia (requires authelia-location.conf in the location block)
|
||||
#include /config/nginx/authelia-server.conf;
|
||||
# enable for Authentik (requires authentik-location.conf in the location block)
|
||||
#include /config/nginx/authentik-server.conf;
|
||||
# enable for Tinyauth (requires tinyauth-location.conf in the location block)
|
||||
#include /config/nginx/tinyauth-server.conf;
|
||||
location / {
|
||||
# enable the next two lines for http auth
|
||||
#auth_basic "Restricted";
|
||||
#auth_basic_user_file /config/nginx/.htpasswd;
|
||||
|
||||
# enable for ldap auth (requires ldap-server.conf in the server block)
|
||||
#include /config/nginx/ldap-location.conf;
|
||||
|
||||
# enable for Authelia (requires authelia-server.conf in the server block)
|
||||
#include /config/nginx/authelia-location.conf;
|
||||
# enable for Authentik (requires authentik-server.conf in the server block)
|
||||
#include /config/nginx/authentik-location.conf;
|
||||
# enable for Tinyauth (requires tinyauth-server.conf in the server block)
|
||||
#include /config/nginx/tinyauth-location.conf;
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
set $upstream_app 192.168.1.241;
|
||||
set $upstream_port 8080;
|
||||
set $upstream_proto http;
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"binarize": true,
|
||||
|
||||
"allowed_encodings": [
|
||||
"JSON-B64",
|
||||
"JSON-URLSAFE-B64",
|
||||
"JSON-B91",
|
||||
"JSON-Z85B",
|
||||
"JSON-Z85P",
|
||||
"JSON-B32",
|
||||
"JSON-HEX"
|
||||
],
|
||||
|
||||
"allowed_ciphers": [
|
||||
"CHACHA20-POLY1305",
|
||||
"AES-GCM"
|
||||
],
|
||||
|
||||
"agent_protocol": {
|
||||
"module": "hivemind-ovos-agent-plugin",
|
||||
"hivemind-ovos-agent-plugin": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 8181
|
||||
}
|
||||
},
|
||||
|
||||
"binary_protocol": {
|
||||
"module": "hivemind-audio-binary-protocol-plugin",
|
||||
"hivemind-audio-binary-protocol-plugin": {},
|
||||
"network_protocol": {
|
||||
"hivemind-websocket-plugin": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 5678,
|
||||
"ssl": false,
|
||||
"cert_dir": "/home/hivemind/.local/share/hivemind",
|
||||
"cert_name": "hivemind"
|
||||
},
|
||||
"hivemind-http-plugin": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 5679,
|
||||
"ssl": false,
|
||||
"cert_dir": "/home/hivemind/.local/share/hivemind",
|
||||
"cert_name": "hivemind"
|
||||
}
|
||||
},
|
||||
|
||||
"database": {
|
||||
"module": "hivemind-json-db-plugin",
|
||||
"hivemind-json-db-plugin": {
|
||||
"name": "clients",
|
||||
"subfolder": "hivemind-core"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"context7": {
|
||||
"type": "streamable-http",
|
||||
"url": "http://context7-mcp:8080/mcp"
|
||||
},
|
||||
"gitea": {
|
||||
"type": "streamable-http",
|
||||
"url": "http://gitea-mcp:8080/mcp"
|
||||
},
|
||||
"searxng": {
|
||||
"type": "streamable-http",
|
||||
"url": "http://searxng-mcp:3000/mcp"
|
||||
},
|
||||
"signoz": {
|
||||
"type": "streamable-http",
|
||||
"url": "http://signoz-mcp-server:8000/mcp"
|
||||
},
|
||||
"wikipedia": {
|
||||
"type": "streamable-http",
|
||||
"url": "http://wikipedia-mcp:8000/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
"confirm_listening": true,
|
||||
"intents": {
|
||||
"persona": {
|
||||
"handle_fallback": true,
|
||||
"handle_fallback": true,
|
||||
"default_persona": "Benedikta"
|
||||
},
|
||||
"pipeline": [
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
},
|
||||
"tts": {
|
||||
"module": "ovos-tts-plugin-server",
|
||||
"module": "ovos-tts-plugin-server",
|
||||
"ovos-tts-plugin-server": {
|
||||
"voice": "alba-medium"
|
||||
},
|
||||
@@ -52,14 +52,11 @@
|
||||
"module": "ovos-stt-plugin-server",
|
||||
"fallback_module": "ovos-stt-plugin-fasterwhisper",
|
||||
"ovos-stt-plugin-fasterwhisper": {
|
||||
"model": "tiny.en"
|
||||
"model": "base.en"
|
||||
}
|
||||
},
|
||||
"listener": {
|
||||
"wake_word": "hey_benedikta",
|
||||
"VAD": {
|
||||
"module": "ovos-vad-plugin-silero"
|
||||
}
|
||||
"wake_word": "hey_benedikta"
|
||||
},
|
||||
"hotwords": {
|
||||
"hey_benedikta": {
|
||||
+10
-10
@@ -4,13 +4,13 @@ template_base_path: "{{ playbook_dir }}/app-configs"
|
||||
# Vault server address
|
||||
vault_addr: "https://vault.trez.wtf"
|
||||
vault_token: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
31386335336463633735623162613537393463393064393062626636343363636131633634666433
|
||||
3634316561633766613436346233333932353763656631360a366266643366636337336338613834
|
||||
61353833663862346533303135363531646166623138613563373738646637303437373264613765
|
||||
3363393563653637310a363736663232643066356266316535393265376236663635353065636138
|
||||
34303935383661633364393864656135323639336463323736653866643238356166356139623733
|
||||
37623438353739343565646464666433656465373135643562383163383862646435393564353166
|
||||
37306663646339313330383465393937353830643235666362393630643065336161363434316563
|
||||
64633563363465313165393461393866313662346135313139363436363365643839643839323532
|
||||
3264
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
33356331366463343032656164363437313263623962303365306632336362353038653738336338
|
||||
3261303838386531653661353231343361316566633531300a326637636135383832386466656235
|
||||
32316564653863346336316331306130333739663832613536323264336530383834323461313064
|
||||
6639383633643866310a343332616235343462346436373035636266636239346438346633303932
|
||||
64383135616261326466643661356539346233633639343865303964366236373161393764353838
|
||||
65633631346166323961393532393133353838393332663963383566663136613232383662626165
|
||||
63643838306332373237393938326131633838613331363663653638623830633364373464376463
|
||||
39623034306164393863343133313135653839363236613232663563346334303333313634333334
|
||||
6635
|
||||
@@ -0,0 +1,9 @@
|
||||
appdata_base_path: /home/charish/.config/docker
|
||||
ansible_become_password: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
65303564363831353738376239316665393435363663323231383436366566353534636164656336
|
||||
6661633033623139376338656131353964666232383331660a343933643030383438626661633661
|
||||
39333338306565383435326465386366356164643834303431623961653731303139633332326133
|
||||
6561653432656462330a303966633132366637633235316631353839383331333765336237353135
|
||||
39363465623933393535643862316262303333363038636634326233316636396666
|
||||
secrets_path: aranea-docker/env
|
||||
@@ -1,2 +0,0 @@
|
||||
appdata_base_path: /home/ovos/ovos/config
|
||||
secrets_path: benedikta-docker/env
|
||||
@@ -0,0 +1,9 @@
|
||||
appdata_base_path: /home/charish/.config/docker
|
||||
ansible_become_password: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
35396634626231373032376235343761316638376262333766376362363930666364303031306533
|
||||
3664323164363738663965343933643536616135393036350a306161626161303935383434326536
|
||||
66376165623634653966313033613230306365393334663334363730653330313031326231383739
|
||||
3036633032376133370a316463653162633566303363376631383033396234383366633737383066
|
||||
35393931393132323062386262623966646139613838373536313631643330313761
|
||||
secrets_path: benedikta-docker/env
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
appdata_base_path: /home/charish/.docker/config/appdata
|
||||
ansible_become_password: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
33393031336537653965343539636434613066326131653737396561653031336665633430353837
|
||||
3166363261623634363162626161633831316539643339620a326538663930396335646631356335
|
||||
39643539313531646566353034313734646432626462646530303762323939613833663237316631
|
||||
3134383462306432630a626163356437336331356339353332613265366564323234613732626331
|
||||
64333464306531303163376566393065643136633165373364373733323838616437
|
||||
30646333393563333364333935396530353265616233323839616266653938396561343539336337
|
||||
6531313061626132636362373833356631336161626435660a643539353930396532653234393663
|
||||
31623863633966303738643733643633353265396264613734333461643862663965663230663437
|
||||
6136373035303834630a653263626365623838363236303931643565656232326536643239653238
|
||||
64313034313663653332343464383565383964373438663661346538366636323162
|
||||
secrets_path: rinoa-docker/env
|
||||
file_metadata:
|
||||
"hashicorp-vault/config/vault-config.hcl.j2":
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appdata_base_path: /home/charish/.config/docker
|
||||
ansible_become_password: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
37363634303539386437373433653834326537613239373539383731333364316461373436646233
|
||||
3965616330356537666537323433666339653166616361370a616639363432643964343131636265
|
||||
64623239343238363763386466626632383230633062383263323433353634373539373861383038
|
||||
3837383436363138330a653566653731653065343538363733353432646136336335643666376133
|
||||
31623634636561636635396136636538613338313862396439376435613337373637
|
||||
secrets_path: ultima-docker/env
|
||||
+11
-5
@@ -1,11 +1,17 @@
|
||||
all:
|
||||
hosts:
|
||||
rinoa:
|
||||
ansible_host: 192.168.1.254
|
||||
aranea:
|
||||
ansible_host: 192.168.1.241
|
||||
ansible_user: charish
|
||||
lunafreya:
|
||||
ansible_host: 192.168.1.250
|
||||
ansible_user: charish
|
||||
rikku:
|
||||
ansible_host: 192.168.1.252
|
||||
ansible_user: pi
|
||||
benedikta:
|
||||
ansible_host: 192.168.1.250
|
||||
ansible_user: ovos
|
||||
rinoa:
|
||||
ansible_host: 192.168.1.254
|
||||
ansible_user: charish
|
||||
ultima:
|
||||
ansible_host: 192.168.1.248
|
||||
ansible_user: charish
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
Copyright 2021, the Mitogen authors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1 @@
|
||||
include LICENSE
|
||||
@@ -0,0 +1,52 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: mitogen
|
||||
Version: 0.3.44
|
||||
Summary: Library for writing distributed self-replicating programs.
|
||||
Home-page: https://github.com/mitogen-hq/mitogen/
|
||||
Author: David Wilson
|
||||
License: BSD-3-Clause
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Framework :: Ansible
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: 3.14
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Topic :: System :: Distributed Computing
|
||||
Classifier: Topic :: System :: Systems Administration
|
||||
Requires-Python: >=2.4, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
|
||||
Description-Content-Type: text/markdown
|
||||
License-File: LICENSE
|
||||
Dynamic: author
|
||||
Dynamic: classifier
|
||||
Dynamic: description
|
||||
Dynamic: description-content-type
|
||||
Dynamic: home-page
|
||||
Dynamic: license
|
||||
Dynamic: license-file
|
||||
Dynamic: requires-python
|
||||
Dynamic: summary
|
||||
|
||||
# Mitogen
|
||||
|
||||
[](https://pypi.org/project/mitogen/)
|
||||
[](https://pypi.org/project/mitogen/)
|
||||
[](https://github.com/mitogen-hq/mitogen/actions?query=branch%3Amaster)
|
||||
|
||||
<a href="https://mitogen.networkgenomics.com/">Please see the documentation</a>.
|
||||
|
||||

|
||||
@@ -0,0 +1,9 @@
|
||||
# Mitogen
|
||||
|
||||
[](https://pypi.org/project/mitogen/)
|
||||
[](https://pypi.org/project/mitogen/)
|
||||
[](https://github.com/mitogen-hq/mitogen/actions?query=branch%3Amaster)
|
||||
|
||||
<a href="https://mitogen.networkgenomics.com/">Please see the documentation</a>.
|
||||
|
||||

|
||||
@@ -0,0 +1,287 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
As Mitogen separates asynchronous IO out to a broker thread, communication
|
||||
necessarily involves context switching and waking that thread. When application
|
||||
threads and the broker share a CPU, this can be almost invisibly fast - around
|
||||
25 microseconds for a full A->B->A round-trip.
|
||||
|
||||
However when threads are scheduled on different CPUs, round-trip delays
|
||||
regularly vary wildly, and easily into milliseconds. Many contributing factors
|
||||
exist, not least scenarios like:
|
||||
|
||||
1. A is preempted immediately after waking B, but before releasing the GIL.
|
||||
2. B wakes from IO wait only to immediately enter futex wait.
|
||||
3. A may wait 10ms or more for another timeslice, as the scheduler on its CPU
|
||||
runs threads unrelated to its transaction (i.e. not B), wake only to release
|
||||
its GIL, before entering IO sleep waiting for a reply from B, which cannot
|
||||
exist yet.
|
||||
4. B wakes, acquires GIL, performs work, and sends reply to A, causing it to
|
||||
wake. B is preempted before releasing GIL.
|
||||
5. A wakes from IO wait only to immediately enter futex wait.
|
||||
6. B may wait 10ms or more for another timeslice, wake only to release its GIL,
|
||||
before sleeping again.
|
||||
7. A wakes, acquires GIL, finally receives reply.
|
||||
|
||||
Per above if we are unlucky, on an even moderately busy machine it is possible
|
||||
to lose milliseconds just in scheduling delay, and the effect is compounded
|
||||
when pairs of threads in process A are communicating with pairs of threads in
|
||||
process B using the same scheme, such as when Ansible WorkerProcess is
|
||||
communicating with ContextService in the connection multiplexer. In the worst
|
||||
case it could involve 4 threads working in lockstep spread across 4 busy CPUs.
|
||||
|
||||
Since multithreading in Python is essentially useless except for waiting on IO
|
||||
due to the presence of the GIL, at least in Ansible there is no good reason for
|
||||
threads in the same process to run on distinct CPUs - they always operate in
|
||||
lockstep due to the GIL, and are thus vulnerable to issues like above.
|
||||
|
||||
Linux lacks any natural API to describe what we want, it only permits
|
||||
individual threads to be constrained to run on specific CPUs, and for that
|
||||
constraint to be inherited by new threads and forks of the constrained thread.
|
||||
|
||||
This module therefore implements a CPU pinning policy for Ansible processes,
|
||||
providing methods that should be called early in any new process, either to
|
||||
rebalance which CPU it is pinned to, or in the case of subprocesses, to remove
|
||||
the pinning entirely. It is likely to require ongoing tweaking, since pinning
|
||||
necessarily involves preventing the scheduler from making load balancing
|
||||
decisions.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import ctypes
|
||||
import logging
|
||||
import mmap
|
||||
import multiprocessing
|
||||
import os
|
||||
import struct
|
||||
|
||||
import mitogen.parent
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
try:
|
||||
_libc = ctypes.CDLL(None, use_errno=True)
|
||||
_strerror = _libc.strerror
|
||||
_strerror.restype = ctypes.c_char_p
|
||||
_sem_init = _libc.sem_init
|
||||
_sem_wait = _libc.sem_wait
|
||||
_sem_post = _libc.sem_post
|
||||
_sched_setaffinity = _libc.sched_setaffinity
|
||||
except (OSError, AttributeError):
|
||||
_libc = None
|
||||
_strerror = None
|
||||
_sem_init = None
|
||||
_sem_wait = None
|
||||
_sem_post = None
|
||||
_sched_setaffinity = None
|
||||
|
||||
|
||||
class sem_t(ctypes.Structure):
|
||||
"""
|
||||
Wrap sem_t to allow storing a lock in shared memory.
|
||||
"""
|
||||
_fields_ = [
|
||||
('data', ctypes.c_uint8 * 128),
|
||||
]
|
||||
|
||||
def init(self):
|
||||
if _sem_init(self.data, 1, 1):
|
||||
raise Exception(_strerror(ctypes.get_errno()))
|
||||
|
||||
def acquire(self):
|
||||
if _sem_wait(self.data):
|
||||
raise Exception(_strerror(ctypes.get_errno()))
|
||||
|
||||
def release(self):
|
||||
if _sem_post(self.data):
|
||||
raise Exception(_strerror(ctypes.get_errno()))
|
||||
|
||||
|
||||
class State(ctypes.Structure):
|
||||
"""
|
||||
Contents of shared memory segment. This allows :meth:`Manager.assign` to be
|
||||
called from any child, since affinity assignment must happen from within
|
||||
the context of the new child process.
|
||||
"""
|
||||
_fields_ = [
|
||||
('lock', sem_t),
|
||||
('counter', ctypes.c_uint8),
|
||||
]
|
||||
|
||||
|
||||
class Policy(object):
|
||||
"""
|
||||
Process affinity policy.
|
||||
"""
|
||||
def assign_controller(self):
|
||||
"""
|
||||
Assign the Ansible top-level policy to this process.
|
||||
"""
|
||||
|
||||
def assign_muxprocess(self, index):
|
||||
"""
|
||||
Assign the MuxProcess policy to this process.
|
||||
"""
|
||||
|
||||
def assign_worker(self):
|
||||
"""
|
||||
Assign the WorkerProcess policy to this process.
|
||||
"""
|
||||
|
||||
def assign_subprocess(self):
|
||||
"""
|
||||
Assign the helper subprocess policy to this process.
|
||||
"""
|
||||
|
||||
class FixedPolicy(Policy):
|
||||
"""
|
||||
:class:`Policy` for machines where the only control method available is
|
||||
fixed CPU placement. The scheme here was tested on an otherwise idle 16
|
||||
thread machine.
|
||||
|
||||
- The connection multiplexer is pinned to CPU 0.
|
||||
- The Ansible top-level (strategy) is pinned to CPU 1.
|
||||
- WorkerProcesses are pinned sequentually to 2..N, wrapping around when no
|
||||
more CPUs exist.
|
||||
- Children such as SSH may be scheduled on any CPU except 0/1.
|
||||
|
||||
If the machine has less than 4 cores available, the top-level and workers
|
||||
are pinned between CPU 2..N, i.e. no CPU is reserved for the top-level
|
||||
process.
|
||||
|
||||
This could at least be improved by having workers pinned to independent
|
||||
cores, before reusing the second hyperthread of an existing core.
|
||||
|
||||
A hook is installed that causes :meth:`reset` to run in the child of any
|
||||
process created with :func:`mitogen.parent.popen`, ensuring CPU-intensive
|
||||
children like SSH are not forced to share the same core as the (otherwise
|
||||
potentially very busy) parent.
|
||||
"""
|
||||
def __init__(self, cpu_count=None):
|
||||
#: For tests.
|
||||
self.cpu_count = cpu_count or multiprocessing.cpu_count()
|
||||
self.mem = mmap.mmap(-1, 4096)
|
||||
self.state = State.from_buffer(self.mem)
|
||||
self.state.lock.init()
|
||||
|
||||
if self.cpu_count < 2:
|
||||
# uniprocessor
|
||||
self._reserve_mux = False
|
||||
self._reserve_controller = False
|
||||
self._reserve_mask = 0
|
||||
self._reserve_shift = 0
|
||||
elif self.cpu_count < 4:
|
||||
# small SMP
|
||||
self._reserve_mux = True
|
||||
self._reserve_controller = False
|
||||
self._reserve_mask = 1
|
||||
self._reserve_shift = 1
|
||||
else:
|
||||
# big SMP
|
||||
self._reserve_mux = True
|
||||
self._reserve_controller = True
|
||||
self._reserve_mask = 3
|
||||
self._reserve_shift = 2
|
||||
|
||||
def _set_affinity(self, descr, mask):
|
||||
if descr:
|
||||
LOG.debug('CPU mask for %s: %#08x', descr, mask)
|
||||
mitogen.parent._preexec_hook = self._clear
|
||||
self._set_cpu_mask(mask)
|
||||
|
||||
def _balance(self, descr):
|
||||
self.state.lock.acquire()
|
||||
try:
|
||||
n = self.state.counter
|
||||
self.state.counter += 1
|
||||
finally:
|
||||
self.state.lock.release()
|
||||
|
||||
self._set_cpu(descr, self._reserve_shift + (
|
||||
(n % (self.cpu_count - self._reserve_shift))
|
||||
))
|
||||
|
||||
def _set_cpu(self, descr, cpu):
|
||||
self._set_affinity(descr, 1 << (cpu % self.cpu_count))
|
||||
|
||||
def _clear(self):
|
||||
all_cpus = (1 << self.cpu_count) - 1
|
||||
self._set_affinity(None, all_cpus & ~self._reserve_mask)
|
||||
|
||||
def assign_controller(self):
|
||||
if self._reserve_controller:
|
||||
self._set_cpu('Ansible top-level process', 1)
|
||||
else:
|
||||
self._balance('Ansible top-level process')
|
||||
|
||||
def assign_muxprocess(self, index):
|
||||
self._set_cpu('MuxProcess %d' % (index,), index)
|
||||
|
||||
def assign_worker(self):
|
||||
self._balance('WorkerProcess')
|
||||
|
||||
def assign_subprocess(self):
|
||||
self._clear()
|
||||
|
||||
|
||||
class LinuxPolicy(FixedPolicy):
|
||||
def _mask_to_bytes(self, mask):
|
||||
"""
|
||||
Convert the (type long) mask to a cpu_set_t.
|
||||
"""
|
||||
chunks = []
|
||||
shiftmask = (2 ** 64) - 1
|
||||
for x in range(16):
|
||||
chunks.append(struct.pack('<Q', mask & shiftmask))
|
||||
mask >>= 64
|
||||
return b''.join(chunks)
|
||||
|
||||
def _get_thread_ids(self):
|
||||
try:
|
||||
ents = os.listdir('/proc/self/task')
|
||||
except OSError:
|
||||
LOG.debug('cannot fetch thread IDs for current process')
|
||||
return [os.getpid()]
|
||||
|
||||
return [int(s) for s in ents if s.isdigit()]
|
||||
|
||||
def _set_cpu_mask(self, mask):
|
||||
s = self._mask_to_bytes(mask)
|
||||
for tid in self._get_thread_ids():
|
||||
_sched_setaffinity(tid, len(s), s)
|
||||
|
||||
|
||||
if _sched_setaffinity is not None:
|
||||
policy = LinuxPolicy()
|
||||
else:
|
||||
policy = Policy()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Stable names for PluginLoader instances across Ansible versions.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import ansible.errors
|
||||
|
||||
import ansible_mitogen.utils
|
||||
|
||||
__all__ = [
|
||||
'action_loader',
|
||||
'become_loader',
|
||||
'connection_loader',
|
||||
'module_loader',
|
||||
'module_utils_loader',
|
||||
'shell_loader',
|
||||
'strategy_loader',
|
||||
]
|
||||
|
||||
|
||||
ANSIBLE_VERSION_MIN = (2, 10)
|
||||
OLD_VERSION_MSG = (
|
||||
"Your version of Ansible (%s) is too old. The oldest version supported by "
|
||||
"Mitogen for Ansible is %s."
|
||||
)
|
||||
|
||||
|
||||
def assert_supported_release():
|
||||
"""
|
||||
Throw AnsibleError with a descriptive message in case of being loaded into
|
||||
an unsupported Ansible release.
|
||||
"""
|
||||
v = ansible_mitogen.utils.ansible_version
|
||||
if v[:2] < ANSIBLE_VERSION_MIN:
|
||||
raise ansible.errors.AnsibleError(
|
||||
OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN)
|
||||
)
|
||||
|
||||
|
||||
# this is the first file our strategy plugins import, so we need to check this here
|
||||
# in prior Ansible versions, connection_loader.get_with_context didn't exist, so if a user
|
||||
# is trying to load an old Ansible version, we'll fail and error gracefully
|
||||
assert_supported_release()
|
||||
|
||||
|
||||
from ansible.plugins.loader import action_loader
|
||||
from ansible.plugins.loader import become_loader
|
||||
from ansible.plugins.loader import connection_loader
|
||||
from ansible.plugins.loader import module_loader
|
||||
from ansible.plugins.loader import module_utils_loader
|
||||
from ansible.plugins.loader import shell_loader
|
||||
from ansible.plugins.loader import strategy_loader
|
||||
|
||||
# These are original, unwrapped implementations
|
||||
action_loader__get_with_context = action_loader.get_with_context
|
||||
connection_loader__get_with_context = connection_loader.get_with_context
|
||||
@@ -0,0 +1,127 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import ansible.utils.display
|
||||
|
||||
import mitogen.utils
|
||||
|
||||
|
||||
display = ansible.utils.display.Display()
|
||||
|
||||
#: The process name set via :func:`set_process_name`.
|
||||
_process_name = None
|
||||
|
||||
#: The PID of the process that last called :func:`set_process_name`, so its
|
||||
#: value can be ignored in unknown fork children.
|
||||
_process_pid = None
|
||||
|
||||
|
||||
def set_process_name(name):
|
||||
"""
|
||||
Set a name to adorn log messages with.
|
||||
"""
|
||||
global _process_name
|
||||
_process_name = name
|
||||
|
||||
global _process_pid
|
||||
_process_pid = os.getpid()
|
||||
|
||||
|
||||
class Handler(logging.Handler):
|
||||
"""
|
||||
Use Mitogen's log format, but send the result to a Display method.
|
||||
"""
|
||||
def __init__(self, normal_method):
|
||||
logging.Handler.__init__(self)
|
||||
self.formatter = mitogen.utils.log_get_formatter()
|
||||
self.normal_method = normal_method
|
||||
|
||||
#: Set of target loggers that produce warnings and errors that spam the
|
||||
#: console needlessly. Their log level is forced to INFO. A better strategy
|
||||
#: may simply be to bury all target logs in DEBUG output, but not by
|
||||
#: overriding their log level as done here.
|
||||
NOISY_LOGGERS = frozenset([
|
||||
'dnf', # issue #272; warns when a package is already installed.
|
||||
'boto', # issue #541; normal boto retry logic can cause ERROR logs.
|
||||
])
|
||||
|
||||
def emit(self, record):
|
||||
mitogen_name = getattr(record, 'mitogen_name', '')
|
||||
if mitogen_name == 'stderr':
|
||||
record.levelno = logging.ERROR
|
||||
if mitogen_name in self.NOISY_LOGGERS and record.levelno >= logging.WARNING:
|
||||
record.levelno = logging.DEBUG
|
||||
|
||||
if _process_pid == os.getpid():
|
||||
process_name = _process_name
|
||||
else:
|
||||
process_name = '?'
|
||||
|
||||
s = '[%-4s %d] %s' % (process_name, os.getpid(), self.format(record))
|
||||
if record.levelno >= logging.ERROR:
|
||||
display.error(s, wrap_text=False)
|
||||
elif record.levelno >= logging.WARNING:
|
||||
display.warning(s, formatted=True)
|
||||
else:
|
||||
self.normal_method(s)
|
||||
|
||||
|
||||
def setup():
|
||||
"""
|
||||
Install handlers for Mitogen loggers to redirect them into the Ansible
|
||||
display framework. Ansible installs its own logging framework handlers when
|
||||
C.DEFAULT_LOG_PATH is set, therefore disable propagation for our handlers.
|
||||
"""
|
||||
l_mitogen = logging.getLogger('mitogen')
|
||||
l_mitogen_io = logging.getLogger('mitogen.io')
|
||||
l_ansible_mitogen = logging.getLogger('ansible_mitogen')
|
||||
l_operon = logging.getLogger('operon')
|
||||
|
||||
for logger in l_mitogen, l_mitogen_io, l_ansible_mitogen, l_operon:
|
||||
logger.handlers = [Handler(display.vvv)]
|
||||
logger.propagate = False
|
||||
|
||||
if display.verbosity > 2:
|
||||
l_ansible_mitogen.setLevel(logging.DEBUG)
|
||||
l_mitogen.setLevel(logging.DEBUG)
|
||||
else:
|
||||
# Mitogen copies the active log level into new children, allowing them
|
||||
# to filter tiny messages before they hit the network, and therefore
|
||||
# before they wake the IO loop. Explicitly setting INFO saves ~4%
|
||||
# running against just the local machine.
|
||||
l_mitogen.setLevel(logging.ERROR)
|
||||
l_ansible_mitogen.setLevel(logging.ERROR)
|
||||
|
||||
if display.verbosity > 3:
|
||||
l_mitogen_io.setLevel(logging.DEBUG)
|
||||
@@ -0,0 +1,504 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pwd
|
||||
import random
|
||||
import traceback
|
||||
|
||||
import ansible
|
||||
import ansible.plugins.action
|
||||
import ansible.utils.unsafe_proxy
|
||||
import ansible.vars.clean
|
||||
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
|
||||
import mitogen.core
|
||||
import mitogen.select
|
||||
|
||||
import ansible_mitogen.connection
|
||||
import ansible_mitogen.planner
|
||||
import ansible_mitogen.target
|
||||
import ansible_mitogen.utils
|
||||
import ansible_mitogen.utils.unsafe
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionModuleMixin(ansible.plugins.action.ActionBase):
|
||||
"""
|
||||
The Mitogen-patched PluginLoader dynamically mixes this into every action
|
||||
class that Ansible attempts to load. It exists to override all the
|
||||
assumptions built into the base action class that should really belong in
|
||||
some middle layer, or at least in the connection layer.
|
||||
|
||||
Functionality is defined here for:
|
||||
|
||||
* Capturing the final set of task variables and giving Connection a chance
|
||||
to update its idea of the correct execution environment, before any
|
||||
attempt is made to call a Connection method. While it's not expected for
|
||||
the interpreter to change on a per-task basis, Ansible permits this, and
|
||||
so it must be supported.
|
||||
|
||||
* Overriding lots of methods that try to call out to shell for mundane
|
||||
reasons, such as copying files around, changing file permissions,
|
||||
creating temporary directories and suchlike.
|
||||
|
||||
* Short-circuiting any use of Ansiballz or related code for executing a
|
||||
module remotely using shell commands and SSH.
|
||||
|
||||
* Short-circuiting most of the logic in dealing with the fact that Ansible
|
||||
always runs become: tasks across at least the SSH user account and the
|
||||
destination user account, and handling the security permission issues
|
||||
that crop up due to this. Mitogen always runs a task completely within
|
||||
the target user account, so it's not a problem for us.
|
||||
"""
|
||||
def __init__(self, task, connection, *args, **kwargs):
|
||||
"""
|
||||
Verify the received connection is really a Mitogen connection. If not,
|
||||
transmute this instance back into the original unadorned base class.
|
||||
|
||||
This allows running the Mitogen strategy in mixed-target playbooks,
|
||||
where some targets use SSH while others use WinRM or some fancier UNIX
|
||||
connection plug-in. That's because when the Mitogen strategy is active,
|
||||
ActionModuleMixin is unconditionally mixed into any action module that
|
||||
is instantiated, and there is no direct way for the monkey-patch to
|
||||
know what kind of connection will be used upfront.
|
||||
"""
|
||||
super(ActionModuleMixin, self).__init__(task, connection, *args, **kwargs)
|
||||
if not isinstance(connection, ansible_mitogen.connection.Connection):
|
||||
_, self.__class__ = type(self).__bases__
|
||||
|
||||
# required for python interpreter discovery
|
||||
connection.templar = self._templar
|
||||
|
||||
self._mitogen_discovering_interpreter = False
|
||||
self._mitogen_interpreter_candidate = None
|
||||
self._mitogen_rediscovered_interpreter = False
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
"""
|
||||
Override run() to notify Connection of task-specific data, so it has a
|
||||
chance to know e.g. the Python interpreter in use.
|
||||
"""
|
||||
self._connection.on_action_run(
|
||||
task_vars=task_vars,
|
||||
delegate_to_hostname=self._task.delegate_to,
|
||||
loader_basedir=self._loader.get_basedir(),
|
||||
)
|
||||
return super(ActionModuleMixin, self).run(tmp, task_vars)
|
||||
|
||||
COMMAND_RESULT = {
|
||||
'rc': 0,
|
||||
'stdout': '',
|
||||
'stdout_lines': [],
|
||||
'stderr': ''
|
||||
}
|
||||
|
||||
def fake_shell(self, func, stdout=False):
|
||||
"""
|
||||
Execute a function and decorate its return value in the style of
|
||||
_low_level_execute_command(). This produces a return value that looks
|
||||
like some shell command was run, when really func() was implemented
|
||||
entirely in Python.
|
||||
|
||||
If the function raises :py:class:`mitogen.core.CallError`, this will be
|
||||
translated into a failed shell command with a non-zero exit status.
|
||||
|
||||
:param func:
|
||||
Function invoked as `func()`.
|
||||
:returns:
|
||||
See :py:attr:`COMMAND_RESULT`.
|
||||
"""
|
||||
dct = self.COMMAND_RESULT.copy()
|
||||
try:
|
||||
rc = func()
|
||||
if stdout:
|
||||
dct['stdout'] = repr(rc)
|
||||
except mitogen.core.CallError:
|
||||
LOG.exception('While emulating a shell command')
|
||||
dct['rc'] = 1
|
||||
dct['stderr'] = traceback.format_exc()
|
||||
|
||||
return dct
|
||||
|
||||
def _remote_file_exists(self, path):
|
||||
"""
|
||||
Determine if `path` exists by directly invoking os.path.exists() in the
|
||||
target user account.
|
||||
"""
|
||||
LOG.debug('_remote_file_exists(%r)', path)
|
||||
return self._connection.get_chain().call(
|
||||
ansible_mitogen.target.file_exists,
|
||||
ansible_mitogen.utils.unsafe.cast(path)
|
||||
)
|
||||
|
||||
def _configure_module(self, module_name, module_args, task_vars=None):
|
||||
"""
|
||||
Mitogen does not use the Ansiballz framework. This call should never
|
||||
happen when ActionMixin is active, so crash if it does.
|
||||
"""
|
||||
assert False, "_configure_module() should never be called."
|
||||
|
||||
def _is_pipelining_enabled(self, module_style, wrap_async=False):
|
||||
"""
|
||||
Mitogen does not use SSH pipelining. This call should never happen when
|
||||
ActionMixin is active, so crash if it does.
|
||||
"""
|
||||
assert False, "_is_pipelining_enabled() should never be called."
|
||||
|
||||
def _generate_tmp_path(self):
|
||||
return os.path.join(
|
||||
self._connection.get_good_temp_dir(),
|
||||
'ansible_mitogen_action_%016x' % (
|
||||
random.getrandbits(8*8),
|
||||
)
|
||||
)
|
||||
|
||||
def _make_tmp_path(self, remote_user=None):
|
||||
"""
|
||||
Create a temporary subdirectory as a child of the temporary directory
|
||||
managed by the remote interpreter.
|
||||
"""
|
||||
LOG.debug('_make_tmp_path(remote_user=%r)', remote_user)
|
||||
path = self._generate_tmp_path()
|
||||
LOG.debug('Temporary directory: %r', path)
|
||||
self._connection.get_chain().call_no_reply(os.mkdir, path)
|
||||
self._connection._shell.tmpdir = path
|
||||
return path
|
||||
|
||||
def _remove_tmp_path(self, tmp_path):
|
||||
"""
|
||||
Replace the base implementation's invocation of rm -rf, replacing it
|
||||
with a pipelined call to :func:`ansible_mitogen.target.prune_tree`.
|
||||
"""
|
||||
LOG.debug('_remove_tmp_path(%r)', tmp_path)
|
||||
if tmp_path is None and ansible_mitogen.utils.ansible_version[:2] >= (2, 6):
|
||||
tmp_path = self._connection._shell.tmpdir # 06f73ad578d
|
||||
if tmp_path is not None:
|
||||
self._connection.get_chain().call_no_reply(
|
||||
ansible_mitogen.target.prune_tree,
|
||||
tmp_path,
|
||||
)
|
||||
self._connection._shell.tmpdir = None
|
||||
|
||||
def _transfer_data(self, remote_path, data):
|
||||
"""
|
||||
Used by the base _execute_module(), and in <2.4 also by the template
|
||||
action module, and probably others.
|
||||
"""
|
||||
if data is None and ansible_mitogen.utils.ansible_version[:2] <= (2, 18):
|
||||
data = '{}'
|
||||
if isinstance(data, dict):
|
||||
try:
|
||||
data = json.dumps(data, ensure_ascii=False)
|
||||
except UnicodeDecodeError:
|
||||
data = json.dumps(data)
|
||||
if not isinstance(data, bytes):
|
||||
data = to_bytes(data, errors='surrogate_or_strict')
|
||||
|
||||
LOG.debug('_transfer_data(%r, %s ..%d bytes)',
|
||||
remote_path, type(data), len(data))
|
||||
self._connection.put_data(remote_path, data)
|
||||
return remote_path
|
||||
|
||||
#: Actions listed here cause :func:`_fixup_perms2` to avoid a needless
|
||||
#: roundtrip, as they modify file modes separately afterwards. This is due
|
||||
#: to the method prototype having a default of `execute=True`.
|
||||
FIXUP_PERMS_RED_HERRING = set(['copy'])
|
||||
|
||||
def _fixup_perms2(self, remote_paths, remote_user=None, execute=True):
|
||||
"""
|
||||
Mitogen always executes ActionBase helper methods in the context of the
|
||||
target user account, so it is never necessary to modify permissions
|
||||
except to ensure the execute bit is set if requested.
|
||||
"""
|
||||
LOG.debug('_fixup_perms2(%r, remote_user=%r, execute=%r)',
|
||||
remote_paths, remote_user, execute)
|
||||
if execute and self._task.action not in self.FIXUP_PERMS_RED_HERRING:
|
||||
return self._remote_chmod(remote_paths, mode='u+x')
|
||||
return self.COMMAND_RESULT.copy()
|
||||
|
||||
def _remote_chmod(self, paths, mode, sudoable=False):
|
||||
"""
|
||||
Issue an asynchronous set_file_mode() call for every path in `paths`,
|
||||
then format the resulting return value list with fake_shell().
|
||||
"""
|
||||
LOG.debug('_remote_chmod(%r, mode=%r, sudoable=%r)',
|
||||
paths, mode, sudoable)
|
||||
return self.fake_shell(lambda: mitogen.select.Select.all(
|
||||
self._connection.get_chain().call_async(
|
||||
ansible_mitogen.target.set_file_mode,
|
||||
ansible_mitogen.utils.unsafe.cast(path),
|
||||
mode,
|
||||
)
|
||||
for path in paths
|
||||
))
|
||||
|
||||
def _remote_chown(self, paths, user, sudoable=False):
|
||||
"""
|
||||
Issue an asynchronous os.chown() call for every path in `paths`, then
|
||||
format the resulting return value list with fake_shell().
|
||||
"""
|
||||
LOG.debug('_remote_chown(%r, user=%r, sudoable=%r)',
|
||||
paths, user, sudoable)
|
||||
ent = self._connection.get_chain().call(pwd.getpwnam, user)
|
||||
return self.fake_shell(lambda: mitogen.select.Select.all(
|
||||
self._connection.get_chain().call_async(
|
||||
os.chown, path, ent.pw_uid, ent.pw_gid
|
||||
)
|
||||
for path in paths
|
||||
))
|
||||
|
||||
def _remote_expand_user(self, path, sudoable=True):
|
||||
"""
|
||||
Replace the base implementation's attempt to emulate
|
||||
os.path.expanduser() with an actual call to os.path.expanduser().
|
||||
|
||||
:param bool sudoable:
|
||||
If :data:`True`, indicate unqualified tilde ("~" with no username)
|
||||
should be evaluated in the context of the login account, not any
|
||||
become_user.
|
||||
"""
|
||||
LOG.debug('_remote_expand_user(%r, sudoable=%r)', path, sudoable)
|
||||
if not path.startswith('~'):
|
||||
# /home/foo -> /home/foo
|
||||
return path
|
||||
if sudoable or not self._connection.become:
|
||||
if path == '~':
|
||||
# ~ -> /home/dmw
|
||||
return self._connection.homedir
|
||||
if path.startswith('~/'):
|
||||
# ~/.ansible -> /home/dmw/.ansible
|
||||
return os.path.join(self._connection.homedir, path[2:])
|
||||
# ~root/.ansible -> /root/.ansible
|
||||
return self._connection.get_chain(use_login=(not sudoable)).call(
|
||||
os.path.expanduser,
|
||||
ansible_mitogen.utils.unsafe.cast(path),
|
||||
)
|
||||
|
||||
def get_task_timeout_secs(self):
|
||||
"""
|
||||
Return the task "async:" value, portable across 2.4-2.5.
|
||||
"""
|
||||
try:
|
||||
return self._task.async_val
|
||||
except AttributeError:
|
||||
return getattr(self._task, 'async')
|
||||
|
||||
def _set_temp_file_args(self, module_args, wrap_async):
|
||||
# Ansible>2.5 module_utils reuses the action's temporary directory if
|
||||
# one exists. Older versions error if this key is present.
|
||||
if ansible_mitogen.utils.ansible_version[:2] >= (2, 5):
|
||||
if wrap_async:
|
||||
# Sharing is not possible with async tasks, as in that case,
|
||||
# the directory must outlive the action plug-in.
|
||||
module_args['_ansible_tmpdir'] = None
|
||||
else:
|
||||
module_args['_ansible_tmpdir'] = self._connection._shell.tmpdir
|
||||
|
||||
# If _ansible_tmpdir is unset, Ansible>2.6 module_utils will use
|
||||
# _ansible_remote_tmp as the location to create the module's temporary
|
||||
# directory. Older versions error if this key is present.
|
||||
if ansible_mitogen.utils.ansible_version[:2] >= (2, 6):
|
||||
module_args['_ansible_remote_tmp'] = (
|
||||
self._connection.get_good_temp_dir()
|
||||
)
|
||||
|
||||
def _execute_module(self, module_name=None, module_args=None, tmp=None,
|
||||
task_vars=None, persist_files=False,
|
||||
delete_remote_tmp=True, wrap_async=False,
|
||||
ignore_unknown_opts=False,
|
||||
):
|
||||
"""
|
||||
Collect up a module's execution environment then use it to invoke
|
||||
target.run_module() or helpers.run_module_async() in the target
|
||||
context.
|
||||
"""
|
||||
if module_name is None:
|
||||
module_name = self._task.action
|
||||
if module_args is None:
|
||||
module_args = self._task.args
|
||||
if task_vars is None:
|
||||
task_vars = {}
|
||||
|
||||
if ansible_mitogen.utils.ansible_version[:2] >= (2, 17):
|
||||
self._update_module_args(
|
||||
module_name, module_args, task_vars,
|
||||
ignore_unknown_opts=ignore_unknown_opts,
|
||||
)
|
||||
else:
|
||||
self._update_module_args(module_name, module_args, task_vars)
|
||||
env = {}
|
||||
self._compute_environment_string(env)
|
||||
self._set_temp_file_args(module_args, wrap_async)
|
||||
|
||||
# there's a case where if a task shuts down the node and then immediately calls
|
||||
# wait_for_connection, the `ping` test from Ansible won't pass because we lost connection
|
||||
# clearing out context forces a reconnect
|
||||
# see https://github.com/dw/mitogen/issues/655 and Ansible's `wait_for_connection` module for more info
|
||||
if module_name == 'ansible.legacy.ping' and type(self).__name__ == 'wait_for_connection':
|
||||
self._connection.context = None
|
||||
|
||||
self._connection._connect()
|
||||
result = ansible_mitogen.planner.invoke(
|
||||
ansible_mitogen.planner.Invocation(
|
||||
action=self,
|
||||
connection=self._connection,
|
||||
module_name=ansible_mitogen.utils.unsafe.cast(mitogen.core.to_text(module_name)),
|
||||
module_args=ansible_mitogen.utils.unsafe.cast(module_args),
|
||||
task_vars=task_vars,
|
||||
templar=self._templar,
|
||||
env=ansible_mitogen.utils.unsafe.cast(env),
|
||||
wrap_async=wrap_async,
|
||||
timeout_secs=self.get_task_timeout_secs(),
|
||||
)
|
||||
)
|
||||
|
||||
if tmp and delete_remote_tmp and ansible_mitogen.utils.ansible_version[:2] < (2, 5):
|
||||
# Built-in actions expected tmpdir to be cleaned up automatically
|
||||
# on _execute_module().
|
||||
self._remove_tmp_path(tmp)
|
||||
|
||||
# prevents things like discovered_interpreter_* or ansible_discovered_interpreter_* from being set
|
||||
ansible.vars.clean.remove_internal_keys(result)
|
||||
|
||||
# taken from _execute_module of ansible 2.8.6
|
||||
# propagate interpreter discovery results back to the controller
|
||||
if self._discovered_interpreter_key:
|
||||
if result.get('ansible_facts') is None:
|
||||
result['ansible_facts'] = {}
|
||||
|
||||
# only cache discovered_interpreter if we're not running a rediscovery
|
||||
# rediscovery happens in places like docker connections that could have different
|
||||
# python interpreters than the main host
|
||||
if not self._mitogen_rediscovered_interpreter:
|
||||
result['ansible_facts'][self._discovered_interpreter_key] = self._discovered_interpreter
|
||||
|
||||
discovery_warnings = getattr(self, '_discovery_warnings', [])
|
||||
if discovery_warnings:
|
||||
if result.get('warnings') is None:
|
||||
result['warnings'] = []
|
||||
result['warnings'].extend(discovery_warnings)
|
||||
|
||||
discovery_deprecation_warnings = getattr(self, '_discovery_deprecation_warnings', [])
|
||||
if discovery_deprecation_warnings:
|
||||
if result.get('deprecations') is None:
|
||||
result['deprecations'] = []
|
||||
result['deprecations'].extend(discovery_deprecation_warnings)
|
||||
|
||||
return ansible.utils.unsafe_proxy.wrap_var(result)
|
||||
|
||||
def _postprocess_response(self, result):
|
||||
"""
|
||||
Apply fixups mimicking ActionBase._execute_module(); this is copied
|
||||
verbatim from action/__init__.py, the guts of _parse_returned_data are
|
||||
garbage and should be removed or reimplemented once tests exist.
|
||||
|
||||
:param dict result:
|
||||
Dictionary with format::
|
||||
|
||||
{
|
||||
"rc": int,
|
||||
"stdout": "stdout data",
|
||||
"stderr": "stderr data"
|
||||
}
|
||||
"""
|
||||
if ansible_mitogen.utils.ansible_version[:2] >= (2, 19):
|
||||
data = self._parse_returned_data(result, profile='legacy')
|
||||
else:
|
||||
data = self._parse_returned_data(result)
|
||||
|
||||
# Cutpasted from the base implementation.
|
||||
if 'stdout' in data and 'stdout_lines' not in data:
|
||||
data['stdout_lines'] = (data['stdout'] or u'').splitlines()
|
||||
if 'stderr' in data and 'stderr_lines' not in data:
|
||||
data['stderr_lines'] = (data['stderr'] or u'').splitlines()
|
||||
|
||||
return data
|
||||
|
||||
def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
|
||||
executable=None,
|
||||
encoding_errors='surrogate_then_replace',
|
||||
chdir=None):
|
||||
"""
|
||||
Override the base implementation by simply calling
|
||||
target.exec_command() in the target context.
|
||||
"""
|
||||
LOG.debug('_low_level_execute_command(%r, in_data=%r, exe=%r, dir=%r)',
|
||||
cmd, type(in_data), executable, chdir)
|
||||
|
||||
if executable is None: # executable defaults to False
|
||||
executable = self._play_context.executable
|
||||
if executable:
|
||||
cmd = executable + ' -c ' + shlex_quote(cmd)
|
||||
|
||||
# TODO: HACK: if finding python interpreter then we need to keep
|
||||
# calling exec_command until we run into the right python we'll use
|
||||
# chicken-and-egg issue, mitogen needs a python to run low_level_execute_command
|
||||
# which is required by Ansible's discover_interpreter function
|
||||
if self._mitogen_discovering_interpreter:
|
||||
possible_pythons = self._mitogen_interpreter_candidates
|
||||
else:
|
||||
# not used, just adding a filler value
|
||||
possible_pythons = ['python']
|
||||
|
||||
for possible_python in possible_pythons:
|
||||
try:
|
||||
self._mitogen_interpreter_candidate = possible_python
|
||||
rc, stdout, stderr = self._connection.exec_command(
|
||||
cmd, in_data, sudoable, mitogen_chdir=chdir,
|
||||
)
|
||||
except BaseException as exc:
|
||||
# we've reached the last python attempted and failed
|
||||
if possible_python == possible_pythons[-1]:
|
||||
raise
|
||||
else:
|
||||
LOG.debug(
|
||||
'%r._low_level_execute_command: candidate=%r ignored: %s, %r',
|
||||
self, possible_python, type(exc), exc,
|
||||
)
|
||||
continue
|
||||
|
||||
stdout_text = to_text(stdout, errors=encoding_errors)
|
||||
stderr_text = to_text(stderr, errors=encoding_errors)
|
||||
|
||||
return {
|
||||
'rc': rc,
|
||||
'stdout': stdout_text,
|
||||
'stdout_lines': stdout_text.splitlines(),
|
||||
'stderr': stderr_text,
|
||||
'stderr_lines': stderr_text.splitlines(),
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import unicode_literals
|
||||
__metaclass__ = type
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
else:
|
||||
import imp
|
||||
|
||||
import mitogen.imports
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PREFIX = 'ansible.module_utils.'
|
||||
|
||||
|
||||
# Analog of `importlib.machinery.ModuleSpec` or `pkgutil.ModuleInfo`.
|
||||
# name Unqualified name of the module.
|
||||
# path Filesystem path of the module.
|
||||
# kind One of the constants in `imp`, as returned in `imp.find_module()`
|
||||
# parent `ansible_mitogen.module_finder.Module` of parent package (if any).
|
||||
Module = collections.namedtuple('Module', 'name path kind parent')
|
||||
|
||||
|
||||
def get_fullname(module):
|
||||
"""
|
||||
Reconstruct a Module's canonical path by recursing through its parents.
|
||||
"""
|
||||
bits = [str(module.name)]
|
||||
while module.parent:
|
||||
bits.append(str(module.parent.name))
|
||||
module = module.parent
|
||||
return '.'.join(reversed(bits))
|
||||
|
||||
|
||||
def get_code(module):
|
||||
"""
|
||||
Compile and return a Module's code object.
|
||||
"""
|
||||
fp = open(module.path, 'rb')
|
||||
try:
|
||||
return compile(fp.read(), str(module.name), 'exec')
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
def is_pkg(module):
|
||||
"""
|
||||
Return :data:`True` if a Module represents a package.
|
||||
"""
|
||||
return module.kind == imp.PKG_DIRECTORY
|
||||
|
||||
|
||||
def find(name, path=(), parent=None):
|
||||
"""
|
||||
Return a Module instance describing the first matching module found on the
|
||||
search path.
|
||||
|
||||
:param str name:
|
||||
Module name.
|
||||
:param list path:
|
||||
List of directory names to search for the module.
|
||||
:param Module parent:
|
||||
Optional module parent.
|
||||
"""
|
||||
assert isinstance(path, tuple)
|
||||
head, _, tail = name.partition('.')
|
||||
try:
|
||||
tup = imp.find_module(head, list(path))
|
||||
except ImportError:
|
||||
return parent
|
||||
|
||||
fp, modpath, (suffix, mode, kind) = tup
|
||||
if fp:
|
||||
fp.close()
|
||||
|
||||
if parent and modpath == parent.path:
|
||||
# 'from timeout import timeout', where 'timeout' is a function but also
|
||||
# the name of the module being imported.
|
||||
return None
|
||||
|
||||
if kind == imp.PKG_DIRECTORY:
|
||||
modpath = os.path.join(modpath, '__init__.py')
|
||||
|
||||
module = Module(head, modpath, kind, parent)
|
||||
# TODO: this code is entirely wrong on Python 3.x, but works well enough
|
||||
# for Ansible. We need a new find_child() that only looks in the package
|
||||
# directory, never falling back to the parent search path.
|
||||
if tail and kind == imp.PKG_DIRECTORY:
|
||||
return find_relative(module, tail, path)
|
||||
return module
|
||||
|
||||
|
||||
def find_relative(parent, name, path=()):
|
||||
if parent.kind == imp.PKG_DIRECTORY:
|
||||
path = (os.path.dirname(parent.path),) + path
|
||||
return find(name, path, parent=parent)
|
||||
|
||||
|
||||
def scan_fromlist(code):
|
||||
"""Return an iterator of (level, name) for explicit imports in a code
|
||||
object.
|
||||
|
||||
Not all names identify a module. `from os import name, path` generates
|
||||
`(0, 'os.name'), (0, 'os.path')`, but `os.name` is usually a string.
|
||||
|
||||
>>> src = 'import a; import b.c; from d.e import f; from g import h, i\\n'
|
||||
>>> code = compile(src, '<str>', 'exec')
|
||||
>>> list(scan_fromlist(code))
|
||||
[(0, 'a'), (0, 'b.c'), (0, 'd.e.f'), (0, 'g.h'), (0, 'g.i')]
|
||||
"""
|
||||
for level, modname_s, fromlist in mitogen.imports.codeobj_imports(code):
|
||||
for name in fromlist:
|
||||
yield level, str('%s.%s' % (modname_s, name))
|
||||
if not fromlist:
|
||||
yield level, modname_s
|
||||
|
||||
|
||||
def walk_imports(code, prefix=None):
|
||||
"""Return an iterator of names for implicit parent imports & explicit
|
||||
imports in a code object.
|
||||
|
||||
If a prefix is provided, then only children of that prefix are included.
|
||||
Not all names identify a module. `from os import name, path` generates
|
||||
`'os', 'os.name', 'os.path'`, but `os.name` is usually a string.
|
||||
|
||||
>>> source = 'import a; import b; import b.c; from b.d import e, f\\n'
|
||||
>>> code = compile(source, '<str>', 'exec')
|
||||
>>> list(walk_imports(code))
|
||||
['a', 'b', 'b', 'b.c', 'b', 'b.d', 'b.d.e', 'b.d.f']
|
||||
>>> list(walk_imports(code, prefix='b'))
|
||||
['b.c', 'b.d', 'b.d.e', 'b.d.f']
|
||||
"""
|
||||
if prefix is None:
|
||||
prefix = ''
|
||||
pattern = re.compile(r'(^|\.)(\w+)')
|
||||
start = len(prefix)
|
||||
for _, name, fromlist in mitogen.imports.codeobj_imports(code):
|
||||
if not name.startswith(prefix):
|
||||
continue
|
||||
for match in pattern.finditer(name, start):
|
||||
yield name[:match.end()]
|
||||
for leaf in fromlist:
|
||||
yield str('%s.%s' % (name, leaf))
|
||||
|
||||
|
||||
def scan(module_name, module_path, search_path):
|
||||
# type: (str, str, list[str]) -> list[(str, str, bool)]
|
||||
"""Return a list of (name, path, is_package) for ansible.module_utils
|
||||
imports used by an Ansible module.
|
||||
"""
|
||||
log = LOG.getChild('scan')
|
||||
log.debug('%r, %r, %r', module_name, module_path, search_path)
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
result = _scan_importlib_find_spec(
|
||||
module_name, module_path, search_path,
|
||||
)
|
||||
log.debug('_scan_importlib_find_spec %r', result)
|
||||
else:
|
||||
result = _scan_imp_find_module(module_name, module_path, search_path)
|
||||
log.debug('_scan_imp_find_module %r', result)
|
||||
return result
|
||||
|
||||
|
||||
def _scan_importlib_find_spec(module_name, module_path, search_path):
|
||||
# type: (str, str, list[str]) -> list[(str, str, bool)]
|
||||
module = importlib.machinery.ModuleSpec(
|
||||
module_name, loader=None, origin=module_path,
|
||||
)
|
||||
prefix = importlib.machinery.ModuleSpec(
|
||||
PREFIX.rstrip('.'), loader=None,
|
||||
)
|
||||
prefix.submodule_search_locations = search_path
|
||||
queue = collections.deque([module])
|
||||
specs = {prefix.name: prefix}
|
||||
while queue:
|
||||
spec = queue.popleft()
|
||||
if spec.origin is None:
|
||||
continue
|
||||
try:
|
||||
with open(spec.origin, 'rb') as f:
|
||||
code = compile(f.read(), spec.name, 'exec')
|
||||
except Exception as exc:
|
||||
raise ValueError((exc, module, spec, specs))
|
||||
|
||||
for name in walk_imports(code, prefix.name):
|
||||
if name in specs:
|
||||
continue
|
||||
|
||||
parent_name = name.rpartition('.')[0]
|
||||
parent = specs[parent_name]
|
||||
if parent is None or not parent.submodule_search_locations:
|
||||
specs[name] = None
|
||||
continue
|
||||
|
||||
child = importlib.util._find_spec(
|
||||
name, parent.submodule_search_locations,
|
||||
)
|
||||
if child is None or child.origin is None:
|
||||
specs[name] = None
|
||||
continue
|
||||
|
||||
specs[name] = child
|
||||
queue.append(child)
|
||||
|
||||
del specs[prefix.name]
|
||||
return sorted(
|
||||
(spec.name, spec.origin, spec.submodule_search_locations is not None)
|
||||
for spec in specs.values() if spec is not None
|
||||
)
|
||||
|
||||
|
||||
def _scan_imp_find_module(module_name, module_path, search_path):
|
||||
# type: (str, str, list[str]) -> list[(str, str, bool)]
|
||||
module = Module(module_name, module_path, imp.PY_SOURCE, None)
|
||||
stack = [module]
|
||||
seen = set()
|
||||
|
||||
while stack:
|
||||
module = stack.pop(0)
|
||||
for level, fromname in scan_fromlist(get_code(module)):
|
||||
if not fromname.startswith(PREFIX):
|
||||
continue
|
||||
|
||||
imported = find(fromname[len(PREFIX):], search_path)
|
||||
if imported is None or imported in seen:
|
||||
continue
|
||||
|
||||
seen.add(imported)
|
||||
stack.append(imported)
|
||||
parent = imported.parent
|
||||
while parent:
|
||||
fullname = get_fullname(parent)
|
||||
module = Module(fullname, parent.path, parent.kind, None)
|
||||
if module not in seen:
|
||||
seen.add(module)
|
||||
stack.append(module)
|
||||
parent = parent.parent
|
||||
|
||||
return sorted(
|
||||
(PREFIX + get_fullname(module), module.path, is_pkg(module))
|
||||
for module in seen
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright 2019, David Wilson
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import unicode_literals
|
||||
__metaclass__ = type
|
||||
|
||||
import mitogen.core
|
||||
|
||||
|
||||
def parse_script_interpreter(source):
|
||||
"""
|
||||
Parse the script interpreter portion of a UNIX hashbang using the rules
|
||||
Linux uses.
|
||||
|
||||
:param str source: String like "/usr/bin/env python".
|
||||
|
||||
:returns:
|
||||
Tuple of `(interpreter, arg)`, where `intepreter` is the script
|
||||
interpreter and `arg` is its sole argument if present, otherwise
|
||||
:py:data:`None`.
|
||||
"""
|
||||
# Find terminating newline. Assume last byte of binprm_buf if absent.
|
||||
nl = source.find(b'\n', 0, 128)
|
||||
if nl == -1:
|
||||
nl = min(128, len(source))
|
||||
|
||||
# Split once on the first run of whitespace. If no whitespace exists,
|
||||
# bits just contains the interpreter filename.
|
||||
bits = source[0:nl].strip().split(None, 1)
|
||||
if len(bits) == 1:
|
||||
return mitogen.core.to_text(bits[0]), None
|
||||
return mitogen.core.to_text(bits[0]), mitogen.core.to_text(bits[1])
|
||||
|
||||
|
||||
def parse_hashbang(source):
|
||||
"""
|
||||
Parse a UNIX "hashbang line" using the syntax supported by Linux.
|
||||
|
||||
:param str source: String like "#!/usr/bin/env python".
|
||||
|
||||
:returns:
|
||||
Tuple of `(interpreter, arg)`, where `intepreter` is the script
|
||||
interpreter and `arg` is its sole argument if present, otherwise
|
||||
:py:data:`None`.
|
||||
"""
|
||||
# Linux requires first 2 bytes with no whitespace, pretty sure it's the
|
||||
# same everywhere. See binfmt_script.c.
|
||||
if not source.startswith(b'#!'):
|
||||
return None, None
|
||||
|
||||
return parse_script_interpreter(source[2:])
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user