Add netbox role
Kinda ouroborosish if you think about it. Better don’t.
This commit is contained in:
parent
43b9010126
commit
c7a3513fa1
|
@ -11,3 +11,8 @@
|
||||||
cluster: '{{ query("netbox.netbox.nb_lookup", "clusters", raw_data=true, api_filter="name="+cluster) | first }}'
|
cluster: '{{ query("netbox.netbox.nb_lookup", "clusters", raw_data=true, api_filter="name="+cluster) | first }}'
|
||||||
nodes: '{{ groups["cluster_"+cluster] | map("extract", hostvars) | rejectattr("is_virtual") }}'
|
nodes: '{{ groups["cluster_"+cluster] | map("extract", hostvars) | rejectattr("is_virtual") }}'
|
||||||
when: cluster
|
when: cluster
|
||||||
|
|
||||||
|
- name: Get my domain names if any
|
||||||
|
set_fact:
|
||||||
|
fqdns: '{{ interfaces | map(attribute="ip_addresses") | flatten
|
||||||
|
| map(attribute="dns_name") | reject("==", "") | sort | unique }}'
|
||||||
|
|
11
roles/netbox/files/default.conf
Normal file
11
roles/netbox/files/default.conf
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# handle .well-known for all domains
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
location /.well-known/ {
|
||||||
|
alias /srv/http/.well-known/;
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
2
roles/netbox/files/local_requirements.txt
Normal file
2
roles/netbox/files/local_requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dulwich # for git data sources
|
||||||
|
netbox-topology-views
|
27
roles/netbox/handlers/main.yml
Normal file
27
roles/netbox/handlers/main.yml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
- name: reload nginx
|
||||||
|
service:
|
||||||
|
name: nginx
|
||||||
|
state: reloaded
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
||||||
|
|
||||||
|
- name: reload package cache
|
||||||
|
package:
|
||||||
|
update_cache: yes
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
||||||
|
|
||||||
|
- name: restart netbox
|
||||||
|
service:
|
||||||
|
name: '{{ item }}'
|
||||||
|
state: restarted
|
||||||
|
loop:
|
||||||
|
- netbox
|
||||||
|
- netbox-rq
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
||||||
|
|
||||||
|
- name: run migrations
|
||||||
|
become: yes
|
||||||
|
become_method: su
|
||||||
|
become_user: '{{ user }}'
|
||||||
|
command: sh ~/app/upgrade.sh
|
||||||
|
notify: restart netbox
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
150
roles/netbox/tasks/app.yml
Normal file
150
roles/netbox/tasks/app.yml
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
- name: Install dependencies
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- git
|
||||||
|
- python3
|
||||||
|
- python3-dev
|
||||||
|
- py3-pip
|
||||||
|
- py3-virtualenv
|
||||||
|
- bash # for upgrade script
|
||||||
|
- build-base # to build psycopg if not available
|
||||||
|
- postgresql-dev # likewise
|
||||||
|
|
||||||
|
- name: Checkout repo
|
||||||
|
become: yes
|
||||||
|
become_method: su
|
||||||
|
become_user: '{{ user }}'
|
||||||
|
git:
|
||||||
|
repo: https://github.com/netbox-community/netbox.git
|
||||||
|
dest: '{{ user_info.home }}/app'
|
||||||
|
version: 'v{{ netbox_version }}'
|
||||||
|
notify: run migrations
|
||||||
|
|
||||||
|
- name: Copy default config
|
||||||
|
copy:
|
||||||
|
dest: '{{ user_info.home }}/app/netbox/netbox/configuration.py'
|
||||||
|
src: '{{ user_info.home }}/app/netbox/netbox/configuration_example.py'
|
||||||
|
remote_src: yes
|
||||||
|
owner: '{{ user_info.uid }}'
|
||||||
|
group: '{{ user_info.group }}'
|
||||||
|
force: no
|
||||||
|
notify: run migrations
|
||||||
|
|
||||||
|
- name: Restrict access to config
|
||||||
|
file:
|
||||||
|
path: '{{ user_info.home }}/app/netbox/netbox/configuration.py'
|
||||||
|
mode: 0600
|
||||||
|
|
||||||
|
- name: Configure secret key
|
||||||
|
lineinfile:
|
||||||
|
path: '{{ user_info.home }}/app/netbox/netbox/configuration.py'
|
||||||
|
regexp: "^SECRET_KEY = ''"
|
||||||
|
line: "SECRET_KEY = '{{ lookup('password', '/dev/null', length=50) }}'"
|
||||||
|
backrefs: yes # don’t set if set already
|
||||||
|
|
||||||
|
- name: Configure base settings and database
|
||||||
|
lineinfile:
|
||||||
|
path: '{{ user_info.home }}/app/netbox/netbox/configuration.py'
|
||||||
|
regexp: '{{ item.key }}'
|
||||||
|
line: '{{ item.line }}'
|
||||||
|
loop:
|
||||||
|
- key: '^ALLOWED_HOSTS = '
|
||||||
|
line: "ALLOWED_HOSTS = [{{ fqdns | map('regex_replace', '^(.*)$', '\"\\1\"') | join(', ') }}]"
|
||||||
|
- key: 'USER.*PostgreSQL username'
|
||||||
|
line: " 'USER': '{{ user }}', # PostgreSQL username"
|
||||||
|
# XXX unnecessary?
|
||||||
|
#- key: '(OPTIONS|PASSWORD).*PostgreSQL password'
|
||||||
|
# line: " 'OPTIONS': { 'passfile': '{{ user_info.home }}/.pgpass' }, # PostgreSQL password"
|
||||||
|
# not yet compatible, see https://github.com/netbox-community/netbox-topology-views/issues/503
|
||||||
|
#- key: '^PLUGINS = '
|
||||||
|
# line: "PLUGINS = ['netbox_topology_views']"
|
||||||
|
notify: run migrations
|
||||||
|
|
||||||
|
- name: Configure OIDC authentication
|
||||||
|
lineinfile:
|
||||||
|
path: '{{ user_info.home }}/app/netbox/netbox/configuration.py'
|
||||||
|
regexp: '{{ item.key }}'
|
||||||
|
line: '{{ item.line }}'
|
||||||
|
loop:
|
||||||
|
- key: "^REMOTE_AUTH_ENABLED ="
|
||||||
|
line: "REMOTE_AUTH_ENABLED = True"
|
||||||
|
- key: "^REMOTE_AUTH_BACKEND ="
|
||||||
|
line: "REMOTE_AUTH_BACKEND = 'social_core.backends.open_id_connect.OpenIdConnectAuth'"
|
||||||
|
- key: "^SOCIAL_AUTH_OIDC_OIDC_ENDPOINT ="
|
||||||
|
line: "SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = '{{ lookup('passwordstore', 'vm/'~inventory_hostname, subkey='oidc_endpoint') }}'"
|
||||||
|
- key: "^SOCIAL_AUTH_OIDC_KEY ="
|
||||||
|
line: "SOCIAL_AUTH_OIDC_KEY = '{{ lookup('passwordstore', 'vm/'~inventory_hostname, subkey='oidc_client_id') }}'"
|
||||||
|
- key: "^SOCIAL_AUTH_OIDC_SECRET ="
|
||||||
|
line: "SOCIAL_AUTH_OIDC_SECRET = '{{ lookup('passwordstore', 'vm/'~inventory_hostname, subkey='oidc_client_secret') }}'"
|
||||||
|
# TODO the key should really be upn but it doesn’t seem to work
|
||||||
|
- key: "^SOCIAL_AUTH_OIDC_USERNAME_KEY ="
|
||||||
|
line: "SOCIAL_AUTH_OIDC_USERNAME_KEY = 'email'"
|
||||||
|
notify: run migrations
|
||||||
|
|
||||||
|
- name: Set additional requirements
|
||||||
|
become: yes
|
||||||
|
become_method: su
|
||||||
|
become_user: '{{ user }}'
|
||||||
|
copy:
|
||||||
|
dest: '{{ user_info.home }}/app/'
|
||||||
|
src: local_requirements.txt
|
||||||
|
notify: run migrations
|
||||||
|
|
||||||
|
- meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Create superuser
|
||||||
|
become: yes
|
||||||
|
become_method: su
|
||||||
|
become_user: '{{ user }}'
|
||||||
|
command:
|
||||||
|
cmd: '{{ user_info.home }}/app/venv/bin/python {{ user_info.home }}/app/netbox/manage.py shell --interface python'
|
||||||
|
stdin: |
|
||||||
|
import sys
|
||||||
|
from users.models import User
|
||||||
|
#from django.contrib.auth.models import User
|
||||||
|
username = '{{ lookup('passwordstore', 'vm/'~inventory_hostname, subkey='admin_user') }}'
|
||||||
|
if not User.objects.filter(username=username):
|
||||||
|
User.objects.create_superuser(username, '', # TODO email
|
||||||
|
'{{ lookup('passwordstore', 'vm/'~inventory_hostname, subkey='admin_pass') }}')
|
||||||
|
sys.exit(1)
|
||||||
|
register: result
|
||||||
|
changed_when: result.rc != 0
|
||||||
|
|
||||||
|
- name: Set up gunicorn
|
||||||
|
copy:
|
||||||
|
dest: /srv/netbox/gunicorn.py
|
||||||
|
src: /srv/netbox/app/contrib/gunicorn.py
|
||||||
|
remote_src: yes
|
||||||
|
force: no
|
||||||
|
owner: netbox
|
||||||
|
group: netbox
|
||||||
|
|
||||||
|
- name: Set up cron job
|
||||||
|
file:
|
||||||
|
dest: /etc/periodic/daily/netbox-housekeeping.sh
|
||||||
|
src: /srv/netbox/app/contrib/netbox-housekeeping.sh
|
||||||
|
state: link
|
||||||
|
|
||||||
|
- name: Install services
|
||||||
|
template:
|
||||||
|
dest: '/etc/init.d/{{ item }}'
|
||||||
|
src: '{{ item }}.initd.j2'
|
||||||
|
mode: 0755
|
||||||
|
loop:
|
||||||
|
- netbox
|
||||||
|
- netbox-rq
|
||||||
|
|
||||||
|
- name: Enable services
|
||||||
|
service:
|
||||||
|
name: '{{ item }}'
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- netbox
|
||||||
|
- netbox-rq
|
||||||
|
|
||||||
|
- name: Set up nginx site
|
||||||
|
template:
|
||||||
|
dest: '/etc/nginx/http.d/netbox.conf'
|
||||||
|
src: 'netbox.conf.j2'
|
||||||
|
notify: reload nginx
|
55
roles/netbox/tasks/db.yml
Normal file
55
roles/netbox/tasks/db.yml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
- name: Install packages
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- postgresql
|
||||||
|
- py3-psycopg2
|
||||||
|
- redis
|
||||||
|
|
||||||
|
- name: Enable services
|
||||||
|
service:
|
||||||
|
name: '{{ item }}'
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
|
||||||
|
- name: Create .pgpass
|
||||||
|
copy:
|
||||||
|
dest: '{{ user_info.home }}/.pgpass'
|
||||||
|
content: |
|
||||||
|
localhost:5432:{{ database }}:{{ user }}:{{ db_password }}
|
||||||
|
force: no
|
||||||
|
mode: 0600
|
||||||
|
owner: '{{ user_info.uid }}'
|
||||||
|
group: '{{ user_info.group }}'
|
||||||
|
|
||||||
|
- become: yes
|
||||||
|
become_method: su
|
||||||
|
become_user: postgres
|
||||||
|
block:
|
||||||
|
- name: Create database
|
||||||
|
postgresql_db:
|
||||||
|
name: '{{ database }}'
|
||||||
|
|
||||||
|
- name: Create database user
|
||||||
|
postgresql_user:
|
||||||
|
db: '{{ database }}'
|
||||||
|
name: '{{ user }}'
|
||||||
|
password: '{{ db_password }}'
|
||||||
|
no_password_changes: yes
|
||||||
|
|
||||||
|
- name: Set schema owner
|
||||||
|
postgresql_owner:
|
||||||
|
db: '{{ database }}'
|
||||||
|
new_owner: '{{ user }}'
|
||||||
|
obj_name: public
|
||||||
|
obj_type: schema
|
||||||
|
|
||||||
|
- name: Grant database privileges
|
||||||
|
postgresql_privs:
|
||||||
|
db: '{{ database }}'
|
||||||
|
role: '{{ user }}'
|
||||||
|
privs: CREATE
|
||||||
|
type: database
|
||||||
|
|
25
roles/netbox/tasks/main.yml
Normal file
25
roles/netbox/tasks/main.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
- name: Set variables
|
||||||
|
set_fact:
|
||||||
|
user: '{{ user | default("netbox") }}'
|
||||||
|
database: '{{ database | default("netbox") }}'
|
||||||
|
db_password: '{{ lookup("password", "/dev/null", chars=["ascii_letters", "digits"]) }}'
|
||||||
|
|
||||||
|
- name: Create group for web service
|
||||||
|
group:
|
||||||
|
name: '{{ user }}'
|
||||||
|
system: yes
|
||||||
|
|
||||||
|
- name: Create user for web service
|
||||||
|
user:
|
||||||
|
name: '{{ user }}'
|
||||||
|
group: '{{ user }}'
|
||||||
|
home: '/srv/{{ user }}'
|
||||||
|
shell: /bin/sh
|
||||||
|
system: yes
|
||||||
|
register: user_info
|
||||||
|
|
||||||
|
- name: Set up database
|
||||||
|
import_tasks: db.yml
|
||||||
|
|
||||||
|
- name: Set up app
|
||||||
|
import_tasks: app.yml
|
10
roles/netbox/templates/netbox-rq.initd.j2
Normal file
10
roles/netbox/templates/netbox-rq.initd.j2
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
description="NetBox request queue worker"
|
||||||
|
|
||||||
|
command="{{ user_info.home }}/app/venv/bin/python3"
|
||||||
|
command_args="{{ user_info.home }}/app/netbox/manage.py rqworker high default low"
|
||||||
|
command_user="{{ user }}:{{ user }}"
|
||||||
|
|
||||||
|
command_background=true
|
||||||
|
pidfile="/run/${RC_SVCNAME}.pid"
|
23
roles/netbox/templates/netbox.conf.j2
Normal file
23
roles/netbox/templates/netbox.conf.j2
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{% for fqdn in fqdns %}
|
||||||
|
server {
|
||||||
|
server_name {{ fqdn }};
|
||||||
|
|
||||||
|
listen [::]:443 ssl ipv6only=off;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/{{ fqdn }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/{{ fqdn }}/privkey.pem;
|
||||||
|
|
||||||
|
client_max_body_size 100m;
|
||||||
|
|
||||||
|
location /static/ {
|
||||||
|
alias {{ user_info.home }}/app/netbox/static/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8001;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endfor %}
|
10
roles/netbox/templates/netbox.initd.j2
Normal file
10
roles/netbox/templates/netbox.initd.j2
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
description="NetBox WSGI service"
|
||||||
|
|
||||||
|
command="{{ user_info.home }}/app/venv/bin/gunicorn"
|
||||||
|
command_args="--pythonpath {{ user_info.home }}/app/netbox --config {{ user_info.home }}/gunicorn.py netbox.wsgi"
|
||||||
|
command_user="{{ user }}:{{ user }}"
|
||||||
|
|
||||||
|
command_background=true
|
||||||
|
pidfile="/run/${RC_SVCNAME}.pid"
|
11
roles/nginx/files/default.conf
Normal file
11
roles/nginx/files/default.conf
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# handle .well-known and HTTPS redirect for all domains
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
location /.well-known/ {
|
||||||
|
alias /srv/http/.well-known/;
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
5
roles/nginx/handlers/main.yml
Normal file
5
roles/nginx/handlers/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- name: reload nginx
|
||||||
|
service:
|
||||||
|
name: nginx
|
||||||
|
state: reloaded
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
39
roles/nginx/tasks/main.yml
Normal file
39
roles/nginx/tasks/main.yml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
- name: Install packages
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- certbot
|
||||||
|
- nginx
|
||||||
|
|
||||||
|
- name: Create HTTP server directories
|
||||||
|
file:
|
||||||
|
path: /srv/http/.well-known
|
||||||
|
recurse: true
|
||||||
|
state: directory
|
||||||
|
owner: nginx
|
||||||
|
group: nginx
|
||||||
|
|
||||||
|
- name: Set up default HTTP server
|
||||||
|
copy:
|
||||||
|
dest: /etc/nginx/http.d
|
||||||
|
src: default.conf
|
||||||
|
notify: reload nginx
|
||||||
|
|
||||||
|
- name: Enable nginx service
|
||||||
|
service:
|
||||||
|
name: nginx
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Get LE certificate
|
||||||
|
command:
|
||||||
|
cmd: certbot certonly --non-interactive --agree-tos --register-unsafely-without-email --webroot --webroot-path /srv/http -d {{ item }}
|
||||||
|
creates: '/etc/letsencrypt/renewal/{{ item }}.conf'
|
||||||
|
loop: '{{ fqdns }}'
|
||||||
|
|
||||||
|
- name: Enable certbot renewal
|
||||||
|
cron:
|
||||||
|
name: "certbot renew"
|
||||||
|
job: "certbot renew --quiet"
|
||||||
|
user: root
|
||||||
|
hour: "2,14"
|
||||||
|
minute: "18"
|
Loading…
Reference in a new issue