/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.instancemanagement.internal; import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; import de.rcenvironment.core.configuration.ConfigurationException; import de.rcenvironment.core.configuration.ConfigurationSegment; import de.rcenvironment.core.configuration.ConfigurationStoreFactory; import de.rcenvironment.core.configuration.WritableConfigurationSegment; import de.rcenvironment.core.configuration.internal.ConfigurationStore; import de.rcenvironment.core.instancemanagement.InstanceManagementCommandPlugin; import de.rcenvironment.core.instancemanagement.InstanceManagementConstants; import de.rcenvironment.core.instancemanagement.internal.ConfigurationSegmentFactory.NetworkConnectionSegment; import de.rcenvironment.core.instancemanagement.internal.ConfigurationSegmentFactory.SegmentBuilder; import de.rcenvironment.core.utils.common.StringUtils; /** * Provides operations to configure the configuration.json via the {@link InstanceManagementCommandPlugin}. * * @author David Scholz */ public class InstanceConfigurationImpl { private static final String ERROR_PATTERN = "Failed to %s"; private final SegmentBuilder builder = ConfigurationSegmentFactory.getSegmentBuilder(); private ConfigurationStore configStore; private ConfigurationSegment snapshot; public InstanceConfigurationImpl(final File config) throws IOException { configStore = ConfigurationStoreFactory.getConfigurationStore(config); snapshot = configStore.getSnapshotOfRootSegment(); } /** * Sets a comment in the "general" section of the instance's configuration. * * @param comment the comment to set. * @throws IOException on failure. */ public void setInstanceComment(String comment) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setString(builder.general().comment().getConfigurationKey(), comment); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "set a comment."), e); } } /** * * Sets the desired instance name. * * @param name the new name. * @throws IOException on failure. */ public void setInstanceName(String name) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setString(builder.general().instanceName().getConfigurationKey(), name); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "set an instance name."), e); } } /** * * Sets the relay flag for a server instance. * * @param isRelay <code>true</code> if the instance should be a relay, else <code>false</code>. * @throws IOException on failure. */ public void setRelayFlag(boolean isRelay) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().isRelay().getConfigurationKey(), isRelay); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "set the relay flag."), e); } } /** * * Sets the workflow host flag for a server instance. * * @param isWorkflowHost <code>true</code> if the instance should be the workflow host, else <code>false</code>. * @throws IOException on failure. */ public void setWorkflowHostFlag(boolean isWorkflowHost) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().isWorkflowHost().getConfigurationKey(), isWorkflowHost); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "set the workflow host flag."), e); } } /** * * Sets the temp directory. * * @param path the path. * @throws IOException on failure. */ public void setTempDirectory(String path) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setString(builder.general().tempDirectory().getConfigurationKey(), path); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "set the temp directory"), e); } } /** * * Enables the deprecated input tab. * * @throws IOException on failure. */ public void enableDeprecatedInputTab() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().enableDeprecatedInputTab().getConfigurationKey(), true); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to enable deprecated input tab."), e); } } /** * * Disables the deprecated input tab. * * @throws IOException on failure. */ public void disableDeprecatedInputTab() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().enableDeprecatedInputTab().getConfigurationKey(), false); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to disable deprecated input tab."), e); } } /** * * Enables the ip filter for a server instance. * * @throws IOException on failure. */ public void enableIpFilter() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ipFilter().getPath()); writableSegment.setBoolean(builder.network().ipFilter().enabled().getConfigurationKey(), true); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to enable the ip filter for a server instance."), e); } } /** * * Disables the ip filter for a server instance. * * @throws IOException on failure. */ public void disableIpFilter() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ipFilter().getPath()); writableSegment.setBoolean(builder.network().ipFilter().enabled().getConfigurationKey(), false); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to disable the ip filter for a server instance."), e); } } /** * * Adds an IP-Adress to the filter. * * @param ip the ip to add to the enabled filter. * @throws IOException on failure. */ public void addAllowedIp(String ip) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ipFilter().getPath()); List<String> ipList = new LinkedList<>(); for (String presentIP : writableSegment.getStringArray(builder.network().ipFilter().allowedIps().getConfigurationKey())) { if (ip.equals(presentIP)) { continue; } ipList.add(presentIP); } ipList.add(ip); String[] array = new String[ipList.size()]; array = ipList.toArray(array); writableSegment.setStringArray(builder.network().ipFilter().allowedIps().getConfigurationKey(), array); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to add an allowed ip adress to the ip filter."), e); } } /** * * Removes an IP-Adress from the filter. * * @param ip the ip to remove from the filter. * @throws IOException on failure. */ public void removeAllowedIp(String ip) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ipFilter().getPath()); List<String> ipList = writableSegment.getStringArray(builder.network().ipFilter().allowedIps().getConfigurationKey()); for (String s : ipList) { if (s.equals(ip)) { ipList.remove(ip); String[] ipArray = new String[ipList.size()]; ipArray = ipList.toArray(ipArray); writableSegment.setStringArray(builder.network().ipFilter().allowedIps().getConfigurationKey(), ipArray); return; } } throw new IOException("Couldn't remove ip: " + ip + " as it isn't present in the current configuration."); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to remove an allowed ip adress to the ip filter."), e); } } /** * * Set background system monitoring. * * @param interval the update time. * @param id indicates whether to log simple or more detailed monitoring data. * @throws IOException on failure. */ public void setBackgroundMonitoring(String id, int interval) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.backgroundMonitoring().getPath()); writableSegment.setString(builder.backgroundMonitoring().enableIds().getConfigurationKey(), id); writableSegment.setInteger(builder.backgroundMonitoring().intervalSeconds().getConfigurationKey(), interval); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to set background monitoring service."), e); } } /** * * Adds a new connection. * * @param connection the connection to add. * @throws IOException on failure. */ public void addConnection(ConfigurationConnection connection) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().connections().getPath()); ConfigurationSegment subsegment = writableSegment.getSubSegment(connection.getConnectionName()); WritableConfigurationSegment newConnectionSegment; if (!subsegment.isPresentInCurrentConfiguration()) { newConnectionSegment = writableSegment.createElement(connection.getConnectionName()); } else { newConnectionSegment = writableSegment.getOrCreateWritableSubSegment(connection.getConnectionName()); } setConnectionFields(connection, newConnectionSegment); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to add new connection."), e); } } private void setConnectionFields(ConfigurationConnection connection, WritableConfigurationSegment segment) throws ConfigurationException { final NetworkConnectionSegment connectionSegment = builder.network().connections().getOrCreateConnection(connection.getConnectionName()); segment.setString(connectionSegment.host().getConfigurationKey(), connection.getHost()); segment.setInteger(connectionSegment.port().getConfigurationKey(), connection.getPort()); segment.setBoolean(connectionSegment.connectOnStartup().getConfigurationKey(), connection.getConnectOnStartup()); segment.setLong(connectionSegment.autoRetryInitialDelay().getConfigurationKey(), connection.getAutoRetryInitialDelay()); segment.setLong(connectionSegment.autoRetryMaximumDelay().getConfigurationKey(), connection.getAutoRetryMaximumDelay()); segment.setInteger(connectionSegment.autoRetryDelayMultiplier().getConfigurationKey(), connection.getAutoRetryDelayMultiplier()); } /** * * Removes a connection. * * @param connection the connection to remove. * @throws IOException on failure. */ public void removeConnection(String connection) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().connections().getPath()); ConfigurationSegment subsegment = writableSegment.getSubSegment(connection); if (!subsegment.isPresentInCurrentConfiguration()) { return; } boolean success = writableSegment.deleteElement(connection); if (!success) { throw new IOException("Failed to delete connection with name: " + connection); } } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to remove connection: " + connection), e); } } /** * * Sets the request timeout. * * @param timeout the timeout. * @throws IOException on failure. */ public void setRequestTimeout(long timeout) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().getPath()); writableSegment.setLong(builder.network().requestTimeoutMsec().getConfigurationKey(), timeout); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to set request timeout.")); } } /** * * Sets the forwarding timeout. * * @param timeout the timeout. * @throws IOException on failure. */ public void setForwardingTimeout(long timeout) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().getPath()); writableSegment.setLong(builder.network().forwardingTimeoutMsec().getConfigurationKey(), timeout); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to set forwarding timeout.")); } } /** * * Adds a new server port. * * @param portName the name of the new port. * @param ip the ip adress. * @param port the port. * @throws IOException on failure. */ public void addServerPort(String portName, String ip, int port) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ports().getPath()); WritableConfigurationSegment newPort = writableSegment.createElement(portName); newPort.setString(builder.network().ports().getOrCreateServerPort(portName).ip().getConfigurationKey(), ip); newPort.setInteger(builder.network().ports().getOrCreateServerPort(portName).port().getConfigurationKey(), port); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to add server ports")); } } /** * * Adds a ssh connection. * * @param sshConnection the connection object. * @throws IOException on failure. */ public void addSshConnection(ConfigurationSshConnection sshConnection) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshRemoteAccess().sshConnections().getPath()); ConfigurationSegment subSegment = writableSegment.getSubSegment(sshConnection.getName()); WritableConfigurationSegment newSegment; if (!subSegment.isPresentInCurrentConfiguration()) { newSegment = writableSegment.createElement(sshConnection.getName()); } else { newSegment = writableSegment.getOrCreateWritableSubSegment(sshConnection.getName()); } newSegment.setString(builder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(sshConnection.getLoginName()) .displayName() .getConfigurationKey(), sshConnection.getDisplayName()); newSegment.setString(builder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(sshConnection.getLoginName()).host() .getConfigurationKey(), sshConnection.getHost()); newSegment.setInteger(builder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(sshConnection.getLoginName()).port() .getConfigurationKey(), sshConnection.getPort()); newSegment.setString(builder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(sshConnection.getLoginName()) .loginName() .getConfigurationKey(), sshConnection.getLoginName()); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to add new ssh connection."), e); } } /** * * Removes a ssh connection. * * @param configName the name of the ssh connection in the configuration to remove. * @throws IOException on failure. */ public void removeSshConnection(String configName) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshRemoteAccess().sshConnections().getPath()); ConfigurationSegment toRemove = writableSegment.getSubSegment(configName); if (!toRemove.isPresentInCurrentConfiguration()) { return; } boolean success = writableSegment.deleteElement(configName); if (!success) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to remove ssh connection: " + configName)); } } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to remove ssh connection: " + configName)); } } /** * * Disables ssh server. * * @throws IOException on failure. */ public void disableSshServer() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getPath()); writableSegment.setBoolean(builder.sshServer().enabled().getConfigurationKey(), false); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to disable ssh server.")); } } /** * * Enables ssh server. * * @throws IOException on failure. */ public void enableSshServer() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getPath()); writableSegment.setBoolean(builder.sshServer().enabled().getConfigurationKey(), true); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to enable ssh server.")); } } /** * * Disables workflowhost. * * @throws IOException on failure. */ public void disableWorkflowHost() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().isWorkflowHost().getConfigurationKey(), false); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to disable workflowhost.")); } } /** * * Enables workflowhost. * * @throws IOException on failure. */ public void enableWorkflowHost() throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.general().getPath()); writableSegment.setBoolean(builder.general().isWorkflowHost().getConfigurationKey(), true); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to enable workflowhost.")); } } /** * * Sets the ssh server ip adress. * * @param ip the desired ip to set. * @throws IOException on failure. */ public void setSshServerIP(String ip) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getPath()); writableSegment.setString(builder.sshServer().ip().getConfigurationKey(), ip); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to set ssh server ip adress.")); } } /** * * Sets the ssh server port. * * @param port the desired port to set. * @throws IOException on failure. */ public void setSshServerPort(int port) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getPath()); writableSegment.setInteger(builder.sshServer().port().getConfigurationKey(), port); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to set ssh server port.")); } } /** * Enabled SSH access for the IM master. * * @param port the desired port to set. * @param passphrase the passphrase for the account. * @throws IOException on failure. */ public void enableImSshAccess(int port, String passphrase) throws IOException { enableSshServer(); if (getSshServerIp() == null) { setSshServerIP(InstanceManagementConstants.LOCALHOST); } if (getSshServerPort() == null) { setSshServerPort(port); } try { // Create account WritableConfigurationSegment writableAccountsSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getSshAccounts().getPath()); ConfigurationSegment accountSegment = writableAccountsSegment.getSubSegment(InstanceManagementConstants.IM_MASTER_USER_NAME); WritableConfigurationSegment newSegment; if (!accountSegment.isPresentInCurrentConfiguration()) { newSegment = writableAccountsSegment.createElement(InstanceManagementConstants.IM_MASTER_USER_NAME); } else { newSegment = writableAccountsSegment.getOrCreateWritableSubSegment(InstanceManagementConstants.IM_MASTER_USER_NAME); } newSegment.setString(builder.sshServer().getSshAccounts() .getOrCreateSshAccount(InstanceManagementConstants.IM_MASTER_USER_NAME).role().getConfigurationKey(), InstanceManagementConstants.IM_MASTER_ROLE); newSegment.setBoolean(builder.sshServer().getSshAccounts() .getOrCreateSshAccount(InstanceManagementConstants.IM_MASTER_USER_NAME).enabled().getConfigurationKey(), true); newSegment.setString(builder.sshServer().getSshAccounts() .getOrCreateSshAccount(InstanceManagementConstants.IM_MASTER_USER_NAME).passwordHash().getConfigurationKey(), passphrase); // Create role WritableConfigurationSegment writableRolesSegment = snapshot.getOrCreateWritableSubSegment(builder.sshServer().getSshAccountRoles().getPath()); ConfigurationSegment roleSegment = writableRolesSegment.getSubSegment(InstanceManagementConstants.IM_MASTER_ROLE); if (!roleSegment.isPresentInCurrentConfiguration()) { newSegment = writableRolesSegment.createElement(InstanceManagementConstants.IM_MASTER_ROLE); } else { newSegment = writableRolesSegment.getOrCreateWritableSubSegment(InstanceManagementConstants.IM_MASTER_ROLE); } String[] allowedCommandsArray = new String[1]; allowedCommandsArray[0] = InstanceManagementConstants.IM_MASTER_ROLE_ALLOWED_COMMANDS; newSegment.setStringArray( builder.sshServer().getSshAccountRoles().getOrCreateSshRole(InstanceManagementConstants.IM_MASTER_ROLE) .getAllowedCommandPatterns().getConfigurationKey(), allowedCommandsArray); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to add IM master account.")); } } /** * * Removes server port. * * @param name port to remove. * @throws IOException on failure. */ public void removeServerPort(String name) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.network().ports().getPath()); boolean success = writableSegment.deleteElement(builder.network().ports().getOrCreateServerPort(name).getPath()); if (!success) { throw new IOException("Failed to remove server port :" + name); } } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to remove server port: " + name)); } } /** * * Publishes new component. * * @param name the component name. * @throws IOException on failure. */ public void publishComponent(String name) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.publishing().getPath()); List<String> componentList = new LinkedList<>(); for (String component : writableSegment.getStringArray(builder.publishing().components().getConfigurationKey())) { if (component.equals(name)) { continue; } componentList.add(component); } componentList.add(name); String[] array = new String[componentList.size()]; array = componentList.toArray(array); writableSegment.setStringArray(builder.publishing().components().getConfigurationKey(), array); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to publish new component."), e); } } /** * * Removes component from the publishing list. * * @param name the component name to remove. * @throws IOException on failure. */ public void unPublishComponent(String name) throws IOException { try { WritableConfigurationSegment writableSegment = snapshot.getOrCreateWritableSubSegment(builder.publishing().getPath()); List<String> ipList = writableSegment.getStringArray(builder.publishing().components().getConfigurationKey()); for (String s : ipList) { if (s.equals(name)) { ipList.remove(name); String[] componentArray = new String[ipList.size()]; componentArray = ipList.toArray(componentArray); writableSegment.setStringArray(builder.publishing().components().getConfigurationKey(), componentArray); return; } } throw new IOException("Couldn't unpublish component: " + name + " as it isn't present in the current configuration."); } catch (ConfigurationException e) { throw new IOException(StringUtils.format(ERROR_PATTERN, "to unpublish component " + name + "."), e); } } /** * Retreives the configured server port from the configuration file. * * @return the server port, or null, if none is configured. * @throws IOException on failure. */ public Integer getSshServerPort() throws IOException { ConfigurationSegment segment = snapshot.getSubSegment(builder.sshServer().getPath()); return segment.getInteger(builder.sshServer().port().getConfigurationKey()); } /** * Retreives the configured server IP from the configuration file. * * @return the server ip, or null, if none is configured. * @throws IOException on failure. */ public String getSshServerIp() throws IOException { ConfigurationSegment segment = snapshot.getSubSegment(builder.sshServer().getPath()); return segment.getString(builder.sshServer().ip().getConfigurationKey()); } /** * * Updates snapshot. * * @throws IOException on failure. */ public void update() throws IOException { try { configStore.update(snapshot); } catch (ConfigurationException e) { throw new IOException("Failed to update configuration."); } } }