Move backoff logic to Updater
This commit is contained in:
parent
da402b0da9
commit
4b0f3cefb8
5 changed files with 58 additions and 27 deletions
10
README.md
10
README.md
|
@ -22,11 +22,11 @@ The configuration can contain a list of update targets:
|
||||||
|
|
||||||
ddnssclient can also be configured using some properties or environment variables
|
ddnssclient can also be configured using some properties or environment variables
|
||||||
|
|
||||||
| Property | Environment variable | Value | Default |
|
| Property | Environment variable | Value | Default |
|
||||||
| -------- |-----------------------|-----------------------------------|---------|
|
|-----------------------------|------------------------------|-----------------------------------|---------|
|
||||||
| ddnsclient.interval | DDNSCLIENT_INTERVAL | e.g. "3600s", "60m", "1h" | "5m" |
|
| ddnsclient.interval | DDNSCLIENT_INTERVAL | e.g. "3600s", "60m", "1h" | "5m" |
|
||||||
| ddnsclient.ip-provider | DDNSCLIENT_IP_PROVIDER | an ip lookup provider (see below) | null |
|
| ddnsclient.ip-provider | DDNSCLIENT_IP_PROVIDER | an ip lookup provider (see below) | null |
|
||||||
| ddnsclient.dyndns.backup-duration | DDNSCLIENT_DYNDNS_BACKUP_DURATION | e.g. "60s", "1m" | "60s" |
|
| ddnsclient.backoff-duration | DDNS_CLIENT_BACKOFF_DURATION | e.g. "60s", "1m" | "60s" |
|
||||||
|
|
||||||
## IP lookup
|
## IP lookup
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,14 @@ import de.rpr.ddnsclient.model.DyndnsAuth;
|
||||||
import de.rpr.ddnsclient.model.IPs;
|
import de.rpr.ddnsclient.model.IPs;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class Updater {
|
public class Updater {
|
||||||
|
|
||||||
|
@ -19,15 +25,23 @@ public class Updater {
|
||||||
private final DynDnsRouter dynDnsRouter;
|
private final DynDnsRouter dynDnsRouter;
|
||||||
private final IpProvider ipProvider;
|
private final IpProvider ipProvider;
|
||||||
private final DnsResolver dnsResolver;
|
private final DnsResolver dnsResolver;
|
||||||
|
private final Duration backoff;
|
||||||
|
|
||||||
private final Config config;
|
private final Config config;
|
||||||
|
|
||||||
|
private final Map<String, LocalDateTime> updateMap = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Updater(DynDnsRouter dynDnsRouter, IpProvider ipProvider, DnsResolver dnsResolver, Config config) {
|
public Updater(DynDnsRouter dynDnsRouter,
|
||||||
|
IpProvider ipProvider,
|
||||||
|
DnsResolver dnsResolver,
|
||||||
|
Config config,
|
||||||
|
@ConfigProperty(name = "ddnsclient.backoff-duration:300s") Duration backoff) {
|
||||||
this.dynDnsRouter = dynDnsRouter;
|
this.dynDnsRouter = dynDnsRouter;
|
||||||
this.ipProvider = ipProvider;
|
this.ipProvider = ipProvider;
|
||||||
this.dnsResolver = dnsResolver;
|
this.dnsResolver = dnsResolver;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.backoff = backoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
|
@ -42,6 +56,12 @@ public class Updater {
|
||||||
|
|
||||||
config.forEach(cfg -> {
|
config.forEach(cfg -> {
|
||||||
|
|
||||||
|
if (updateMap.containsKey(cfg.hostname())
|
||||||
|
&& Duration.between(updateMap.get(cfg.hostname()), LocalDateTime.now()).toSeconds() < backoff.toSeconds()) {
|
||||||
|
log.debug("Back-off period, skipping update.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.infof("Handling %s.", cfg.hostname());
|
log.infof("Handling %s.", cfg.hostname());
|
||||||
|
|
||||||
IPs registeredIps = dnsResolver.resolve(cfg.hostname());
|
IPs registeredIps = dnsResolver.resolve(cfg.hostname());
|
||||||
|
@ -51,6 +71,7 @@ public class Updater {
|
||||||
log.tracef("IPs changed, updating...");
|
log.tracef("IPs changed, updating...");
|
||||||
DynDns dynDns = dynDnsRouter.get(cfg.provider());
|
DynDns dynDns = dynDnsRouter.get(cfg.provider());
|
||||||
dynDns.update(cfg.hostname(), publicIps, new DyndnsAuth(null, null, cfg.token()));
|
dynDns.update(cfg.hostname(), publicIps, new DyndnsAuth(null, null, cfg.token()));
|
||||||
|
updateMap.put(cfg.hostname(), LocalDateTime.now());
|
||||||
} else {
|
} else {
|
||||||
log.infof("Hostname is up-to-date.", cfg.hostname());
|
log.infof("Hostname is up-to-date.", cfg.hostname());
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,6 @@ public class Ddnss implements DynDns {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(Ddnss.class);
|
private static final Logger log = Logger.getLogger(Ddnss.class);
|
||||||
|
|
||||||
@ConfigProperty(name = "ddnsclient.dyndns.backoff-duration")
|
|
||||||
Duration backoff;
|
|
||||||
|
|
||||||
private final Map<String, LocalDateTime> updateMap = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() {
|
public String name() {
|
||||||
return "ddnss";
|
return "ddnss";
|
||||||
|
@ -34,12 +29,6 @@ public class Ddnss implements DynDns {
|
||||||
|
|
||||||
public void update(String hostname, IPs currentIps, DyndnsAuth auth) {
|
public void update(String hostname, IPs currentIps, DyndnsAuth auth) {
|
||||||
|
|
||||||
if (updateMap.containsKey(hostname)
|
|
||||||
&& Duration.between(updateMap.get(hostname), LocalDateTime.now()).toSeconds() < backoff.toSeconds()) {
|
|
||||||
log.debug("Back-off period, skipping update.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String updateUrl = MessageFormat.format("https://ddnss.de/upd.php?key={0}&host={1}&ip={2}&ip6={3}",
|
String updateUrl = MessageFormat.format("https://ddnss.de/upd.php?key={0}&host={1}&ip={2}&ip6={3}",
|
||||||
auth.token(), hostname, currentIps.v4(), currentIps.v6());
|
auth.token(), hostname, currentIps.v4(), currentIps.v6());
|
||||||
|
|
||||||
|
@ -55,7 +44,6 @@ public class Ddnss implements DynDns {
|
||||||
if (response.statusCode() != 200) {
|
if (response.statusCode() != 200) {
|
||||||
log.errorf("Couldn't update hostname %s." + hostname);
|
log.errorf("Couldn't update hostname %s." + hostname);
|
||||||
}
|
}
|
||||||
updateMap.put(hostname, LocalDateTime.now());
|
|
||||||
log.info("Hostname updated.");
|
log.info("Hostname updated.");
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
quarkus.naming.enable-jndi=true
|
quarkus.naming.enable-jndi=true
|
||||||
quarkus.log.level=INFO
|
quarkus.log.level=INFO
|
||||||
quarkus.log.category."de.rpr.ddnsclient".min-level=TRACE
|
quarkus.log.category."de.rpr.ddnsclient".min-level=TRACE
|
||||||
quarkus.log.category."de.rpr.ddnsclient".level=INFO
|
quarkus.log.category."de.rpr.ddnsclient".level=INFO
|
||||||
|
|
||||||
ddnsclient.interval=15s
|
|
||||||
#ddnsclient.ip-provider=
|
|
||||||
ddnsclient.dyndns.backoff-duration=60s
|
|
|
@ -15,6 +15,7 @@ import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -34,10 +35,12 @@ class UpdaterTest {
|
||||||
add(new Value("ddnss", "example.org", null, null, "token"));
|
add(new Value("ddnss", "example.org", null, null, "token"));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
Duration backoff = Duration.ofMinutes(5);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_throw_exception_if_config_is_empty() {
|
void should_throw_exception_if_config_is_empty() {
|
||||||
Config config = new Config();
|
Config config = new Config();
|
||||||
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, config);
|
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, config, backoff);
|
||||||
Assertions.assertThrows(IllegalStateException.class, updater::run);
|
Assertions.assertThrows(IllegalStateException.class, updater::run);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +56,7 @@ class UpdaterTest {
|
||||||
add(new Value("ddnss", "host2.example.org", null, null, "token"));
|
add(new Value("ddnss", "host2.example.org", null, null, "token"));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, multipleConfigEntries);
|
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, multipleConfigEntries, backoff);
|
||||||
updater.run();
|
updater.run();
|
||||||
|
|
||||||
ArgumentCaptor<String> hostnameCaptor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> hostnameCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
@ -71,7 +74,7 @@ class UpdaterTest {
|
||||||
when(ipProvider.getPublicIps()).thenReturn(ips);
|
when(ipProvider.getPublicIps()).thenReturn(ips);
|
||||||
when(dnsResolver.resolve("example.org")).thenReturn(ips);
|
when(dnsResolver.resolve("example.org")).thenReturn(ips);
|
||||||
|
|
||||||
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, ddnssConfig);
|
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, ddnssConfig, backoff);
|
||||||
updater.run();
|
updater.run();
|
||||||
|
|
||||||
verify(dynDnsRouter, never()).get(any());
|
verify(dynDnsRouter, never()).get(any());
|
||||||
|
@ -89,7 +92,7 @@ class UpdaterTest {
|
||||||
when(ipProvider.getPublicIps()).thenReturn(publicIps);
|
when(ipProvider.getPublicIps()).thenReturn(publicIps);
|
||||||
when(dnsResolver.resolve("example.org")).thenReturn(new IPs("registered_ipv4", "registered_ipv6"));
|
when(dnsResolver.resolve("example.org")).thenReturn(new IPs("registered_ipv4", "registered_ipv6"));
|
||||||
|
|
||||||
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, ddnssConfig);
|
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, ddnssConfig, backoff);
|
||||||
updater.run();
|
updater.run();
|
||||||
|
|
||||||
verify(ddnss).update(
|
verify(ddnss).update(
|
||||||
|
@ -99,4 +102,27 @@ class UpdaterTest {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_not_try_to_update_hostname_within_configured_backoff_duration() {
|
||||||
|
|
||||||
|
DynDns ddnss = mock(Ddnss.class);
|
||||||
|
|
||||||
|
when(dynDnsRouter.get("ddnss")).thenReturn(ddnss);
|
||||||
|
|
||||||
|
IPs publicIps = new IPs("ipv4", "ipv6");
|
||||||
|
when(ipProvider.getPublicIps()).thenReturn(publicIps);
|
||||||
|
when(dnsResolver.resolve("example.org")).thenReturn(new IPs("registered_ipv4", "registered_ipv6"));
|
||||||
|
|
||||||
|
Updater updater = new Updater(dynDnsRouter, ipProvider, dnsResolver, ddnssConfig, backoff);
|
||||||
|
updater.run();
|
||||||
|
|
||||||
|
updater.run();
|
||||||
|
|
||||||
|
verify(ddnss, times(1)).update(
|
||||||
|
"example.org",
|
||||||
|
publicIps,
|
||||||
|
new DyndnsAuth(null, null, "token")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue