Skip to content

Commit

Permalink
fix for multiple workers looping registration, resilience for
Browse files Browse the repository at this point in the history
remote credentials deleted externally

Signed-off-by: Andrew Azores <aazores@redhat.com>
  • Loading branch information
andrewazores committed Mar 29, 2023
1 parent d484fc0 commit 81ed5ed
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 39 deletions.
3 changes: 2 additions & 1 deletion src/main/java/io/cryostat/agent/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public static void main(String[] args) {
break;
}
});
webServer.start().thenRun(registration::start).get();
webServer.start();
registration.start();
log.info("Startup complete");
} catch (Exception e) {
log.error(Agent.class.getSimpleName() + " startup failure", e);
Expand Down
94 changes: 72 additions & 22 deletions src/main/java/io/cryostat/agent/Registration.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.Instant;
import java.util.HashSet;
Expand All @@ -48,6 +49,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

Expand Down Expand Up @@ -80,6 +82,8 @@ class Registration {
private final PluginInfo pluginInfo = new PluginInfo();
private final Set<Consumer<RegistrationEvent>> listeners = new HashSet<>();

private ScheduledFuture<?> registrationCheckTask;

Registration(
ScheduledExecutorService executor,
CryostatClient cryostat,
Expand Down Expand Up @@ -112,9 +116,75 @@ void start() {
evt -> {
switch (evt.state) {
case REGISTERED:
if (this.registrationCheckTask != null) {
log.warn("Re-registered without previous de-registration");
this.registrationCheckTask.cancel(true);
}
this.registrationCheckTask =
executor.scheduleAtFixedRate(
() -> {
try {
cryostat.checkRegistration(pluginInfo)
.handle(
(v, t) -> {
if (t != null
|| !Boolean.TRUE
.equals(
v)) {
this.pluginInfo.clear();
notify(
RegistrationEvent
.State
.UNREGISTERED);
}
return null;
})
.get();
} catch (ExecutionException
| InterruptedException e) {
log.warn(
"Could not check registration status",
e);
}
},
registrationCheckMs,
registrationCheckMs,
TimeUnit.MILLISECONDS);
break;
case UNREGISTERED:
executor.submit(this::tryRegister);
if (this.registrationCheckTask != null) {
this.registrationCheckTask.cancel(true);
}
executor.submit(
() -> {
try {
webServer
.generateCredentials()
.handle(
(t, v) -> {
if (t != null) {
log.warn(
"Failed to generate"
+ " credentials",
t);
executor.schedule(
() ->
notify(
RegistrationEvent
.State
.UNREGISTERED),
registrationRetryMs,
TimeUnit.MILLISECONDS);
} else {
executor.submit(
this::tryRegister);
}
return null;
});
} catch (NoSuchAlgorithmException nsae) {
log.error("Could not regenerate credentials", nsae);
}
});
break;
case REFRESHED:
break;
Expand All @@ -124,26 +194,7 @@ void start() {
break;
}
});
executor.scheduleAtFixedRate(
() -> {
try {
cryostat.checkRegistration(pluginInfo)
.handle(
(v, t) -> {
if (t != null || !Boolean.TRUE.equals(v)) {
this.pluginInfo.clear();
notify(RegistrationEvent.State.UNREGISTERED);
}
return null;
})
.get();
} catch (ExecutionException | InterruptedException e) {
log.warn("Could not check registration status", e);
}
},
0,
registrationCheckMs,
TimeUnit.MILLISECONDS);
notify(RegistrationEvent.State.UNREGISTERED);
log.info("{} started", getClass().getName());
}

Expand Down Expand Up @@ -175,7 +226,6 @@ void tryRegister() {
tryUpdate();
} else if (t != null) {
this.pluginInfo.clear();
notify(RegistrationEvent.State.UNREGISTERED);
throw new RegistrationException(t);
}

Expand Down
23 changes: 7 additions & 16 deletions src/main/java/io/cryostat/agent/WebServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -109,16 +108,11 @@ class WebServer {
this.compressionFilter = new CompressionFilter();
}

CompletableFuture<Void> start() throws IOException, NoSuchAlgorithmException {
List<CompletableFuture<Void>> cfs = new ArrayList<>();
void start() throws IOException, NoSuchAlgorithmException {
if (this.http != null) {
stop();
}

CompletableFuture<Void> credentialSubmission = new CompletableFuture<>();
cfs.add(credentialSubmission);
this.generateCredentials(credentialSubmission);

this.http = HttpServer.create(new InetSocketAddress(host, port), 0);
this.http.setExecutor(executor);

Expand All @@ -133,8 +127,6 @@ CompletableFuture<Void> start() throws IOException, NoSuchAlgorithmException {
});

this.http.start();

return CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0]));
}

void stop() {
Expand All @@ -148,10 +140,10 @@ int getCredentialId() {
return credentialId;
}

void generateCredentials(CompletableFuture<Void> future) throws NoSuchAlgorithmException {
CompletableFuture<Void> generateCredentials() throws NoSuchAlgorithmException {
synchronized (this.credentials) {
this.credentials.regenerate();
this.cryostat
return this.cryostat
.get()
.submitCredentialsIfRequired(this.credentialId, this.credentials)
.handle(
Expand All @@ -161,15 +153,13 @@ void generateCredentials(CompletableFuture<Void> future) throws NoSuchAlgorithmE
executor.schedule(
() -> {
try {
this.generateCredentials(future);
this.generateCredentials();
} catch (NoSuchAlgorithmException e) {
log.error("Cannot submit credentials", e);
}
},
registrationRetryMs,
TimeUnit.MILLISECONDS);
} else {
future.complete(null);
}
return v;
})
Expand All @@ -195,7 +185,7 @@ public void handle(HttpExchange exchange) throws IOException {
switch (mtd) {
case "POST":
synchronized (WebServer.this.credentials) {
executor.execute(registration.get()::tryRegister);
executor.execute(registration.get()::deregister);
exchange.sendResponseHeaders(HttpStatus.SC_NO_CONTENT, -1);
exchange.close();
}
Expand Down Expand Up @@ -310,7 +300,8 @@ static class Credentials {

synchronized boolean checkUserInfo(String username, String password)
throws NoSuchAlgorithmException {
return Objects.equals(username, Credentials.user)
return passHash.length > 0
&& Objects.equals(username, Credentials.user)
&& Arrays.equals(hash(password), this.passHash);
}

Expand Down

0 comments on commit 81ed5ed

Please sign in to comment.