From 58f754d76da6816169c85db8b06bddcbd5a04cf2 Mon Sep 17 00:00:00 2001 From: Simon Cornet Date: Wed, 22 Oct 2025 15:10:46 +0200 Subject: [PATCH] feat: initial commit --- .ansible-lint | 23 +++++++++ .gitignore | 1 + .gitlab-ci.yml | 22 ++++++++ .gitlab/deployment.yaml | 32 ++++++++++++ .gitlab/gitleaks.yaml | 18 +++++++ .markdownlint-cli2.jsonc | 12 +++++ .yamllint | 30 +++++++++++ handlers/main.yaml | 7 +++ meta/main.yaml | 9 ++++ playbook.yaml | 20 ++++++++ readme.md | 13 +++++ renovate.json | 4 ++ roles/requirements.yml | 9 ++++ tasks/bazarr.yaml | 68 +++++++++++++++++++++++++ tasks/cleanup.yaml | 14 +++++ tasks/main.yaml | 13 +++++ tasks/network.yaml | 6 +++ templates/pangolin/config.yml.j2 | 30 +++++++++++ templates/traefik/traefik_config.yml.j2 | 48 +++++++++++++++++ 19 files changed, 379 insertions(+) create mode 100644 .ansible-lint create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .gitlab/deployment.yaml create mode 100644 .gitlab/gitleaks.yaml create mode 100644 .markdownlint-cli2.jsonc create mode 100644 .yamllint create mode 100644 handlers/main.yaml create mode 100644 meta/main.yaml create mode 100644 playbook.yaml create mode 100644 readme.md create mode 100644 renovate.json create mode 100644 roles/requirements.yml create mode 100644 tasks/bazarr.yaml create mode 100644 tasks/cleanup.yaml create mode 100644 tasks/main.yaml create mode 100644 tasks/network.yaml create mode 100644 templates/pangolin/config.yml.j2 create mode 100644 templates/traefik/traefik_config.yml.j2 diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..9b9b52a --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,23 @@ +--- + +exclude_paths: + - ".gitlab/*" + - ".gitlab-ci.yml" + - "defaults/main.yaml" + - "meta/main.yaml" + - "vars/*" + +kinds: + - playbook: "**/*.{yml,yaml}" + +skip_list: + - "command-shell" + - "experimental" + - "git-latest" + - "no-changed-when" + - "no-handler" + - "name[casing]" + - "name[template]" + - "risky-file-permissions" + - "schema[playbook]" + - "var-naming[no-role-prefix]" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..904cae8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.ansible diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..54a4cb4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,22 @@ +--- + +# gitLab ci stages +stages: + + # deployment + - "gitleaks" + - "linting" + - "deployment" + + +# include jobs +include: + + # deployment + - local: ".gitlab/gitleaks.yaml" + - local: ".gitlab/deployment.yaml" + + # linting + - component: "$CI_SERVER_FQDN/components/ansible/linting@v3.0.3" + - component: "$CI_SERVER_FQDN/components/markdownlint/markdownlint@1.0.0" + - component: "$CI_SERVER_FQDN/components/yamllint/yamllint@1.0.2" diff --git a/.gitlab/deployment.yaml b/.gitlab/deployment.yaml new file mode 100644 index 0000000..869badc --- /dev/null +++ b/.gitlab/deployment.yaml @@ -0,0 +1,32 @@ +--- +# deploy ansible/roles/common code +deployment: + stage: "deployment" + image: + name: "registry.gitlab.simoncor.net/oci/ssh-client:v25.06.03" + entrypoint: ["/bin/sh", "-c"] + rules: + + # run only on push to default branch + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + - when: "never" + + # prepare ssh + before_script: + + # prepare ssh + - | + # prepare ssh + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "$SSH_CONFIG" > ~/.ssh/config + echo "$SSH_DEPLOYMENT_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + + # deployment commands + script: + + - | + # install ansible roles dependancies + ssh $SSH_DEPLOYMENT_USER@$ANSIBLE_SERVER \ + "sudo /usr/local/bin/ansible-galaxy install -r /etc/ansible/roles/requirements.yaml --force" diff --git a/.gitlab/gitleaks.yaml b/.gitlab/gitleaks.yaml new file mode 100644 index 0000000..b369d97 --- /dev/null +++ b/.gitlab/gitleaks.yaml @@ -0,0 +1,18 @@ +--- + +# gitleaks +gitleaks: + stage: "gitleaks" + image: + name: "ghcr.io/gitleaks/gitleaks:latest" + variables: + GIT_DEPTH: 1 + rules: + + # run only on push to default branch + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + - when: "never" + + # start linting + script: + - "gitleaks detect --source . --verbose --redact" diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..56cd87c --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,12 @@ +{ + // files to lint + "globs": [ + "readme.md" + ], + // linting rules + "config": { + "MD013": { + "line_length": 120 + } + } +} diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..f11bd84 --- /dev/null +++ b/.yamllint @@ -0,0 +1,30 @@ +--- +extends: 'default' + +rules: + braces: + max-spaces-inside: 1 + forbid: true + comments: + min-spaces-from-content: 1 + comments-indentation: false + empty-lines: + max: 2 + indentation: + spaces: 2 + check-multi-line-strings: true + line-length: + max: 120 + allow-non-breakable-words: true + allow-non-breakable-inline-mappings: true + new-line-at-end-of-file: 'enable' + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true + truthy: + allowed-values: + - 'true' + - 'false' + quoted-strings: + quote-type: 'any' + required: true diff --git a/handlers/main.yaml b/handlers/main.yaml new file mode 100644 index 0000000..6616bf3 --- /dev/null +++ b/handlers/main.yaml @@ -0,0 +1,7 @@ +--- + +# restart pangolin +- name: "restart pangolin" + community.docker.docker_container: + name: "pangolin" + restart: true diff --git a/meta/main.yaml b/meta/main.yaml new file mode 100644 index 0000000..f37d5db --- /dev/null +++ b/meta/main.yaml @@ -0,0 +1,9 @@ +--- + +galaxy_info: + author: "siempie" + description: "install and configure an pangolin server" + license: "MIT" + role_name: "pangolin" +dependencies: + - role: "docker" diff --git a/playbook.yaml b/playbook.yaml new file mode 100644 index 0000000..edac17a --- /dev/null +++ b/playbook.yaml @@ -0,0 +1,20 @@ +--- + +# execute this role +- name: "install bazarr" + hosts: "all" + become: true + pre_tasks: + + # due to semaphore bug we need to do this ourselves + - name: "force-update requirements" + ansible.builtin.command: + cmd: "ansible-galaxy install -f -r roles/requirements.yml" + become: false + delegate_to: "localhost" + changed_when: false + failed_when: false + + roles: + - role: "docker" + - role: "bazarr" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..78d6bf5 --- /dev/null +++ b/readme.md @@ -0,0 +1,13 @@ +# Overview + +This role configures [Bazarr]() server, for reasons. + +## Supported Operating Systems + +| Operating System | Version | +| --- | ----- | +| Debian | 13 | + +## Tags + +This role has no tags. diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..91260cb --- /dev/null +++ b/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ "local>cicd/renovate:ansible" ] +} diff --git a/roles/requirements.yml b/roles/requirements.yml new file mode 100644 index 0000000..5734acd --- /dev/null +++ b/roles/requirements.yml @@ -0,0 +1,9 @@ +--- + +roles: + - name: "docker" + src: "https://gitlab.simoncor.net/ansible/ans-docker.git" + scm: "git" + - name: "bazarr" + src: "https://gitlab.simoncor.net/ansible/ans-bazarr.git" + scm: "git" diff --git a/tasks/bazarr.yaml b/tasks/bazarr.yaml new file mode 100644 index 0000000..6fbbee2 --- /dev/null +++ b/tasks/bazarr.yaml @@ -0,0 +1,68 @@ +--- + +# create bazarr data directory +- name: "create bazarr data directory" + ansible.builtin.file: + path: "/mnt/bazarr/data" + state: "directory" + owner: "bazarr" + group: "blackbeard" + mode: "0775" + + +# create nfs mount +- name: "create media volume" + community.docker.docker_volume: + driver: "local" + driver_options: + type: "nfs4" + o: "rw,relatime,vers=4.2,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,nconnect=2,timeo=600,retrans=2,sec=sys,local_lock=none,addr=192.168.10.30" + device: ":/tank/media" + volume_name: "media" + + +# docker pull bazarr +- name: "run bazarr" + community.docker.docker_container: + + # container_default_behavior + auto_remove: "no" + container_default_behavior: "no_defaults" + detach: "yes" + init: "no" + interactive: "no" + log_driver: "json-file" + log_options: + max-size: "5m" + max-file: "3" + memory: "0" + paused: "no" + privileged: "no" + pull: "always" + read_only: "no" + state: "started" + tty: "no" + + # bazarr + name: "bazarr" + image: "lscr.io/linuxserver/bazarr:1.5.3" + image_name_mismatch: "recreate" + restart_policy: "unless-stopped" + + networks: + - name: "bazarr" + + volumes: + - "/mnt/bazarr/data:/config" + - "media:/mnt/media" + + ports: + - "6767:6767/tcp" + + env: + # basics + PUID: "{{ bazarr_puid }}" + GUID: "{{ blackbeard_guid }}" + + # global + TZ: "{{ timezone }}" diff --git a/tasks/cleanup.yaml b/tasks/cleanup.yaml new file mode 100644 index 0000000..d2d89f5 --- /dev/null +++ b/tasks/cleanup.yaml @@ -0,0 +1,14 @@ +--- + +# cleanup +- name: "docker - prune all" + community.docker.docker_prune: + containers: true + images: true + networks: true + volumes: true + builder_cache: true + +- name: "docker - force prune" + ansible.builtin.command: "docker system prune --all --force --volumes" + changed_when: false diff --git a/tasks/main.yaml b/tasks/main.yaml new file mode 100644 index 0000000..5ae5c93 --- /dev/null +++ b/tasks/main.yaml @@ -0,0 +1,13 @@ +--- + +# create network +- name: "create network" + ansible.builtin.import_tasks: "network.yaml" + +# install bazarr +- name: "install bazarr" + ansible.builtin.import_tasks: "bazarr.yaml" + +# cleanup docker +- name: "cleanup docker" + ansible.builtin.import_tasks: "cleanup.yaml" diff --git a/tasks/network.yaml b/tasks/network.yaml new file mode 100644 index 0000000..501d44d --- /dev/null +++ b/tasks/network.yaml @@ -0,0 +1,6 @@ +--- + +# create network +- name: "docker create bazarr network" + community.docker.docker_network: + name: "bazarr" diff --git a/templates/pangolin/config.yml.j2 b/templates/pangolin/config.yml.j2 new file mode 100644 index 0000000..c622ef5 --- /dev/null +++ b/templates/pangolin/config.yml.j2 @@ -0,0 +1,30 @@ +app: + dashboard_url: "https://{{ pangolin_domain }}" + log_level: "info" + +domains: + domain1: + base_domain: "simoncor.net" + cert_resolver: "letsencrypt" + domain2: + base_domain: "mirahsimon.us" + cert_resolver: "letsencrypt" + +server: + secret: "{{ pangolin_server_secret }}" + cors: + origins: ["https://{{ pangolin_domain }}"] + methods: ["GET", "POST", "PUT", "DELETE", "PATCH"] + allowed_headers: ["X-CSRF-Token", "Content-Type"] + credentials: false + +gerbil: + start_port: 51820 + base_endpoint: "{{ pangolin_domain }}" + +flags: + require_email_verification: false + disable_signup_without_invite: true + disable_user_create_org: false + allow_raw_resources: true + allow_base_domain_resources: true diff --git a/templates/traefik/traefik_config.yml.j2 b/templates/traefik/traefik_config.yml.j2 new file mode 100644 index 0000000..4fab359 --- /dev/null +++ b/templates/traefik/traefik_config.yml.j2 @@ -0,0 +1,48 @@ +api: + insecure: true + dashboard: true + +providers: + http: + endpoint: "http://pangolin:3001/api/v1/traefik-config" + pollInterval: "5s" + file: + filename: "/etc/traefik/dynamic_config.yml" + +experimental: + plugins: + badger: + moduleName: "github.com/fosrl/badger" + version: "v1.2.0" + +log: + level: "INFO" + format: "common" + maxSize: 100 + maxBackups: 3 + maxAge: 3 + compress: true + +certificatesResolvers: + letsencrypt: + acme: + dnsChallenge: + provider: "transip" + email: "letsencrypt@simoncor.net" + storage: "/letsencrypt/acme.json" + caServer: "https://acme-v02.api.letsencrypt.org/directory" + +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + transport: + respondingTimeouts: + readTimeout: "30m" + http: + tls: + certResolver: "letsencrypt" + +serversTransport: + insecureSkipVerify: true