public StartPageResults save() { LOG.info("Installer raw values: " + configuration); // if auto-install is enabled, the db password will be encrypted - decrypt it internally and // we'll re-encrypt later if (isAutoinstallEnabled()) { try { PropertyItemWithValue prop = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PASSWORD); String pass = prop.getValue(); pass = decodePassword(pass); prop.setValue(pass); // log the unencrypted pw, but only at the trace level so it isn't put in the log file // unless someone explicitly enables the trace level so they can see the pass that is to be // used for debugging LOG.trace(">" + pass); } catch (Exception e) { LOG.fatal("Could not decrypt the password for some reason - auto-installation failed", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } } // its possible the JDBC URL was changed, clear the factory cache in case the DB version is // different now DatabaseTypeFactory.clearDatabaseTypeCache(); try { // update server properties with the latest ha info to keep the form and server properties // file up to date getConfigurationPropertyFromAll(ServerProperties.PROP_HIGH_AVAILABILITY_NAME) .setValue(getHaServer().getName()); getConfigurationPropertyFromAll(ServerProperties.PROP_HTTP_PORT) .setValue(getHaServer().getEndpointPortString()); getConfigurationPropertyFromAll(ServerProperties.PROP_HTTPS_PORT) .setValue(getHaServer().getEndpointSecurePortString()); // the comm bind port is a special setting - it is allowed to be blank; // if it was originally blank, it will have been set to 0 because its an integer property; // but we do not want it to be 0, so make sure we switch it back to empty PropertyItemWithValue portConfig = getConfigurationPropertyFromAll(ServerProperties.PROP_CONNECTOR_BIND_PORT); if ("0".equals(portConfig.getValue())) { portConfig.setRawValue(""); } } catch (Exception e) { LOG.fatal("Could not save the settings for some reason", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } try { String url = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_CONNECTION_URL).getValue(); String db = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_TYPE).getValue(); Pattern pattern = null; if (db.toLowerCase().indexOf("postgres") > -1) { pattern = Pattern.compile( ".*://(.*):([0123456789]+)/(.*)"); // jdbc:postgresql://host.name:5432/rhq } else if (db.toLowerCase().indexOf("oracle") > -1) { LOG.info( "Oracle does not need to have server-name, port and db-name individually set, skipping"); // if we ever find that we'll need these props set, uncomment below and it should all work // pattern = Pattern.compile(".*@(.*):([0123456789]+):(.*)"); // // jdbc:oracle:thin:@host.name:1521:rhq } else if (db.toLowerCase().indexOf("h2") > -1) { LOG.info( "H2 does not need to have server-name, port and db-name individually set, skipping"); } else if (db.toLowerCase().indexOf("sqlserver") > -1) { pattern = Pattern.compile( "(?i).*://(.*):([0123456789]+).*databaseName=([^;]*)"); // jdbc:jtds:sqlserver://localhost:7777;databaseName=rhq } else { LOG.info("Unknown database type - will not set server-name, port and db-name"); // don't bother throwing error; these three extra settings may not be necessary anyway } if (pattern != null) { Matcher match = pattern.matcher(url); if (match.find() && (match.groupCount() == 3)) { String serverName = match.group(1); String port = match.group(2); String dbName = match.group(3); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_SERVER_NAME) .setValue(serverName); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PORT).setValue(port); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_DB_NAME).setValue(dbName); } else { throw new Exception("Cannot get server, port or db name from connection URL: " + url); } } else { getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_SERVER_NAME).setValue(""); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PORT).setValue(""); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_DB_NAME).setValue(""); } } catch (Exception e) { LOG.fatal("JDBC connection URL seems to be invalid", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } try { String db = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_TYPE).getValue(); String dialect; String quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"; String quartzSelectWithLockSQL = "SELECT * FROM {0}LOCKS ROWLOCK WHERE LOCK_NAME = ? FOR UPDATE"; String quartzLockHandlerClass = "org.quartz.impl.jdbcjobstore.StdRowLockSemaphore"; if (db.toLowerCase().indexOf("postgres") > -1) { dialect = "org.hibernate.dialect.PostgreSQLDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; } else if (db.toLowerCase().indexOf("oracle") > -1) { dialect = "org.hibernate.dialect.Oracle10gDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.oracle.OracleDelegate"; } else if (db.toLowerCase().indexOf("h2") > -1) { dialect = "org.rhq.core.server.H2CustomDialect"; } else if (db.toLowerCase().indexOf("sqlserver") > -1) { dialect = "org.hibernate.dialect.SQLServerDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.MSSQLDelegate"; quartzSelectWithLockSQL = "SELECT * FROM {0}LOCKS ROWLOCK WITH (HOLDLOCK,XLOCK) WHERE LOCK_NAME = ?"; quartzLockHandlerClass = "org.quartz.impl.jdbcjobstore.UpdateLockRowSemaphore"; } else if (db.toLowerCase().indexOf("mysql") > -1) { dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; } else { throw new Exception("Unknown db type: " + db); } getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_HIBERNATE_DIALECT) .setValue(dialect); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_DRIVER_DELEGATE_CLASS) .setValue(quartzDriverDelegateClass); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_SELECT_WITH_LOCK_SQL) .setValue(quartzSelectWithLockSQL); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_LOCK_HANDLER_CLASS) .setValue(quartzLockHandlerClass); } catch (Exception e) { LOG.fatal("Invalid database type", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } Properties configurationAsProperties = getConfigurationAsProperties(configuration); testConnection(); // so our lastTest gets set and the user will be able to get the error in the // UI if (lastTest == null || !lastTest.equals("OK")) { lastError = lastTest; return StartPageResults.ERROR; } // Ensure server info has been set if ((null == haServer) || (null == haServer.getName()) || "".equals(haServer.getName().trim())) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_STRING, I18Nmsg.getMsg(InstallerI18NResourceKeys.PROP_HIGH_AVAILABILITY_NAME)); return StartPageResults.ERROR; } for (PropertyItemWithValue newValue : configuration) { if (Integer.class.isAssignableFrom(newValue.getItemDefinition().getPropertyType())) { try { Integer.parseInt(newValue.getValue()); } catch (Exception e) { // there is one special property - the connector bind port - that is allowed to be empty // ignore this error if we are looking at that property and its empty; otherwise, this is // an error if (!(newValue .getItemDefinition() .getPropertyName() .equals(ServerProperties.PROP_CONNECTOR_BIND_PORT) && newValue.getValue().length() == 0)) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_NUMBER, newValue.getItemDefinition().getPropertyLabel(), newValue.getValue()); return StartPageResults.ERROR; } } } else if (Boolean.class.isAssignableFrom(newValue.getItemDefinition().getPropertyType())) { try { if (newValue.getValue() == null) { newValue.setValue(Boolean.FALSE.toString()); } Boolean.parseBoolean(newValue.getValue()); } catch (Exception e) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_BOOLEAN, newValue.getItemDefinition().getPropertyLabel(), newValue.getValue()); return StartPageResults.ERROR; } } } try { // indicate that no errors occurred lastError = null; // save the properties serverInfo.setServerProperties(configurationAsProperties); // prepare the db schema if (!ExistingSchemaOption.SKIP.name().equals(existingSchemaOption)) { if (serverInfo.isDatabaseSchemaExist(configurationAsProperties)) { if (existingSchemaOption == null) { if (!isAutoinstallEnabled()) { return StartPageResults .STAY; // user didn't tell us what to do, re-display the page with the question } // we are supposed to auto-install but wasn't explicitly told what to do - the default // is "auto" // and since we know the database schema exists, that means we upgrade it } if (ExistingSchemaOption.OVERWRITE.name().equals(existingSchemaOption)) { serverInfo.createNewDatabaseSchema(configurationAsProperties); } else { serverInfo.upgradeExistingDatabaseSchema(configurationAsProperties); } } else { serverInfo.createNewDatabaseSchema(configurationAsProperties); } } // Ensure the install server info is up to date and stored in the DB serverInfo.storeServer(configurationAsProperties, haServer); // encode database password and set updated properties String pass = configurationAsProperties.getProperty(ServerProperties.PROP_DATABASE_PASSWORD); pass = encryptPassword(pass); configurationAsProperties.setProperty(ServerProperties.PROP_DATABASE_PASSWORD, pass); serverInfo.setServerProperties(configurationAsProperties); // We have changed the password of the database connection, so we need to // tell the login config about it serverInfo.restartLoginConfig(); // build a keystore whose cert has a CN of this server's public endpoint address serverInfo.createKeystore(haServer); // now deploy RHQ Server fully serverInfo.moveDeploymentArtifacts(true); } catch (Exception e) { LOG.fatal( "Failed to updated properties and fully deploy - RHQ Server will not function properly", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_FAILURE, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } LOG.info("Installer: final submitted values: " + configurationAsProperties); return StartPageResults.SUCCESS; }
/** * This method will set the HA Server information based solely on the server configuration * properties. It does not rely on any database access. * * <p>This is used by the auto-installation process - see {@link AutoInstallServlet}. * * @throws Exception */ public void setHaServerFromPropertiesOnly() throws Exception { PropertyItemWithValue preconfigDb = getConfigurationPropertyFromAll(ServerProperties.PROP_AUTOINSTALL_DB); if (preconfigDb != null && preconfigDb.getValue() != null) { if ("overwrite".equals(preconfigDb.getValue().toLowerCase())) { setExistingSchemaOption(ExistingSchemaOption.OVERWRITE.name()); } else if ("skip".equals(preconfigDb.getValue().toLowerCase())) { setExistingSchemaOption(ExistingSchemaOption.SKIP.name()); } else if ("auto".equals(preconfigDb.getValue().toLowerCase())) { setExistingSchemaOption(null); } else { LOG.warn( "An invalid setting for [" + ServerProperties.PROP_AUTOINSTALL_DB + "] was provided: [" + preconfigDb.getValue() + "]. Valid values are 'auto', 'overwrite' or 'skip'. Defaulting to 'auto'"); preconfigDb.setRawValue("auto"); setExistingSchemaOption(null); } } else { LOG.debug( "[" + ServerProperties.PROP_AUTOINSTALL_DB + "] was not provided. Defaulting to 'auto'"); setExistingSchemaOption(null); } // create a ha server stub with some defaults - we'll fill this in based on our property // settings ServerInformation.Server preconfiguredHaServer = new ServerInformation.Server( "", "", ServerInformation.Server.DEFAULT_ENDPOINT_PORT, ServerInformation.Server.DEFAULT_ENDPOINT_SECURE_PORT, ServerInformation.Server.DEFAULT_AFFINITY_GROUP); // determine the name of the server - its either preconfigured as the high availability name, or // we auto-determine it by using the machine's canonical hostname PropertyItemWithValue haNameProp = getPropHaServerName(); if (haNameProp != null) { preconfiguredHaServer.setName( haNameProp.getValue()); // this leaves it alone if value is null or empty } if (preconfiguredHaServer.getName().equals("")) { String serverName = getDefaultServerName(); // gets hostname if (serverName == null || "".equals(serverName)) { throw new Exception( "Server name is not preconfigured and could not be determined automatically"); } preconfiguredHaServer.setName(serverName); } // the public endpoint address is one that can be preconfigured in the special autoinstall // property. // if that is not specified, then we use either the connector's bind address or the server bind // address. // if nothing was specified, we'll default to the canonical host name. String publicEndpointAddress; PropertyItemWithValue preconfigAddr = getConfigurationPropertyFromAll(ServerProperties.PROP_AUTOINSTALL_PUBLIC_ENDPOINT); if (preconfigAddr != null && preconfigAddr.getValue() != null && !"".equals(preconfigAddr.getValue().trim())) { // its preconfigured using the autoinstall setting, use that and ignore the other settings publicEndpointAddress = preconfigAddr.getValue().trim(); } else { PropertyItemWithValue connBindAddress = getConfigurationPropertyFromAll(ServerProperties.PROP_CONNECTOR_BIND_ADDRESS); if (connBindAddress != null && connBindAddress.getValue() != null && !"".equals(connBindAddress.getValue().trim()) && !"0.0.0.0".equals(connBindAddress.getValue().trim())) { // the server-side connector bind address is explicitly set, use that publicEndpointAddress = connBindAddress.getValue().trim(); } else { PropertyItemWithValue serverBindAddress = getConfigurationPropertyFromAll(ServerProperties.PROP_SERVER_BIND_ADDRESS); if (serverBindAddress != null && serverBindAddress.getValue() != null && !"".equals(serverBindAddress.getValue().trim()) && !"0.0.0.0".equals(serverBindAddress.getValue().trim())) { // the main JBossAS server bind address is set and it isn't 0.0.0.0, use that publicEndpointAddress = serverBindAddress.getValue().trim(); } else { publicEndpointAddress = InetAddress.getLocalHost().getCanonicalHostName(); } } } preconfiguredHaServer.setEndpointAddress(publicEndpointAddress); // define the public endpoint ports. // note that if using a different transport other than (ssl)servlet, we'll // take the connector's bind port and use it for both ports. This is to support a special // deployment // use-case - 99% of the time, the agents will go through the web/tomcat connector and thus // we'll use // the http/https ports for the public endpoints. PropertyItemWithValue connectorTransport = getConfigurationPropertyFromAll(ServerProperties.PROP_CONNECTOR_TRANSPORT); if (connectorTransport != null && connectorTransport.getValue() != null && connectorTransport.getValue().contains("socket")) { // we aren't using the (ssl)servlet protocol, take the connector bind port and use it for the // public endpoint ports PropertyItemWithValue connectorBindPort = getConfigurationPropertyFromAll(ServerProperties.PROP_CONNECTOR_BIND_PORT); if (connectorBindPort == null || connectorBindPort.getValue() == null || "".equals(connectorBindPort.getValue().trim()) || "0".equals(connectorBindPort.getValue().trim())) { throw new Exception( "Using non-servlet transport [" + connectorTransport + "] but didn't define a port"); } preconfiguredHaServer.setEndpointPort(Integer.parseInt(connectorBindPort.getValue())); preconfiguredHaServer.setEndpointSecurePort(Integer.parseInt(connectorBindPort.getValue())); } else { // this is the typical use-case - the transport is probably (ssl)servlet so use the web // http/https ports try { PropertyItemWithValue httpPort = getPropHaEndpointPort(); preconfiguredHaServer.setEndpointPortString(httpPort.getValue()); } catch (Exception e) { LOG.warn("Could not determine port, will use default: " + e); } try { PropertyItemWithValue httpsPort = getPropHaEndpointSecurePort(); preconfiguredHaServer.setEndpointSecurePortString(httpsPort.getValue()); } catch (Exception e) { LOG.warn("Could not determine secure port, will use default: " + e); } } // everything looks good - remember these setHaServer(preconfiguredHaServer); this.haServerName = preconfiguredHaServer.getName(); }