Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HiveMQ export command for client details #151

Merged
merged 50 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
096e077
Add export command
gitseti Jul 30, 2020
0353324
Remove unused dependency
gitseti Jul 30, 2020
c368104
Change export command to a help command
gitseti Jul 30, 2020
9daf14b
Add help options to export commands
gitseti Jul 30, 2020
ffd4a61
Fix usage message of export command
gitseti Jul 30, 2020
236d6d6
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Jul 31, 2020
213952b
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Jul 31, 2020
8fd5bbe
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Jul 31, 2020
0453c90
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Jul 31, 2020
50fa8cf
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Jul 31, 2020
56385e8
Update src/main/java/com/hivemq/cli/commands/hivemq/export/ExportComm…
gitseti Jul 31, 2020
cca541c
Fix ordering of csv options
gitseti Jul 31, 2020
4413578
Unify header namings
gitseti Jul 31, 2020
90e6440
Fix abbreviated variable name
gitseti Jul 31, 2020
4757604
Change file timestamp to 'yyyyMMdd-HHmmss'
gitseti Jul 31, 2020
e011e9f
Remove retry logic for a received HIVEMQ_IN_REPLICATION response
gitseti Jul 31, 2020
263b658
Use BlockingQueues and Semaphores instead of Thread.sleep()
gitseti Jul 31, 2020
9af0fa5
Increase client id queue limit to 100_000
gitseti Jul 31, 2020
45be83f
Check if URL is parseable
gitseti Jul 31, 2020
d86305e
Add OkHttp connect timeout duration
gitseti Jul 31, 2020
3449bb5
Generate hivemq openapi package with name 'com.hivemq.cli.openapi.hiv…
gitseti Jul 31, 2020
07845e0
Rename csvLineSeparator to csvSeparator
gitseti Jul 31, 2020
86162b8
Close and flush CSV writer on interrupt
gitseti Jul 31, 2020
57e666c
Comment row.add(null) lines with the corresponding header value
gitseti Jul 31, 2020
011451a
Update Swagger version to most recent one
gitseti Jul 31, 2020
3075616
Refactor hivemq command line to be properly injected as subcommand
gitseti Jul 31, 2020
d62a2bf
Remove all unused imports
gitseti Jul 31, 2020
f2cdc8b
Remove 'test_' prefix of all tests
gitseti Jul 31, 2020
9c4a386
Dynamically use HiveMQ version for generation of the openapi spec and…
gitseti Jul 31, 2020
606ecfb
Optimize code
gitseti Jul 31, 2020
4246176
Refactor CompletionService to CompletableFuture
gitseti Aug 3, 2020
2cd0283
Make writteClientDetails variable synchronized
gitseti Aug 3, 2020
ac0a190
Make ExportCommand a Callable
gitseti Aug 3, 2020
c8d5d30
Small refactoring
gitseti Aug 3, 2020
d1507d4
Add integration tests
gitseti Aug 3, 2020
d0bb005
Add tests for command line calls
gitseti Aug 4, 2020
873ced2
Add license
gitseti Aug 4, 2020
7068660
Add optional logging option
gitseti Aug 4, 2020
4c30947
Optimize imports
gitseti Aug 4, 2020
2b61877
Consistent option naming
gitseti Aug 4, 2020
30687a3
Update dependencies
gitseti Aug 4, 2020
dd9a76b
Update src/main/java/com/hivemq/cli/commands/hivemq/export/clients/Cl…
gitseti Aug 6, 2020
e9decee
Update src/main/java/com/hivemq/cli/commands/hivemq/export/AbstractEx…
gitseti Aug 6, 2020
53fab10
Update src/main/java/com/hivemq/cli/commands/hivemq/export/clients/Cl…
gitseti Aug 6, 2020
6b19728
Update src/main/java/com/hivemq/cli/commands/hivemq/export/clients/Ex…
gitseti Aug 6, 2020
5fb278a
Remove snap package
gitseti Aug 6, 2020
4106fb0
Make API version of hivemq a variable
gitseti Aug 6, 2020
9c3e328
Fix Logger calls
gitseti Aug 6, 2020
d33ea9b
Override .jar with shadow jar
gitseti Aug 6, 2020
48fc41b
Update github release task
gitseti Aug 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ apply plugin: 'com.palantir.graal'
javadoc.options.encoding = 'UTF-8'

