Merge pull request 'PowerDNS instead of bind9' (#2) from kunsi-feature-powerdns-instead-of-bind into main
All checks were successful
bundlewrap/pipeline/head This commit looks good

Reviewed-on: https://git.kunsmann.eu/kunsi/bundlewrap/pulls/2
This commit is contained in:
kunsi 2020-10-17 11:12:35 +00:00
commit 5635571f97
35 changed files with 739 additions and 330 deletions

View file

@ -67,10 +67,12 @@ pkg_apt = {
'arping': {},
'at': {},
'build-essential': {},
'bzip2': {},
'curl': {},
'diffutils': {},
'dnsutils': {},
'git': {},
'grep': {},
'gzip': {},
'htop': {},
@ -88,6 +90,7 @@ pkg_apt = {
'netcat': {},
'nmap': {},
'python3': {},
'python3-dev': {},
'python3-pip': {},
'python3-virtualenv': {},
'tar': {},

View file

@ -1,6 +0,0 @@
% for key in keys:
key ${key['name']} {
algorithm ${key['algorithm']};
secret "${key['secret']}";
};
% endfor

View file

@ -1,30 +0,0 @@
include "/etc/bind/keys.conf";
% for zone in sorted(primary_zones):
zone "${zone}" IN {
type master;
file "/var/lib/bind/primary/${zone}";
};
% endfor
zone "10.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "16.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "17.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "18.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "19.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "20.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "21.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "22.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "23.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "24.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "25.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "26.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "27.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "28.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "29.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "30.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "31.172.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };
zone "168.192.in-addr.arpa" { type master; file "/etc/bind/db.empty"; };

View file

@ -1,3 +0,0 @@
% for o in node.metadata.get('bind', {}).get('options', []):
<%include file="options/${o}"/>
% endfor

View file

@ -1,146 +0,0 @@
from os import listdir
from os.path import isfile, join
from datetime import datetime
from subprocess import check_output
ZONE_HEADER = """
; _ ____ _ _ _____ _ _ _ _ ____
; / \\ / ___| | | |_ _| | | | \\ | |/ ___|
; / _ \\| | | |_| | | | | | | | \\| | | _
; / ___ \\ |___| _ | | | | |_| | |\\ | |_| |
; /_/ \\_\\____|_| |_| |_| \\___/|_| \\_|\\____|
;
; --> Diese Datei wird von BundleWrap verwaltet! <--
$TTL 60
@ IN SOA ns-1.kunbox.net. hostmaster.kunbox.net. (
{serial}
3600
3600
86400
300
)
@ IN NS bind01.gce.kunbox.net.
IN NS b.ns14.net.
IN NS c.ns14.net.
IN NS d.ns14.net.
"""
svc_systemd = {
'bind9': {
'needs': {
'pkg_apt:bind9',
},
},
}
pkg_apt = {
'bind9': {},
}
directories = {
"/var/lib/bind/primary": {
'group': 'bind',
'needs': {
'pkg_apt:bind9',
},
'owner': 'bind',
'purge': True,
},
"/var/log/named": {
'group': 'bind',
'needs': {
'pkg_apt:bind9',
},
'owner': 'bind',
},
}
files = {
"/etc/bind/keys.conf": {
'content_type': 'mako',
'group': 'bind',
'mode': '0440',
'context': {
'keys': node.metadata.get('bind', {}).get('keys', []),
},
'triggers': {
'svc_systemd:bind9:reload',
},
'needs': {
'pkg_apt:bind9',
},
},
"/etc/bind/named.conf.options": {
'content_type': 'mako',
'group': 'bind',
'mode': '0440',
'triggers': {
'svc_systemd:bind9:reload',
},
'needs': {
'pkg_apt:bind9',
},
},
}
if node.metadata.get('bind', {}).get('rndc', ''):
files['/etc/bind/rndc.conf'] = {
'mode': '0440',
'source': 'rndc/{}'.format(node.metadata['bind']['rndc']),
'content_type': 'mako',
'triggers': {
'svc_systemd:bind9:reload',
},
}
# this looks for zones either directly at data/bind/zones/ or in a subdirectory if so configured
zone_path = join(
repo.path,
'data', 'bind', 'files', 'zones',
node.metadata.get('bind', {}).get('zone_path', ""),
)
primary_zones = set()
for zone in listdir(zone_path):
if not isfile(join(zone_path, zone)) or zone.startswith(".") or zone.startswith("_"):
continue
output = check_output(['git', 'log', '-1', '--pretty=%ci', join(zone_path, zone)]).decode('utf-8').strip()
serial = datetime.strptime(output, '%Y-%m-%d %H:%M:%S %z').strftime('%y%m%d%H%M')
primary_zones.add(zone)
files["/var/lib/bind/primary/{}".format(zone)] = {
'content_type': 'mako',
'context': {
'header': ZONE_HEADER.format(serial=serial),
'metadata_records': node.metadata.get('bind', {}).get('zones_primary', {}).get(zone, {}).get('records', []),
},
'mode': '0444',
'owner': 'bind',
'source': 'zones/{}'.format(join(node.metadata.get('bind', {}).get('zone_path', ""), zone)),
'triggers': {
'svc_systemd:bind9:reload',
},
'needs': {
'pkg_apt:bind9'
},
}
primary_zones.union(set(node.metadata.get('bind', {}).get('zones_primary', {}).keys()))
files['/etc/bind/named.conf.local'] = {
'content_type': 'mako',
'context': {
'primary_zones': list(primary_zones),
},
'group': 'bind',
'triggers': {
'svc_systemd:bind9:reload',
},
'needs': {
'pkg_apt:bind9',
},
}

View file

@ -1,72 +0,0 @@
from bundlewrap.metadata import atomic
defaults = {
'icinga2_api': {
'bind': {
'services': {
'BIND PROCESS': {
'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -C named -c 1:1',
},
},
},
},
}
@metadata_reactor
def port_checks(metadata):
services = {}
for interface in metadata.get('bind/listen', set()):
services[f'BIND PORT {interface}'] = {
'check_command': 'tcp',
'vars.tcp_address': metadata.get(f'interfaces/{interface}/ip_addresses')[0],
'vars.tcp_port': 53,
}
return {
'icinga2_api': {
'bind': {
'services': services,
},
},
}
@metadata_reactor
def generate_dns_entries_for_nodes(metadata):
results = set()
for rnode in repo.nodes:
node_name_split = rnode.name.split('.')
node_name_split.reverse()
dns_name = '.'.join(node_name_split)
ip4 = None
ip6 = None
# We only need this for GCE, because machines over there don't
# have a public ipv4 address.
if rnode.metadata.get('external_ipv4', None):
ip4 = rnode.metadata.get('external_ipv4')
for iface, config in sorted(rnode.metadata.get('interfaces', {}).items()):
if not ip4 and 'ipv4' in config:
ip4 = sorted(config['ipv4'])[0]
if not ip6 and 'ipv6' in config:
ip6 = sorted(config['ipv6'])[0]
if ip4:
results.add('{} IN A {}'.format(dns_name, ip4))
if ip6:
results.add('{} IN AAAA {}'.format(dns_name, ip6))
return {
'bind': {
'zones_primary': {
'kunbox.net': {
'records': results,
},
},
},
}

View file

@ -1,6 +1,7 @@
pkg_apt = {
'postgresql-11': {},
'postgresql-client-11': {},
'postgresql-server-dev-11': {},
}
if node.has_bundle('zfs'):

View file

@ -0,0 +1,2 @@
launch+=bind
bind-config=/etc/powerdns/named.conf

View file

@ -0,0 +1,6 @@
% for zone in sorted(zones):
zone "${zone}" {
file "/var/lib/powerdns/zones/${zone}";
type native;
};
% endfor

View file

@ -0,0 +1,28 @@
launch=
include-dir=/etc/powerdns/pdns.d
api=yes
api-key=${api_key}
webserver=yes
disable-syslog=yes
log-timestamp=no
max-tcp-connections=500
max-tcp-connections-per-client=10
security-poll-suffix=
server-id=${my_hostname}
default-ttl=60
% if is_secondary:
# Primary servers: ${', '.join(sorted(my_primary_servers['nodes']))}
slave=yes
superslave=yes
allow-notify-from=${','.join(sorted(my_primary_servers['ips']))}
% else:
allow-notify-from=
master=yes
% endif

View file

@ -0,0 +1,6 @@
launch+=gpgsql
gpgsql-host=localhost
gpgsql-port=5432
gpgsql-dbname=powerdns
gpgsql-user=powerdns
gpgsql-password=${password}

View file

@ -0,0 +1,105 @@
-- 4.3 schema, https://doc.powerdns.com/authoritative/backends/generic-postgresql.html
CREATE TABLE domains (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
master VARCHAR(128) DEFAULT NULL,
last_check INT DEFAULT NULL,
type VARCHAR(6) NOT NULL,
notified_serial BIGINT DEFAULT NULL,
account VARCHAR(40) DEFAULT NULL,
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);
CREATE UNIQUE INDEX name_index ON domains(name);
ALTER TABLE domains OWNER TO ${user};
CREATE TABLE records (
id BIGSERIAL PRIMARY KEY,
domain_id INT DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
type VARCHAR(10) DEFAULT NULL,
content VARCHAR(65535) DEFAULT NULL,
ttl INT DEFAULT NULL,
prio INT DEFAULT NULL,
change_date INT DEFAULT NULL,
disabled BOOL DEFAULT 'f',
ordername VARCHAR(255),
auth BOOL DEFAULT 't',
CONSTRAINT domain_exists
FOREIGN KEY(domain_id) REFERENCES domains(id)
ON DELETE CASCADE,
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);
CREATE INDEX rec_name_index ON records(name);
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
ALTER TABLE records OWNER TO ${user};
CREATE TABLE supermasters (
ip INET NOT NULL,
nameserver VARCHAR(255) NOT NULL,
account VARCHAR(40) NOT NULL,
PRIMARY KEY(ip, nameserver)
);
ALTER TABLE supermasters OWNER TO ${user};
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
domain_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
type VARCHAR(10) NOT NULL,
modified_at INT NOT NULL,
account VARCHAR(40) DEFAULT NULL,
comment VARCHAR(65535) NOT NULL,
CONSTRAINT domain_exists
FOREIGN KEY(domain_id) REFERENCES domains(id)
ON DELETE CASCADE,
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);
CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
ALTER TABLE comments OWNER TO ${user};
CREATE TABLE domainmetadata (
id SERIAL PRIMARY KEY,
domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
kind VARCHAR(32),
content TEXT
);
CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
ALTER TABLE domainmetadata OWNER TO ${user};
CREATE TABLE cryptokeys (
id SERIAL PRIMARY KEY,
domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
flags INT NOT NULL,
active BOOL,
content TEXT
);
CREATE INDEX domainidindex ON cryptokeys(domain_id);
ALTER TABLE cryptokeys OWNER TO ${user};
CREATE TABLE tsigkeys (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
algorithm VARCHAR(50),
secret VARCHAR(255),
CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);
CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
ALTER TABLE tsigkeys OWNER TO ${user};

163
bundles/powerdns/items.py Normal file
View file

@ -0,0 +1,163 @@
from datetime import datetime
from os import listdir
from os.path import isfile, join
from subprocess import check_output
zone_path = join(repo.path, 'data', 'powerdns', 'files', 'bind-zones')
ZONE_HEADER = """
; _ ____ _ _ _____ _ _ _ _ ____
; / \\ / ___| | | |_ _| | | | \\ | |/ ___|
; / _ \\| | | |_| | | | | | | | \\| | | _
; / ___ \\ |___| _ | | | | |_| | |\\ | |_| |
; /_/ \\_\\____|_| |_| |_| \\___/|_| \\_|\\____|
;
; --> Diese Datei wird von BundleWrap verwaltet! <--
$TTL 60
@ IN SOA ns-1.kunbox.net. hostmaster.kunbox.net. (
{serial}
3600
3600
86400
300
)
"""
for rnode in sorted(repo.nodes_in_group('dns')):
ZONE_HEADER += '@ IN NS {}.\n'.format(rnode.metadata.get('powerdns', {}).get('my_hostname', rnode.hostname))
directories = {
'/etc/powerdns/pdns.d': {
'purge': True,
'needs': {
'pkg_apt:pdns-server',
'pkg_apt:pdns-backend-bind',
'pkg_apt:pdns-backend-pgsql',
},
'triggers': {
'svc_systemd:pdns:restart',
},
},
'/var/lib/powerdns/zones': {
'purge': True,
'needs': {
'pkg_apt:pdns-backend-bind',
},
}
}
files = {
'/etc/powerdns/pdns.conf': {
'content_type': 'mako',
'context': {
'api_key': node.metadata['powerdns']['api_key'],
'my_hostname': node.metadata['powerdns'].get('my_hostname', node.name),
'is_secondary': node.metadata['powerdns'].get('is_secondary', False),
'my_primary_servers': node.metadata['powerdns'].get('my_primary_servers', {}),
},
'needs': {
'pkg_apt:pdns-server',
},
'triggers': {
'svc_systemd:pdns:restart',
},
},
}
svc_systemd = {
'pdns': {
'needs': {
'directory:',
'file:',
'pkg_apt:pdns-server',
'pkg_apt:pdns-backend-bind',
'pkg_apt:pdns-backend-pgsql',
},
},
}
actions = {
'powerdns_reload_zones': {
'triggered': True,
'command': 'pdns_control rediscover; pdns_control reload',
'needs': {
'svc_systemd:pdns',
},
},
}
if node.metadata['powerdns'].get('features', {}).get('bind', False):
primary_zones = set()
for zone in listdir(zone_path):
if not isfile(join(zone_path, zone)) or zone.startswith(".") or zone.startswith("_"):
continue
try:
output = check_output(['git', 'log', '-1', '--pretty=%ci', join(zone_path, zone)]).decode('utf-8').strip()
serial = datetime.strptime(output, '%Y-%m-%d %H:%M:%S %z').strftime('%y%m%d%H%M')
except:
serial = datetime.now().strftime('%y%m%d0000')
primary_zones.add(zone)
files["/var/lib/powerdns/zones/{}".format(zone)] = {
'content_type': 'mako',
'context': {
'header': ZONE_HEADER.format(serial=serial),
'metadata_records': node.metadata.get('powerdns', {}).get('bind-zones', {}).get(zone, {}).get('records', []),
},
'source': 'bind-zones/{}'.format(zone),
'triggers': {
'action:powerdns_reload_zones',
},
}
files['/etc/powerdns/pdns.d/bind.conf'] = {
'needs': {
'pkg_apt:pdns-backend-bind',
},
'triggers': {
'action:powerdns_reload_zones',
},
}
files['/etc/powerdns/named.conf'] = {
'content_type': 'mako',
'context': {
'zones': primary_zones,
},
'needs': {
'pkg_apt:pdns-backend-bind',
},
'triggers': {
'action:powerdns_reload_zones',
},
}
if node.metadata['powerdns'].get('features', {}).get('pgsql', False):
files['/etc/powerdns/pdns.d/pgsql.conf'] = {
'content_type': 'mako',
'context': {
'password': node.metadata['postgresql']['users']['powerdns']['password'],
},
'needs': {
'pkg_apt:pdns-backend-pgsql',
},
'triggers': {
'action:powerdns_reload_zones',
},
}
files['/etc/powerdns/schema.pgsql.sql'] = {}
actions['powerdns_load_pgsql_schema'] = {
'command': node.metadata['postgresql']['users']['powerdns']['password'].format_into('PGPASSWORD={} psql -h 127.0.0.1 -d powerdns -U powerdns -w < /etc/powerdns/schema.pgsql.sql'),
'unless': 'sudo -u postgres psql -d powerdns -c "\dt" | grep domains 2>&1 >/dev/null',
'needs': {
'bundle:postgresql',
'file:/etc/powerdns/schema.pgsql.sql',
},
'needed_by': {
'svc_systemd:pdns',
},
}

View file

@ -0,0 +1,91 @@
from bundlewrap.exceptions import NoSuchGroup
defaults = {
'apt': {
'packages': {
'pdns-server': {},
'pdns-tools': {},
'pdns-backend-bind': {},
'pdns-backend-pgsql': {},
},
},
'powerdns': {
'api_key': repo.vault.password_for('{} powerdns api'.format(node.name)),
},
'postgresql': {
'users': {
'powerdns': {
'password': repo.vault.password_for('{} postgresql powerdns'.format(node.name)),
},
},
'databases': {
'powerdns': {
'owner': 'powerdns',
},
},
},
}
@metadata_reactor
def get_ips_of_primary_nameservers(metadata):
if not metadata.get('powerdns/is_secondary', False):
return {}
ips = set()
nodes = set()
for rnode in repo.nodes_in_group('dns'):
if not rnode.metadata.get('powerdns/is_secondary', False):
ips.update({
str(ip) for ip in repo.libs.tools.resolve_identifier(repo, rnode.name)
})
nodes.add(rnode.name)
return {
'powerdns': {
'my_primary_servers': {
'ips': ips,
'nodes': nodes,
},
},
}
@metadata_reactor
def generate_dns_entries_for_nodes(metadata):
results = set()
for rnode in repo.nodes:
node_name_split = rnode.name.split('.')
node_name_split.reverse()
dns_name = '.'.join(node_name_split)
ip4 = None
ip6 = None
# We only need this for GCE, because machines over there don't
# have a public ipv4 address.
if rnode.metadata.get('external_ipv4', None):
ip4 = rnode.metadata.get('external_ipv4')
for iface, config in sorted(rnode.metadata.get('interfaces', {}).items()):
if not ip4 and 'ipv4' in config:
ip4 = sorted(config['ipv4'])[0]
if not ip6 and 'ipv6' in config:
ip6 = sorted(config['ipv6'])[0]
if ip4:
results.add('{} IN A {}'.format(dns_name, ip4))
if ip6:
results.add('{} IN AAAA {}'.format(dns_name, ip6))
return {
'powerdns': {
'bind-zones': {
'kunbox.net': {
'records': results,
},
},
},
}

View file

@ -0,0 +1,14 @@
SALT = '${repo.vault.decrypt('encrypt$gAAAAABfidFVqVEgWvlXgP-GSQUgVtcTxzoZx2G8VYWHaGKRpgaLDchlTRcKwqgvfG5orNpXt7aDd5i2aehi6cvIlxYNdL87twfVhDLBDho8j-Uz5Vga8-9cEzEZULl5pFCIcRlYUCKyEIOcdXSaLCM3p8pGjrh-O8_g49rbADKmLFoJx2vVTVs=')}'
SECRET_KEY = '${repo.vault.password_for('{} powerdnsadmin secret_key'.format(node.name))}'
BIND_ADDRESS = '127.0.0.1'
PORT = 9191
OFFLINE_MODE = True
SQLA_DB_USER = 'powerdnsadmin'
SQLA_DB_PASSWORD = '${node.metadata['postgresql']['users']['powerdnsadmin']['password']}'
SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_NAME = 'powerdnsadmin'
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_DATABASE_URI = 'postgresql://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + '/' + SQLA_DB_NAME
SAML_ENABLED = False

View file

@ -0,0 +1,14 @@
[Unit]
Description=PowerDNS-Admin
After=network.target postgresql.service
[Service]
User=powerdnsadmin
Group=powerdnsadmin
Environment=FLASK_CONF=/opt/powerdnsadmin/config.py
WorkingDirectory=/opt/powerdnsadmin/src
ExecStartPre=-/bin/chown powerdnsadmin:powerdnsadmin /opt/powerdnsadmin/src/powerdnsadmin/static
ExecStart=/opt/powerdnsadmin/venv/bin/gunicorn 'powerdnsadmin:create_app()'
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,87 @@
assert node.has_bundle('nodejs')
assert node.has_bundle('postgresql')
directories = {
'/opt/powerdnsadmin/src': {},
}
git_deploy = {
'/opt/powerdnsadmin/src': {
'repo': 'https://github.com/ngoduykhanh/PowerDNS-Admin.git',
'rev': 'master',
'triggers': {
'action:powerdnsadmin_install_deps',
'action:powerdnsadmin_upgrade_database',
'action:powerdnsadmin_compile_assets',
'svc_systemd:powerdnsadmin:restart',
},
},
}
files = {
'/opt/powerdnsadmin/config.py': {
'content_type': 'mako',
},
'/etc/systemd/system/powerdnsadmin.service': {
'triggers': {
'action:systemd-reload',
},
},
}
actions = {
'powerdnsadmin_create_virtualenv': {
'command': '/usr/bin/python3 -m virtualenv -p python3 /opt/powerdnsadmin/venv/',
'unless': 'test -d /opt/powerdnsadmin/venv/',
'needs': {
'directory:/opt/powerdnsadmin', # provided by bundle:users
},
},
'powerdnsadmin_install_deps': {
'triggered': True,
'command': '/opt/powerdnsadmin/venv/bin/pip install -r /opt/powerdnsadmin/src/requirements.txt',
'needs': {
'action:powerdnsadmin_create_virtualenv',
'pkg_apt:',
},
},
'powerdnsadmin_install_deps': {
'triggered': True,
'command': '/opt/powerdnsadmin/venv/bin/pip install -r /opt/powerdnsadmin/src/requirements.txt',
'needs': {
'action:powerdnsadmin_create_virtualenv',
'pkg_apt:',
},
},
'powerdnsadmin_upgrade_database': {
'triggered': True,
'command': 'FLASK_CONF=/opt/powerdnsadmin/config.py FLASK_APP=/opt/powerdnsadmin/src/powerdnsadmin/__init__.py /opt/powerdnsadmin/venv/bin/flask db upgrade',
# TODO unless
'needs': {
'action:powerdnsadmin_install_deps',
'bundle:postgresql',
'pkg_apt:',
},
},
'powerdnsadmin_compile_assets': {
'triggered': True,
'command': 'cd /opt/powerdnsadmin/src && yarn install --pure-lockfile && FLASK_APP=/opt/powerdnsadmin/src/powerdnsadmin/__init__.py /opt/powerdnsadmin/venv/bin/flask assets build',
'needs': {
'action:powerdnsadmin_install_deps',
'pkg_apt:',
},
},
}
svc_systemd = {
'powerdnsadmin': {
'needs': {
'file:/opt/powerdnsadmin/config.py',
'file:/etc/systemd/system/powerdnsadmin.service',
'git_deploy:/opt/powerdnsadmin/src',
'action:powerdnsadmin_install_deps',
'action:powerdnsadmin_upgrade_database',
'action:powerdnsadmin_compile_assets',
},
},
}

View file

@ -0,0 +1,35 @@
defaults = {
'apt': {
'packages': {
'default-libmysqlclient-dev': {},
'libffi-dev': {},
'libldap2-dev': {},
'libsasl2-dev': {},
'libssl-dev': {},
'libxml2-dev': {},
'libxmlsec1-dev': {},
'libxslt1-dev': {},
'pkg-config': {},
'python3-psycopg2': {},
'python3-wheel': {},
},
},
'users': {
'powerdnsadmin': {
'home': '/opt/powerdnsadmin',
},
},
'postgresql': {
'users': {
'powerdnsadmin': {
'password': repo.vault.password_for('{} postgresql powerdnsadmin'.format(node.name)),
},
},
'databases': {
'powerdnsadmin': {
'owner': 'powerdnsadmin',
},
},
},
}