From 14bfddd0ee6559e04bdbf38beb0a2e0c21dc6723 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Thu, 17 Mar 2022 15:14:02 -0500 Subject: [PATCH] r/nbd-server: Deploy nbd-server The *nbd-server* role configures a machine as a Network Block Device (NDB) server, using the reference `nbd-server` implementation. It configures a systemd socket unit to listen on the port and accept incoming connections, and a template service unit for systemd to instantiate and pass each incoming connection. The reference `nbd-server` is actually not very good. It does not clean up closed connections reliably, especially if the client disconnects unexpectedly. Fortunately, systemd provides the necessary tools to work around these bugs. Specifically, spawning one process per connection allows processes to be killed externally. Further, since systemd creates the listening socket, it can control the keep-alive interval. By setting this to a rather low value, we can clean up server processes for disconnected clients more quickly. Configuration of the server itself is minimal; most of the configuration is done on a per-export basis using drop-in configuration files. Other Ansible roles should create these configuration files to configure application-specific exports. Nothing needs to be reloaded or restarted for changes to take effect; the next incoming connection will spawn a new process, which will use the latest configuration file automatically. --- roles/nbd-server/defaults/main.yml | 1 + roles/nbd-server/files/nbd-server.socket | 13 +++ roles/nbd-server/files/nbd-server@.service | 11 +++ roles/nbd-server/handlers/main.yml | 9 ++ roles/nbd-server/tasks/main.yml | 96 +++++++++++++++++++ .../nbd-server/templates/nbd-server.config.j2 | 4 + 6 files changed, 134 insertions(+) create mode 100644 roles/nbd-server/defaults/main.yml create mode 100644 roles/nbd-server/files/nbd-server.socket create mode 100644 roles/nbd-server/files/nbd-server@.service create mode 100644 roles/nbd-server/handlers/main.yml create mode 100644 roles/nbd-server/tasks/main.yml create mode 100644 roles/nbd-server/templates/nbd-server.config.j2 diff --git a/roles/nbd-server/defaults/main.yml b/roles/nbd-server/defaults/main.yml new file mode 100644 index 0000000..7147ffa --- /dev/null +++ b/roles/nbd-server/defaults/main.yml @@ -0,0 +1 @@ +nbd_server_allow_list: true diff --git a/roles/nbd-server/files/nbd-server.socket b/roles/nbd-server/files/nbd-server.socket new file mode 100644 index 0000000..8be0fdd --- /dev/null +++ b/roles/nbd-server/files/nbd-server.socket @@ -0,0 +1,13 @@ +[Unit] +Description=Network Block Device Server socket + +[Socket] +# NBD clients cannot handle their addresses changing, which happens +# frequently for IPv6. Only bind to the IPv4 socket to work around this. +ListenStream=0.0.0.0:10809 +Accept=yes +KeepAlive=yes +KeepAliveTimeSec=5m + +[Install] +WantedBy=sockets.target diff --git a/roles/nbd-server/files/nbd-server@.service b/roles/nbd-server/files/nbd-server@.service new file mode 100644 index 0000000..a77ea64 --- /dev/null +++ b/roles/nbd-server/files/nbd-server@.service @@ -0,0 +1,11 @@ +[Unit] +Description=Network Block Device Server +CollectMode=inactive-or-failed +After=network.target + +[Service] +ExecStart=/usr/bin/nbd-server -d +User=nbd +Group=nbd +StandardInput=socket +StandardOutput=journal diff --git a/roles/nbd-server/handlers/main.yml b/roles/nbd-server/handlers/main.yml new file mode 100644 index 0000000..7ea76b6 --- /dev/null +++ b/roles/nbd-server/handlers/main.yml @@ -0,0 +1,9 @@ +- name: reload systemd + systemd: + daemon_reload: true + changed_when: true + +- name: restart nbd-server + systemd: + name: nbd-server.socket + state: restarted diff --git a/roles/nbd-server/tasks/main.yml b/roles/nbd-server/tasks/main.yml new file mode 100644 index 0000000..1c7f52c --- /dev/null +++ b/roles/nbd-server/tasks/main.yml @@ -0,0 +1,96 @@ +- name: ensure nbd is installed + package: + name: nbd + state: present + tags: + - install + +- name: ensure nbd user group exists + group: + name: nbd + system: true + state: present + tags: + - user + - group +- name: ensure nbd user exists + user: + name: nbd + system: true + group: nbd + home: /var/lib/nbd + create_home: false + shell: /sbin/nologin + state: present + tags: + - user + +- name: ensure nbd data directory exists + file: + path: /var/lib/nbd + mode: ug=rwx,o=rx + owner: nbd + group: nbd + state: directory + +- name: ensure nbd-server configuration directory exists + file: + path: /etc/nbd-server + mode: u=rwx,go=rx + owner: root + group: root + state: directory + tags: + - config +- name: ensure nbd-server configuration drop-in directory exists + file: + path: /etc/nbd-server/config.d + mode: u=rwx,go=rx + owner: root + group: root + state: directory + tags: + - config +- name: ensure nbd-server is configured + template: + src: nbd-server.config.j2 + dest: /etc/nbd-server/config + mode: u=rw,go=r + owner: root + group: root + notify: + - restart nbd-server + tags: + - config + +- name: ensure nbd-server unit files exist + copy: + src: '{{ item }}' + dest: /etc/systemd/system/ + mode: u=rw,go=r + owner: root + group: root + loop: + - nbd-server.socket + - nbd-server@.service + notify: + - reload systemd + - restart nbd-server + tags: + - systemd + +- name: ensure nbd-server socket is listening + systemd: + name: nbd-server.socket + state: started + tags: + - service + +- name: ensure firewall is configured for nbd-server + firewalld: + service: nbd + state: enabled + permanent: true + immediate: true + tags: + - firewall diff --git a/roles/nbd-server/templates/nbd-server.config.j2 b/roles/nbd-server/templates/nbd-server.config.j2 new file mode 100644 index 0000000..e110dc9 --- /dev/null +++ b/roles/nbd-server/templates/nbd-server.config.j2 @@ -0,0 +1,4 @@ +[generic] +port = 0 +allowlist = {{ nbd_server_allow_list|bool|string|lower }} +includedir = /etc/nbd-server/config.d