Skip to content

Commit

Permalink
Implement Node Id as base64
Browse files Browse the repository at this point in the history
  • Loading branch information
no2chem committed Dec 11, 2017
1 parent bcca6e2 commit 4594794
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import com.google.common.collect.ImmutableList;

import com.google.common.io.BaseEncoding;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
Expand All @@ -22,8 +23,10 @@
import io.netty.util.concurrent.EventExecutorGroup;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand All @@ -32,6 +35,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.net.ssl.SSLEngine;

import javax.net.ssl.SSLException;
Expand All @@ -44,6 +48,7 @@
import org.corfudb.security.tls.SslContextConstructor;
import org.corfudb.security.tls.TlsUtils;
import org.corfudb.util.GitRepositoryState;
import org.corfudb.util.UuidUtils;
import org.corfudb.util.Version;
import org.docopt.Docopt;
import org.fusesource.jansi.AnsiConsole;
Expand Down Expand Up @@ -275,6 +280,9 @@ public static void main(String[] args) {
// Create a common Server Context for all servers to access.
serverContext = new ServerContext(opts, router);

// Generate a node ID if necessary.
generateNodeId(serverContext);

// Add each role to the router.
addSequencer();
addLayoutServer();
Expand Down Expand Up @@ -480,4 +488,21 @@ public static void addManagementServer() {
managementServer = new ManagementServer(serverContext);
router.addServer(managementServer);
}

/** Generate a Node Id if not present.
*
* @param context The server context to use.
*/
private static void generateNodeId(@Nonnull ServerContext context) {
String currentId = context.getDataStore().get(String.class, "",
ServerContext.NODE_ID);
if (currentId == null) {
String idString = UuidUtils.asBase64(UUID.randomUUID());
log.info("No Node Id, setting to new Id={}", idString);
context.getDataStore().put(String.class, "", ServerContext.NODE_ID, idString);

} else {
log.info("Node Id = {}", currentId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public class ServerContext {
private static final String PREFIX_STARTING_ADDRESS = "STARTING_ADDRESS";
private static final String KEY_STARTING_ADDRESS = "CURRENT";

/** The node Id, stored as a base64 string. */
public static final String NODE_ID = "NODE_ID";

/**
* various duration constants.
*/
Expand Down
40 changes: 40 additions & 0 deletions runtime/src/main/java/org/corfudb/util/UuidUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.corfudb.util;

import com.google.common.io.BaseEncoding;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.UUID;
import javax.annotation.Nonnull;

/** A collection of utilities to manage and maniupulate UUIDs. */
public class UuidUtils {

/** Generate a base64 URL-safe string from a given UUID.
*
* @param uuid The UUID to convert.
* @return A base64 URL-safe string for the UUID.
*/
public static String asBase64(@Nonnull UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return BaseEncoding.base64Url().omitPadding().encode(bb.array());
}

/** Generate a UUID from a base64 URL-safe string.
*
* @param uuidString The base64 URL-safe string to convert.
*
* @throws IllegalArgumentException If decoding fails due to a malformed string.
* @return A UUID from the string.
*/
public static UUID fromBase64(@Nonnull String uuidString) {
ByteBuffer bb = ByteBuffer.wrap(BaseEncoding.base64Url().decode(uuidString));
if (bb.remaining() < 16) {
throw new IllegalArgumentException("Input too short: must be 16 bytes");
} else if (bb.remaining() > 16) {
throw new IllegalArgumentException("Input too long: must be 16 bytes");
}
return new UUID(bb.getLong(), bb.getLong());
}
}
45 changes: 45 additions & 0 deletions test/src/test/java/org/corfudb/util/UuidUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.corfudb.util;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.util.UUID;
import org.junit.Test;

public class UuidUtilsTest {

/** Test that a UUID can be converted back and forth between base64 and UUID. */
@Test
public void base64StringEqualsUuid() {
final UUID testId = UUID.nameUUIDFromBytes("test".getBytes());
final String base64 = UuidUtils.asBase64(testId);

assertThat(UuidUtils.fromBase64(base64))
.isEqualTo(testId);
}

/** Test that a invalid string throws {@link java.lang.IllegalArgumentException}. */
@Test
public void nonBase64StringThrowsException() {
assertThatThrownBy(() -> UuidUtils.fromBase64("!!!!!!!!!!!"))
.isInstanceOf(IllegalArgumentException.class);
}

/** Test that a short base64 string, which is insufficient (< 16 bytes) to reconstruct
* an UUID throws an exception.
*/
@Test
public void shortBase64StringThrowsException() {
assertThatThrownBy(() -> UuidUtils.fromBase64("AAAA"))
.isInstanceOf(IllegalArgumentException.class);
}

/** Test that a long base64 string, which is too long (> 16 bytes) to reconstruct
* an UUID throws an exception.
*/
@Test
public void longBase64StringThrowsException() {
assertThatThrownBy(() -> UuidUtils.fromBase64("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
.isInstanceOf(IllegalArgumentException.class);
}
}

0 comments on commit 4594794

Please sign in to comment.