import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.Reader;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsState;
-import org.argeo.api.uuid.UuidFactory;
+import org.argeo.api.uuid.NodeIdSupplier;
+import org.argeo.api.uuid.UuidBinaryUtils;
import org.argeo.cms.CmsDeployProperty;
import org.argeo.cms.auth.ident.IdentClient;
-import org.argeo.util.FsUtils;
+import org.argeo.cms.util.DigestUtils;
+import org.argeo.cms.util.FsUtils;
+import org.argeo.cms.util.OS;
/**
* Implementation of a {@link CmsState}, initialising the required services.
*/
-public class CmsStateImpl implements CmsState {
+public class CmsStateImpl implements CmsState, NodeIdSupplier {
private final static CmsLog log = CmsLog.getLog(CmsStateImpl.class);
// REFERENCES
private UUID uuid;
// private final boolean cleanState;
private String hostname;
+ private InetAddress inetAddress;
- private UuidFactory uuidFactory;
+// private UuidFactory uuidFactory;
private final Map<CmsDeployProperty, String> deployPropertyDefaults;
}
public void start() {
-// Runtime.getRuntime().addShutdownHook(new CmsShutdown());
-
+ Charset defaultCharset = Charset.defaultCharset();
+ if (!StandardCharsets.UTF_8.equals(defaultCharset))
+ log.error("Default JVM charset is " + defaultCharset + " and not " + StandardCharsets.UTF_8);
try {
+ // First init check
+ Path privateBase = getDataPath(KernelConstants.DIR_PRIVATE);
+ if (privateBase != null && !Files.exists(privateBase)) {// first init
+ firstInit();
+ Files.createDirectories(privateBase);
+ }
+
initSecurity();
// initArgeoLogger();
if (log.isTraceEnabled())
log.trace("CMS State started");
-// String stateUuidStr = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
-// this.uuid = UUID.fromString(stateUuidStr);
- this.uuid = uuidFactory.timeUUID();
-// this.cleanState = stateUuid.equals(frameworkUuid);
+ String frameworkUuid = KernelUtils.getFrameworkProp(KernelUtils.OSGI_FRAMEWORK_UUID);
+ this.uuid = frameworkUuid != null ? UUID.fromString(frameworkUuid) : UUID.randomUUID();
// hostname
this.hostname = getDeployProperty(CmsDeployProperty.HOST);
final String LOCALHOST_IP = "::1";
ForkJoinTask<String> hostnameFJT = ForkJoinPool.commonPool().submit(() -> {
try {
- String hostname = InetAddress.getLocalHost().getHostName();
+ this.inetAddress = InetAddress.getLocalHost();
+ String hostname = this.inetAddress.getHostName();
return hostname;
} catch (UnknownHostException e) {
throw new IllegalStateException("Cannot get local hostname", e);
this.hostname = LOCALHOST_IP;
log.warn("Could not get local hostname, using " + this.hostname);
}
+ } else {
+ InetAddress[] addresses = InetAddress.getAllByName(this.hostname);
+ InetAddress selectedAddr = null;
+ addresses: for (InetAddress addr : addresses) {
+ if (selectedAddr == null)
+ selectedAddr = addr;
+ if (selectedAddr instanceof Inet6Address)
+ break addresses;
+ }
+ this.inetAddress = selectedAddr;
}
availableSince = System.currentTimeMillis();
}
}
}
- log.debug("## CMS starting... (" + uuid + ")\n" + sb + "\n");
+ log.debug("## CMS starting on " + hostname + " ... (" + uuid + ")\n" + sb + "\n");
}
- Path privateBase = getDataPath(KernelConstants.DIR_PRIVATE);
- if (privateBase != null && !Files.exists(privateBase)) {// first init
- firstInit();
- Files.createDirectories(privateBase);
+ if (log.isTraceEnabled()) {
+ // print system properties
+ StringJoiner sb = new StringJoiner("\n");
+ for (Object key : new TreeMap<>(System.getProperties()).keySet()) {
+ sb.add(key + "=" + System.getProperty(key.toString()));
+ }
+ log.trace("System properties:\n" + sb + "\n");
+
}
} catch (RuntimeException | IOException e) {
log.error("## FATAL: CMS state failed", e);
+ throw new IllegalStateException(e);
}
}
private void initSecurity() {
// private directory permissions
- Path privateDir = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_PRIVATE);
+ Path privateDir = getDataPath(KernelConstants.DIR_PRIVATE);
if (privateDir != null) {
// TODO rather check whether we can read and write
Set<PosixFilePermission> posixPermissions = new HashSet<>();
try {
if (!Files.exists(privateDir))
Files.createDirectories(privateDir);
- Files.setPosixFilePermissions(privateDir, posixPermissions);
+ if (!OS.LOCAL.isMSWindows())
+ Files.setPosixFilePermissions(privateDir, posixPermissions);
} catch (IOException e) {
log.error("Cannot set permissions on " + privateDir, e);
}
// explicitly load JAAS configuration
Configuration.getConfiguration();
- boolean initSsl = getDeployProperty(CmsDeployProperty.HTTPS_PORT) != null;
- if (initSsl) {
+ boolean initCertificates = (getDeployProperty(CmsDeployProperty.HTTPS_PORT) != null)
+ || (getDeployProperty(CmsDeployProperty.SSHD_PORT) != null);
+ if (initCertificates) {
initCertificates();
}
}
log.error("Cannot trust CA certificate", e);
}
}
-
-// if (!Files.exists(keyStorePath))
-// PkiUtils.createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
}
public void stop() {
log.debug("CMS stopping... (" + this.uuid + ")");
long duration = ((System.currentTimeMillis() - availableSince) / 1000) / 60;
- log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##");
+ log.info("## ARGEO CMS " + uuid + " STOPPED after " + (duration / 60) + "h " + (duration % 60)
+ + "min uptime ##");
}
private void firstInit() throws IOException {
return KernelUtils.getOsgiInstancePath(relativePath);
}
+ @Override
+ public Path getStatePath(String relativePath) {
+ return KernelUtils.getOsgiConfigurationPath(relativePath);
+ }
+
@Override
public Long getAvailableSince() {
return availableSince;
}
+ /*
+ * NodeID supplier
+ */
+
+ @Override
+ public Long get() {
+ return NodeIdSupplier.toNodeIdBase(getIpBytes());
+ }
+
+ /** Returns an SHA1 digest of one of the IP addresses. */
+ protected byte[] getIpBytes() {
+// Enumeration<NetworkInterface> netInterfaces = null;
+// try {
+// netInterfaces = NetworkInterface.getNetworkInterfaces();
+// } catch (SocketException e) {
+// throw new IllegalStateException(e);
+// }
+//
+// InetAddress selectedIpv6 = null;
+// InetAddress selectedIpv4 = null;
+// if (netInterfaces != null) {
+// netInterfaces: while (netInterfaces.hasMoreElements()) {
+// NetworkInterface netInterface = netInterfaces.nextElement();
+// byte[] hardwareAddress = null;
+// try {
+// hardwareAddress = netInterface.getHardwareAddress();
+// if (hardwareAddress != null) {
+// // first IPv6
+// addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+// InetAddress ip = addr.getAddress();
+// if (ip instanceof Inet6Address) {
+// Inet6Address ipv6 = (Inet6Address) ip;
+// if (ipv6.isAnyLocalAddress() || ipv6.isLinkLocalAddress() || ipv6.isLoopbackAddress())
+// continue addr;
+// selectedIpv6 = ipv6;
+// break netInterfaces;
+// }
+//
+// }
+// // then IPv4
+// addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+// InetAddress ip = addr.getAddress();
+// if (ip instanceof Inet4Address) {
+// Inet4Address ipv4 = (Inet4Address) ip;
+// if (ipv4.isAnyLocalAddress() || ipv4.isLinkLocalAddress() || ipv4.isLoopbackAddress())
+// continue addr;
+// selectedIpv4 = ipv4;
+// // we keep searching for IPv6
+// }
+//
+// }
+// }
+// } catch (SocketException e) {
+// throw new IllegalStateException(e);
+// }
+// }
+// }
+// InetAddress selectedIp = selectedIpv6 != null ? selectedIpv6 : selectedIpv4;
+ if (this.inetAddress.isLoopbackAddress()) {
+ log.warn("No IP address found, using a random node id for UUID generation");
+ return NodeIdSupplier.randomNodeId();
+ }
+ InetAddress selectedIp = this.inetAddress;
+ byte[] digest = DigestUtils.sha1(selectedIp.getAddress());
+ log.debug("Use IP " + selectedIp + " hashed as " + UuidBinaryUtils.toHexString(digest) + " as node id");
+ byte[] nodeId = NodeIdSupplier.toNodeIdBytes(digest, 0);
+ // marks that this is not based on MAC address
+ NodeIdSupplier.forceToNoMacAddress(nodeId, 0);
+ return nodeId;
+ }
+
/*
* ACCESSORS
*/
return uuid;
}
- public void setUuidFactory(UuidFactory uuidFactory) {
- this.uuidFactory = uuidFactory;
- }
+// public void setUuidFactory(UuidFactory uuidFactory) {
+// this.uuidFactory = uuidFactory;
+// }
public String getHostname() {
return hostname;
// TODO make passphrase more configurable
return new IdentClient(remoteAddr);
}
+
}