fix: an upgrade keeps the configuration and asks nothing.
Release / release (push) Successful in 18s
Release / release (push) Successful in 18s
This commit is contained in:
1 parent
08693f7e68
commit
cda33fc4c7
4 files changed
+77
-33
No files matched your search
@@ -85,8 +85,10 @@ that deploy a router on Azure or GCP.
|
|||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
`/etc/vpn-router/vpn-router.json` is JSON, mode 0600, and is created on first install. It
|
`/etc/vpn-router/vpn-router.json` is JSON, mode 0600, and is created on first install. It
|
||||||
is managed with `ucf`, so it is yours to edit: a later `dpkg-reconfigure` applies what
|
is managed with `ucf`, so it is yours to edit: a later `dpkg-reconfigure` applies the answers
|
||||||
changed and asks before touching anything you altered by hand. A complete example is
|
given and asks before touching anything you altered by hand, and an upgrade leaves the file as
|
||||||
|
it is and asks nothing. Settings the file leaves out take their defaults when it is read, so a
|
||||||
|
file written by cloud-init or by hand needs only the settings that differ. A complete example is
|
||||||
installed at `/usr/share/doc/vpn-router/vpn-router.json.example`.
|
installed at `/usr/share/doc/vpn-router/vpn-router.json.example`.
|
||||||
|
|
||||||
The file is an object of sections, each an object of settings. A section or setting that
|
The file is an object of sections, each an object of settings. A section or setting that
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
|
vpn-router (0.5.8-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
fix: an upgrade keeps the configuration and asks nothing.
|
||||||
|
|
||||||
|
* postinst passes on only the debconf answers that were given. The
|
||||||
|
defaults of questions never asked, such as platform none, no longer
|
||||||
|
replace settings of vpn-router.json.
|
||||||
|
* Without an answer that changes it, the configuration ucf is given is
|
||||||
|
vpn-router.json byte for byte, so an upgrade has no conflict to ask
|
||||||
|
about; settings the file leaves out keep their defaults when it is read.
|
||||||
|
|
||||||
|
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Sat, 24 Oct 2026 20:00:00 +0200
|
||||||
|
|
||||||
vpn-router (0.5.7-1) unstable; urgency=medium
|
vpn-router (0.5.7-1) unstable; urgency=medium
|
||||||
|
|
||||||
feature: users have a first name, a last name and an e-mail address.
|
feature: users have a first name, a last name and an e-mail address.
|
||||||
|
|||||||
@@ -2,28 +2,39 @@
|
|||||||
set -e
|
set -e
|
||||||
. /usr/share/debconf/confmodule
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
# The answer to a question in ANSWER, or "" when the question has not been seen; the
|
||||||
|
# default debconf holds for an unseen question is not an answer.
|
||||||
|
answer() {
|
||||||
|
ANSWER=""
|
||||||
|
db_fget "$1" seen
|
||||||
|
if [ "$RET" = "true" ]; then
|
||||||
|
db_get "$1"
|
||||||
|
ANSWER="$RET"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
configure)
|
configure)
|
||||||
# --- Read the installer's answers ---
|
# --- Read the installer's answers ---
|
||||||
db_get vpn-router/platform; VPN_ROUTER_PLATFORM="$RET"
|
answer vpn-router/platform; VPN_ROUTER_PLATFORM="$ANSWER"
|
||||||
db_get vpn-router/mode; VPN_ROUTER_MODE="$RET"
|
answer vpn-router/mode; VPN_ROUTER_MODE="$ANSWER"
|
||||||
db_get vpn-router/int_addr; VPN_ROUTER_INT_ADDR="$RET"
|
answer vpn-router/int_addr; VPN_ROUTER_INT_ADDR="$ANSWER"
|
||||||
db_get vpn-router/external_interface; VPN_ROUTER_EXTERNAL_INTERFACE="$RET"
|
answer vpn-router/external_interface; VPN_ROUTER_EXTERNAL_INTERFACE="$ANSWER"
|
||||||
db_get vpn-router/internal_interface; VPN_ROUTER_INTERNAL_INTERFACE="$RET"
|
answer vpn-router/internal_interface; VPN_ROUTER_INTERNAL_INTERFACE="$ANSWER"
|
||||||
db_get vpn-router/local_fqdn; VPN_ROUTER_LOCAL_FQDN="$RET"
|
answer vpn-router/local_fqdn; VPN_ROUTER_LOCAL_FQDN="$ANSWER"
|
||||||
db_get vpn-router/local_id_mode; VPN_ROUTER_LOCAL_ID_MODE="$RET"
|
answer vpn-router/local_id_mode; VPN_ROUTER_LOCAL_ID_MODE="$ANSWER"
|
||||||
db_get vpn-router/local_cidrs; VPN_ROUTER_LOCAL_CIDRS="$RET"
|
answer vpn-router/local_cidrs; VPN_ROUTER_LOCAL_CIDRS="$ANSWER"
|
||||||
db_get vpn-router/int_gateway_ip; VPN_ROUTER_INT_GATEWAY_IP="$RET"
|
answer vpn-router/int_gateway_ip; VPN_ROUTER_INT_GATEWAY_IP="$ANSWER"
|
||||||
db_get vpn-router/remote_addrs; VPN_ROUTER_REMOTE_ADDRS="$RET"
|
answer vpn-router/remote_addrs; VPN_ROUTER_REMOTE_ADDRS="$ANSWER"
|
||||||
db_get vpn-router/remote_id; VPN_ROUTER_REMOTE_ID="$RET"
|
answer vpn-router/remote_id; VPN_ROUTER_REMOTE_ID="$ANSWER"
|
||||||
db_get vpn-router/remote_cidrs; VPN_ROUTER_REMOTE_CIDRS="$RET"
|
answer vpn-router/remote_cidrs; VPN_ROUTER_REMOTE_CIDRS="$ANSWER"
|
||||||
db_get vpn-router/psk; VPN_ROUTER_PSK="$RET"
|
answer vpn-router/psk; VPN_ROUTER_PSK="$ANSWER"
|
||||||
db_get vpn-router/p2s_enabled; VPN_ROUTER_P2S_ENABLED="$RET"
|
answer vpn-router/p2s_enabled; VPN_ROUTER_P2S_ENABLED="$ANSWER"
|
||||||
db_get vpn-router/p2s_address_pool; VPN_ROUTER_P2S_ADDRESS_POOL="$RET"
|
answer vpn-router/p2s_address_pool; VPN_ROUTER_P2S_ADDRESS_POOL="$ANSWER"
|
||||||
db_get vpn-router/p2s_ca_name; VPN_ROUTER_P2S_CA_NAME="$RET"
|
answer vpn-router/p2s_ca_name; VPN_ROUTER_P2S_CA_NAME="$ANSWER"
|
||||||
db_get vpn-router/wg_enabled; VPN_ROUTER_WG_ENABLED="$RET"
|
answer vpn-router/wg_enabled; VPN_ROUTER_WG_ENABLED="$ANSWER"
|
||||||
db_get vpn-router/wg_address; VPN_ROUTER_WG_ADDRESS="$RET"
|
answer vpn-router/wg_address; VPN_ROUTER_WG_ADDRESS="$ANSWER"
|
||||||
db_get vpn-router/wg_listen_port; VPN_ROUTER_WG_LISTEN_PORT="$RET"
|
answer vpn-router/wg_listen_port; VPN_ROUTER_WG_LISTEN_PORT="$ANSWER"
|
||||||
|
|
||||||
export VPN_ROUTER_PLATFORM VPN_ROUTER_MODE VPN_ROUTER_INT_ADDR \
|
export VPN_ROUTER_PLATFORM VPN_ROUTER_MODE VPN_ROUTER_INT_ADDR \
|
||||||
VPN_ROUTER_EXTERNAL_INTERFACE \
|
VPN_ROUTER_EXTERNAL_INTERFACE \
|
||||||
|
|||||||
@@ -6,18 +6,15 @@ Called from postinst, which hands the result to ucf(1). ucf compares it with
|
|||||||
this script never writes to /etc and never has to worry about destroying an
|
this script never writes to /etc and never has to worry about destroying an
|
||||||
administrator's edits.
|
administrator's edits.
|
||||||
|
|
||||||
The candidate is built in three layers, each overriding the one before:
|
The candidate is the current /etc/vpn-router/vpn-router.json as it is, or the
|
||||||
|
shipped defaults when there is none, with every debconf answer that was given
|
||||||
1. the shipped defaults
|
written over it. Without an answer that changes it, the candidate is the current
|
||||||
2. the current contents of /etc/vpn-router/vpn-router.json, if it exists
|
file byte for byte, so
|
||||||
3. any debconf answer that was actually given
|
an upgrade or a reconfiguration that changes nothing gives ucf nothing to ask;
|
||||||
|
defaults the file leaves out are applied by vpnrouter.load_config() when the
|
||||||
Layer 2 is what makes reconfiguration safe: a setting the administrator edited
|
file is read. An empty answer means "leave alone", which is why clearing the
|
||||||
by hand, and that debconf has nothing to say about, is carried through
|
pre-shared key from the debconf database after installation does not blank it
|
||||||
unchanged, so ucf only sees a diff where something really changed. An empty
|
on the next dpkg-reconfigure.
|
||||||
answer means "leave alone", which is why clearing the pre-shared key from the
|
|
||||||
debconf database after installation does not blank it on the next
|
|
||||||
dpkg-reconfigure.
|
|
||||||
|
|
||||||
Answers arrive as VPN_ROUTER_* environment variables and are converted to the
|
Answers arrive as VPN_ROUTER_* environment variables and are converted to the
|
||||||
type of the setting they fill: comma-separated lists become arrays, "true" and
|
type of the setting they fill: comma-separated lists become arrays, "true" and
|
||||||
@@ -62,8 +59,21 @@ def main():
|
|||||||
return 2
|
return 2
|
||||||
output = sys.argv[1]
|
output = sys.argv[1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
current = vpnrouter.CONFIG_FILE.read_text(encoding='utf-8')
|
||||||
|
except FileNotFoundError:
|
||||||
|
current = None
|
||||||
|
if current is None:
|
||||||
cfg = vpnrouter.load_config()
|
cfg = vpnrouter.load_config()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
cfg = json.loads(current)
|
||||||
|
except ValueError as exc:
|
||||||
|
vpnrouter.fail(f'cannot parse {vpnrouter.CONFIG_FILE}: {exc}')
|
||||||
|
if not isinstance(cfg, dict):
|
||||||
|
vpnrouter.fail(f'cannot parse {vpnrouter.CONFIG_FILE}: the top level is not an object')
|
||||||
|
|
||||||
|
answered = False
|
||||||
for variable, (section, option) in ANSWERS.items():
|
for variable, (section, option) in ANSWERS.items():
|
||||||
value = os.environ.get(variable)
|
value = os.environ.get(variable)
|
||||||
if not value:
|
if not value:
|
||||||
@@ -76,9 +86,17 @@ def main():
|
|||||||
value = int(value) if value.isdigit() else value
|
value = int(value) if value.isdigit() else value
|
||||||
elif isinstance(default, list):
|
elif isinstance(default, list):
|
||||||
value = [item.strip() for item in value.split(',') if item.strip()]
|
value = [item.strip() for item in value.split(',') if item.strip()]
|
||||||
|
if not isinstance(cfg.get(section, {}), dict):
|
||||||
|
vpnrouter.fail(f'cannot parse {vpnrouter.CONFIG_FILE}: {section} is not an object')
|
||||||
|
if cfg.setdefault(section, {}).get(option) != value:
|
||||||
cfg[section][option] = value
|
cfg[section][option] = value
|
||||||
|
answered = True
|
||||||
|
|
||||||
|
# Without a change the candidate is the current file byte for byte, as ucf compares checksums.
|
||||||
with open(output, 'w', encoding='utf-8') as handle:
|
with open(output, 'w', encoding='utf-8') as handle:
|
||||||
|
if current is not None and not answered:
|
||||||
|
handle.write(current)
|
||||||
|
else:
|
||||||
json.dump(cfg, handle, indent=2)
|
json.dump(cfg, handle, indent=2)
|
||||||
handle.write('\n')
|
handle.write('\n')
|
||||||
os.chmod(output, 0o600)
|
os.chmod(output, 0o600)
|
||||||
|
|||||||
Reference in new issue
Block a user