group = 'com.hivemq'
version = '1.2.0' + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
version = '4.4.0' + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
description = 'MQTT CLI is a tool that provides a feature rich command line interface for connecting, ' +
'publishing, subscribing, unsubscribing and disconnecting ' +
'various MQTT clients simultaneously and supports MQTT 5.0 and MQTT 3.1.1 '
Expand Down Expand Up @@ -66,8 +66,10 @@ repositories {

openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/specs/HiveMQ-4.4.0-SNAPSHOT-OpenAPI-spec.yaml".toString()
inputSpec = "$rootDir/specs/HiveMQ-$project.version-OpenAPI-spec.yaml".toString()
gitseti marked this conversation as resolved.
Show resolved Hide resolved
outputDir = "$buildDir/generated/openapi".toString()
apiPackage = "com.hivemq.cli.openapi.hivemq"
modelPackage = "com.hivemq.cli.openapi.hivemq"
configOptions = [
dateLibrary: "java8"
]
Expand Down Expand Up @@ -154,7 +156,7 @@ ext {
substrateVmVersion = '19.2.0'
junitJupiterVersion = '5.5.1'
openCsvVersion = '5.2'
swaggerVersion = '1.5.24'
swaggerVersion = '1.6.2'
findBugsVersion = '3.0.2'
okHttpVersion = '3.14.7'
gsonFireVersion = '1.8.4'
Expand Down Expand Up @@ -230,7 +232,7 @@ downloadLicenses {

license {
include "**/*.java"
exclude "**/org/openapitools/client/**"
exclude "**/com/hivemq/cli/openapi/**"
header = file('HEADER')
}

Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/main/java/com/hivemq/cli/DefaultCLIProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@


import com.hivemq.cli.converters.EnvVarToByteBufferConverter;
import com.hivemq.cli.converters.PasswordFileToByteBufferConverter;
import com.hivemq.cli.converters.FileToCertificateConverter;
import com.hivemq.cli.converters.FileToPrivateKeyConverter;
import com.hivemq.cli.converters.PasswordFileToByteBufferConverter;
import com.hivemq.client.mqtt.MqttVersion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down
10 changes: 1 addition & 9 deletions src/main/java/com/hivemq/cli/MqttCLIMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -59,14 +58,7 @@ public static void main(final String[] args) {

Runtime.getRuntime().addShutdownHook(new DisconnectAllClientsTask());

int exitCode = 0;

if (args.length > 1 && args[0].equals("hivemq")) {
exitCode = MQTTCLI.hivemqCli().execute(Arrays.copyOfRange(args, 1, args.length));
}
else {
exitCode = commandLine.execute(args);
}
final int exitCode = commandLine.execute(args);

System.exit(exitCode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import com.hivemq.cli.converters.ByteBufferConverter;
import com.hivemq.cli.converters.DirectoryToCertificateCollectionConverter;
import com.hivemq.cli.converters.EnvVarToByteBufferConverter;
import com.hivemq.cli.converters.PasswordFileToByteBufferConverter;
import com.hivemq.cli.converters.FileToCertificateConverter;
import com.hivemq.cli.converters.FileToPrivateKeyConverter;
import com.hivemq.cli.converters.PasswordFileToByteBufferConverter;
import com.hivemq.cli.converters.UnsignedShortConverter;
import com.hivemq.client.mqtt.MqttClientSslConfig;
import com.hivemq.client.mqtt.MqttWebSocketConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@
import com.hivemq.cli.converters.MqttVersionConverter;
import com.hivemq.cli.mqtt.test.Mqtt3FeatureTester;
import com.hivemq.cli.mqtt.test.Mqtt5FeatureTester;
import com.hivemq.cli.mqtt.test.results.*;
import com.hivemq.cli.mqtt.test.results.AsciiCharsInClientIdTestResults;
import com.hivemq.cli.mqtt.test.results.ClientIdLengthTestResults;
import com.hivemq.cli.mqtt.test.results.PayloadTestResults;
import com.hivemq.cli.mqtt.test.results.QosTestResult;
import com.hivemq.cli.mqtt.test.results.SharedSubscriptionTestResult;
import com.hivemq.cli.mqtt.test.results.TopicLengthTestResults;
import com.hivemq.cli.mqtt.test.results.WildcardSubscriptionsTestResult;
import com.hivemq.client.mqtt.MqttClientSslConfig;
import com.hivemq.client.mqtt.MqttVersion;
import com.hivemq.client.mqtt.datatypes.MqttQos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
versionProvider = MqttCLIMain.CLIVersionProvider.class)
public class HiveMQCLICommand implements Callable<Integer> {

@CommandLine.Spec
CommandLine.Model.CommandSpec spec;

@Inject
public HiveMQCLICommand() { }

@Override
public Integer call() {
System.out.println(MqttCLIMain.MQTTCLI.hivemqCli().getUsageMessage());
System.out.println(spec.commandLine().getUsageMessage(spec.commandLine().getColorScheme()));
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public enum OutputFormat {
csv
}

@CommandLine.Option(names = {"-url"}, defaultValue = "http://localhost:8888", description = "The url of the HiveMQ API endpoint (default http://localhost:8888)", order = 1)
@CommandLine.Option(names = {"-url"}, defaultValue = "http://localhost:8888", description = "The URL of the HiveMQ REST API endpoint (default http://localhost:8888)", order = 1)
protected @NotNull String url;

@CommandLine.Option(names = {"-f", "--file"}, description = "The file to write the output to (defaults to a timestamped file in the current working directory)", order = 2)
Expand All @@ -41,16 +41,16 @@ public enum OutputFormat {
@CommandLine.Option(names = {"--format"}, defaultValue = "csv", description = "The export output format (default csv)", order = 4)
protected @NotNull OutputFormat format;

@CommandLine.Option(names = {"--csvLineSeparator"}, defaultValue = "" + CSVWriter.DEFAULT_SEPARATOR, description = "An own defined line separator for the csv writing (default " + CSVWriter.DEFAULT_SEPARATOR + ")", order = 5)
public char csvLineSeparator;
@CommandLine.Option(names = {"--csvSeparator"}, defaultValue = "" + CSVWriter.DEFAULT_SEPARATOR, description = "The separator for csv export (default " + CSVWriter.DEFAULT_SEPARATOR + ")", order = 5)
gitseti marked this conversation as resolved.
Show resolved Hide resolved
public char csvSeparator;

@CommandLine.Option(names = {"--csvQuoteChar"}, defaultValue = "" + CSVWriter.DEFAULT_QUOTE_CHARACTER, description = "An own defined quote character for the csv writing (default " + CSVWriter.DEFAULT_QUOTE_CHARACTER + ")", order = 5)
@CommandLine.Option(names = {"--csvQuoteChar"}, defaultValue = "" + CSVWriter.DEFAULT_QUOTE_CHARACTER, description = "The quote character for CSV export (default " + CSVWriter.DEFAULT_QUOTE_CHARACTER + ")", order = 6)
public char csvQuoteCharacter;

@CommandLine.Option(names = {"--csvEscChar"}, defaultValue = "" + CSVWriter.DEFAULT_ESCAPE_CHARACTER, description = "An own defined escape character for the csv writing (default " + CSVWriter.DEFAULT_ESCAPE_CHARACTER + ")", order = 5)
@CommandLine.Option(names = {"--csvEscChar"}, defaultValue = "" + CSVWriter.DEFAULT_ESCAPE_CHARACTER, description = "The escape character for CSV export (default " + CSVWriter.DEFAULT_ESCAPE_CHARACTER + ")", order = 7)
public char csvEscapeChar;

@CommandLine.Option(names = {"--csvLineEndChar"}, defaultValue = CSVWriter.DEFAULT_LINE_END, description = "An own defined line end character for the csv writing (default \\n)", order = 5)
@CommandLine.Option(names = {"--csvLineEndChar"}, defaultValue = CSVWriter.DEFAULT_LINE_END, description = "The line-end character for CSV export (default \\n)", order = 8)
public @NotNull String csvLineEndCharacter;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

@CommandLine.Command(
name = "export",
description = "Exports the specified details from a HiveMQ API endpoint",
description = "Exports the specified details from HiveMQ",
synopsisHeading = "%n@|bold Usage:|@ ",
descriptionHeading = "%n",
optionListHeading = "%n@|bold Options:|@%n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,34 @@
*/
package com.hivemq.cli.commands.hivemq.export.clients;

import com.hivemq.cli.openapi.hivemq.CertificateInformation;
import com.hivemq.cli.openapi.hivemq.ClientDetails;
import com.hivemq.cli.openapi.hivemq.ClientRestrictions;
import com.hivemq.cli.openapi.hivemq.ConnectionDetails;
import com.hivemq.cli.openapi.hivemq.ProxyInformation;
import com.hivemq.cli.openapi.hivemq.TLV;
import com.hivemq.cli.openapi.hivemq.TlsInformation;
import com.opencsv.CSVWriter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.openapitools.client.model.CertificateInformation;
import org.openapitools.client.model.ClientDetails;
import org.openapitools.client.model.ClientRestrictions;
import org.openapitools.client.model.ConnectionDetails;
import org.openapitools.client.model.ProxyInformation;
import org.openapitools.client.model.TLV;
import org.openapitools.client.model.TlsInformation;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class ClientDetailsCsvWriterTask implements Callable<Void> {

public static final String[] EXPORT_CSV_HEADER = {
"ClientId",
"Connected",
"clientId",
"connected",
"sessionExpiryInterval",
"connectedAt",
"messageQueueSize",
Expand All @@ -65,25 +66,26 @@ public class ClientDetailsCsvWriterTask implements Callable<Void> {
"cleanStart",
"cipherSuite",
"tlsVersion",
"cert-commonName",
"cert-organization",
"cert-organizationalUnit",
"cert-serial",
"cert-validFrom",
"cert-validUntil",
"cert-country",
"cert-state"
"certificateCommonName",
"certificateOrganization",
"certificateOrganizationalUnit",
"certificateSerial",
"certificateValidFrom",
"certificateValidUntil",
"certificateCountry",
"certificateState"
};

final @NotNull Future<Void> clientDetailsFuture;
final @NotNull Queue<ClientDetails> clientDetailsQueue;
final @NotNull BlockingQueue<ClientDetails> clientDetailsQueue;
final @NotNull File file;
final @NotNull CSVWriter csvWriter;
final @NotNull BufferedWriter bufferedFileWriter;

long writtenClientDetails = 0;
gitseti marked this conversation as resolved.
Show resolved Hide resolved

public ClientDetailsCsvWriterTask(final @NotNull Future<Void> clientDetailsFuture,
final @NotNull Queue<ClientDetails> clientDetailsQueue,
final @NotNull BlockingQueue<ClientDetails> clientDetailsQueue,
final @NotNull File file,
final char lineSeparator,
final char quoteCharacter,
Expand All @@ -92,8 +94,10 @@ public ClientDetailsCsvWriterTask(final @NotNull Future<Void> clientDetailsFutur
this.clientDetailsFuture = clientDetailsFuture;
this.clientDetailsQueue = clientDetailsQueue;
this.file = file;
this.bufferedFileWriter = new BufferedWriter(new FileWriter(file, false));

csvWriter = new CSVWriter(
new FileWriter(file, false),
bufferedFileWriter,
lineSeparator,
quoteCharacter,
escapeCharacter,
Expand All @@ -104,20 +108,29 @@ public ClientDetailsCsvWriterTask(final @NotNull Future<Void> clientDetailsFutur
@Override
public Void call() throws IOException, InterruptedException {

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
bufferedFileWriter.close();
} catch (IOException e) {
System.err.println("Interrupted before CSV could be written - CSV may be malformed");
gitseti marked this conversation as resolved.
Show resolved Hide resolved
}
}));

writeHeader();

while (!clientDetailsFuture.isDone() || !clientDetailsQueue.isEmpty()) {

while (!clientDetailsQueue.isEmpty()) {
final ClientDetails clientDetails = clientDetailsQueue.poll();
final ClientDetails clientDetails = clientDetailsQueue.poll(50, TimeUnit.MILLISECONDS);

if (clientDetails != null) {
writeRow(clientDetails);
writtenClientDetails += 1;
}

csvWriter.flush();

Thread.sleep(50);
}

csvWriter.close();

return null;
}

Expand Down Expand Up @@ -163,7 +176,7 @@ private void addConnectionDetails(List<String> row, ConnectionDetails connection
if (password != null) {
row.add(new String(password, StandardCharsets.UTF_8));
} else {
row.add(null);
row.add(null); // password
}

row.add(toCsvString(connectionDetails.getCleanStart()));
Expand All @@ -172,15 +185,15 @@ private void addConnectionDetails(List<String> row, ConnectionDetails connection
addTlsInformation(row, tlsInformation);
}
else {
row.add(null);
row.add(null); // Ip
addProxyInformation(row, null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null); // mqttVersion
row.add(null); // connectedListenerId
row.add(null); // connectedNodeId
row.add(null); // keepAlive
row.add(null); // username
row.add(null); // password
row.add(null); // cleanStart
addTlsInformation(row, null);
}
}
Expand All @@ -195,8 +208,8 @@ private void addTlsInformation(List<String> row, TlsInformation tlsInformation)
addCertificateInformation(row, certificateInformation);
}
else {
row.add(null);
row.add(null);
row.add(null); // cipherSuite
row.add(null); // tlsVersion
addCertificateInformation(row, null);
}
}
Expand All @@ -213,14 +226,14 @@ private void addCertificateInformation(List<String> row, CertificateInformation
row.add(toCsvString(certificateInformation.getState()));
}
else {
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null); // certificateCommonName
row.add(null); // certificateOrganization
row.add(null); // certificateOrganizationalUnit
row.add(null); // certificateSerial
row.add(null); // certificateValidFrom
row.add(null); // certificateValidUntil
row.add(null); // certificateCountry
row.add(null); // certificateState
}
}

Expand All @@ -244,15 +257,15 @@ private void addProxyInformation(List<String> row, ProxyInformation proxyInforma
}
row.add(sb.toString());
} else {
row.add(null);
row.add(null); // tlvs
}
}
else {
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null);
row.add(null); // sourceIp
row.add(null); // sourcePort
row.add(null); // destinationIp
row.add(null); // destinationPort
row.add(null); // tlvs
}
}

Expand All @@ -262,9 +275,9 @@ private void addRestrictions(List<String> row, ClientRestrictions restrictions)
row.add(toCsvString(restrictions.getMaxQueueSize()));
row.add(toCsvString(restrictions.getQueuedMessageStrategy()));
} else {
row.add(null);
row.add(null);
row.add(null);
row.add(null); // maxMessageSize
row.add(null); // maxQueueSize
row.add(null); // queuedMessageStrategy
}
}

Expand Down
Loading