Compare commits
64 Commits
feature/zf
...
feature/au
Author | SHA1 | Date | |
---|---|---|---|
dbdd2cfe11
|
|||
1be4868f09
|
|||
ee24d69906
|
|||
f0a10cc1d2
|
|||
263f7eea17
|
|||
3006e3e424
|
|||
0e43a68754
|
|||
fc6e485a61
|
|||
dd0330c85a
|
|||
40fbdc414e
|
|||
aaca0f94f8
|
|||
97b812eb10
|
|||
97d1db61d8
|
|||
a8bc344aa2
|
|||
f9d590170d
|
|||
e1f3a22a23
|
|||
f3c6c61130
|
|||
ef40b1ba7d
|
|||
2e22d4c7f2
|
|||
bc963f28ee
|
|||
5b1e346282
|
|||
8061a2773f
|
|||
3dba4e6fe9
|
|||
d54193e0d5
|
|||
6c05da2b58
|
|||
50ca5d6d0d
|
|||
3d1a509681
|
|||
be14ddd5fc
|
|||
b15b1fca40
|
|||
eed1b78625
|
|||
405d837407
|
|||
18c1d96b0a
|
|||
74679ed8e5
|
|||
d2401f11f4
|
|||
30a2744830
|
|||
de37042061
|
|||
6a92053232
|
|||
1ef7f1cf6e
|
|||
9844a1ab5c
|
|||
bd8e1b8e38
|
|||
40964c0f60
|
|||
145c5db29f
|
|||
ec335e5d3c
|
|||
659d5ffebc
|
|||
40de9b87a1
|
|||
20ce67472d
|
|||
7e94d27824
|
|||
de566c0395
|
|||
a5370f49f5
|
|||
c3f6bd2ea9
|
|||
ed426593d4
|
|||
a6c370b85a
|
|||
a0d52958e8
|
|||
d42dc7b5e4
|
|||
07bc176758
|
|||
14f79e9990
|
|||
f951a5ff43
|
|||
2a686f9372
|
|||
0f1ca446cd
|
|||
1fdfe560aa
|
|||
13de80c361
|
|||
8267a66def
|
|||
ff123ee762
|
|||
33678b8b07
|
5
.idea/alpina.iml
generated
5
.idea/alpina.iml
generated
@@ -23,9 +23,8 @@
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/roles/traefik/templates" />
|
||||
<option value="$MODULE_DIR$/roles/gitea/templates" />
|
||||
<option value="$MODULE_DIR$/roles/nextcloud/templates" />
|
||||
<option value="$MODULE_DIR$/roles/docker_host/templates" />
|
||||
<option value="$MODULE_DIR$/roles/alpina/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
|
123
.idea/jsonSchemas.xml
generated
123
.idea/jsonSchemas.xml
generated
@@ -3,6 +3,58 @@
|
||||
<component name="JsonSchemaMappingsProjectConfiguration">
|
||||
<state>
|
||||
<map>
|
||||
<entry key="Ansible Tasks File">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="name" value="Ansible Tasks File" />
|
||||
<option name="relativePathToSchema" value="https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible.json#/$defs/tasks" />
|
||||
<option name="applicationDefined" value="true" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="pattern" value="true" />
|
||||
<option name="path" value="*/tasks/*.yml" />
|
||||
<option name="mappingKind" value="Pattern" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="Authentik Blueprint">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="generatedName" value="New Schema" />
|
||||
<option name="name" value="Authentik Blueprint" />
|
||||
<option name="relativePathToSchema" value="https://goauthentik.io/blueprints/schema.json" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="directory" value="true" />
|
||||
<option name="path" value="roles/alpina/templates/services/authentik/blueprints" />
|
||||
<option name="mappingKind" value="Directory" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="Loki">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="name" value="Loki" />
|
||||
<option name="relativePathToSchema" value="https://json.schemastore.org/loki.json" />
|
||||
<option name="applicationDefined" value="true" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="path" value="roles/alpina/templates/services/monitoring/loki_config/loki-config.yaml.j2" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="Traefik v2">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
@@ -12,7 +64,76 @@
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="path" value="roles/traefik/templates/traefik.yml.j2" />
|
||||
<option name="pattern" value="true" />
|
||||
<option name="path" value="*/traefik.yml.j2" />
|
||||
<option name="mappingKind" value="Pattern" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="Traefik v2 File Provider">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="generatedName" value="New Schema" />
|
||||
<option name="name" value="Traefik v2 File Provider" />
|
||||
<option name="relativePathToSchema" value="https://json.schemastore.org/traefik-v2-file-provider.json" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="path" value="file://$APPLICATION_CONFIG_DIR$/scratches/scratch.yml" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="file://$APPLICATION_CONFIG_DIR$/scratches/scratch_1.yml" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="file:///run/user/1000/kio-fuse-kipURF/sftp/root@debbi.lab.home/mnt/dock/traefik/rules/hello-world.yml" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="roles/alpina/templates/services/traefik/rules/traefik-dash.yml.j2" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="docker-compose.yml">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="name" value="docker-compose.yml" />
|
||||
<option name="relativePathToSchema" value="https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json" />
|
||||
<option name="applicationDefined" value="true" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="pattern" value="true" />
|
||||
<option name="path" value="*/docker-compose.yml" />
|
||||
<option name="mappingKind" value="Pattern" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="pattern" value="true" />
|
||||
<option name="path" value="*/docker-compose.yml.j2" />
|
||||
<option name="mappingKind" value="Pattern" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="prometheus.json">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="name" value="prometheus.json" />
|
||||
<option name="relativePathToSchema" value="https://json.schemastore.org/prometheus.json" />
|
||||
<option name="applicationDefined" value="true" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="path" value="roles/alpina/collections/services/monitoring/templates/prometheus_config/prometheus.yml.j2" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="roles/alpina/templates/services/monitoring/prometheus_config/prometheus.yml.j2" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
|
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (alpina)" project-jdk-type="Python SDK" />
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Poetry (alpina) (2)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (alpina)" project-jdk-type="Python SDK" />
|
||||
</project>
|
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
.POSIX:
|
||||
.PHONY: *
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
|
||||
env ?= staging
|
||||
vault_id ?= alpina@contrib/rbw-client.sh
|
||||
|
||||
clean_desired ?= false
|
||||
|
||||
all: site
|
||||
|
||||
setup:
|
||||
poetry install --quiet
|
||||
|
||||
site: setup
|
||||
poetry run ansible-playbook --vault-id ${vault_id} -i inventories/${env} --extra-vars "clean_desired_arg=${clean_desired}" site.yml
|
||||
|
||||
services: setup
|
||||
poetry run ansible-playbook --vault-id ${vault_id} -i inventories/${env} services.yml
|
75
README.md
Normal file
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Alpina
|
||||
|
||||
A home for configuring all of my homelab containers on a Debian Linux machine.
|
||||
This assumes a Debian Linux machine with Docker and Docker Compose installed.
|
||||
|
||||
My particular setup is based on a [jailmaker](https://github.com/Jip-Hop/jailmaker) container
|
||||
running on top of TrueNAS SCALE, separating all the docker stuff from the appliance.
|
||||
|
||||
# Notes
|
||||
|
||||
## Monitoring
|
||||
The monitoring stack is set up to monitor all the containers and the host.
|
||||
|
||||
This is a work in progress, Grafana is set up with grafanalib, a Python library that generates Grafana dashboards.
|
||||
The dashboards are generated from Python scripts in
|
||||
[grafana_config/dashboards](roles/alpina/templates/services/monitoring/grafana_config/dashboards).
|
||||
|
||||
This requires a custom grafana image, which is built from the
|
||||
[Dockerfile](roles/alpina/templates/services/monitoring/Dockerfile).
|
||||
|
||||
This also means it has to be manually rebuilt whenever the dashboards are updated.
|
||||
From the services/monitoring directory, run:
|
||||
```bash
|
||||
docker compose up -d --build --force-recreate grafana
|
||||
```
|
||||
|
||||
## IPv6
|
||||
The current configuration is designed to work with IPv6.
|
||||
However, because of how (not properly) I'm doing the subnetting
|
||||
from the host's network, NDP doesn't work.
|
||||
This means that container IPs are not accessible from other hosts on the local network.
|
||||
I simply have a static route on my router to the container subnet,
|
||||
that uses the IP of this host as the gateway.
|
||||
|
||||
This is a limitation of my current ISP, I only have a single /64 subnet for my lab network.
|
||||
I'd like to get a /56 or /48, perhaps using Hurricane Electric's tunnel broker.
|
||||
*Sigh* ISPs being stingy with the 2^48 prefixes they're afraid of running out of.
|
||||
|
||||
## Upgrading Postgres
|
||||
Upgrading the postgres container for a given stack requires a dump and restore.
|
||||
|
||||
After making a snapshot or backup of postgres data directory,
|
||||
in the compose directory for a given stack, run the following commands:
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d <db_service>
|
||||
docker compose exec -it <db_service> pg_dumpall -U <db_user> | tee /tmp/dump.sql
|
||||
docker compose down
|
||||
|
||||
rm -r <postgres_data_dir>/* # as root
|
||||
# Edit the docker-compose.yml file to use the new postgres image
|
||||
docker compose up -d <db_service>
|
||||
# For some reason, compose exec doesn't like the input redirection
|
||||
docker exec -i <db_container_name> psql -U <db_user> < /tmp/dump.sql
|
||||
docker compose up -d
|
||||
rm /tmp/dump.sql
|
||||
```
|
||||
|
||||
Additionally, if upgrading from postgres <= 13, it is necessary to upgrade the
|
||||
password hashes. This can be done by running the following command:
|
||||
```bash
|
||||
docker compose exec -it <db_service> psql -U <db_user> -c "\password"
|
||||
```
|
||||
|
||||
## Nextcloud
|
||||
Nextcloud requires some additional work to set up notify_push.
|
||||
|
||||
- Initially, comment out the notify_push service in the docker compose.
|
||||
- Set up nextcloud and install the Client Push (notify_push) app.
|
||||
- Uncomment the notify_push service in the docker compose and `up -d` the stack.
|
||||
- ```bash
|
||||
docker compose exec app ./occ notify_push:setup https://nc.<domain>/push
|
||||
```
|
||||
|
||||
I should probably get around to automating this at some point.
|
28
contrib/compose_helpers.j2
Normal file
28
contrib/compose_helpers.j2
Normal file
@@ -0,0 +1,28 @@
|
||||
{% macro default_network(subnet_index) %}
|
||||
default:
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
config:
|
||||
- subnet: {{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, subnet_index) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro traefik_labels(host, service="", port="", auth=false) %}
|
||||
traefik.enable=true
|
||||
- traefik.http.routers.{{ host }}.rule=Host(`{{ host }}.{{ domain }}`)
|
||||
- traefik.http.routers.{{ host }}.entrypoints=web
|
||||
- traefik.http.routers.{{ host }}-tls.rule=Host(`{{ host }}.{{ domain }}`)
|
||||
- traefik.http.routers.{{ host }}-tls.entrypoints=websecure
|
||||
- traefik.http.routers.{{ host }}-tls.tls=true
|
||||
- traefik.http.routers.{{ host }}-tls.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.{{ host }}-tls.tls.domains.0.main={{ domain }}
|
||||
- traefik.http.routers.{{ host }}-tls.tls.domains.0.sans=*.{{ domain }}
|
||||
{% if service -%}
|
||||
- traefik.http.routers.{{ host }}.service={{ service }}
|
||||
{% endif %}
|
||||
{% if port -%}
|
||||
- traefik.http.services.{{ host }}.loadbalancer.server.port={{ port }}
|
||||
{% endif %}
|
||||
{% if auth -%}
|
||||
- traefik.http.routers.{{ host }}-tls.middlewares=authentik@docker
|
||||
{% endif %}
|
||||
{% endmacro %}
|
51
group_vars/alpina/vars.yml
Normal file
51
group_vars/alpina/vars.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
# Shared variables between environments
|
||||
|
||||
---
|
||||
alpina_svc_path: ~/alpina
|
||||
base_volume_path: /mnt/dock
|
||||
media_volume_path: /mnt/media
|
||||
|
||||
traefik_subnet: 172.16.122.0
|
||||
|
||||
# Authentik
|
||||
authentik_db_password: "{{ vault_authentik_db_password }}"
|
||||
authentik_secret_key: "{{ vault_authentik_secret_key }}"
|
||||
|
||||
authentik_sendgrid_api_key: "{{ vault_authentik_sendgrid_api_key }}"
|
||||
|
||||
auth_grafana_client_secret: "{{ vault_auth_grafana_client_secret }}"
|
||||
auth_gitea_client_secret: "{{ vault_auth_gitea_client_secret }}"
|
||||
auth_nextcloud_client_secret: "{{ vault_auth_nextcloud_client_secret }}"
|
||||
auth_minio_client_secret: "{{ vault_auth_minio_client_secret }}"
|
||||
arrstack_password: "{{ vault_arrstack_password }}"
|
||||
|
||||
# Minio
|
||||
minio_password: "{{ vault_minio_password }}"
|
||||
|
||||
# Monitoring
|
||||
## auth_grafana_client_secret:
|
||||
influxdb_admin_password: "{{ vault_influxdb_admin_password }}"
|
||||
influxdb_admin_token: "{{ vault_influxdb_admin_token }}"
|
||||
|
||||
# Traefik
|
||||
acme_email: "{{ vault_acme_email }}"
|
||||
cloudflare_api_token: "{{ vault_cloudflare_api_token }}"
|
||||
|
||||
# Arrstack
|
||||
wg_peer_pubkey: "{{ vault_wg_peer_pubkey }}"
|
||||
vpn_server_names: "{{ vault_vpn_server_names }}"
|
||||
|
||||
# Gitea
|
||||
gitea_db_password: "{{ vault_gitea_db_password }}"
|
||||
gitea_sendgrid_api_key: "{{ vault_gitea_sendgrid_api_key }}"
|
||||
## Security
|
||||
secret_key: "{{ vault_secret_key }}"
|
||||
internal_token: "{{ vault_internal_token }}"
|
||||
jwt_secret: "{{ vault_jwt_secret }}"
|
||||
|
||||
# Jellyfin
|
||||
|
||||
# Nextcloud
|
||||
nextcloud_db_password: "{{ vault_nextcloud_db_password }}"
|
||||
redis_password: "{{ vault_redis_password }}"
|
||||
nextcloud_sendgrid_api_key: "{{ vault_nextcloud_sendgrid_api_key }}"
|
113
group_vars/alpina/vault.yml
Normal file
113
group_vars/alpina/vault.yml
Normal file
@@ -0,0 +1,113 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
62376365353162306161343336623464386634383663663165393632366666633530373636633032
|
||||
6536633438613664316163613236663334663635363665630a666135396430306536646534616535
|
||||
65383432356339643063373232393861333366393038666134346363646130626130633861646536
|
||||
3134613738333465300a363031626561376533343730353361646462306434663564336538666565
|
||||
38643166326439356138653163323030626539393265613833303661313036336562373938323663
|
||||
39336533383636626464343461653836313734393430306238336561323038306238646236393835
|
||||
62643638636137646162616239636561666432376561393338336663366438346530346666396662
|
||||
63626432326263383561633532613039643862303135643262383636666161663539643465616566
|
||||
66303364333133393932643666656263613063373162373265353433616337636337363363353938
|
||||
31613638633462383031356433393765353439373434356366336234316361393862343763643333
|
||||
61623233633664396564376462336131353061303831316466306632663261666161323137333633
|
||||
39623938633861356136636532373139356339636334373137303034646431363438613936636438
|
||||
38363463386664643439313564313364613962346631343663633837326532613933336462636265
|
||||
32616161663065316661313335373234353161653732303965613731633665646532386139383732
|
||||
32363834636532363262646433616563363232643864653365643736353434346130383963393564
|
||||
34333861326633393763653639663666333061613161393864323165303638353962333531333661
|
||||
36316534303365626562643366393836356337303533313237613534313565643832373438373530
|
||||
32393065653538393762333232636235316439653935663437616236326162313464323037336630
|
||||
39323262333530363230353334356461343866346438626533633339386162336337623137393366
|
||||
32373361393231343134626237323062663634323939613461633866353561636334613234336532
|
||||
61306235363037306466656463653836396434313830333031366630373364343637376662346663
|
||||
65663132346239343937636261643238623364633062356163323364363466666661346364356239
|
||||
32653266303837663237333136316464626161626136336333363964636461616138323962313166
|
||||
64643930333964303639393439666432366435386464326561323165353333623765653132383636
|
||||
34326633663331376563613766383734613762653834356561616461303361373662653337623863
|
||||
37633135393861366137613137633265306137326536363632373962353233373735663065653534
|
||||
37333038363330633931353233623236313332336234393333616238353137656363643230633966
|
||||
32636336663762636130343933373834386465396536316439386465623130396266393438396262
|
||||
63636561623533366166393831383035373935643037326265636634646339336264383937366334
|
||||
37373961663330326131343531356238363632663861376362643561643966636364653235303032
|
||||
33363861396336666332356130353638373135376336373236383730373665623336373830643137
|
||||
35613234343966383264643834353162353533373939346561363438376339656239323364353036
|
||||
63623630643930363739326236653435613538393438326331383366666332383763356631356533
|
||||
39393363366261393231386239363161313939396431323630323062393962313933633462303439
|
||||
35623831356638333431313430343832616438343134613538343064323535613539663431643830
|
||||
32623363343733623837366236393136393864353332316538306463346337363264613763326463
|
||||
65366536326463303062663262636563306565323861666661376338633334383138626364333039
|
||||
34333734656331346334316465333339333535333632383963663633383361383661643235383866
|
||||
32326634643633366566306137383066653334323935363066316366313934373663383234316438
|
||||
35346139633239323431386536656464666161656434316238356333323665333661623364653865
|
||||
33636139333866356630323031323162323834303062363637313430313164326636383436383465
|
||||
35333434613632353265633935343164613266383463633631323763633565353039306134656431
|
||||
37616430633736326139366438613666346434646363313032366231616436616535393334613264
|
||||
34646132303061383034363139613362626235383938393535626339353438626635396561346166
|
||||
36666530613634336666653638353734323336366639626465346135323838343565383335313233
|
||||
62356631666135666434363061666234396337323838303866343839383164643939323862616632
|
||||
34646433333031653939313434613435623036346631643265643663613537323061343733326534
|
||||
64626663306338623533333132613333386562306162343438653266356666663535623036616666
|
||||
64613866663261386233343236353931353766323833623631373438353664393137613032366461
|
||||
63623164353435336564613739353863383037326465363462376536663934626362393132313465
|
||||
66353965643763656564366630353131313465656265613434363538343331313666613564313036
|
||||
35396436633233623261323432666237303335333339393363636362376536343837346264383935
|
||||
30346163353338336661646536643536623262343762303766393438343666623063326463346566
|
||||
34663538656133353639333830316562376137643666323832363666623766366131303830626531
|
||||
62313832316533663261353365343733636236643333396561333636303065653732646665386136
|
||||
31386535663732386165623037373763333731343461393431306339393634346130646462646661
|
||||
61646539613964666437623631643333333435353039633531313364366338316365396131346331
|
||||
30363963633236653364643061316237326362653462656563656165346134656338383738613932
|
||||
65333432393534643331396563643865656435373563613939616234636533383731336561623037
|
||||
61373839343132376465343332343165316361383831333538313531333063633632643832633536
|
||||
33313464643239323963346338386566313031306233336562616638353365666237346262666134
|
||||
33646134393531346637376133393039326638316334626333363162313239393239663865323730
|
||||
30343731363031303565643833313135643036666461366666376132663433343662333730373137
|
||||
65636236313561613637343262653833666135653832363466613138363332393061653032333933
|
||||
66376263663830333937336566333461333431393336333161623233353332396437396664316137
|
||||
64363737323036366635613938346261383634353237346337613933303334623434623439616533
|
||||
32353465336237396133643039613730646661643039363836333733353033343236373864626634
|
||||
37666562653233336464633337353963363361646334373863653032353137363738613561613135
|
||||
66356132393630613031316466663837633633383033633064326565303837633062336531373866
|
||||
34666537303033323362363163353666383962333536303135363666653930326166323637636266
|
||||
34306537343238353833313635306663643737653531313435383064383133366364646331306261
|
||||
66363763353534643833316533383364353632343439393032313437633734323031383438633333
|
||||
31616362343332373333626135396435366235313465346639326564353265643133313339376639
|
||||
63333233653833653333373162633033623035633832333566653536343832373035636664643839
|
||||
38393864666430313162366337653836333135333738653763653261343233663666373865383366
|
||||
65343038646166343934376633613337306436336130626363396339313236653731653265383661
|
||||
34633332343639333533316631643763363664666563353137383639616132313363383137383132
|
||||
33343635386139366230363464363731383166393430396533613438366661353439353537346530
|
||||
62366461653534333834386637363364346432333964306639376339313531383431323930333530
|
||||
37383665373937303732643636383539393039663363623337663938303139663039366536323031
|
||||
66613036326263316239646535656163626232626130336465303166336336316435343262373631
|
||||
39613536336366366435326230653339356635636432303862306636613935306432323966313234
|
||||
65623938316162393931343337326334666235666362313739343564633339653962313062393431
|
||||
35373338306332326133333638636137386337343261386663333261333030343635336532373134
|
||||
38626136383936393339613534386539663035316335656566656639613837313239626431386362
|
||||
62643733326636323635373363333964643132323562633430626666616531656639383231336432
|
||||
61653439376663613161396465343638623639653135363863336363343230636336346434326234
|
||||
32343962666337646435653035333431333632363239616535333835393761353366386561356366
|
||||
37356530333763346137653566643134376136656638386334343038376439643037623338643333
|
||||
66626537633931333465383062303766333436346433636434653139333966613865656234346539
|
||||
36376239393632653536306363313633636464343366373862343039306235303766623462633932
|
||||
32313537306530343032663365626330363838396566356534343766383865653231613538323461
|
||||
37303439393733376539613061663937633665663963613236323764653835656563346565636531
|
||||
30363239376139343166346664306234363031623031663266643966636265666163353536346132
|
||||
65623638323065633361373330386334636332306634636336613365663133373835666135396230
|
||||
38373939366534663336376135646237633232646261383964383735353533303862623064313333
|
||||
33633533653537376138623635663465336131383838663237653933623634343761623731366335
|
||||
64653233366335656365656336303862656663303138643531356661373831633062633734363661
|
||||
39306633323337356366383863643034656135393432386638353761323337373631353436383664
|
||||
34623631306663636439376464383831323566666266613536613661633266343732646264306162
|
||||
36353030343538316330313831626232353165323038363034666161336338316536353832353966
|
||||
35336365393563643733363535393763613865663436616130343066303638353431653039356661
|
||||
34393936363764393032646133326432656230353232623339646165663932366130363734663762
|
||||
34303433376666383639663661356334653939663739643139363237623031666632623239343562
|
||||
30656438623236616637643132613666343133393436346635316638633664316363323832393862
|
||||
39643831363633643562323664613666393033656132333964643639333230353763383330343835
|
||||
64383530373332343838666536303363313033303931646232343037303863343835366139326135
|
||||
34336330343365663837396134653566633536643832373433393035366531323035616462363639
|
||||
66336133346139336264346636643735383136343336303133313031653230366166396239303335
|
||||
64656535326465363563396532376538336434643964336264303061393139656139376635633730
|
||||
62326664613766393435383464363538393937313236363630656337356264633134353464393835
|
||||
32653133383732656235
|
@@ -1,2 +0,0 @@
|
||||
---
|
||||
my_svc_path: ~/services
|
14
inventories/prod/group_vars/alpina/vars.yml
Normal file
14
inventories/prod/group_vars/alpina/vars.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# Environment specific variables (prod)
|
||||
|
||||
---
|
||||
docker_ipv6_index: 255
|
||||
|
||||
# Arrstack VPN
|
||||
wg_privkey: "{{ vault_wg_privkey }}"
|
||||
wg_psk: "{{ vault_wg_psk }}"
|
||||
wg_addresses: "{{ vault_wg_addresses }}"
|
||||
fw_vpn_input_ports: "{{ vault_fw_vpn_input_ports }}"
|
||||
|
||||
# Authentik GitHub OAuth
|
||||
github_consumer_key: 32d5cae58d744c56fcc9
|
||||
github_consumer_secret: "{{ vault_github_consumer_secret }}"
|
21
inventories/prod/group_vars/alpina/vault.yml
Normal file
21
inventories/prod/group_vars/alpina/vault.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
61656162363565633436373135333536623561663136303736393865623830633539376362363363
|
||||
3938333137343336626634346262363964316563643261310a366538363037343965363766646535
|
||||
61636239326464373039333462653562373933396665393039633266326234663335363337666439
|
||||
6137323332303533640a383062383135633762323561313666636566306531306636633466316536
|
||||
66623731626266333731303336323733343336626366343833633365616330343565363035323039
|
||||
35313961383131616133386663376331336639633137383137346164353632653939363266613562
|
||||
36316631366661353632386230306532633862393963663465383862653964646462666334396666
|
||||
66626636353539316266343937623662613336616331626439306538363764636366656635356639
|
||||
30663535393366383261333832356237373230663037373638303161303534636230616464636265
|
||||
37623938303638646233346338616239393838396433313063343065386666323264646461373032
|
||||
63376661646139316430303533643063336634333364643231336130613638626431623732646434
|
||||
63643833353164313465633333646232653761356333323933396666323837656334343866363762
|
||||
39646263653137356632323534356631366531636530613736343438393136363835373435636230
|
||||
30313163386335353935663432323033326235653963653930396235373863373232666334326661
|
||||
34336632666365666563326366376461386130343965363832343430396537323734363533353065
|
||||
64313837623366356261383437306465633730353332636561333462356363326132313933653234
|
||||
66363634333664333433613466396639306436353035346134373430663532373934343861323262
|
||||
30666664336336393835346234316238613839326436363162626439376530306133343530303365
|
||||
65393030633237333166336637363435646435323736353461333932366638333264333239373733
|
||||
30623062643336643431
|
@@ -1,2 +1,2 @@
|
||||
[docker_hosts]
|
||||
root@alpina.lab.home
|
||||
[alpina]
|
||||
debbi.lab.home
|
||||
|
14
inventories/staging/group_vars/alpina/vars.yml
Normal file
14
inventories/staging/group_vars/alpina/vars.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# Environment specific variables (staging)
|
||||
|
||||
---
|
||||
docker_ipv6_index: 254
|
||||
|
||||
# Arrstack VPN
|
||||
wg_privkey: "{{ vault_wg_privkey }}"
|
||||
wg_psk: "{{ vault_wg_psk }}"
|
||||
wg_addresses: "{{ vault_wg_addresses }}"
|
||||
fw_vpn_input_ports: "{{ vault_fw_vpn_input_ports }}"
|
||||
|
||||
# Authentik GitHub OAuth
|
||||
github_consumer_key: dbacb8621c37320eb745
|
||||
github_consumer_secret: "{{ vault_github_consumer_secret }}"
|
21
inventories/staging/group_vars/alpina/vault.yml
Normal file
21
inventories/staging/group_vars/alpina/vault.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
63633535633462326534626562373461373363643166383961303861623531663263323534366537
|
||||
3263633238646439306430356365623233313838326639350a386633363434623737313565316535
|
||||
33393734633937333637373432366132323366343836393538366339626235613937323066613666
|
||||
3737393262646333390a623331333461373563313166323232343234616538623433376166313532
|
||||
32323834346336336164343938303062336438643566343866316164643535663039326331646465
|
||||
36666162393365323633646635333666613030386265306238633434303234336439646663356363
|
||||
63323638373035326465633934326363316364616539613462653232393465633233366666373664
|
||||
66616361646564303530356331323864343966633736643434653237316236363063613634646438
|
||||
35303238646632616465643264316164363139393834626362326538613033656464323435396638
|
||||
31346631653764303332386331663361623766333332366537313634636333346538653537346631
|
||||
62363438303036386530633236376633326162336434343861346261373835653735323161323965
|
||||
62353965373164616537346134303232363033323134323130316439386339613966646330666533
|
||||
65346239383230646565346133663530613462363532663562326136376233303638323332326630
|
||||
35656432363563653663616236393932663637323139666664636237336136366438656666633865
|
||||
66353162656364356638313236643131613830393838636264663833343461373963613431656364
|
||||
32303331623033303433333631313038316336653638656638373031653234356164333363336532
|
||||
37316334353463376562643138346633613633353536653939376564333166323931353634333736
|
||||
63616133663266383339323562343265613461623865623263623139396163343065623264366230
|
||||
32633362336335396562366563363830636133376238646433386236666461333731353337386333
|
||||
61323931643766326338
|
@@ -1,2 +1,2 @@
|
||||
[docker_hosts]
|
||||
root@etapp.lab.home
|
||||
[alpina]
|
||||
etappi.lab.home
|
||||
|
442
poetry.lock
generated
Normal file
442
poetry.lock
generated
Normal file
@@ -0,0 +1,442 @@
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "ansible"
|
||||
version = "10.5.0"
|
||||
description = "Radically simple IT automation"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "ansible-10.5.0-py3-none-any.whl", hash = "sha256:1d10bddba58f1edd0fe0b8e0387e0fafc519535066bb3c919c33b6ea3ec32a0f"},
|
||||
{file = "ansible-10.5.0.tar.gz", hash = "sha256:ba2045031a7d60c203b6e5fe1f8eaddd53ae076f7ada910e636494384135face"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ansible-core = ">=2.17.5,<2.18.0"
|
||||
|
||||
[[package]]
|
||||
name = "ansible-core"
|
||||
version = "2.17.5"
|
||||
description = "Radically simple IT automation"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "ansible_core-2.17.5-py3-none-any.whl", hash = "sha256:10f165b475cf2bc8d886e532cadb32c52ee6a533649793101d3166bca9bd3ea3"},
|
||||
{file = "ansible_core-2.17.5.tar.gz", hash = "sha256:ae7f51fd13dc9d57c9bcd43ef23f9c255ca8f18f4b5c0011a4f9b724d92c5a8e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = "*"
|
||||
jinja2 = ">=3.0.0"
|
||||
packaging = "*"
|
||||
PyYAML = ">=5.1"
|
||||
resolvelib = ">=0.5.3,<1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ansible-vault"
|
||||
version = "2.1.0"
|
||||
description = "R/W an ansible-vault yaml file"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "ansible-vault-2.1.0.tar.gz", hash = "sha256:5ce8fdb5470f1449b76bf07ae2abc56480dad48356ae405c85b686efb64dbd5e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ansible = "*"
|
||||
setuptools = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "flake8", "isort[pyproject]", "pytest"]
|
||||
release = ["twine"]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "24.2.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
|
||||
{file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
|
||||
tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "1.17.1"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
|
||||
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "43.0.1"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
|
||||
{file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
|
||||
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
nox = ["nox"]
|
||||
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||
sdist = ["build"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
name = "grafanalib"
|
||||
version = "0.7.1"
|
||||
description = "Library for building Grafana dashboards"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "grafanalib-0.7.1-py3-none-any.whl", hash = "sha256:6fab5d7b837a1f2d1322ef762cd52e565ec0422707a7512765c59f668bdceb58"},
|
||||
{file = "grafanalib-0.7.1.tar.gz", hash = "sha256:3d92bb4e92ae78fe4e21c5b252ab51f4fdcacd8523ba5a44545b897b2a375b83"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=15.2.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["flake8", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.4"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
|
||||
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
MarkupSafe = ">=2.0"
|
||||
|
||||
[package.extras]
|
||||
i18n = ["Babel (>=2.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "markupsafe"
|
||||
version = "3.0.1"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-win32.whl", hash = "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97"},
|
||||
{file = "MarkupSafe-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-win32.whl", hash = "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635"},
|
||||
{file = "MarkupSafe-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-win32.whl", hash = "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa"},
|
||||
{file = "MarkupSafe-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-win32.whl", hash = "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-win32.whl", hash = "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b"},
|
||||
{file = "MarkupSafe-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-win32.whl", hash = "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8"},
|
||||
{file = "MarkupSafe-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b"},
|
||||
{file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netaddr"
|
||||
version = "1.3.0"
|
||||
description = "A network address manipulation library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe"},
|
||||
{file = "netaddr-1.3.0.tar.gz", hash = "sha256:5c3c3d9895b551b763779ba7db7a03487dc1f8e3b385af819af341ae9ef6e48a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
nicer-shell = ["ipython"]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.22"
|
||||
description = "C parser in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.2"
|
||||
description = "YAML parser and emitter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
|
||||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resolvelib"
|
||||
version = "1.0.1"
|
||||
description = "Resolve abstract dependencies into concrete ones"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"},
|
||||
{file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
examples = ["html5lib", "packaging", "pygraphviz", "requests"]
|
||||
lint = ["black", "flake8", "isort", "mypy", "types-requests"]
|
||||
release = ["build", "towncrier", "twine"]
|
||||
test = ["commentjson", "packaging", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "75.1.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"},
|
||||
{file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"]
|
||||
core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
|
||||
cover = ["pytest-cov"]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
|
||||
enabler = ["pytest-enabler (>=2.2)"]
|
||||
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
|
||||
type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "334448cb0c7d192f0e10987a995ecefca5e136733cce4dd15dcc2238f1c371c8"
|
20
pyproject.toml
Normal file
20
pyproject.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[tool.poetry]
|
||||
name = "alpina"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Iurii Tatishchev <itatishch@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
ansible = "^10.1.0"
|
||||
ansible-vault = "^2.1.0"
|
||||
netaddr = "^1.3.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
grafanalib = "^0.7.1"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
@@ -1 +0,0 @@
|
||||
ansible==6.0.0
|
15
roles/alpina/tasks/deploy_collection.yml
Normal file
15
roles/alpina/tasks/deploy_collection.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
- name: Ensure {{ collection }} collection directory exists
|
||||
file:
|
||||
path: "{{ alpina_svc_path }}/{{ collection }}"
|
||||
state: directory
|
||||
mode: "700"
|
||||
|
||||
- name: Deploy docker compose stacks for {{ collection }}
|
||||
vars:
|
||||
current_stack_name: "{{ stack }}"
|
||||
current_stack_dest: "{{ alpina_svc_path }}/{{ collection }}/{{ stack }}"
|
||||
current_stack_source: "{{ role_path }}/templates/{{ collection }}/{{ stack }}"
|
||||
include_tasks: deploy_compose_stack.yml
|
||||
loop: "{{ stacks }}"
|
||||
loop_control:
|
||||
loop_var: stack
|
42
roles/alpina/tasks/deploy_compose_stack.yml
Normal file
42
roles/alpina/tasks/deploy_compose_stack.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure {{ stack }} stack directory exists
|
||||
file:
|
||||
path: "{{ current_stack_dest }}"
|
||||
state: directory
|
||||
mode: "700"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_stack_dest }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "755"
|
||||
loop: "{{ lookup('community.general.filetree', current_stack_source) }}"
|
||||
when: item.state == "directory"
|
||||
|
||||
- name: Generate {{ current_stack_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_stack_dest }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "644"
|
||||
loop: "{{ lookup('community.general.filetree', current_stack_source) }}"
|
||||
when: item.state == "file" and item.path | regex_search('\\.j2$')
|
||||
|
||||
- name: Generate {{ current_stack_name }} deployment from static files
|
||||
copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_stack_dest }}/{{ item.path }}"
|
||||
mode: "644"
|
||||
loop: "{{ lookup('community.general.filetree', current_stack_source) }}"
|
||||
when: item.state == "file" and not item.path | regex_search('\\.j2$')
|
||||
|
||||
- name: Deploy docker-compose for {{ current_stack_name }}
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ current_stack_dest }}"
|
||||
state: present
|
||||
pull: always
|
||||
remove_orphans: yes
|
||||
register: docker_compose_output
|
||||
|
||||
# - debug:
|
||||
# var: docker_compose_output
|
34
roles/alpina/tasks/main.yml
Normal file
34
roles/alpina/tasks/main.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
- name: Register uid of remote user
|
||||
command: id -u
|
||||
register: remote_uid_command
|
||||
changed_when: false
|
||||
|
||||
- name: Set fact for uid
|
||||
set_fact:
|
||||
remote_uid: "{{ remote_uid_command.stdout }}"
|
||||
|
||||
- name: Ensure alpina directory exists
|
||||
file:
|
||||
state: directory
|
||||
path: "{{ alpina_svc_path }}"
|
||||
mode: "700"
|
||||
|
||||
- name: Deploy collection services
|
||||
vars:
|
||||
collection: services
|
||||
stacks:
|
||||
- traefik
|
||||
- monitoring
|
||||
- authentik
|
||||
- minio
|
||||
import_tasks: deploy_collection.yml
|
||||
|
||||
- name: Deploy collection apps
|
||||
vars:
|
||||
collection: apps
|
||||
stacks:
|
||||
- gitea
|
||||
- nextcloud
|
||||
- jellyfin
|
||||
- arrstack
|
||||
import_tasks: deploy_collection.yml
|
33
roles/alpina/templates/apps/arrstack/.env.gluetun.j2
Normal file
33
roles/alpina/templates/apps/arrstack/.env.gluetun.j2
Normal file
@@ -0,0 +1,33 @@
|
||||
## ProtonVPN OpenVPN
|
||||
#VPN_SERVICE_PROVIDER=protonvpn
|
||||
#OPENVPN_USER=+pmp
|
||||
#OPENVPN_PASSWORD=
|
||||
#SERVER_HOSTNAMES=node-us-160.protonvpn.net,node-us-161.protonvpn.net
|
||||
#VPN_PORT_FORWARDING=on
|
||||
|
||||
## ProtonVPN WireGuard
|
||||
#VPN_SERVICE_PROVIDER=custom
|
||||
#VPN_TYPE=wireguard
|
||||
#VPN_ENDPOINT_IP=
|
||||
#VPN_ENDPOINT_PORT=
|
||||
#WIREGUARD_PUBLIC_KEY=
|
||||
#WIREGUARD_PRIVATE_KEY=
|
||||
#WIREGUARD_PRESHARED_KEY=
|
||||
#WIREGUARD_ADDRESSES=
|
||||
#VPN_DNS_ADDRESS=
|
||||
#VPN_PORT_FORWARDING=on
|
||||
#VPN_PORT_FORWARDING_PROVIDER=protonvpn
|
||||
|
||||
## AirVPN
|
||||
VPN_SERVICE_PROVIDER=airvpn
|
||||
VPN_TYPE=wireguard
|
||||
SERVER_NAMES={{ vpn_server_names }}
|
||||
WIREGUARD_PUBLIC_KEY={{ wg_peer_pubkey }}
|
||||
WIREGUARD_PRIVATE_KEY={{ wg_privkey }}
|
||||
WIREGUARD_PRESHARED_KEY={{ wg_psk }}
|
||||
WIREGUARD_ADDRESSES={{ wg_addresses }}
|
||||
FIREWALL_VPN_INPUT_PORTS={{ fw_vpn_input_ports }}
|
||||
|
||||
UPDATER_PERIOD=24h
|
||||
|
||||
#FIREWALL_OUTBOUND_SUBNETS=10.0.0.0/8,{{ docker_ipv6_subnet }}
|
88
roles/alpina/templates/apps/arrstack/docker-compose.yml.j2
Normal file
88
roles/alpina/templates/apps/arrstack/docker-compose.yml.j2
Normal file
@@ -0,0 +1,88 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(249) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
sysctls:
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
env_file:
|
||||
- .env.gluetun
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/gluetun:/gluetun
|
||||
|
||||
qbittorrent:
|
||||
image: linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('qbit', port='8080', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
{# Keeping this for debugging purposes -#}
|
||||
- DOCKER_MODS=linuxserver/mods:universal-package-install
|
||||
network_mode: service:gluetun
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/qbittorrent:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
||||
- {{ media_volume_path }}/iso-img:/media/iso-img
|
||||
depends_on:
|
||||
gluetun:
|
||||
condition: service_healthy
|
||||
|
||||
prowlarr:
|
||||
image: linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('prowlarr', port='9696', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/prowlarr:/config
|
||||
|
||||
sonarr:
|
||||
image: linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('sonarr', port='8989', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/sonarr:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
||||
|
||||
radarr:
|
||||
image: linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('radarr', port='7878', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/radarr:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
3
roles/alpina/templates/apps/gitea/.env.db.j2
Normal file
3
roles/alpina/templates/apps/gitea/.env.db.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
POSTGRES_USER=gitea
|
||||
POSTGRES_DB=gitea
|
||||
POSTGRES_PASSWORD={{ gitea_db_password }}
|
29
roles/alpina/templates/apps/gitea/.env.gitea.j2
Normal file
29
roles/alpina/templates/apps/gitea/.env.gitea.j2
Normal file
@@ -0,0 +1,29 @@
|
||||
GITEA____APP_NAME=CazGitea
|
||||
|
||||
# Database
|
||||
GITEA__database__DB_TYPE=postgres
|
||||
GITEA__database__HOST=db:5432
|
||||
GITEA__database__NAME=gitea
|
||||
GITEA__database__USER=gitea
|
||||
GITEA__database__PASSWD={{ gitea_db_password }}
|
||||
|
||||
# Server
|
||||
GITEA__server__ROOT_URL=https://gitea.{{ domain }}/
|
||||
GITEA__server__DISABLE_SSH=true
|
||||
|
||||
# Mail
|
||||
GITEA__mailer__ENABLED=true
|
||||
GITEA__mailer__SMTP_ADDR=smtp.sendgrid.net
|
||||
GITEA__mailer__SMTP_PORT=587
|
||||
GITEA__mailer__FROM=gitea@cazzzer.com
|
||||
GITEA__mailer__USER=apikey
|
||||
GITEA__mailer__PASSWD={{ gitea_sendgrid_api_key }}
|
||||
|
||||
# Security
|
||||
GITEA__security__SECRET_KEY={{ secret_key }}
|
||||
GITEA__security__INTERNAL_TOKEN={{ internal_token }}
|
||||
|
||||
GITEA__oauth2__JWT_SECRET={{ jwt_secret }}
|
||||
|
||||
# Indexer
|
||||
GITEA__indexer__REPO_INDEXER_ENABLED=true
|
@@ -1,22 +1,16 @@
|
||||
version: "3.9"
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
default:
|
||||
{{ helpers.default_network(199) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
gitea:
|
||||
postgres:
|
||||
|
||||
services:
|
||||
server:
|
||||
image: gitea/gitea:1.17.2
|
||||
image: gitea/gitea:1.22
|
||||
container_name: gitea_server
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.gitea.rule=Host(`gitea.{{ domain }}`)
|
||||
- traefik.http.services.gitea.loadbalancer.server.port=3000
|
||||
- {{ helpers.traefik_labels('gitea', port='3000') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.gitea
|
||||
@@ -24,11 +18,11 @@ services:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- gitea:/data
|
||||
- {{ base_volume_path }}/gitea/gitea:/data
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:14-alpine
|
||||
image: postgres:16-alpine
|
||||
container_name: gitea_db
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
@@ -36,4 +30,4 @@ services:
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
- {{ base_volume_path }}/gitea/postgres:/var/lib/postgresql/data
|
1
roles/alpina/templates/apps/jellyfin/.env.jellyfin.j2
Normal file
1
roles/alpina/templates/apps/jellyfin/.env.jellyfin.j2
Normal file
@@ -0,0 +1 @@
|
||||
JELLYFIN_PublishedServerUrl=https://jellyfin.{{ domain }}
|
28
roles/alpina/templates/apps/jellyfin/docker-compose.yml.j2
Normal file
28
roles/alpina/templates/apps/jellyfin/docker-compose.yml.j2
Normal file
@@ -0,0 +1,28 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(197) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
container_name: jellyfin_jellyfin
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('jellyfin', port='8096') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.jellyfin
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/jellyfin/config:/config
|
||||
- {{ base_volume_path }}/jellyfin/cache:/cache
|
||||
- {{ media_volume_path }}/Plex/media:/data/media:ro
|
||||
- {{ media_volume_path }}/other_videos:/data/other_videos:ro
|
||||
tmpfs:
|
||||
- /tmp/transcodes
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
@@ -1,3 +1,3 @@
|
||||
POSTGRES_USER=nextcloud
|
||||
POSTGRES_DB=nextcloud
|
||||
POSTGRES_PASSWORD="{{ db_password }}"
|
||||
POSTGRES_PASSWORD={{ nextcloud_db_password }}
|
1
roles/alpina/templates/apps/nextcloud/.env.j2
Normal file
1
roles/alpina/templates/apps/nextcloud/.env.j2
Normal file
@@ -0,0 +1 @@
|
||||
NEXTCLOUD_VERSION=30-apache
|
24
roles/alpina/templates/apps/nextcloud/.env.nextcloud.j2
Normal file
24
roles/alpina/templates/apps/nextcloud/.env.nextcloud.j2
Normal file
@@ -0,0 +1,24 @@
|
||||
POSTGRES_DB=nextcloud
|
||||
POSTGRES_USER=nextcloud
|
||||
POSTGRES_PASSWORD={{ nextcloud_db_password }}
|
||||
POSTGRES_HOST=db
|
||||
|
||||
NEXTCLOUD_TRUSTED_DOMAINS=nc.{{ domain }}
|
||||
|
||||
REDIS_HOST=redis
|
||||
REDIS_HOST_PASSWORD={{ redis_password }}
|
||||
|
||||
SMTP_HOST=smtp.sendgrid.net
|
||||
SMTP_SECURE=tls
|
||||
SMTP_PORT=587
|
||||
SMTP_AUTHTYPE=LOGIN
|
||||
SMTP_NAME=apikey
|
||||
SMTP_PASSWORD={{ nextcloud_sendgrid_api_key }}
|
||||
MAIL_FROM_ADDRESS=nc
|
||||
MAIL_DOMAIN=cazzzer.com
|
||||
|
||||
# host IPv4 and IPv6 addresses, loopback for notify_push
|
||||
TRUSTED_PROXIES={{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }} {{ hostvars[inventory_hostname]['ansible_default_ipv6']['address'] }} 127.0.0.1 ::1
|
||||
OVERWRITEHOST=nc.{{ domain }}
|
||||
OVERWRITEPROTOCOL=https
|
||||
OVERWRITECLIURL=https://nc.{{ domain }}
|
@@ -0,0 +1,4 @@
|
||||
DATABASE_URL=postgres://nextcloud:{{ nextcloud_db_password }}@db/nextcloud
|
||||
DATABASE_PREFIX=oc_
|
||||
REDIS_URL=redis://:{{ redis_password }}@redis
|
||||
NEXTCLOUD_URL=http://localhost
|
1
roles/alpina/templates/apps/nextcloud/.env.redis.j2
Normal file
1
roles/alpina/templates/apps/nextcloud/.env.redis.j2
Normal file
@@ -0,0 +1 @@
|
||||
REDIS_PASSWORD={{ redis_password }}
|
87
roles/alpina/templates/apps/nextcloud/docker-compose.yml.j2
Normal file
87
roles/alpina/templates/apps/nextcloud/docker-compose.yml.j2
Normal file
@@ -0,0 +1,87 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(198) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_app
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('nc', port='80') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
env_file:
|
||||
- .env.nextcloud
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
|
||||
cron:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_cron
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
entrypoint: /cron.sh
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
|
||||
notify_push:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_notify_push
|
||||
{# TODO: Refactor this and minio -#}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.nc-notify.rule=Host(`nc.{{ domain }}`) && PathPrefix(`/push`)
|
||||
- traefik.http.routers.nc-notify.entrypoints=websecure
|
||||
- traefik.http.routers.nc-notify.tls=true
|
||||
- traefik.http.routers.nc-notify.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.nc-notify.tls.domains.0.main={{ domain }}
|
||||
- traefik.http.routers.nc-notify.tls.domains.0.sans=*.{{ domain }}
|
||||
- traefik.http.services.nc-notify.loadbalancer.server.port=7867
|
||||
restart: unless-stopped
|
||||
user: www-data
|
||||
env_file:
|
||||
- .env.notify_push
|
||||
network_mode: service:app
|
||||
entrypoint:
|
||||
- /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
container_name: nextcloud_db
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/db:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: nextcloud_redis
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.redis
|
||||
networks:
|
||||
- default
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- redis-server --requirepass $$REDIS_PASSWORD
|
21
roles/alpina/templates/services/authentik/.env.authentik.j2
Normal file
21
roles/alpina/templates/services/authentik/.env.authentik.j2
Normal file
@@ -0,0 +1,21 @@
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED=true
|
||||
|
||||
AUTHENTIK_REDIS__HOST=redis
|
||||
AUTHENTIK_POSTGRESQL__HOST=postgres
|
||||
AUTHENTIK_POSTGRESQL__USER=authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME=authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD={{ authentik_db_password }}
|
||||
|
||||
AUTHENTIK_SECRET_KEY={{ authentik_secret_key }}
|
||||
|
||||
AUTHENTIK_EMAIL__HOST=smtp.sendgrid.net
|
||||
AUTHENTIK_EMAIL__PORT=587
|
||||
AUTHENTIK_EMAIL__USERNAME=apikey
|
||||
AUTHENTIK_EMAIL__PASSWORD={{ authentik_sendgrid_api_key }}
|
||||
|
||||
AUTHENTIK_EMAIL__USE_TLS=true
|
||||
AUTHENTIK_EMAIL__TIMEOUT=10
|
||||
AUTHENTIK_EMAIL__FROM=auth@cazzzer.com
|
||||
|
||||
AUTHENTIK_DEFAULT_USER_CHANGE_EMAIL=false
|
||||
AUTHENTIK_DEFAULT_USER_CHANGE_USERNAME=false
|
3
roles/alpina/templates/services/authentik/.env.db.j2
Normal file
3
roles/alpina/templates/services/authentik/.env.db.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
POSTGRES_USER=authentik
|
||||
POSTGRES_DB=authentik
|
||||
POSTGRES_PASSWORD={{ authentik_db_password }}
|
@@ -0,0 +1,84 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - OAuth2 Apps
|
||||
entries:
|
||||
{% set apps = {
|
||||
"Grafana": {
|
||||
"redirect_uri": "https://grafana."~ domain ~"/login/generic_oauth",
|
||||
"icon": "https://grafana."~ domain ~"/public/img/grafana_icon.svg",
|
||||
"client_secret": auth_grafana_client_secret,
|
||||
"ui_group": "Services",
|
||||
"allowed_for_groups": ["admins"],
|
||||
},
|
||||
"Minio": {
|
||||
"redirect_uri": "https://minio."~ domain ~"/oauth_callback",
|
||||
"icon": "https://minio."~ domain ~"/logo192.png",
|
||||
"client_secret": auth_minio_client_secret,
|
||||
"ui_group": "Services",
|
||||
"allowed_for_groups": ["admins"],
|
||||
},
|
||||
"Gitea": {
|
||||
"redirect_uri": "https://gitea."~ domain ~"/user/oauth2/Authentik/callback",
|
||||
"icon": "https://gitea."~ domain ~"/assets/img/logo.svg",
|
||||
"client_secret": auth_gitea_client_secret,
|
||||
"ui_group": "Apps",
|
||||
"allowed_for_groups": ["admins", "users"],
|
||||
},
|
||||
"Nextcloud": {
|
||||
"redirect_uri": "https://nc."~ domain ~"/apps/sociallogin/custom_oidc/authentik",
|
||||
"icon": "https://nc."~ domain ~"/apps/theming/favicon",
|
||||
"client_secret": auth_nextcloud_client_secret,
|
||||
"ui_group": "Apps",
|
||||
"allowed_for_groups": ["admins", "users"],
|
||||
},
|
||||
} -%}
|
||||
{% for app in apps.keys() -%}
|
||||
- identifiers:
|
||||
name: {{ app }}
|
||||
model: authentik_providers_oauth2.oauth2provider
|
||||
id: {{ app }}
|
||||
attrs:
|
||||
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
|
||||
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
|
||||
client_type: confidential
|
||||
client_id: {{ app | lower }}
|
||||
client_secret: {{ apps[app]["client_secret"] }}
|
||||
property_mappings:
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
|
||||
{% if app == "Minio" -%}
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, minio]]
|
||||
{%- endif %}
|
||||
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: {{ apps[app]["redirect_uri"] }}
|
||||
# Necessary for JWKS to be generated correctly
|
||||
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
|
||||
|
||||
- identifiers:
|
||||
slug: {{ app | lower }}
|
||||
model: authentik_core.application
|
||||
id: app-{{ app }}
|
||||
attrs:
|
||||
name: {{ app }}
|
||||
group: "{{ apps[app]["ui_group"] }}"
|
||||
meta_description: "Hello, I'm {{ app }}!"
|
||||
meta_publisher: Alpina
|
||||
icon: "{{ apps[app]["icon"] }}"
|
||||
open_in_new_tab: true
|
||||
provider: !KeyOf {{ app }}
|
||||
|
||||
{% for group in apps[app]["allowed_for_groups"] -%}
|
||||
- identifiers:
|
||||
group: !Find [authentik_core.group, [name, {{ group }}]]
|
||||
target: !KeyOf app-{{ app }}
|
||||
model: authentik_policies.policybinding
|
||||
attrs:
|
||||
order: 10
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
@@ -0,0 +1,88 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - Proxied Apps
|
||||
entries:
|
||||
# TODO: Possibly refactor this into a jinja macro (?)
|
||||
{% set apps = {
|
||||
"Uptime Kuma": {
|
||||
"host": "uptime",
|
||||
"icon": "https://uptime."~ domain ~"/icon.svg",
|
||||
"unauthenticated_paths": "^/icon.svg$",
|
||||
"ui_group": "Services",
|
||||
"allowed_for_groups": ["admins"],
|
||||
},
|
||||
"qBit": {
|
||||
"host": "qbit",
|
||||
"icon": "https://qbit."~ domain ~"/images/qbittorrent-tray.svg",
|
||||
"unauthenticated_paths": "^/images/qbittorrent-tray.svg$",
|
||||
"ui_group": "Arrstack",
|
||||
"allowed_for_groups": ["arrstack"],
|
||||
},
|
||||
"Prowlarr": {
|
||||
"host": "prowlarr",
|
||||
"icon": "https://prowlarr."~ domain ~"/Content/Images/logo.svg",
|
||||
"unauthenticated_paths": "^/Content/Images/logo.svg$",
|
||||
"ui_group": "Arrstack",
|
||||
"allowed_for_groups": ["arrstack"],
|
||||
},
|
||||
"Sonarr": {
|
||||
"host": "sonarr",
|
||||
"icon": "https://sonarr."~ domain ~"/Content/Images/logo.svg",
|
||||
"unauthenticated_paths": "^/Content/Images/logo.svg$",
|
||||
"ui_group": "Arrstack",
|
||||
"allowed_for_groups": ["arrstack"],
|
||||
},
|
||||
"Radarr": {
|
||||
"host": "radarr",
|
||||
"icon": "https://radarr."~ domain ~"/Content/Images/logo.svg",
|
||||
"unauthenticated_paths": "^/Content/Images/logo.svg$",
|
||||
"ui_group": "Arrstack",
|
||||
"allowed_for_groups": ["arrstack"],
|
||||
},
|
||||
} -%}
|
||||
{% for app in apps.keys() -%}
|
||||
- identifiers:
|
||||
name: {{ app }}
|
||||
model: authentik_providers_proxy.proxyprovider
|
||||
id: {{ app }}
|
||||
attrs:
|
||||
authorization_flow: !Find [authentik_flows.flow, [ slug, default-provider-authorization-implicit-consent ] ]
|
||||
mode: forward_single
|
||||
external_host: "https://{{ apps[app]["host"] }}.{{ domain }}/"
|
||||
skip_path_regex: "{{ apps[app]["unauthenticated_paths"] }}"
|
||||
|
||||
- identifiers:
|
||||
slug: {{ app | lower | replace(" ", "-") }}
|
||||
model: authentik_core.application
|
||||
id: app-{{ app }}
|
||||
attrs:
|
||||
name: {{ app }}
|
||||
group: {{ apps[app]["ui_group"] }}
|
||||
meta_description: "Hello, I'm {{ app }}!"
|
||||
meta_publisher: Alpina
|
||||
icon: "{{ apps[app]["icon"] }}"
|
||||
open_in_new_tab: true
|
||||
provider: !KeyOf {{ app }}
|
||||
|
||||
{% for group in apps[app]["allowed_for_groups"] -%}
|
||||
- identifiers:
|
||||
group: !Find [authentik_core.group, [name, {{ group }}]]
|
||||
target: !KeyOf app-{{ app }}
|
||||
model: authentik_policies.policybinding
|
||||
attrs:
|
||||
order: 10
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
- identifiers:
|
||||
managed: goauthentik.io/outposts/embedded
|
||||
name: authentik Embedded Outpost
|
||||
model: authentik_outposts.outpost
|
||||
attrs:
|
||||
providers:
|
||||
{% for app in apps.keys() -%}
|
||||
- !KeyOf {{ app }}
|
||||
{% endfor %}
|
@@ -0,0 +1,58 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - Default Authentication Modifications
|
||||
entries:
|
||||
# Add a new flow for passwordless WebAuthn authentication
|
||||
- identifiers:
|
||||
slug: authentication-passwordless-flow
|
||||
model: authentik_flows.flow
|
||||
attrs:
|
||||
designation: authentication
|
||||
name: WebAuthn Authentication Flow
|
||||
title: Sign in with a passkey
|
||||
|
||||
# Add a new stage to the flow to validate just WebAuthn devices
|
||||
- identifiers:
|
||||
name: webauthn-validation
|
||||
model: authentik_stages_authenticator_validate.authenticatorvalidatestage
|
||||
attrs:
|
||||
device_classes:
|
||||
- webauthn
|
||||
not_configured_action: deny
|
||||
webauthn_user_verification: required
|
||||
|
||||
# Stage bindings for passwordless flow,
|
||||
# 1. Validate WebAuthn key
|
||||
- identifiers:
|
||||
order: 10
|
||||
stage: !Find [authentik_stages_authenticator_validate.authenticatorvalidatestage, [name, webauthn-validation]]
|
||||
target: !Find [authentik_flows.flow, [slug, authentication-passwordless-flow]]
|
||||
model: authentik_flows.flowstagebinding
|
||||
# 2. Finish authenticating user
|
||||
- identifiers:
|
||||
order: 100
|
||||
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]]
|
||||
target: !Find [authentik_flows.flow, [slug, authentication-passwordless-flow]]
|
||||
model: authentik_flows.flowstagebinding
|
||||
|
||||
# Some modifications to the default identification stage
|
||||
- identifiers:
|
||||
name: default-authentication-identification
|
||||
model: authentik_stages_identification.identificationstage
|
||||
attrs:
|
||||
# Allow username and password fields to be on the same page
|
||||
password_stage: !Find [authentik_stages_password.passwordstage, [name, default-authentication-password]]
|
||||
# Add a button to use the passwordless WebAuthn flow
|
||||
passwordless_flow: !Find [authentik_flows.flow, [slug, authentication-passwordless-flow]]
|
||||
sources:
|
||||
- !Find [authentik_core.source, [slug, authentik-built-in]]
|
||||
- !Find [authentik_sources_oauth.oauthsource, [slug, github]]
|
||||
|
||||
# Enable compatibility mode for the default authentication flow for better autofill support
|
||||
- identifiers:
|
||||
slug: default-authentication-flow
|
||||
model: authentik_flows.flow
|
||||
attrs:
|
||||
compatibility_mode: true
|
@@ -0,0 +1,40 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - Default Groups
|
||||
entries:
|
||||
- identifiers:
|
||||
name: "admins"
|
||||
model: authentik_core.group
|
||||
id: "admins"
|
||||
attrs:
|
||||
is_superuser: true
|
||||
|
||||
- identifiers:
|
||||
name: "users"
|
||||
model: authentik_core.group
|
||||
id: "users"
|
||||
|
||||
- identifiers:
|
||||
name: "arrstack"
|
||||
model: authentik_core.group
|
||||
id: "arrstack"
|
||||
attrs:
|
||||
arrstack_username: "arr"
|
||||
arrstack_password: "{{ arrstack_password }}"
|
||||
|
||||
- identifiers:
|
||||
scope_name: "minio"
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
id: "scope-minio"
|
||||
attrs:
|
||||
name: "Minio Policy"
|
||||
expression: |
|
||||
policy = "default"
|
||||
if ak_is_group_member(request.user, name="admins"):
|
||||
policy = "consoleAdmin"
|
||||
|
||||
return {
|
||||
"policy": policy,
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - GitHub OAuth
|
||||
entries:
|
||||
- identifiers:
|
||||
slug: github
|
||||
model: authentik_sources_oauth.oauthsource
|
||||
attrs:
|
||||
name: GitHub
|
||||
slug: github
|
||||
access_token_url: https://github.com/login/oauth/access_token
|
||||
additional_scopes: openid read:org
|
||||
authentication_flow: !Find [authentik_flows.flow, [slug, default-source-authentication]]
|
||||
authorization_url: https://github.com/login/oauth/authorize
|
||||
consumer_key: {{ github_consumer_key }}
|
||||
consumer_secret: {{ github_consumer_secret }}
|
||||
enabled: true
|
||||
enrollment_flow: !Find [authentik_flows.flow, [slug, default-source-enrollment]]
|
||||
policy_engine_mode: any
|
||||
profile_url: https://api.github.com/user
|
||||
provider_type: github
|
||||
user_matching_mode: email_link
|
||||
user_path_template: goauthentik.io/sources/%(slug)s
|
@@ -0,0 +1,66 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(253) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
server:
|
||||
image: ghcr.io/goauthentik/server:latest
|
||||
container_name: authentik_server
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('auth', port='9000') | indent(6) }}
|
||||
- traefik.http.middlewares.authentik.forwardauth.address=http://localhost:9000/outpost.goauthentik.io/auth/traefik
|
||||
- traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true
|
||||
- traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=Authorization,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version
|
||||
restart: unless-stopped
|
||||
# Port forward is needed because traefik can't resolve the container name from the host network
|
||||
ports:
|
||||
- "9000:9000"
|
||||
command: server
|
||||
env_file:
|
||||
- .env.authentik
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
|
||||
worker:
|
||||
image: ghcr.io/goauthentik/server:latest
|
||||
container_name: authentik_worker
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
env_file:
|
||||
- .env.authentik
|
||||
volumes:
|
||||
- ./blueprints:/blueprints/alpina
|
||||
- {{ base_volume_path }}/authentik/certs:/certs
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: authentik_postgres
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 5s
|
||||
volumes:
|
||||
- {{ base_volume_path }}/authentik/postgres:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: authentik_redis
|
||||
restart: unless-stopped
|
||||
command: --save 60 1 --loglevel warning
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- {{ base_volume_path }}/authentik/redis:/data
|
20
roles/alpina/templates/services/minio/.env.minio.j2
Normal file
20
roles/alpina/templates/services/minio/.env.minio.j2
Normal file
@@ -0,0 +1,20 @@
|
||||
MINIO_ROOT_USER=minio
|
||||
MINIO_ROOT_PASSWORD={{ minio_password }}
|
||||
|
||||
MINIO_DOMAIN=s3.{{ domain }}
|
||||
MINIO_SERVER_URL=https://s3.{{ domain }}
|
||||
MINIO_BROWSER_REDIRECT_URL=https://minio.{{ domain }}
|
||||
|
||||
# https://min.io/docs/minio/linux/reference/minio-server/settings/iam/openid.html
|
||||
MINIO_IDENTITY_OPENID_CONFIG_URL=https://auth.{{ domain }}/application/o/minio/.well-known/openid-configuration
|
||||
MINIO_IDENTITY_OPENID_CLIENT_ID=minio
|
||||
MINIO_IDENTITY_OPENID_CLIENT_SECRET={{ auth_minio_client_secret }}
|
||||
# defaults to "policy"
|
||||
#MINIO_IDENTITY_OPENID_CLAIM_NAME=policy
|
||||
MINIO_IDENTITY_OPENID_DISPLAY_NAME=Authentik
|
||||
# no need to specify scopes,
|
||||
# as it defaults to the ones advertised at the discovery url
|
||||
#MINIO_IDENTITY_OPENID_SCOPES=openid,profile,email,minio
|
||||
#MINIO_IDENTITY_OPENID_REDIRECT_URI_DYNAMIC=off
|
||||
#MINIO_IDENTITY_OPENID_CLAIM_USERINFO=on
|
||||
#MINIO_IDENTITY_OPENID_COMMENT=
|
32
roles/alpina/templates/services/minio/docker-compose.yml.j2
Normal file
32
roles/alpina/templates/services/minio/docker-compose.yml.j2
Normal file
@@ -0,0 +1,32 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(252) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
container_name: minio
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('minio', port='9090') | indent(6) }}
|
||||
- traefik.http.routers.minio.service=minio
|
||||
- traefik.http.routers.minio-tls.service=minio
|
||||
- traefik.http.routers.minio-s3.rule=Host(`s3.{{ domain }}`) || HostRegexp(`^.+[.]s3[.]{{ domain }}`)
|
||||
- traefik.http.routers.minio-s3.entrypoints=websecure
|
||||
- traefik.http.routers.minio-s3.tls=true
|
||||
- traefik.http.routers.minio-s3.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.minio-s3.tls.domains.0.main=s3.{{ domain }}
|
||||
- traefik.http.routers.minio-s3.tls.domains.0.sans=*.s3.{{ domain }}
|
||||
- traefik.http.routers.minio-s3.service=minio-s3
|
||||
- traefik.http.services.minio-s3.loadbalancer.server.port=9000
|
||||
restart: unless-stopped
|
||||
command: server --console-address ":9090" /data
|
||||
env_file:
|
||||
- .env.minio
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/minio/data:/data
|
@@ -0,0 +1,7 @@
|
||||
DOCKER_INFLUXDB_INIT_MODE=setup
|
||||
DOCKER_INFLUXDB_INIT_ORG=home
|
||||
DOCKER_INFLUXDB_INIT_BUCKET=influx
|
||||
DOCKER_INFLUXDB_INIT_USERNAME=CaZzzer
|
||||
DOCKER_INFLUXDB_INIT_PASSWORD={{ influxdb_admin_password }}
|
||||
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN={{ influxdb_admin_token }}
|
||||
DOCKER_INFLUXDB_INIT_RETENTION=1w
|
17
roles/alpina/templates/services/monitoring/Dockerfile
Normal file
17
roles/alpina/templates/services/monitoring/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM python:3-alpine AS builder
|
||||
|
||||
RUN pip install grafanalib
|
||||
|
||||
COPY ./grafana_config/dashboards /dashboards
|
||||
|
||||
# Required for grafanalib to find the shared python files like common.py
|
||||
# https://github.com/weaveworks/grafanalib/issues/58
|
||||
ENV PYTHONPATH=/dashboards
|
||||
|
||||
RUN generate-dashboards /dashboards/*.dashboard.py
|
||||
|
||||
FROM grafana/grafana:latest
|
||||
|
||||
#COPY ./grafana_config /etc/grafana
|
||||
COPY ./grafana_config/dashboards/*.yaml /etc/grafana/provisioning/dashboards
|
||||
COPY --from=builder /dashboards/*.json /etc/grafana/provisioning/dashboards
|
119
roles/alpina/templates/services/monitoring/docker-compose.yml.j2
Normal file
119
roles/alpina/templates/services/monitoring/docker-compose.yml.j2
Normal file
@@ -0,0 +1,119 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(251) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
grafana:
|
||||
{# image: grafana/grafana:latest#}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: grafana
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('grafana', port='3000') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
# Needed to make config files readable (not anymore, TODO: remove)
|
||||
user: "{{ remote_uid }}"
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/monitoring/grafana:/var/lib/grafana
|
||||
- ./grafana_config/grafana.ini:/etc/grafana/grafana.ini:ro
|
||||
- ./grafana_config/datasources:/etc/grafana/provisioning/datasources:ro
|
||||
{# - ./grafana_config:/etc/grafana:ro#}
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
# Needed to make config files readable (not anymore, TODO: remove)
|
||||
user: "{{ remote_uid }}"
|
||||
command:
|
||||
- -config.file=/etc/loki/loki-config.yaml
|
||||
# Port forward is needed because not possible to resolve the container name from the host network
|
||||
ports:
|
||||
- 3100:3100
|
||||
volumes:
|
||||
- {{ base_volume_path }}/monitoring/loki:/loki
|
||||
- ./loki_config:/etc/loki:ro
|
||||
tmpfs:
|
||||
- /tmp/loki
|
||||
|
||||
promtail:
|
||||
image: grafana/promtail:latest
|
||||
container_name: promtail
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- -config.file=/etc/promtail/promtail-config.yaml
|
||||
ports:
|
||||
- 514:514
|
||||
volumes:
|
||||
- ./promtail_config:/etc/promtail:ro
|
||||
- /var/log:/var/log:ro
|
||||
tmpfs:
|
||||
- /tmp
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
# Needed to make config files readable (not anymore, TODO: remove)
|
||||
user: "{{ remote_uid }}"
|
||||
command:
|
||||
- --config.file=/etc/prometheus/prometheus.yml
|
||||
- --storage.tsdb.retention.time=30d
|
||||
volumes:
|
||||
- ./prometheus_config:/etc/prometheus:ro
|
||||
- {{ base_volume_path }}/monitoring/prometheus_configs:/etc/prometheus/extra:ro
|
||||
- {{ base_volume_path }}/monitoring/prometheus:/prometheus
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:latest
|
||||
container_name: node-exporter
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
pid: host
|
||||
volumes:
|
||||
- /:/host:ro,rslave
|
||||
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
container_name: cadvisor
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --docker_only=true
|
||||
- --store_container_labels=false
|
||||
- --whitelisted_container_labels=com.docker.compose.project,com.docker.compose.service
|
||||
- --enable_metrics=cpu,cpuLoad,diskIO,memory,network,oom_event,process
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:rw
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker/:/var/lib/docker:ro
|
||||
|
||||
influxdb:
|
||||
image: influxdb:2.7-alpine
|
||||
container_name: influxdb
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('influxdb', port='8086') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.influxdb
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/monitoring/influxdb:/var/lib/influxdb2
|
||||
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:1
|
||||
container_name: uptime-kuma
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('uptime', port='3001', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- {{ base_volume_path }}/monitoring/uptime-kuma:/app/data
|
@@ -0,0 +1,9 @@
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: "Grafana"
|
||||
org_id: 1
|
||||
folder: "Alpina"
|
||||
type: "file"
|
||||
options:
|
||||
path: "/etc/grafana/provisioning/dashboards"
|
@@ -0,0 +1,27 @@
|
||||
from grafanalib.core import Template
|
||||
|
||||
# TODO: consider default params for common params like line width, show points, tooltip
|
||||
|
||||
PrometheusTemplate = Template(
|
||||
name='datasource',
|
||||
type='datasource',
|
||||
label='Prometheus',
|
||||
query='prometheus',
|
||||
)
|
||||
|
||||
# TODO: this slightly less (clown emoji), normal Target gave me errors in grafana
|
||||
class LokiTarget(object):
|
||||
def __init__(self, loki_datasource, expr, legendFormat, refId):
|
||||
self.loki_datasource = loki_datasource
|
||||
self.expr = expr
|
||||
self.legendFormat = legendFormat
|
||||
self.refId = refId
|
||||
|
||||
def to_json_data(self):
|
||||
return {
|
||||
'datasource': self.loki_datasource,
|
||||
'expr': self.expr,
|
||||
'legendFormat': self.legendFormat,
|
||||
'refId': self.refId,
|
||||
'queryType': 'range',
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
from grafanalib.core import (
|
||||
Dashboard, TimeSeries,
|
||||
Target, GridPos,
|
||||
Templating, Template, REFRESH_ON_TIME_RANGE_CHANGE, Logs
|
||||
)
|
||||
from grafanalib.formatunits import BYTES_IEC, SECONDS, BYTES_SEC_IEC
|
||||
|
||||
from common import LokiTarget, PrometheusTemplate
|
||||
|
||||
prom_datasource='${datasource}'
|
||||
loki_datasource='loki'
|
||||
|
||||
dashboard = Dashboard(
|
||||
title='Containers',
|
||||
uid='containers',
|
||||
description='Data for compose projects from default Prometheus datasource collected by Cadvisor',
|
||||
tags=[
|
||||
'linux',
|
||||
'docker',
|
||||
],
|
||||
templating=Templating(list=[
|
||||
PrometheusTemplate,
|
||||
Template(
|
||||
name='compose_project',
|
||||
label='Compose Project',
|
||||
dataSource=prom_datasource,
|
||||
query='label_values({__name__=~"container.*"}, container_label_com_docker_compose_project)',
|
||||
includeAll=True,
|
||||
multi=True,
|
||||
refresh=REFRESH_ON_TIME_RANGE_CHANGE,
|
||||
),
|
||||
Template(
|
||||
name='container_name',
|
||||
label='Container',
|
||||
dataSource=prom_datasource,
|
||||
query='label_values({__name__=~"container.*", container_label_com_docker_compose_project=~"$compose_project"}, name)',
|
||||
includeAll=True,
|
||||
multi=True,
|
||||
refresh=REFRESH_ON_TIME_RANGE_CHANGE,
|
||||
),
|
||||
Template(
|
||||
name='logs_query',
|
||||
label='Log Search',
|
||||
query='',
|
||||
type='textbox',
|
||||
),
|
||||
]),
|
||||
timezone='browser',
|
||||
panels=[
|
||||
TimeSeries(
|
||||
title='Container Memory Usage',
|
||||
unit=BYTES_IEC,
|
||||
gridPos=GridPos(h=8, w=12, x=0, y=0),
|
||||
lineWidth=2,
|
||||
fillOpacity=10,
|
||||
showPoints='never',
|
||||
stacking={'mode': 'normal'},
|
||||
tooltipMode='all',
|
||||
tooltipSort='desc',
|
||||
targets=[
|
||||
Target(
|
||||
datasource=prom_datasource,
|
||||
expr='max by (name) (container_memory_usage_bytes{name=~"$container_name", container_label_com_docker_compose_project=~"$compose_project"})',
|
||||
legendFormat='{{ name }}',
|
||||
refId='A',
|
||||
),
|
||||
],
|
||||
),
|
||||
TimeSeries(
|
||||
title='Container CPU Usage',
|
||||
unit=SECONDS,
|
||||
gridPos=GridPos(h=8, w=12, x=12, y=0),
|
||||
lineWidth=2,
|
||||
fillOpacity=10,
|
||||
showPoints='never',
|
||||
tooltipMode='all',
|
||||
tooltipSort='desc',
|
||||
targets=[
|
||||
Target(
|
||||
datasource=prom_datasource,
|
||||
expr='max by (name) (rate(container_cpu_usage_seconds_total{name=~"$container_name", container_label_com_docker_compose_project=~"$compose_project"}[$__rate_interval]))',
|
||||
legendFormat='{{ name }}',
|
||||
refId='A',
|
||||
),
|
||||
],
|
||||
),
|
||||
TimeSeries(
|
||||
title='Container Network Traffic',
|
||||
unit=BYTES_SEC_IEC,
|
||||
gridPos=GridPos(h=8, w=12, x=0, y=8),
|
||||
lineWidth=2,
|
||||
fillOpacity=10,
|
||||
showPoints='never',
|
||||
tooltipMode='all',
|
||||
tooltipSort='desc',
|
||||
targets=[
|
||||
Target(
|
||||
datasource=prom_datasource,
|
||||
expr='max by (name) (rate(container_network_receive_bytes_total{name=~"$container_name", container_label_com_docker_compose_project=~"$compose_project"}[$__rate_interval]))',
|
||||
legendFormat="rx {{ name }}",
|
||||
refId='A',
|
||||
),
|
||||
Target(
|
||||
datasource=prom_datasource,
|
||||
expr='-max by (name) (rate(container_network_transmit_bytes_total{name=~"$container_name", container_label_com_docker_compose_project=~"$compose_project"}[$__rate_interval]))',
|
||||
legendFormat="tx {{ name }}",
|
||||
refId='B',
|
||||
),
|
||||
],
|
||||
),
|
||||
Logs(
|
||||
title='',
|
||||
gridPos=GridPos(h=8, w=12, x=12, y=8),
|
||||
showLabels=True,
|
||||
showCommonLabels=True,
|
||||
wrapLogMessages=True,
|
||||
prettifyLogMessage=True,
|
||||
dedupStrategy='numbers',
|
||||
targets=[
|
||||
LokiTarget(
|
||||
loki_datasource=loki_datasource,
|
||||
expr='{compose_project=~"$compose_project", container_name=~"$container_name"} |= `$logs_query`',
|
||||
legendFormat='{{ container_name }}',
|
||||
refId='A',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
).auto_panel_ids()
|
@@ -0,0 +1,139 @@
|
||||
from grafanalib.core import Dashboard, Templating, Template, TimeSeries, PERCENT_UNIT_FORMAT, GridPos, Target
|
||||
from grafanalib.formatunits import BYTES_IEC
|
||||
|
||||
from common import PrometheusTemplate
|
||||
from node_consts import CPU_BASIC_COLORS, MEMORY_BASIC_COLORS
|
||||
|
||||
dashboard = Dashboard(
|
||||
title='Node Exporter',
|
||||
uid='node',
|
||||
description='Node Exporter (not quite full)',
|
||||
tags=[
|
||||
'linux',
|
||||
],
|
||||
timezone='browser',
|
||||
templating=Templating(list=[
|
||||
# Datasource
|
||||
PrometheusTemplate,
|
||||
# Job
|
||||
Template(
|
||||
name='job',
|
||||
label='Job',
|
||||
dataSource='${datasource}',
|
||||
query='label_values(node_uname_info, job)',
|
||||
),
|
||||
# Instance
|
||||
Template(
|
||||
name='instance',
|
||||
label='Instance',
|
||||
dataSource='${datasource}',
|
||||
query='label_values(node_uname_info{job="$job"}, instance)',
|
||||
),
|
||||
]),
|
||||
panels=[
|
||||
# CPU Basic
|
||||
TimeSeries(
|
||||
title='CPU Basic',
|
||||
description='Basic CPU usage info',
|
||||
unit=PERCENT_UNIT_FORMAT,
|
||||
gridPos=GridPos(h=8, w=12, x=0, y=0),
|
||||
lineWidth=1,
|
||||
fillOpacity=30,
|
||||
showPoints='never',
|
||||
stacking={'mode': 'percent', 'group': 'A'},
|
||||
tooltipMode='all',
|
||||
tooltipSort='desc',
|
||||
targets=[
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode="system"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Busy System',
|
||||
refId='A',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode="user"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Busy User',
|
||||
refId='B',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode="iowait"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Busy Iowait',
|
||||
refId='C',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode=~".*irq"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Busy IRQs',
|
||||
refId='D',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode!="idle",mode!="user",mode!="system",mode!="iowait",mode!="irq",mode!="softirq"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Busy Other',
|
||||
refId='E',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='sum(irate(node_cpu_seconds_total{instance="$instance",job="$job", mode="idle"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance="$instance",job="$job"}) by (cpu)))',
|
||||
legendFormat='Idle',
|
||||
refId='F',
|
||||
),
|
||||
],
|
||||
# Extra JSON for the colors
|
||||
extraJson=CPU_BASIC_COLORS,
|
||||
),
|
||||
# Memory Basic
|
||||
TimeSeries(
|
||||
title='Memory Basic',
|
||||
description='Basic memory usage',
|
||||
unit=BYTES_IEC,
|
||||
gridPos=GridPos(h=8, w=12, x=12, y=0),
|
||||
lineWidth=1,
|
||||
fillOpacity=30,
|
||||
showPoints='never',
|
||||
stacking={'mode': 'normal', 'group': 'A'},
|
||||
tooltipMode='all',
|
||||
tooltipSort='desc',
|
||||
targets=[
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='node_memory_MemTotal_bytes{instance="$instance",job="$job"}',
|
||||
format='time_series',
|
||||
legendFormat='RAM Total',
|
||||
refId='A',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='node_memory_MemTotal_bytes{instance="$instance",job="$job"} - node_memory_MemFree_bytes{instance="$instance",job="$job"} - (node_memory_Cached_bytes{instance="$instance",job="$job"} + node_memory_Buffers_bytes{instance="$instance",job="$job"} + node_memory_SReclaimable_bytes{instance="$instance",job="$job"})',
|
||||
format='time_series',
|
||||
legendFormat='RAM Used',
|
||||
refId='B',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='node_memory_Cached_bytes{instance="$instance",job="$job"} + node_memory_Buffers_bytes{instance="$instance",job="$job"} + node_memory_SReclaimable_bytes{instance="$instance",job="$job"}',
|
||||
legendFormat='RAM Cache + Buffer',
|
||||
refId='C',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='node_memory_MemFree_bytes{instance="$instance",job="$job"}',
|
||||
legendFormat='RAM Free',
|
||||
refId='D',
|
||||
),
|
||||
Target(
|
||||
datasource='${datasource}',
|
||||
expr='(node_memory_SwapTotal_bytes{instance="$instance",job="$job"} - node_memory_SwapFree_bytes{instance="$instance",job="$job"})',
|
||||
legendFormat='SWAP Used',
|
||||
refId='E',
|
||||
),
|
||||
],
|
||||
# Extra JSON for the colors
|
||||
extraJson=MEMORY_BASIC_COLORS,
|
||||
),
|
||||
# TODO: Network Basic
|
||||
# TODO: Disk Basic
|
||||
],
|
||||
).auto_panel_ids()
|
@@ -0,0 +1,487 @@
|
||||
# TODO: Question life decisions (I'm not sure if this is good)
|
||||
|
||||
CPU_BASIC_COLORS = {
|
||||
"fieldConfig": {
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Busy Iowait"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#890F02",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Idle"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#052B51",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Busy Iowait"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#890F02",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Idle"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#7EB26D",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Busy System"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#EAB839",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Busy User"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#0A437C",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Busy Other"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#6D1F62",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
MEMORY_BASIC_COLORS = {
|
||||
"fieldConfig": {
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Apps"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#629E51",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Buffers"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#614D93",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Cache"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#6D1F62",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Cached"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#511749",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Committed"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#508642",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Free"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#0A437C",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#CFFAFF",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Inactive"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#584477",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "PageTables"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#0A50A1",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Page_Tables"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#0A50A1",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "RAM_Free"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#E0F9D7",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "SWAP Used"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#BF1B00",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Slab"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#806EB7",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Slab_Cache"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#E0752D",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Swap"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#BF1B00",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Swap Used"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#BF1B00",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Swap_Cache"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#C15C17",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Swap_Free"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#2F575E",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Unused"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#EAB839",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "RAM Total"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#E0F9D7",
|
||||
"mode": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "custom.fillOpacity",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"id": "custom.stacking",
|
||||
"value": {
|
||||
"group": False,
|
||||
"mode": "normal"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "RAM Cache + Buffer"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#052B51",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "RAM Free"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#7EB26D",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Available"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "#DEDAF7",
|
||||
"mode": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "custom.fillOpacity",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"id": "custom.stacking",
|
||||
"value": {
|
||||
"group": False,
|
||||
"mode": "normal"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
uid: loki
|
||||
url: http://loki:3100
|
||||
editable: false
|
||||
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
uid: prometheus
|
||||
url: http://prometheus:9090
|
||||
editable: false
|
||||
|
||||
- name: InfluxDB
|
||||
type: influxdb
|
||||
access: proxy
|
||||
uid: influxdb
|
||||
url: http://influxdb:8086
|
||||
jsonData:
|
||||
version: Flux
|
||||
organization: home
|
||||
defaultBucket: influx
|
||||
secureJsonData:
|
||||
token: {{ influxdb_admin_token }}
|
||||
editable: false
|
@@ -0,0 +1,34 @@
|
||||
[server]
|
||||
domain = grafana.{{ domain }}
|
||||
root_url = https://%(domain)s/
|
||||
|
||||
;[security]
|
||||
;admin_user =
|
||||
;admin_email =
|
||||
;admin_password =
|
||||
|
||||
; https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/generic-oauth/
|
||||
[auth]
|
||||
disable_login_form = true
|
||||
signout_redirect_url = https://auth.{{ domain }}/application/o/grafana/end-session/
|
||||
|
||||
[auth.generic_oauth]
|
||||
name = Authentik
|
||||
enabled = true
|
||||
allow_sign_up = true
|
||||
|
||||
client_id = grafana
|
||||
client_secret = {{ auth_grafana_client_secret }}
|
||||
|
||||
scopes = openid profile email
|
||||
auth_url = https://auth.{{ domain }}/application/o/authorize/
|
||||
token_url = https://auth.{{ domain }}/application/o/token/
|
||||
api_url = https://auth.{{ domain }}/application/o/userinfo/
|
||||
|
||||
email_attribute_path = email
|
||||
login_attribute_path = preferred_username
|
||||
name_attribute_path = name
|
||||
|
||||
# Optionally map user groups to Grafana roles
|
||||
allow_assign_grafana_admin = true
|
||||
role_attribute_path = contains(groups[*], 'Grafana Admins') && 'GrafanaAdmin' || 'Viewer'
|
@@ -0,0 +1,30 @@
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
|
||||
common:
|
||||
path_prefix: /loki
|
||||
# TODO: Consider setting up S3 for storage
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2024-10-18
|
||||
index:
|
||||
period: 24h
|
||||
prefix: index_
|
||||
object_store: filesystem
|
||||
schema: v13
|
||||
store: tsdb
|
||||
|
||||
# TODO: Figure this out
|
||||
# ruler:
|
||||
# alertmanager_url: http://localhost:9093
|
@@ -0,0 +1,39 @@
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
external_labels:
|
||||
monitor: "{{ ansible_host }}"
|
||||
|
||||
scrape_configs:
|
||||
- job_name: "prometheus"
|
||||
static_configs:
|
||||
- targets: ["localhost:9090"]
|
||||
|
||||
- job_name: "node"
|
||||
static_configs:
|
||||
- targets: ["{{ ansible_host }}:9100"]
|
||||
|
||||
- job_name: "cadvisor"
|
||||
static_configs:
|
||||
- targets: ["cadvisor:8080"]
|
||||
|
||||
- job_name: "traefik"
|
||||
static_configs:
|
||||
- targets: ["{{ ansible_host }}:8082"]
|
||||
|
||||
- job_name: "loki"
|
||||
static_configs:
|
||||
- targets: ["loki:3100"]
|
||||
|
||||
- job_name: "promtail"
|
||||
static_configs:
|
||||
- targets: ["promtail:9080"]
|
||||
|
||||
rule_files:
|
||||
- "/etc/prometheus/extra/rules/*.yml"
|
||||
- "/etc/prometheus/extra/rules/*.json"
|
||||
|
||||
scrape_config_files:
|
||||
- "/etc/prometheus/extra/scrape_configs/*.yml"
|
||||
- "/etc/prometheus/extra/scrape_configs/*.json"
|
@@ -0,0 +1,48 @@
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://loki:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
|
||||
# local machine logs
|
||||
- job_name: local
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: varlogs
|
||||
__path__: /var/log/*log
|
||||
|
||||
# syslog target
|
||||
- job_name: syslog
|
||||
syslog:
|
||||
listen_address: "0.0.0.0:514" # make sure you also expose this port on the container
|
||||
idle_timeout: 60s
|
||||
label_structured_data: yes
|
||||
labels:
|
||||
job: "syslog"
|
||||
relabel_configs:
|
||||
- source_labels: ['__syslog_message_hostname']
|
||||
target_label: 'host'
|
||||
- source_labels: ['__syslog_message_facility']
|
||||
target_label: 'facility'
|
||||
- source_labels: ['__syslog_message_severity']
|
||||
target_label: 'severity'
|
||||
- source_labels: ['__syslog_message_app_name']
|
||||
target_label: 'app_name'
|
||||
|
||||
## docker logs
|
||||
|
||||
#- job_name: docker
|
||||
# pipeline_stages:
|
||||
# - docker: {}
|
||||
# static_configs:
|
||||
# - labels:
|
||||
# job: docker
|
||||
# __path__: /var/lib/docker/containers/*/*-json.log
|
1
roles/alpina/templates/services/traefik/.env.traefik.j2
Normal file
1
roles/alpina/templates/services/traefik/.env.traefik.j2
Normal file
@@ -0,0 +1 @@
|
||||
CF_DNS_API_TOKEN={{ cloudflare_api_token }}
|
@@ -0,0 +1,36 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
internal: true
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
config:
|
||||
# TODO: Consider removing traefik network, it shouldn't be needed with host networking
|
||||
- subnet: {{ traefik_subnet }}/24
|
||||
- subnet: {{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, 255) }}
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.0
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.traefik
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./rules:/rules:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- {{ base_volume_path }}/traefik/rules:/rules/extra:ro
|
||||
- {{ base_volume_path }}/traefik/logs:/logs
|
||||
- {{ base_volume_path }}/traefik/acme:/acme
|
||||
|
||||
# This is mostly just so that the traefik network gets created
|
||||
whoami:
|
||||
image: containous/whoami
|
||||
container_name: whoami
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('whoami', port=80) | indent(6) }}
|
||||
networks:
|
||||
- traefik
|
@@ -0,0 +1,25 @@
|
||||
http:
|
||||
routers:
|
||||
traefik-dash:
|
||||
rule: "Host(`traefik.{{ domain }}`)"
|
||||
entryPoints:
|
||||
- web
|
||||
service: traefik-dash
|
||||
|
||||
traefik-dash-tls:
|
||||
rule: "Host(`traefik.{{ domain }}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: traefik-dash
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
domains:
|
||||
- main: "{{ domain }}"
|
||||
sans:
|
||||
- "*.{{ domain }}"
|
||||
|
||||
services:
|
||||
traefik-dash:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://localhost:8080"
|
45
roles/alpina/templates/services/traefik/traefik.yml.j2
Normal file
45
roles/alpina/templates/services/traefik/traefik.yml.j2
Normal file
@@ -0,0 +1,45 @@
|
||||
api:
|
||||
insecure: true
|
||||
|
||||
log:
|
||||
filePath: /logs/traefik.log
|
||||
level: INFO
|
||||
accessLog:
|
||||
filePath: /logs/access.log
|
||||
bufferingSize: 100
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
http3:
|
||||
advertisedPort: 443
|
||||
metrics:
|
||||
address: ":8082"
|
||||
|
||||
metrics:
|
||||
prometheus:
|
||||
entryPoint: metrics
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: {{ acme_email }}
|
||||
storage: "/acme/acme.json"
|
||||
keyType: "EC384"
|
||||
dnsChallenge:
|
||||
provider: "cloudflare"
|
||||
delayBeforeCheck: 10
|
||||
resolvers:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
- 9.9.9.9
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: traefik_traefik
|
||||
file:
|
||||
directory: /rules
|
||||
watch: true
|
@@ -1,43 +1,70 @@
|
||||
- name: Upgrade alpine packages
|
||||
community.general.apk:
|
||||
upgrade: yes
|
||||
update_cache: yes
|
||||
register: apk_upgrades
|
||||
|
||||
- name: Install alpine packages
|
||||
community.general.apk:
|
||||
- name: Install Debian packages
|
||||
become: yes
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- qemu-guest-agent
|
||||
- dhcpcd
|
||||
- python3
|
||||
- fish
|
||||
- docker
|
||||
- docker-compose
|
||||
- docker-fish-completion
|
||||
- docker-compose-fish-completion
|
||||
- zfs
|
||||
- docker-ce
|
||||
- docker-compose-plugin
|
||||
- firewalld
|
||||
state: latest
|
||||
|
||||
- name: Upgrade Debian packages
|
||||
become: yes
|
||||
ansible.builtin.apt:
|
||||
upgrade: dist
|
||||
update_cache: yes
|
||||
register: apk_installs
|
||||
cache_valid_time: 3600
|
||||
autoremove: yes
|
||||
state: latest
|
||||
register: apt_upgrades
|
||||
|
||||
- name: Enable qemu-guest-agent service
|
||||
- name: Ensure firewalld is running
|
||||
become: yes
|
||||
service:
|
||||
name: qemu-guest-agent
|
||||
runlevel: boot
|
||||
name: firewalld
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Enable zfs-import service
|
||||
service:
|
||||
name: zfs-import
|
||||
runlevel: sysinit
|
||||
enabled: yes
|
||||
- name: Allow SSH
|
||||
become: yes
|
||||
firewalld:
|
||||
service: ssh
|
||||
permanent: yes
|
||||
state: enabled
|
||||
immediate: yes
|
||||
|
||||
- name: Enable zfs-mount service
|
||||
service:
|
||||
name: zfs-mount
|
||||
runlevel: sysinit
|
||||
enabled: yes
|
||||
- name: Allow Web
|
||||
become: yes
|
||||
firewalld:
|
||||
service: http
|
||||
permanent: yes
|
||||
state: disabled
|
||||
immediate: yes
|
||||
|
||||
- name: Allow Web Secure
|
||||
become: yes
|
||||
firewalld:
|
||||
service: https
|
||||
permanent: yes
|
||||
state: enabled
|
||||
immediate: yes
|
||||
|
||||
- name: Allow 443 udp for http3
|
||||
become: yes
|
||||
firewalld:
|
||||
port: 443/udp
|
||||
permanent: yes
|
||||
state: enabled
|
||||
immediate: yes
|
||||
|
||||
- name: Allow 514 tcp for syslog
|
||||
become: yes
|
||||
firewalld:
|
||||
port: 514/tcp
|
||||
permanent: yes
|
||||
state: enabled
|
||||
immediate: yes
|
||||
|
||||
- name: Reboot if needed
|
||||
reboot:
|
||||
when: apk_upgrades.changed or apk_installs.changed
|
||||
become: yes
|
||||
ansible.builtin.reboot:
|
||||
when: apt_upgrades.changed
|
||||
|
@@ -1,5 +1,70 @@
|
||||
- name: Create my service directory
|
||||
- name: Get IPv6 subnet for Docker
|
||||
set_fact:
|
||||
docker_ipv6_subnet: "{{ \
|
||||
ansible_default_ipv6.address \
|
||||
| ansible.utils.ipsubnet(64) \
|
||||
| ansible.utils.ipsubnet(72, docker_ipv6_index) \
|
||||
}}"
|
||||
|
||||
- debug:
|
||||
var: docker_ipv6_subnet
|
||||
|
||||
- name: Configure Docker daemon
|
||||
become: yes
|
||||
template:
|
||||
src: "daemon.json.j2"
|
||||
dest: "/etc/docker/daemon.json"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: docker_daemon_config
|
||||
|
||||
- name: Install Docker loki plugin for logs
|
||||
community.docker.docker_plugin:
|
||||
plugin_name: grafana/loki-docker-driver:latest
|
||||
alias: loki
|
||||
state: enable
|
||||
|
||||
- name: Remove docker0 from firewalld trusted zone
|
||||
become: yes
|
||||
firewalld:
|
||||
zone: trusted
|
||||
interface: docker0
|
||||
permanent: yes
|
||||
immediate: yes
|
||||
state: disabled
|
||||
register: docker0_firewalld
|
||||
|
||||
- name: Get list of running Docker containers
|
||||
docker_host_info:
|
||||
containers: yes
|
||||
register: docker_container_list
|
||||
when: clean_desired is true
|
||||
|
||||
- name: Stop all running Docker containers
|
||||
docker_container:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
loop: "{{ docker_container_list.containers | map(attribute='Id') | list }}"
|
||||
async: 300
|
||||
poll: 0
|
||||
when: clean_desired is true and docker_container_list.containers | length > 0
|
||||
|
||||
- name: Prune all Docker containers and networks
|
||||
docker_prune:
|
||||
containers: yes
|
||||
networks: yes
|
||||
when: clean_desired is true
|
||||
|
||||
- name: Clean alpina directory
|
||||
file:
|
||||
state: directory
|
||||
path: "{{ my_svc_path }}"
|
||||
mode: "700"
|
||||
path: "{{ alpina_svc_path }}"
|
||||
state: absent
|
||||
when: clean_desired is true
|
||||
|
||||
- name: Restart Docker daemon
|
||||
become: yes
|
||||
service:
|
||||
name: docker
|
||||
state: restarted
|
||||
when: docker_daemon_config.changed or docker0_firewalld.changed
|
||||
|
10
roles/docker_host/templates/daemon.json.j2
Normal file
10
roles/docker_host/templates/daemon.json.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ipv6": true,
|
||||
"fixed-cidr-v6": "{{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, 0) }}",
|
||||
"log-driver": "loki",
|
||||
"log-opts": {
|
||||
"loki-url": "http://localhost:3100/loki/api/v1/push",
|
||||
"loki-batch-size": "400",
|
||||
"loki-retries": "5"
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure service directory exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "directory"
|
||||
|
||||
|
||||
- name: Include app config variables
|
||||
include_vars:
|
||||
file: "{{ role_path }}/vars/app_config.yml"
|
||||
|
||||
- name: Generate {{ current_svc_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "400"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "file"
|
||||
|
||||
- name: Deploy docker-compose for {{ current_svc_name }}
|
||||
community.docker.docker_compose:
|
||||
project_src: "{{ current_svc_path }}"
|
||||
state: present
|
@@ -1,3 +0,0 @@
|
||||
POSTGRES_USER=gitea
|
||||
POSTGRES_DB=gitea
|
||||
POSTGRES_PASSWORD="{{ db_password }}"
|
@@ -1,25 +0,0 @@
|
||||
GITEA____APP_NAME=CazGitea
|
||||
|
||||
# Database
|
||||
GITEA__database__DB_TYPE=postgres
|
||||
GITEA__database__HOST=db:5432
|
||||
GITEA__database__NAME="{{ db_user }}"
|
||||
GITEA__database__USER="{{ db_name }}"
|
||||
GITEA__database__PASSWD="{{ db_password }}"
|
||||
|
||||
# Server
|
||||
GITEA__server__ROOT_URL=https://gitea.cazzzer.com/
|
||||
GITEA__server__DISABLE_SSH=true
|
||||
|
||||
# Mail
|
||||
GITEA__mailer__ENABLED=true
|
||||
GITEA__mailer__HOST=smtp.sendgrid.net:587
|
||||
GITEA__mailer__FROM=gitea@cazzzer.com
|
||||
GITEA__mailer__USER=apikey
|
||||
GITEA__mailer__PASSWD="{{ sendgrid_api_key }}"
|
||||
|
||||
# Security
|
||||
GITEA__security__SECRET_KEY="{{ secret_key }}"
|
||||
GITEA__security__INTERNAL_TOKEN="{{ internal_token }}"
|
||||
|
||||
GITEA__oauth2__JWT_SECRET="{{ jwt_secret }}"
|
@@ -1,27 +0,0 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
35303032386566343430633238343936366234333434343763666231666232633539303232383534
|
||||
3035346233346162373939333531613535353232626531640a646537616163353736653161326265
|
||||
31336530316335623335353661373834613264326436303933326135396166346562343136353931
|
||||
6439383039346465300a366266393130356630316630333336616565366562613038393239623738
|
||||
65626664643630353236333932373337333363626337386163613464306638633964663264363964
|
||||
30373661393531306662323134626664656233323762393037356434353066343830333033316365
|
||||
65616636613437663737306263373066306361376630616331663031346434336663393862316464
|
||||
62343339663461353934323063653566303932656264363562333136353665336263646230323832
|
||||
35376666303531383961646234663230663634393135326664386665633538616233613866373965
|
||||
64363361313232316336376631646662376565353536316438306361306261663532386564616566
|
||||
61663534393035343233326562303863646165346538393761326335376165623964396130393831
|
||||
64333665313461666335383134613831376138393061343238643661366439636534626265323865
|
||||
35393035336632653038623438626366373733626331633866373935616531623664303063376562
|
||||
31356332346164663364636235333461383437623161343338643839323765336237633266633864
|
||||
64363234646533616439313638363865373364623637636537623666383664656630333533303233
|
||||
64383734366666633832393230663739333435666138636462336332373061346239306136336263
|
||||
39643666303863303035313738343664636536663939616335303834333834363739303938646665
|
||||
66303637633239373461393434313036316563313132356432633337666537616363373830313034
|
||||
61313538633663653230643262613333306361666131663036643162343966313365653566393235
|
||||
36623832663034373734653664613038363137366437326565373761663963636336393536386435
|
||||
30393831326134376639366661653439616138643438646363343632346131306532663439396534
|
||||
32383661306539306635336262383563376561303862396532633362666266313562623336383235
|
||||
36366565633734633639653239306331333237353233326563653930653739316230666362323931
|
||||
39663931376562653530323434656436353166393836643238643632396430353034333034333665
|
||||
62323338373839383132323537353431636537616366393965643463316164323034316536383961
|
||||
6164333537633631646663333463306236613038326339643439
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
current_svc_name: gitea
|
||||
current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}"
|
||||
|
||||
templates_source: "{{ role_path }}/templates"
|
@@ -1,33 +0,0 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure service directory exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "directory"
|
||||
|
||||
|
||||
- name: Include app config variables
|
||||
include_vars:
|
||||
file: "{{ role_path }}/vars/app_config.yml"
|
||||
|
||||
- name: Generate {{ current_svc_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "400"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "file"
|
||||
|
||||
- name: Deploy docker-compose for {{ current_svc_name }}
|
||||
community.docker.docker_compose:
|
||||
project_src: "{{ current_svc_path }}"
|
||||
state: present
|
@@ -1 +0,0 @@
|
||||
JELLYFIN_PublishedServerUrl="https://jellyfin.{{ domain }}"
|
@@ -1,35 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
default:
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
config:
|
||||
cache:
|
||||
media:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: nfs
|
||||
o: "addr=truenas.lab.home,nfsvers=4,ro,noatime"
|
||||
device: ":/mnt/Mass-Storage-New/JailStorage/Plex"
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:10.8.5
|
||||
container_name: jellyfin_jellyfin
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.jellyfin.rule=Host(`jellyfin.{{ domain }}`)
|
||||
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.jellyfin
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- config:/config
|
||||
- cache:/cache
|
||||
- media:/data/media
|
@@ -1,6 +0,0 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
61626665353536663033663661393434616339396434383530306265363837313839303939623465
|
||||
3634333839333530383464613966326238363738663637360a343837623832343232316565346131
|
||||
66663831356162653363383131396665326531363430656539333866313031306537343864343262
|
||||
3730643765633232620a643734623336646565663266656262343162613239306166386665333139
|
||||
6366
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
current_svc_name: jellyfin
|
||||
current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}"
|
||||
|
||||
templates_source: "{{ role_path }}/templates"
|
@@ -1,33 +0,0 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure service directory exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "directory"
|
||||
|
||||
|
||||
- name: Include app config variables
|
||||
include_vars:
|
||||
file: "{{ role_path }}/vars/app_config.yml"
|
||||
|
||||
- name: Generate {{ current_svc_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "400"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "file"
|
||||
|
||||
- name: Deploy docker-compose for {{ current_svc_name }}
|
||||
community.docker.docker_compose:
|
||||
project_src: "{{ current_svc_path }}"
|
||||
state: present
|
@@ -1,18 +0,0 @@
|
||||
POSTGRES_DB=nextcloud
|
||||
POSTGRES_USER=nextcloud
|
||||
POSTGRES_PASSWORD="{{ db_password }}"
|
||||
POSTGRES_HOST=db
|
||||
|
||||
NEXTCLOUD_TRUSTED_DOMAINS=nc.cazzzer.com
|
||||
|
||||
REDIS_HOST=redis
|
||||
REDIS_HOST_PASSWORD="{{ redis_password }}"
|
||||
|
||||
SMTP_HOST=smtp.sendgrid.net
|
||||
SMTP_SECURE=tls
|
||||
SMTP_PORT=587
|
||||
SMTP_AUTHTYPE=LOGIN
|
||||
SMTP_NAME=apikey
|
||||
SMTP_PASSWORD="{{ sendgrid_api_key }}"
|
||||
MAIL_FROM_ADDRESS=nc
|
||||
MAIL_DOMAIN=cazzzer.com
|
@@ -1 +0,0 @@
|
||||
REDIS_PASSWORD="{{ redis_password }}"
|
@@ -1,96 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
default:
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
nextcloud:
|
||||
nextcloud_config:
|
||||
nextcloud_data:
|
||||
db:
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nextcloud:24-fpm-alpine
|
||||
container_name: nextcloud_app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
env_file:
|
||||
- .env.nextcloud
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- nextcloud:/var/www/html
|
||||
- nextcloud_config:/var/www/html/config
|
||||
- nextcloud_data:/var/www/html/data
|
||||
|
||||
cron:
|
||||
image: nextcloud:24-fpm-alpine
|
||||
container_name: nextcloud_cron
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
entrypoint: /cron.sh
|
||||
networks:
|
||||
- default
|
||||
volumes_from:
|
||||
- app
|
||||
|
||||
notify_push:
|
||||
image: nextcloud:24-fpm-alpine
|
||||
container_name: nextcloud_notify_push
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
entrypoint:
|
||||
- /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push
|
||||
- /var/www/html/config/config.php
|
||||
networks:
|
||||
- default
|
||||
volumes_from:
|
||||
- app
|
||||
|
||||
db:
|
||||
image: postgres:13-alpine
|
||||
container_name: nextcloud_db
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nextcloud_redis
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.redis
|
||||
networks:
|
||||
- default
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- redis-server --requirepass $$REDIS_PASSWORD
|
||||
|
||||
web:
|
||||
image: nginx:1.23-alpine
|
||||
container_name: nextcloud_web
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.nextcloud.rule=Host(`nc.{{ domain }}`)
|
||||
restart: unless-stopped
|
||||
links:
|
||||
- app
|
||||
networks:
|
||||
- traefik_traefik
|
||||
- default
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
volumes_from:
|
||||
- app
|
@@ -1,182 +0,0 @@
|
||||
# https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/with-nginx-proxy/postgres/fpm/web/nginx.conf
|
||||
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
# Prevent nginx HTTP Server Detection
|
||||
server_tokens off;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
upstream php-handler {
|
||||
server app:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# HSTS settings
|
||||
# WARNING: Only add the preload option once you read about
|
||||
# the consequences in https://hstspreload.org/. This option
|
||||
# will add the domain to a hardcoded list that is shipped
|
||||
# in all major browsers and getting removed from this list
|
||||
# could take several months.
|
||||
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
|
||||
|
||||
# set max upload size
|
||||
client_max_body_size 512M;
|
||||
fastcgi_buffers 64 4K;
|
||||
|
||||
# Enable gzip but do not remove ETag headers
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_comp_level 4;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
||||
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
||||
|
||||
# Pagespeed is not supported by Nextcloud, so if your server is built
|
||||
# with the `ngx_pagespeed` module, uncomment this line to disable it.
|
||||
#pagespeed off;
|
||||
|
||||
# HTTP response headers borrowed from Nextcloud `.htaccess`
|
||||
add_header Referrer-Policy "no-referrer" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Download-Options "noopen" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
||||
add_header X-Robots-Tag "none" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Remove X-Powered-By, which is an information leak
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
|
||||
# Path to the root of your installation
|
||||
root /var/www/html;
|
||||
|
||||
# Specify how to handle directories -- specifying `/index.php$request_uri`
|
||||
# here as the fallback means that Nginx always exhibits the desired behaviour
|
||||
# when a client requests a path that corresponds to a directory that exists
|
||||
# on the server. In particular, if that directory contains an index.php file,
|
||||
# that file is correctly served; if it doesn't, then the request is passed to
|
||||
# the front-end controller. This consistent behaviour means that we don't need
|
||||
# to specify custom rules for certain paths (e.g. images and other assets,
|
||||
# `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
|
||||
# `try_files $uri $uri/ /index.php$request_uri`
|
||||
# always provides the desired behaviour.
|
||||
index index.php index.html /index.php$request_uri;
|
||||
|
||||
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
|
||||
location = / {
|
||||
if ( $http_user_agent ~ ^DavClnt ) {
|
||||
return 302 /remote.php/webdav/$is_args$args;
|
||||
}
|
||||
}
|
||||
|
||||
location = /robots.txt {
|
||||
allow all;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Make a regex exception for `/.well-known` so that clients can still
|
||||
# access it despite the existence of the regex rule
|
||||
# `location ~ /(\.|autotest|...)` which would otherwise handle requests
|
||||
# for `/.well-known`.
|
||||
location ^~ /.well-known {
|
||||
# The rules in this block are an adaptation of the rules
|
||||
# in `.htaccess` that concern `/.well-known`.
|
||||
|
||||
location = /.well-known/carddav { return 301 /remote.php/dav/; }
|
||||
location = /.well-known/caldav { return 301 /remote.php/dav/; }
|
||||
|
||||
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
|
||||
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
|
||||
|
||||
# Let Nextcloud's API for `/.well-known` URIs handle all other
|
||||
# requests by passing them to the front-end controller.
|
||||
return 301 /index.php$request_uri;
|
||||
}
|
||||
|
||||
# Rules borrowed from `.htaccess` to hide certain paths from clients
|
||||
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
|
||||
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
|
||||
|
||||
# Ensure this block, which passes PHP files to the PHP process, is above the blocks
|
||||
# which handle static assets (as seen below). If this block is not declared first,
|
||||
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
|
||||
# to the URI, resulting in a HTTP 500 error response.
|
||||
location ~ \.php(?:$|/) {
|
||||
# Required for legacy support
|
||||
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
|
||||
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
set $path_info $fastcgi_path_info;
|
||||
|
||||
try_files $fastcgi_script_name =404;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $path_info;
|
||||
#fastcgi_param HTTPS on;
|
||||
|
||||
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
|
||||
fastcgi_param front_controller_active true; # Enable pretty urls
|
||||
fastcgi_pass php-handler;
|
||||
|
||||
fastcgi_intercept_errors on;
|
||||
fastcgi_request_buffering off;
|
||||
}
|
||||
|
||||
location ~ \.(?:css|js|svg|gif)$ {
|
||||
try_files $uri /index.php$request_uri;
|
||||
expires 6M; # Cache-Control policy borrowed from `.htaccess`
|
||||
access_log off; # Optional: Don't log access to assets
|
||||
}
|
||||
|
||||
location ~ \.woff2?$ {
|
||||
try_files $uri /index.php$request_uri;
|
||||
expires 7d; # Cache-Control policy borrowed from `.htaccess`
|
||||
access_log off; # Optional: Don't log access to assets
|
||||
}
|
||||
|
||||
# Rule borrowed from `.htaccess`
|
||||
location /remote {
|
||||
return 301 /remote.php$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php$request_uri;
|
||||
}
|
||||
|
||||
location ^~ /push/ {
|
||||
proxy_pass http://notify_push:7867/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
65313636646233613364363933616361346639653939346337303832646339316632383966666237
|
||||
3766396134383434613534373937663162393134306536300a626139373732393037346630333838
|
||||
63663439353238643532316231623866396434303034313130386635623363353263626362376334
|
||||
3933346434633662320a386432373465646432343338666561366161646335636232353133393933
|
||||
65313364666564353039626238383033343765323730316633356139326666623135326131353864
|
||||
32386237643538636538356261393164633137636235346564393930346539623731386633336339
|
||||
31303466653936343166366164383134306232613236663735623834393963306331376435616365
|
||||
31313866383730393063353335626164303632636331303830636530656131636139376633623439
|
||||
63663639323964623231343066373538633336353561646230363363643762393634643435306164
|
||||
31366364326237636365336363343264343562353337303235633034383635373934376334353336
|
||||
61373065386639643064303431623162373665363937353832313561386134613834613935653964
|
||||
64656339316165313936333736643030356366663162316462636662326134396539356262666536
|
||||
64336133393937396330353234316563356337623733326264363333373536633833
|
@@ -1,6 +0,0 @@
|
||||
---
|
||||
# vars file for roles/nextcloud/
|
||||
current_svc_name: nextcloud
|
||||
current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}"
|
||||
|
||||
templates_source: "{{ role_path }}/templates"
|
@@ -1,33 +0,0 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure service directory exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_svc_path }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "500"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "directory"
|
||||
|
||||
|
||||
#- name: Include app config variables
|
||||
# include_vars:
|
||||
# file: "{{ role_path }}/vars/app_config.yml"
|
||||
|
||||
- name: Generate {{ current_svc_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "400"
|
||||
with_community.general.filetree: "{{ templates_source }}"
|
||||
when: item.state == "file"
|
||||
|
||||
- name: Deploy docker-compose for {{ current_svc_name }}
|
||||
community.docker.docker_compose:
|
||||
project_src: "{{ current_svc_path }}"
|
||||
state: present
|
@@ -1,20 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.8
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "8080:8080"
|
||||
env_file:
|
||||
- .env.traefik
|
||||
networks:
|
||||
- traefik
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
@@ -1,7 +0,0 @@
|
||||
api:
|
||||
insecure: true
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: traefik_traefik
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
current_svc_name: traefik
|
||||
current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}"
|
||||
|
||||
templates_source: "{{ role_path }}/templates"
|
18
services.yml
18
services.yml
@@ -1,7 +1,15 @@
|
||||
- hosts: docker_hosts
|
||||
- hosts: alpina
|
||||
roles:
|
||||
- docker_host
|
||||
- traefik
|
||||
- nextcloud
|
||||
- role: gitea
|
||||
|
||||
- alpina
|
||||
post_tasks:
|
||||
- name: Docker prune objects
|
||||
docker_prune:
|
||||
containers: true
|
||||
# Keep images for building grafana
|
||||
images: true
|
||||
images_filters:
|
||||
until: "720h"
|
||||
networks: true
|
||||
volumes: true
|
||||
builder_cache: false
|
||||
|
6
site.yml
6
site.yml
@@ -1,6 +1,12 @@
|
||||
- hosts: all
|
||||
roles:
|
||||
- common
|
||||
pre_tasks:
|
||||
- name: Set fact for clean desired of docker objects and compose files
|
||||
set_fact:
|
||||
# clean_desired_arg is an extra variable passed to the playbook
|
||||
clean_desired: "{{ clean_desired_arg | bool }}"
|
||||
|
||||
|
||||
- name: Install services
|
||||
import_playbook: services.yml
|
||||
|
Reference in New Issue
Block a user