Ejemplo n.º 1
0
  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;
  }
Ejemplo n.º 2
0
  /**
   * 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();
  }