mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
Provision current metadata schemas
This commit is contained in:
+147
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Owns the Flyway-compatible history layout and current-baseline marker. */
|
||||
final class FlywaySchemaHistory {
|
||||
|
||||
private static final String TABLE = "flyway_schema_history";
|
||||
private final MetadataDatabaseKind kind;
|
||||
|
||||
FlywaySchemaHistory(MetadataDatabaseKind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
boolean isCurrent(Connection connection, TargetSchemaBaseline baseline) throws SQLException {
|
||||
Set<String> currentTables = currentBaselineTables(connection);
|
||||
if (!currentTables.contains(TABLE)) {
|
||||
return false;
|
||||
}
|
||||
String sql = "SELECT installed_rank, version, type, script, checksum, success FROM " + TABLE;
|
||||
try (Statement statement = connection.createStatement(); ResultSet result = statement.executeQuery(sql)) {
|
||||
if (!result.next()) {
|
||||
throw unexpectedTargetState();
|
||||
}
|
||||
boolean current = result.getInt("installed_rank") == 1
|
||||
&& TargetSchemaBaseline.VERSION.equals(result.getString("version"))
|
||||
&& TargetSchemaBaseline.TYPE.equals(result.getString("type"))
|
||||
&& TargetSchemaBaseline.SCRIPT.equals(result.getString("script"))
|
||||
&& baseline.checksum() == result.getInt("checksum")
|
||||
&& !result.wasNull()
|
||||
&& result.getBoolean("success");
|
||||
if (!current || result.next() || !currentTables.contains(TargetSchemaContract.TABLE)
|
||||
|| !currentTables.containsAll(baseline.expectedTables())
|
||||
|| !new TargetSchemaContract(kind).matches(connection, baseline.expectedTables())) {
|
||||
throw unexpectedTargetState();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void requireEmptyTarget(Connection connection) throws SQLException {
|
||||
if (!currentCatalogSchemaObjects(connection).isEmpty()) {
|
||||
throw unexpectedTargetState();
|
||||
}
|
||||
}
|
||||
|
||||
void record(
|
||||
Connection connection,
|
||||
TargetSchemaBaseline baseline,
|
||||
String installedBy,
|
||||
int executionTimeMillis) throws SQLException {
|
||||
new TargetSchemaContract(kind).record(connection, baseline.expectedTables());
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
for (String sql : createStatements()) {
|
||||
statement.execute(sql);
|
||||
}
|
||||
}
|
||||
String insert = "INSERT INTO " + TABLE
|
||||
+ " (installed_rank, version, description, type, script, checksum, installed_by, execution_time, success)"
|
||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
try (PreparedStatement statement = connection.prepareStatement(insert)) {
|
||||
statement.setInt(1, 1);
|
||||
statement.setString(2, TargetSchemaBaseline.VERSION);
|
||||
statement.setString(3, TargetSchemaBaseline.DESCRIPTION);
|
||||
statement.setString(4, TargetSchemaBaseline.TYPE);
|
||||
statement.setString(5, TargetSchemaBaseline.SCRIPT);
|
||||
statement.setInt(6, baseline.checksum());
|
||||
statement.setString(7, abbreviate(installedBy, 100));
|
||||
statement.setInt(8, executionTimeMillis);
|
||||
statement.setBoolean(9, true);
|
||||
statement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private String[] createStatements() {
|
||||
String table = switch (kind) {
|
||||
case MYSQL -> "CREATE TABLE " + TABLE + " ("
|
||||
+ "installed_rank INT NOT NULL, version VARCHAR(50), description VARCHAR(200) NOT NULL, "
|
||||
+ "type VARCHAR(20) NOT NULL, script VARCHAR(1000) NOT NULL, checksum INT, "
|
||||
+ "installed_by VARCHAR(100) NOT NULL, installed_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
|
||||
+ "execution_time INT NOT NULL, success BOOL NOT NULL, "
|
||||
+ "CONSTRAINT flyway_schema_history_pk PRIMARY KEY (installed_rank)) ENGINE=InnoDB";
|
||||
case POSTGRESQL -> "CREATE TABLE " + TABLE + " ("
|
||||
+ "installed_rank INT NOT NULL, version VARCHAR(50), description VARCHAR(200) NOT NULL, "
|
||||
+ "type VARCHAR(20) NOT NULL, script VARCHAR(1000) NOT NULL, checksum INTEGER, "
|
||||
+ "installed_by VARCHAR(100) NOT NULL, installed_on TIMESTAMP NOT NULL DEFAULT now(), "
|
||||
+ "execution_time INTEGER NOT NULL, success BOOLEAN NOT NULL, "
|
||||
+ "CONSTRAINT flyway_schema_history_pk PRIMARY KEY (installed_rank))";
|
||||
case H2 -> throw new IllegalArgumentException("H2 has no external target schema history");
|
||||
};
|
||||
return new String[]{table, "CREATE INDEX flyway_schema_history_s_idx ON " + TABLE + " (success)"};
|
||||
}
|
||||
|
||||
private Set<String> currentBaselineTables(Connection connection) throws SQLException {
|
||||
return currentCatalogSchemaObjects(connection, new String[]{"TABLE"});
|
||||
}
|
||||
|
||||
private Set<String> currentCatalogSchemaObjects(Connection connection) throws SQLException {
|
||||
return currentCatalogSchemaObjects(connection, null);
|
||||
}
|
||||
|
||||
private Set<String> currentCatalogSchemaObjects(Connection connection, String[] types) throws SQLException {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
String schema = kind == MetadataDatabaseKind.POSTGRESQL ? connection.getSchema() : null;
|
||||
Set<String> names = new HashSet<>();
|
||||
try (ResultSet objects = metadata.getTables(connection.getCatalog(), schema, "%", types)) {
|
||||
while (objects.next()) {
|
||||
names.add(objects.getString("TABLE_NAME").toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
return Set.copyOf(names);
|
||||
}
|
||||
|
||||
private static String abbreviate(String value, int maximumLength) {
|
||||
return value.length() <= maximumLength ? value : value.substring(0, maximumLength);
|
||||
}
|
||||
|
||||
private static SQLException unexpectedTargetState() {
|
||||
return new SQLException("Target schema is not empty or does not contain the current baseline", "55000");
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseConfiguration;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Applies the static baseline and writes a history row compatible with subsequent standard Flyway runs. */
|
||||
public final class FlywayTargetSchemaProvisioner implements TargetSchemaProvisioner {
|
||||
|
||||
// Admission rejects multi-node migration. The lock prevents concurrent work in this JVM, while a failed MySQL DDL
|
||||
// sequence can leave partial state that deliberately fails the next precondition instead of pretending to resume.
|
||||
private static final ReentrantLock PROVISIONING_LOCK = new ReentrantLock();
|
||||
|
||||
@Override
|
||||
public void provision(MetadataDatabaseConfiguration target) {
|
||||
Objects.requireNonNull(target, "target");
|
||||
MetadataDatabaseKind kind = supportedKind(target.kind());
|
||||
PROVISIONING_LOCK.lock();
|
||||
try {
|
||||
provisionLocked(target, kind);
|
||||
} finally {
|
||||
PROVISIONING_LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void provisionLocked(MetadataDatabaseConfiguration target, MetadataDatabaseKind kind) {
|
||||
Connection connection;
|
||||
try {
|
||||
connection = DriverManager.getConnection(target.jdbcUrl(), target.username(), target.password());
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.CONNECTION, exception);
|
||||
}
|
||||
boolean completed = false;
|
||||
try {
|
||||
configureTransaction(connection, kind);
|
||||
provision(connection, target, kind);
|
||||
commitTransaction(connection, kind);
|
||||
completed = true;
|
||||
} catch (TargetSchemaProvisioningException exception) {
|
||||
rollbackTransaction(connection, kind);
|
||||
throw exception;
|
||||
} finally {
|
||||
if (!completed) {
|
||||
closeQuietly(connection);
|
||||
}
|
||||
}
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.CLEANUP, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static void configureTransaction(Connection connection, MetadataDatabaseKind kind) {
|
||||
if (kind == MetadataDatabaseKind.POSTGRESQL) {
|
||||
try {
|
||||
connection.setAutoCommit(false);
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.TRANSACTION, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void commitTransaction(Connection connection, MetadataDatabaseKind kind) {
|
||||
if (kind == MetadataDatabaseKind.POSTGRESQL) {
|
||||
try {
|
||||
connection.commit();
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.TRANSACTION, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void rollbackTransaction(Connection connection, MetadataDatabaseKind kind) {
|
||||
if (kind == MetadataDatabaseKind.POSTGRESQL) {
|
||||
try {
|
||||
connection.rollback();
|
||||
} catch (SQLException ignored) {
|
||||
// Preserve the sanitized failure from the operation phase.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeQuietly(Connection connection) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException ignored) {
|
||||
// Never attach raw driver diagnostics to the sanitized operation failure.
|
||||
}
|
||||
}
|
||||
|
||||
private static void provision(
|
||||
Connection connection, MetadataDatabaseConfiguration target, MetadataDatabaseKind kind) {
|
||||
TargetSchemaBaseline baseline;
|
||||
try {
|
||||
baseline = TargetSchemaBaseline.load(kind);
|
||||
} catch (IOException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.BASELINE_RESOURCE, exception);
|
||||
}
|
||||
FlywaySchemaHistory history = new FlywaySchemaHistory(kind);
|
||||
try {
|
||||
if (history.isCurrent(connection, baseline)) {
|
||||
return;
|
||||
}
|
||||
history.requireEmptyTarget(connection);
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.PRECONDITION, exception);
|
||||
}
|
||||
int executionTimeMillis;
|
||||
try {
|
||||
executionTimeMillis = execute(connection, baseline);
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.BASELINE_EXECUTION, exception);
|
||||
}
|
||||
try {
|
||||
history.record(connection, baseline, target.username(), executionTimeMillis);
|
||||
} catch (SQLException exception) {
|
||||
throw failure(kind, TargetSchemaProvisioningFailure.Phase.HISTORY_WRITE, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static int execute(Connection connection, TargetSchemaBaseline baseline) throws SQLException {
|
||||
long startedAt = System.nanoTime();
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
for (String sql : baseline.statements()) {
|
||||
statement.execute(sql);
|
||||
}
|
||||
}
|
||||
return Math.toIntExact(Math.min(Integer.MAX_VALUE, (System.nanoTime() - startedAt) / 1_000_000L));
|
||||
}
|
||||
|
||||
private static TargetSchemaProvisioningException failure(
|
||||
MetadataDatabaseKind kind, TargetSchemaProvisioningFailure.Phase phase, Throwable exception) {
|
||||
return new TargetSchemaProvisioningException(kind, TargetSchemaProvisioningFailure.from(phase, exception));
|
||||
}
|
||||
|
||||
private static MetadataDatabaseKind supportedKind(MetadataDatabaseKind kind) {
|
||||
return switch (Objects.requireNonNull(kind, "target kind")) {
|
||||
case MYSQL -> MetadataDatabaseKind.MYSQL;
|
||||
case POSTGRESQL -> MetadataDatabaseKind.POSTGRESQL;
|
||||
case H2 -> throw new IllegalArgumentException("External target schema provisioning does not support H2");
|
||||
};
|
||||
}
|
||||
}
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Captures only JDBC metadata that is stable across compatible drivers and vendor versions. */
|
||||
final class JdbcTargetSchemaState {
|
||||
|
||||
private JdbcTargetSchemaState() {
|
||||
}
|
||||
|
||||
static SchemaState capture(
|
||||
Connection connection,
|
||||
MetadataDatabaseKind kind,
|
||||
Set<String> baselineTables) throws SQLException {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
String catalog = connection.getCatalog();
|
||||
String schema = kind == MetadataDatabaseKind.POSTGRESQL ? connection.getSchema() : null;
|
||||
FactCollector facts = new FactCollector();
|
||||
for (String table : baselineTables.stream().sorted().toList()) {
|
||||
facts.add("table", table);
|
||||
readColumns(metadata, catalog, schema, table, kind, facts);
|
||||
readPrimaryKey(metadata, catalog, schema, table, facts);
|
||||
readIndexes(metadata, catalog, schema, table, facts);
|
||||
readForeignKeys(metadata, catalog, schema, table, facts);
|
||||
}
|
||||
return facts.build();
|
||||
}
|
||||
|
||||
private static void readColumns(
|
||||
DatabaseMetaData metadata,
|
||||
String catalog,
|
||||
String schema,
|
||||
String table,
|
||||
MetadataDatabaseKind kind,
|
||||
FactCollector facts) throws SQLException {
|
||||
try (ResultSet columns = metadata.getColumns(catalog, schema, table, null)) {
|
||||
while (columns.next()) {
|
||||
int jdbcType = columns.getInt("DATA_TYPE");
|
||||
int size = columns.getInt("COLUMN_SIZE");
|
||||
int scale = columns.getInt("DECIMAL_DIGITS");
|
||||
facts.add(
|
||||
"column",
|
||||
table,
|
||||
normalize(columns.getString("COLUMN_NAME")),
|
||||
stableTypeFamily(kind, jdbcType, size, scale),
|
||||
nullable(columns.getInt("NULLABLE")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readPrimaryKey(
|
||||
DatabaseMetaData metadata,
|
||||
String catalog,
|
||||
String schema,
|
||||
String table,
|
||||
FactCollector facts) throws SQLException {
|
||||
OrderedColumns columns = new OrderedColumns();
|
||||
try (ResultSet keys = metadata.getPrimaryKeys(catalog, schema, table)) {
|
||||
while (keys.next()) {
|
||||
columns.add(keys.getShort("KEY_SEQ"), normalize(keys.getString("COLUMN_NAME")));
|
||||
}
|
||||
}
|
||||
if (!columns.isEmpty()) {
|
||||
facts.add("primary-key", table, columns.definition());
|
||||
}
|
||||
}
|
||||
|
||||
private static void readIndexes(
|
||||
DatabaseMetaData metadata,
|
||||
String catalog,
|
||||
String schema,
|
||||
String table,
|
||||
FactCollector facts) throws SQLException {
|
||||
Map<String, IndexColumns> indexes = new HashMap<>();
|
||||
int unnamedIndex = 0;
|
||||
try (ResultSet rows = metadata.getIndexInfo(catalog, schema, table, false, false)) {
|
||||
while (rows.next()) {
|
||||
String name = rows.getString("INDEX_NAME");
|
||||
String column = rows.getString("COLUMN_NAME");
|
||||
short position = rows.getShort("ORDINAL_POSITION");
|
||||
if (column == null || rows.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) {
|
||||
continue;
|
||||
}
|
||||
// Names group composite rows from one JDBC result only; the semantic fact never retains the name.
|
||||
if (name == null && position == 1) {
|
||||
unnamedIndex++;
|
||||
}
|
||||
String group = name == null ? "<unnamed-index-" + unnamedIndex + '>' : normalize(name);
|
||||
boolean unique = !rows.getBoolean("NON_UNIQUE");
|
||||
indexes.computeIfAbsent(group, ignored -> new IndexColumns(unique))
|
||||
.add(position, normalize(column));
|
||||
}
|
||||
}
|
||||
indexes.values().forEach(index -> facts.add(
|
||||
"index", table, Boolean.toString(index.unique()), index.columns().definition()));
|
||||
}
|
||||
|
||||
private static void readForeignKeys(
|
||||
DatabaseMetaData metadata,
|
||||
String catalog,
|
||||
String schema,
|
||||
String table,
|
||||
FactCollector facts) throws SQLException {
|
||||
Map<String, ForeignKeyColumns> keys = new HashMap<>();
|
||||
int unnamedKey = 0;
|
||||
try (ResultSet rows = metadata.getImportedKeys(catalog, schema, table)) {
|
||||
while (rows.next()) {
|
||||
String referencedTable = normalize(rows.getString("PKTABLE_NAME"));
|
||||
String name = rows.getString("FK_NAME");
|
||||
short position = rows.getShort("KEY_SEQ");
|
||||
String updateRule = foreignKeyRule(rows.getShort("UPDATE_RULE"));
|
||||
String deleteRule = foreignKeyRule(rows.getShort("DELETE_RULE"));
|
||||
String deferrability = foreignKeyDeferrability(rows.getShort("DEFERRABILITY"));
|
||||
// As with indexes, the provider name only groups rows and is absent from the persisted definition.
|
||||
if (name == null && position == 1) {
|
||||
unnamedKey++;
|
||||
}
|
||||
String group = name == null ? "<unnamed-key-" + unnamedKey + '>' : normalize(name);
|
||||
keys.computeIfAbsent(group, ignored ->
|
||||
new ForeignKeyColumns(referencedTable, updateRule, deleteRule, deferrability))
|
||||
.add(
|
||||
position,
|
||||
normalize(rows.getString("FKCOLUMN_NAME")),
|
||||
normalize(rows.getString("PKCOLUMN_NAME")));
|
||||
}
|
||||
}
|
||||
keys.values().forEach(key -> facts.add(
|
||||
"foreign-key", table, key.localColumns(), key.referencedTable(), key.referencedColumns(),
|
||||
key.updateRule(), key.deleteRule(), key.deferrability()));
|
||||
}
|
||||
|
||||
private static String stableTypeFamily(
|
||||
MetadataDatabaseKind kind,
|
||||
int jdbcType,
|
||||
int size,
|
||||
int scale) {
|
||||
return switch (jdbcType) {
|
||||
case Types.BOOLEAN -> "boolean";
|
||||
case Types.BIT -> kind == MetadataDatabaseKind.MYSQL ? "boolean" : "binary-bit(" + size + ')';
|
||||
case Types.TINYINT -> kind == MetadataDatabaseKind.MYSQL && size == 1 ? "boolean" : "tinyint";
|
||||
case Types.SMALLINT -> "smallint";
|
||||
case Types.INTEGER -> "integer";
|
||||
case Types.BIGINT -> "bigint";
|
||||
case Types.NUMERIC, Types.DECIMAL -> "decimal(" + size + ',' + scale + ')';
|
||||
case Types.REAL -> "real";
|
||||
case Types.FLOAT -> "float";
|
||||
case Types.DOUBLE -> "double";
|
||||
case Types.CHAR, Types.NCHAR, Types.VARCHAR, Types.NVARCHAR -> "character(" + size + ')';
|
||||
case Types.LONGVARCHAR, Types.LONGNVARCHAR, Types.CLOB, Types.NCLOB -> "large-text";
|
||||
case Types.BINARY, Types.VARBINARY -> "binary(" + size + ')';
|
||||
case Types.LONGVARBINARY, Types.BLOB -> "large-binary";
|
||||
case Types.DATE -> "date";
|
||||
case Types.TIME, Types.TIME_WITH_TIMEZONE -> "time";
|
||||
case Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE -> "timestamp";
|
||||
default -> "jdbc-type(" + jdbcType + ')';
|
||||
};
|
||||
}
|
||||
|
||||
private static String nullable(int value) throws SQLException {
|
||||
return switch (value) {
|
||||
case DatabaseMetaData.columnNoNulls -> "required";
|
||||
case DatabaseMetaData.columnNullable -> "nullable";
|
||||
default -> throw new SQLException("Target schema column nullability is unknown", "55000");
|
||||
};
|
||||
}
|
||||
|
||||
private static String foreignKeyRule(short value) throws SQLException {
|
||||
return switch (value) {
|
||||
case DatabaseMetaData.importedKeyCascade -> "cascade";
|
||||
case DatabaseMetaData.importedKeyRestrict -> "restrict";
|
||||
case DatabaseMetaData.importedKeySetNull -> "set-null";
|
||||
case DatabaseMetaData.importedKeyNoAction -> "no-action";
|
||||
case DatabaseMetaData.importedKeySetDefault -> "set-default";
|
||||
default -> throw new SQLException("Target schema foreign-key rule is unknown", "55000");
|
||||
};
|
||||
}
|
||||
|
||||
private static String foreignKeyDeferrability(short value) throws SQLException {
|
||||
return switch (value) {
|
||||
case DatabaseMetaData.importedKeyInitiallyDeferred -> "initially-deferred";
|
||||
case DatabaseMetaData.importedKeyInitiallyImmediate -> "initially-immediate";
|
||||
case DatabaseMetaData.importedKeyNotDeferrable -> "not-deferrable";
|
||||
default -> throw new SQLException("Target schema foreign-key deferrability is unknown", "55000");
|
||||
};
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
return value == null ? "<unnamed>" : value.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
record SchemaState(Map<String, Integer> facts) {
|
||||
|
||||
SchemaState {
|
||||
facts = Map.copyOf(facts);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FactCollector {
|
||||
|
||||
private final Map<String, Integer> facts = new TreeMap<>();
|
||||
|
||||
void add(String... parts) {
|
||||
facts.merge(String.join("|", parts), 1, Integer::sum);
|
||||
}
|
||||
|
||||
SchemaState build() {
|
||||
return new SchemaState(facts);
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrderedColumns {
|
||||
|
||||
private final Map<Short, String> columns = new TreeMap<>();
|
||||
|
||||
void add(short position, String column) {
|
||||
columns.put(position, column);
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return columns.isEmpty();
|
||||
}
|
||||
|
||||
String definition() {
|
||||
return String.join(",", columns.values());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IndexColumns {
|
||||
|
||||
private final boolean unique;
|
||||
private final OrderedColumns columns = new OrderedColumns();
|
||||
|
||||
private IndexColumns(boolean unique) {
|
||||
this.unique = unique;
|
||||
}
|
||||
|
||||
void add(short position, String column) {
|
||||
columns.add(position, column);
|
||||
}
|
||||
|
||||
boolean unique() {
|
||||
return unique;
|
||||
}
|
||||
|
||||
OrderedColumns columns() {
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ForeignKeyColumns {
|
||||
|
||||
private final String referencedTable;
|
||||
private final String updateRule;
|
||||
private final String deleteRule;
|
||||
private final String deferrability;
|
||||
private final OrderedColumns localColumns = new OrderedColumns();
|
||||
private final OrderedColumns referencedColumns = new OrderedColumns();
|
||||
|
||||
private ForeignKeyColumns(
|
||||
String referencedTable, String updateRule, String deleteRule, String deferrability) {
|
||||
this.referencedTable = referencedTable;
|
||||
this.updateRule = updateRule;
|
||||
this.deleteRule = deleteRule;
|
||||
this.deferrability = deferrability;
|
||||
}
|
||||
|
||||
void add(short position, String localColumn, String referencedColumn) {
|
||||
localColumns.add(position, localColumn);
|
||||
referencedColumns.add(position, referencedColumn);
|
||||
}
|
||||
|
||||
String localColumns() {
|
||||
return localColumns.definition();
|
||||
}
|
||||
|
||||
String referencedTable() {
|
||||
return referencedTable;
|
||||
}
|
||||
|
||||
String referencedColumns() {
|
||||
return referencedColumns.definition();
|
||||
}
|
||||
|
||||
String updateRule() {
|
||||
return "update=" + updateRule;
|
||||
}
|
||||
|
||||
String deleteRule() {
|
||||
return "delete=" + deleteRule;
|
||||
}
|
||||
|
||||
String deferrability() {
|
||||
return "deferrability=" + deferrability;
|
||||
}
|
||||
}
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.CRC32;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Loaded current-version baseline plus the metadata expected by Flyway schema history. */
|
||||
final class TargetSchemaBaseline {
|
||||
|
||||
private static final Pattern CREATE_TABLE = Pattern.compile(
|
||||
"(?i)^create\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?([a-z][a-z0-9_]*)\\s*\\(");
|
||||
static final String VERSION = "206";
|
||||
static final String DESCRIPTION = "current schema";
|
||||
static final String SCRIPT = "B206__current_schema.sql";
|
||||
static final String TYPE = "SQL_BASELINE";
|
||||
|
||||
private final List<String> statements;
|
||||
private final Set<String> expectedTables;
|
||||
private final int checksum;
|
||||
|
||||
private TargetSchemaBaseline(List<String> statements, Set<String> expectedTables, int checksum) {
|
||||
this.statements = statements;
|
||||
this.expectedTables = expectedTables;
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
static TargetSchemaBaseline load(MetadataDatabaseKind kind) throws IOException {
|
||||
String vendor = switch (kind) {
|
||||
case MYSQL -> "mysql";
|
||||
case POSTGRESQL -> "postgresql";
|
||||
case H2 -> throw new IllegalArgumentException("H2 has no external target baseline");
|
||||
};
|
||||
String location = "/db/migration/" + vendor + "/" + SCRIPT;
|
||||
try (InputStream input = TargetSchemaBaseline.class.getResourceAsStream(location)) {
|
||||
if (input == null) {
|
||||
throw new IOException("Target schema baseline resource is missing");
|
||||
}
|
||||
String sql = new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||
List<String> statements = splitStatements(sql);
|
||||
return new TargetSchemaBaseline(statements, expectedTables(statements), checksum(sql));
|
||||
}
|
||||
}
|
||||
|
||||
List<String> statements() {
|
||||
return statements;
|
||||
}
|
||||
|
||||
int checksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
Set<String> expectedTables() {
|
||||
return expectedTables;
|
||||
}
|
||||
|
||||
private static int checksum(String sql) throws IOException {
|
||||
CRC32 checksum = new CRC32();
|
||||
try (BufferedReader reader = new BufferedReader(new StringReader(sql))) {
|
||||
String line = reader.readLine();
|
||||
if (line != null) {
|
||||
line = removeByteOrderMark(line);
|
||||
do {
|
||||
checksum.update(line.getBytes(StandardCharsets.UTF_8));
|
||||
} while ((line = reader.readLine()) != null);
|
||||
}
|
||||
}
|
||||
return (int) checksum.getValue();
|
||||
}
|
||||
|
||||
private static String removeByteOrderMark(String line) {
|
||||
return line.startsWith("\ufeff") ? line.substring(1) : line;
|
||||
}
|
||||
|
||||
private static List<String> splitStatements(String script) throws IOException {
|
||||
List<String> statements = new ArrayList<>();
|
||||
StringBuilder current = new StringBuilder();
|
||||
char quote = 0;
|
||||
boolean lineComment = false;
|
||||
for (int index = 0; index < script.length(); index++) {
|
||||
char character = script.charAt(index);
|
||||
char next = index + 1 < script.length() ? script.charAt(index + 1) : 0;
|
||||
if (lineComment) {
|
||||
if (character == '\n' || character == '\r') {
|
||||
lineComment = false;
|
||||
current.append(character);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (quote == 0 && character == '-' && next == '-') {
|
||||
lineComment = true;
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
if (quote == 0 && (character == '\'' || character == '"' || character == '`')) {
|
||||
quote = character;
|
||||
current.append(character);
|
||||
continue;
|
||||
}
|
||||
if (quote != 0 && character == quote) {
|
||||
current.append(character);
|
||||
if (next == quote) {
|
||||
current.append(next);
|
||||
index++;
|
||||
} else {
|
||||
quote = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (quote == 0 && character == ';') {
|
||||
addStatement(statements, current);
|
||||
continue;
|
||||
}
|
||||
current.append(character);
|
||||
}
|
||||
if (quote != 0) {
|
||||
throw new IOException("Target schema baseline contains an unterminated quoted value");
|
||||
}
|
||||
addStatement(statements, current);
|
||||
return List.copyOf(statements);
|
||||
}
|
||||
|
||||
private static void addStatement(List<String> statements, StringBuilder current) {
|
||||
String statement = current.toString().trim();
|
||||
if (!statement.isEmpty()) {
|
||||
statements.add(statement);
|
||||
}
|
||||
current.setLength(0);
|
||||
}
|
||||
|
||||
private static Set<String> expectedTables(List<String> statements) throws IOException {
|
||||
Set<String> tables = new LinkedHashSet<>();
|
||||
for (String statement : statements) {
|
||||
Matcher matcher = CREATE_TABLE.matcher(statement);
|
||||
if (matcher.find()) {
|
||||
tables.add(matcher.group(1).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
if (tables.isEmpty()) {
|
||||
throw new IOException("Target schema baseline does not declare any tables");
|
||||
}
|
||||
return Set.copyOf(tables);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Persists and compares the human-readable semantic contract for a provisioned baseline. */
|
||||
final class TargetSchemaContract {
|
||||
|
||||
static final String TABLE = "flyway_schema_contract";
|
||||
private static final String CREATE_TABLE = "CREATE TABLE " + TABLE + " ("
|
||||
+ "contract_id INT NOT NULL, database_kind VARCHAR(20) NOT NULL, definition TEXT NOT NULL, "
|
||||
+ "occurrences INT NOT NULL, CONSTRAINT flyway_schema_contract_pk PRIMARY KEY (contract_id))";
|
||||
|
||||
private final MetadataDatabaseKind kind;
|
||||
|
||||
TargetSchemaContract(MetadataDatabaseKind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
void record(Connection connection, Set<String> baselineTables) throws SQLException {
|
||||
JdbcTargetSchemaState.SchemaState state = JdbcTargetSchemaState.capture(connection, kind, baselineTables);
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute(CREATE_TABLE);
|
||||
}
|
||||
String insert = "INSERT INTO " + TABLE
|
||||
+ " (contract_id, database_kind, definition, occurrences) VALUES (?, ?, ?, ?)";
|
||||
try (PreparedStatement statement = connection.prepareStatement(insert)) {
|
||||
int contractId = 1;
|
||||
for (Map.Entry<String, Integer> fact : state.facts().entrySet()) {
|
||||
statement.setInt(1, contractId++);
|
||||
statement.setString(2, kind.name());
|
||||
statement.setString(3, fact.getKey());
|
||||
statement.setInt(4, fact.getValue());
|
||||
statement.addBatch();
|
||||
}
|
||||
statement.executeBatch();
|
||||
}
|
||||
}
|
||||
|
||||
boolean matches(Connection connection, Set<String> baselineTables) throws SQLException {
|
||||
return JdbcTargetSchemaState.capture(connection, kind, baselineTables).equals(readRecordedState(connection));
|
||||
}
|
||||
|
||||
private JdbcTargetSchemaState.SchemaState readRecordedState(Connection connection) throws SQLException {
|
||||
Map<String, Integer> facts = new TreeMap<>();
|
||||
String select = "SELECT database_kind, definition, occurrences FROM " + TABLE;
|
||||
try (PreparedStatement statement = connection.prepareStatement(select)) {
|
||||
try (ResultSet rows = statement.executeQuery()) {
|
||||
while (rows.next()) {
|
||||
if (!kind.name().equals(rows.getString("database_kind"))) {
|
||||
throw new SQLException("Target schema contract contains another database kind", "55000");
|
||||
}
|
||||
String definition = rows.getString("definition");
|
||||
if (facts.put(definition, rows.getInt("occurrences")) != null) {
|
||||
throw new SQLException("Target schema contract contains duplicate definitions", "55000");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new JdbcTargetSchemaState.SchemaState(facts);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseConfiguration;
|
||||
|
||||
/** Provisions an empty external metadata target at the current schema version. */
|
||||
public interface TargetSchemaProvisioner {
|
||||
|
||||
void provision(MetadataDatabaseConfiguration target);
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Safe failure boundary that does not retain target credentials, URLs, or baseline SQL. */
|
||||
public final class TargetSchemaProvisioningException extends RuntimeException {
|
||||
|
||||
private final TargetSchemaProvisioningFailure failure;
|
||||
|
||||
TargetSchemaProvisioningException(
|
||||
MetadataDatabaseKind kind, TargetSchemaProvisioningFailure failure) {
|
||||
super("Target schema provisioning failed for " + kind);
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
public TargetSchemaProvisioningFailure failure() {
|
||||
return failure;
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Stable failure fields suitable for a durable setup-operation diagnostic. */
|
||||
public record TargetSchemaProvisioningFailure(
|
||||
Phase phase,
|
||||
String migrationVersion,
|
||||
String sqlState,
|
||||
int vendorCode) {
|
||||
|
||||
private static final Pattern SQL_STATE = Pattern.compile("[0-9A-Z]{5}");
|
||||
|
||||
public TargetSchemaProvisioningFailure {
|
||||
Objects.requireNonNull(phase, "phase");
|
||||
Objects.requireNonNull(migrationVersion, "migrationVersion");
|
||||
}
|
||||
|
||||
static TargetSchemaProvisioningFailure from(Phase phase, Throwable exception) {
|
||||
SQLException sqlException = findSqlException(exception);
|
||||
return new TargetSchemaProvisioningFailure(
|
||||
phase,
|
||||
TargetSchemaBaseline.VERSION,
|
||||
sqlException == null ? null : sanitizedSqlState(sqlException.getSQLState()),
|
||||
sqlException == null ? 0 : sqlException.getErrorCode());
|
||||
}
|
||||
|
||||
private static String sanitizedSqlState(String sqlState) {
|
||||
if (sqlState == null) {
|
||||
return null;
|
||||
}
|
||||
String normalized = sqlState.toUpperCase(Locale.ROOT);
|
||||
return SQL_STATE.matcher(normalized).matches() ? normalized : null;
|
||||
}
|
||||
|
||||
private static SQLException findSqlException(Throwable exception) {
|
||||
Throwable current = exception;
|
||||
for (int depth = 0; current != null && depth < 16; depth++) {
|
||||
if (current instanceof SQLException sqlException) {
|
||||
return sqlException;
|
||||
}
|
||||
current = current.getCause();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Lifecycle boundary that failed without retaining an exception or SQL text. */
|
||||
public enum Phase {
|
||||
CONNECTION,
|
||||
BASELINE_RESOURCE,
|
||||
PRECONDITION,
|
||||
BASELINE_EXECUTION,
|
||||
HISTORY_WRITE,
|
||||
TRANSACTION,
|
||||
CLEANUP
|
||||
}
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.DriverPropertyInfo;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseConfiguration;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.flywaydb.core.api.logging.Log;
|
||||
import org.flywaydb.core.api.logging.LogCreator;
|
||||
import org.flywaydb.core.api.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.parallel.ResourceLock;
|
||||
|
||||
class FlywayTargetSchemaProvisionerTest {
|
||||
|
||||
private static final String FLYWAY_LOG_FACTORY = "flyway-log-factory";
|
||||
|
||||
@Test
|
||||
void rejectsEmbeddedTargetsBeforeConnectionOpen() {
|
||||
MetadataDatabaseConfiguration target = new MetadataDatabaseConfiguration(
|
||||
MetadataDatabaseKind.H2, "jdbc:h2:mem:not-opened", "sa", "not-retained");
|
||||
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("External target schema provisioning does not support H2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failureDoesNotRetainJdbcUrlPasswordOrFlywayDetails() {
|
||||
String jdbcUrl = "jdbc:mysql://invalid.example.test:3306/hertzbeat";
|
||||
String password = "not-retained";
|
||||
MetadataDatabaseConfiguration target =
|
||||
new MetadataDatabaseConfiguration(MetadataDatabaseKind.MYSQL, jdbcUrl, "operator", password);
|
||||
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOf(TargetSchemaProvisioningException.class)
|
||||
.hasMessage("Target schema provisioning failed for MYSQL")
|
||||
.hasNoCause()
|
||||
.message()
|
||||
.doesNotContain(jdbcUrl, password, "SELECT", "CREATE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failureExposesOnlyStableStructuredDiagnostics() throws Exception {
|
||||
String jdbcUrl = "jdbc:diagnostic://private.example.test/hertzbeat?password=secret-value";
|
||||
Driver driver = new DiagnosticFailureDriver(jdbcUrl);
|
||||
DriverManager.registerDriver(driver);
|
||||
try {
|
||||
MetadataDatabaseConfiguration target = new MetadataDatabaseConfiguration(
|
||||
MetadataDatabaseKind.MYSQL, jdbcUrl, "operator", "secret-value");
|
||||
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception -> {
|
||||
assertThat(exception.failure()).isEqualTo(new TargetSchemaProvisioningFailure(
|
||||
TargetSchemaProvisioningFailure.Phase.CONNECTION,
|
||||
"206",
|
||||
"08006",
|
||||
1045));
|
||||
assertThat(exception).hasNoCause();
|
||||
assertThat(exception.getMessage())
|
||||
.doesNotContain(jdbcUrl, "secret-value", "SELECT", "CREATE");
|
||||
});
|
||||
} finally {
|
||||
DriverManager.deregisterDriver(driver);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void closeFailureIsNotAttachedToSanitizedOperationFailure() throws Exception {
|
||||
String jdbcUrl = "jdbc:close-failure://private.example.test/hertzbeat";
|
||||
Driver driver = new CloseFailureDriver(jdbcUrl);
|
||||
DriverManager.registerDriver(driver);
|
||||
try {
|
||||
MetadataDatabaseConfiguration target = new MetadataDatabaseConfiguration(
|
||||
MetadataDatabaseKind.MYSQL, jdbcUrl, "operator", "secret-value");
|
||||
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception -> {
|
||||
assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.BASELINE_RESOURCE);
|
||||
assertThat(exception.getSuppressed()).isEmpty();
|
||||
assertThat(exception.getMessage()).doesNotContain(jdbcUrl, "secret-value", "SELECT");
|
||||
});
|
||||
} finally {
|
||||
DriverManager.deregisterDriver(driver);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ResourceLock(FLYWAY_LOG_FACTORY)
|
||||
void provisioningDoesNotReplaceLoggerUsedByAnInterleavedFlywayOperation() throws Exception {
|
||||
RecordingLogCreator recording = new RecordingLogCreator();
|
||||
LogFactory.setLogCreator(recording);
|
||||
CountDownLatch provisioningFinished = new CountDownLatch(1);
|
||||
try (ExecutorService executor = Executors.newFixedThreadPool(2)) {
|
||||
Future<?> provisioning = executor.submit(() -> {
|
||||
try {
|
||||
MetadataDatabaseConfiguration target = new MetadataDatabaseConfiguration(
|
||||
MetadataDatabaseKind.MYSQL,
|
||||
"jdbc:mysql://127.0.0.1:1/hertzbeat?connectTimeout=100",
|
||||
"operator",
|
||||
"test-only-password");
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOf(TargetSchemaProvisioningException.class);
|
||||
} finally {
|
||||
provisioningFinished.countDown();
|
||||
}
|
||||
});
|
||||
Future<?> interleavedLog = executor.submit(() -> {
|
||||
provisioningFinished.await();
|
||||
LogFactory.getLog(FlywayTargetSchemaProvisionerTest.class).info("unrelated-flyway-operation");
|
||||
return null;
|
||||
});
|
||||
|
||||
provisioning.get();
|
||||
interleavedLog.get();
|
||||
assertThat(recording.messages()).contains("unrelated-flyway-operation");
|
||||
} finally {
|
||||
LogFactory.setConfiguration(Flyway.configure());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class RecordingLogCreator implements LogCreator {
|
||||
|
||||
private final List<String> messages = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public Log createLogger(Class<?> clazz) {
|
||||
return new RecordingLog(messages);
|
||||
}
|
||||
|
||||
List<String> messages() {
|
||||
return List.copyOf(messages);
|
||||
}
|
||||
}
|
||||
|
||||
private record RecordingLog(List<String> messages) implements Log {
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message, Exception exception) {
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice(String message) {
|
||||
messages.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
private record DiagnosticFailureDriver(String acceptedUrl) implements Driver {
|
||||
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) throws SQLException {
|
||||
if (!acceptsURL(url)) {
|
||||
return null;
|
||||
}
|
||||
throw new SQLException("Connection failed for " + url + " after SELECT secret-value", "08006", 1045);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsURL(String url) {
|
||||
return acceptedUrl.equals(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
|
||||
return new DriverPropertyInfo[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcCompliant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getAnonymousLogger();
|
||||
}
|
||||
}
|
||||
|
||||
private record CloseFailureDriver(String acceptedUrl) implements Driver {
|
||||
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) {
|
||||
if (!acceptsURL(url)) {
|
||||
return null;
|
||||
}
|
||||
return (Connection) Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(), new Class<?>[]{Connection.class}, (proxy, method, arguments) -> {
|
||||
if (method.getName().equals("close")) {
|
||||
throw new SQLException("close leaked " + url + " after SELECT secret-value", "08006", 999);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsURL(String url) {
|
||||
return acceptedUrl.equals(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
|
||||
return new DriverPropertyInfo[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcCompliant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getAnonymousLogger();
|
||||
}
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Set;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TargetSchemaContractCompatibilityTest {
|
||||
|
||||
private static final Set<String> TABLES = Set.of("contract_parent", "contract_child");
|
||||
|
||||
@Test
|
||||
void equivalentSchemaDoesNotDependOnJdbcPresentationMetadata() throws Exception {
|
||||
try (Connection first = schema("representation_a", "alpha", "1", "first", "asc", true);
|
||||
Connection second = schema("representation_b", "beta", "2", "second", "desc", false)) {
|
||||
assertThat(JdbcTargetSchemaState.capture(first, MetadataDatabaseKind.MYSQL, TABLES))
|
||||
.isEqualTo(JdbcTargetSchemaState.capture(second, MetadataDatabaseKind.MYSQL, TABLES));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordedContractRejectsDuplicateHumanReadableDefinitions() throws Exception {
|
||||
try (Connection connection = schema("duplicate_contract", "stable", "1", "remarks", "asc", false);
|
||||
Statement statement = connection.createStatement()) {
|
||||
TargetSchemaContract contract = new TargetSchemaContract(MetadataDatabaseKind.MYSQL);
|
||||
contract.record(connection, TABLES);
|
||||
statement.execute("INSERT INTO flyway_schema_contract "
|
||||
+ "(contract_id, database_kind, definition, occurrences) "
|
||||
+ "SELECT 9999, database_kind, definition, occurrences FROM flyway_schema_contract "
|
||||
+ "FETCH FIRST 1 ROW ONLY");
|
||||
|
||||
assertThatThrownBy(() -> contract.matches(connection, TABLES))
|
||||
.isInstanceOf(SQLException.class)
|
||||
.hasMessage("Target schema contract contains duplicate definitions");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void semanticStatePreservesIntegerWidth() throws Exception {
|
||||
try (Connection baseline = semanticSchema("semantic_baseline", "BIGINT", "");
|
||||
Connection narrowerInteger = semanticSchema("semantic_integer", "INTEGER", "")) {
|
||||
JdbcTargetSchemaState.SchemaState baselineState =
|
||||
JdbcTargetSchemaState.capture(baseline, MetadataDatabaseKind.MYSQL, TABLES);
|
||||
|
||||
assertThat(JdbcTargetSchemaState.capture(narrowerInteger, MetadataDatabaseKind.MYSQL, TABLES))
|
||||
.isNotEqualTo(baselineState);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void semanticStatePreservesForeignKeyActions() throws Exception {
|
||||
try (Connection baseline = semanticSchema("foreign_key_baseline", "BIGINT", "");
|
||||
Connection cascadingDelete =
|
||||
semanticSchema("foreign_key_cascade", "BIGINT", " ON DELETE CASCADE")) {
|
||||
JdbcTargetSchemaState.SchemaState baselineState =
|
||||
JdbcTargetSchemaState.capture(baseline, MetadataDatabaseKind.MYSQL, TABLES);
|
||||
|
||||
assertThat(JdbcTargetSchemaState.capture(cascadingDelete, MetadataDatabaseKind.MYSQL, TABLES))
|
||||
.isNotEqualTo(baselineState);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordedContractRejectsRowsForAnotherDatabaseKind() throws Exception {
|
||||
try (Connection connection = schema("cross_kind_contract", "stable", "1", "remarks", "asc", false);
|
||||
Statement statement = connection.createStatement()) {
|
||||
TargetSchemaContract contract = new TargetSchemaContract(MetadataDatabaseKind.MYSQL);
|
||||
contract.record(connection, TABLES);
|
||||
statement.execute("INSERT INTO flyway_schema_contract "
|
||||
+ "(contract_id, database_kind, definition, occurrences) "
|
||||
+ "VALUES (9999, 'POSTGRESQL', 'table|intruder', 1)");
|
||||
|
||||
assertThatThrownBy(() -> contract.matches(connection, TABLES))
|
||||
.isInstanceOfSatisfying(SQLException.class,
|
||||
exception -> assertThat(exception.getSQLState()).isEqualTo("55000"));
|
||||
}
|
||||
}
|
||||
|
||||
private static Connection schema(
|
||||
String database,
|
||||
String objectSuffix,
|
||||
String defaultValue,
|
||||
String remarks,
|
||||
String indexOrder,
|
||||
boolean identity) throws Exception {
|
||||
Connection connection = DriverManager.getConnection(
|
||||
"jdbc:h2:mem:" + database + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1", "sa", "");
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
String id = identity ? "BIGINT GENERATED BY DEFAULT AS IDENTITY" : "BIGINT";
|
||||
statement.execute("CREATE TABLE contract_parent (id " + id
|
||||
+ ", CONSTRAINT pk_parent_" + objectSuffix + " PRIMARY KEY (id))");
|
||||
statement.execute("CREATE TABLE contract_child (id BIGINT NOT NULL, parent_id BIGINT, "
|
||||
+ "label VARCHAR(64) NOT NULL DEFAULT '" + defaultValue + "', "
|
||||
+ "CONSTRAINT pk_child_" + objectSuffix + " PRIMARY KEY (id), "
|
||||
+ "CONSTRAINT fk_child_" + objectSuffix
|
||||
+ " FOREIGN KEY (parent_id) REFERENCES contract_parent(id))");
|
||||
statement.execute("COMMENT ON COLUMN contract_child.label IS '" + remarks + "'");
|
||||
statement.execute("CREATE INDEX ix_child_" + objectSuffix
|
||||
+ " ON contract_child(parent_id " + indexOrder + ", label " + indexOrder + ")");
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static Connection semanticSchema(String database, String integerType, String foreignKeyAction)
|
||||
throws Exception {
|
||||
Connection connection = DriverManager.getConnection(
|
||||
"jdbc:h2:mem:" + database + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1", "sa", "");
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE TABLE contract_parent (id BIGINT PRIMARY KEY)");
|
||||
statement.execute("CREATE TABLE contract_child (id BIGINT PRIMARY KEY, parent_id " + integerType
|
||||
+ ", CONSTRAINT fk_child FOREIGN KEY (parent_id) REFERENCES contract_parent(id)"
|
||||
+ foreignKeyAction + ")");
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,881 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
-- contributor license agreements. See the NOTICE file distributed with
|
||||
-- this work for additional information regarding copyright ownership.
|
||||
-- The ASF licenses this file to You under the Apache License, Version 2.0.
|
||||
--
|
||||
-- Static V206 schema baseline for provisioning an empty MySQL target.
|
||||
-- Future versioned migrations start at V207 or later.
|
||||
|
||||
create table hzb_ai_conversation (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
title varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_ai_message (
|
||||
conversation_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
role varchar(255),
|
||||
content longtext not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_define (
|
||||
enable bit not null,
|
||||
period integer,
|
||||
times integer,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
datasource varchar(100),
|
||||
name varchar(100) not null,
|
||||
expr varchar(2048),
|
||||
labels varchar(2048),
|
||||
template varchar(2048),
|
||||
annotations varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_define_monitor_bind (
|
||||
alert_define_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_group (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
common_labels varchar(2048),
|
||||
group_key varchar(2048) character set ascii,
|
||||
group_labels varchar(2048),
|
||||
alert_fingerprints TEXT,
|
||||
common_annotations TEXT,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_group_converge (
|
||||
enable bit,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
group_interval bigint,
|
||||
group_wait bigint,
|
||||
id bigint not null auto_increment,
|
||||
repeat_interval bigint,
|
||||
name varchar(100) not null,
|
||||
group_labels varchar(1024),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_inhibit (
|
||||
enable bit,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(100) not null,
|
||||
equal_labels varchar(2048),
|
||||
source_labels varchar(2048),
|
||||
target_labels varchar(2048),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_silence (
|
||||
enable bit not null,
|
||||
match_all bit not null,
|
||||
times integer,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
period_end datetime(6),
|
||||
period_start datetime(6),
|
||||
name varchar(100) not null,
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_single (
|
||||
trigger_times integer,
|
||||
active_at bigint,
|
||||
end_at bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
start_at bigint,
|
||||
fingerprint varchar(2048) character set ascii,
|
||||
labels varchar(2048),
|
||||
annotations varchar(4096),
|
||||
content varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_bulletin (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
fields varchar(4096),
|
||||
monitor_ids varchar(4096),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_collector (
|
||||
status tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
ip varchar(255) not null,
|
||||
mode varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
version varchar(255),
|
||||
|
||||
primary key (id),
|
||||
check ((status>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_collector_monitor_bind (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
collector varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_config (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
|
||||
content varchar(8192),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255) not null,
|
||||
primary key (type)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_define (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
app varchar(255) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content longtext,
|
||||
primary key (app)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_grafana_dashboard (
|
||||
enabled bit not null,
|
||||
monitor_id bigint not null,
|
||||
version bigint,
|
||||
folder_uid varchar(255),
|
||||
slug varchar(255),
|
||||
status varchar(255),
|
||||
uid varchar(255),
|
||||
url varchar(255),
|
||||
primary key (monitor_id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_history (
|
||||
dou float(53),
|
||||
int32 integer,
|
||||
metric_type tinyint,
|
||||
id bigint not null auto_increment,
|
||||
time bigint,
|
||||
str varchar(2048),
|
||||
app varchar(255),
|
||||
metric_labels varchar(5000),
|
||||
metric varchar(255),
|
||||
metrics varchar(255),
|
||||
instance varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_metrics_favorite (
|
||||
create_time datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint not null,
|
||||
creator varchar(255) not null,
|
||||
metrics_name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_monitor (
|
||||
intervals integer,
|
||||
status tinyint not null,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null,
|
||||
job_id bigint,
|
||||
schedule_type varchar(20),
|
||||
app varchar(100),
|
||||
cron_expression varchar(100),
|
||||
instance varchar(100),
|
||||
name varchar(100),
|
||||
scrape varchar(100),
|
||||
annotations varchar(4096),
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id),
|
||||
check ((status<=4) and (status>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_monitor_bind (
|
||||
biz_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
creator varchar(255),
|
||||
key_str varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_receiver (
|
||||
agent_id integer,
|
||||
lark_receive_type tinyint,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
smn_ak varchar(22),
|
||||
smn_project_id varchar(32),
|
||||
smn_region varchar(32),
|
||||
smn_sk varchar(42),
|
||||
email varchar(100),
|
||||
name varchar(100) not null,
|
||||
phone varchar(100),
|
||||
access_token varchar(300),
|
||||
discord_bot_token varchar(300),
|
||||
discord_channel_id varchar(300),
|
||||
gotify_token varchar(300),
|
||||
hook_auth_token varchar(300),
|
||||
hook_auth_type varchar(300),
|
||||
server_chan_token varchar(300),
|
||||
slack_web_hook_url varchar(300),
|
||||
smn_topic_urn varchar(300),
|
||||
wechat_id varchar(300),
|
||||
hook_url varchar(1000),
|
||||
app_id varchar(255),
|
||||
app_secret varchar(255),
|
||||
chat_id varchar(255),
|
||||
corp_id varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
party_id varchar(255),
|
||||
tag_id varchar(255),
|
||||
tg_bot_token varchar(255),
|
||||
tg_message_thread_id varchar(255),
|
||||
tg_user_id varchar(255),
|
||||
user_id varchar(255),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_rule (
|
||||
enable bit not null,
|
||||
filter_all bit not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
period_end datetime(6),
|
||||
period_start datetime(6),
|
||||
template_id bigint,
|
||||
name varchar(100) not null,
|
||||
template_name varchar(100),
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
receiver_id varchar(255) not null,
|
||||
receiver_name varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_template (
|
||||
preset boolean default false,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(100) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content text not null,
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_param (
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_param_define (
|
||||
hide bit not null,
|
||||
param_limit smallint,
|
||||
required bit not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(2048),
|
||||
param_options varchar(2048),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
default_value varchar(255),
|
||||
depend varchar(255),
|
||||
field varchar(255),
|
||||
key_alias varchar(255),
|
||||
modifier varchar(255),
|
||||
param_range varchar(255),
|
||||
placeholder varchar(255),
|
||||
type varchar(255),
|
||||
value_alias varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_item (
|
||||
id bigint not null auto_increment,
|
||||
metadata_id bigint,
|
||||
class_identifier varchar(255),
|
||||
type enum ('POST_ALERT','POST_COLLECT'),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_metadata (
|
||||
enable_status bit,
|
||||
param_count integer,
|
||||
gmt_create datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
jar_file_path varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_param (
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
plugin_metadata_id bigint not null,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_push_metrics (
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
time bigint,
|
||||
metrics varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_sop_schedule (
|
||||
id bigint not null auto_increment,
|
||||
conversation_id bigint not null comment 'Conversation ID to push results to',
|
||||
sop_name varchar(64) not null comment 'Name of the SOP skill to execute',
|
||||
sop_params varchar(1024) comment 'SOP execution parameters in JSON format',
|
||||
cron_expression varchar(64) not null comment 'Cron expression for scheduling',
|
||||
enabled tinyint default 1 comment 'Whether the schedule is enabled',
|
||||
last_run_time datetime comment 'Last execution time',
|
||||
next_run_time datetime comment 'Next scheduled execution time',
|
||||
creator varchar(64) comment 'Creator of this record',
|
||||
modifier varchar(64) comment 'Last modifier',
|
||||
gmt_create datetime default current_timestamp comment 'Create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'Update time',
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_component (
|
||||
config_state tinyint not null,
|
||||
method tinyint not null,
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
org_id bigint,
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_history (
|
||||
abnormal integer,
|
||||
normal integer,
|
||||
state tinyint not null,
|
||||
unknowing integer,
|
||||
uptime float(53),
|
||||
component_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident (
|
||||
state tinyint not null,
|
||||
end_time bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
org_id bigint,
|
||||
start_time bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident_component_bind (
|
||||
component_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
incident_id bigint,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident_content (
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
incident_id bigint,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
message TEXT,
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_org (
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
color varchar(255),
|
||||
creator varchar(255),
|
||||
description varchar(255) not null,
|
||||
feedback varchar(255),
|
||||
home varchar(255) not null,
|
||||
logo varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_tag (
|
||||
type tinyint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
tag_value varchar(2048),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id),
|
||||
check ((type<=3) and (type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
|
||||
create index idx_message_conversation_id
|
||||
on hzb_ai_message (conversation_id);
|
||||
|
||||
create index idx_alert_define_id
|
||||
on hzb_alert_define_monitor_bind (alert_define_id);
|
||||
|
||||
create index idx_monitor_id
|
||||
on hzb_alert_define_monitor_bind (monitor_id);
|
||||
|
||||
alter table hzb_alert_group
|
||||
add constraint unique_group_key unique (group_key);
|
||||
|
||||
create index idx_name
|
||||
on hzb_alert_group_converge (name);
|
||||
|
||||
alter table hzb_alert_single
|
||||
add constraint unique_fingerprint unique (fingerprint);
|
||||
|
||||
alter table hzb_collector
|
||||
add constraint uk_hzb_collector_name unique (name);
|
||||
|
||||
create index idx_collector_monitor_collector
|
||||
on hzb_collector_monitor_bind (collector);
|
||||
|
||||
create index idx_collector_monitor_monitor_id
|
||||
on hzb_collector_monitor_bind (monitor_id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
create index idx_hzb_history_instance
|
||||
on hzb_history (instance);
|
||||
|
||||
create index idx_hzb_history_app
|
||||
on hzb_history (app);
|
||||
|
||||
create index idx_hzb_history_metrics
|
||||
on hzb_history (metrics);
|
||||
|
||||
create index idx_hzb_history_metric
|
||||
on hzb_history (metric);
|
||||
|
||||
alter table hzb_metrics_favorite
|
||||
add constraint uk_hzb_metrics_favorite unique (creator, monitor_id, metrics_name);
|
||||
|
||||
create index idx_hzb_monitor_app
|
||||
on hzb_monitor (app);
|
||||
|
||||
create index idx_hzb_monitor_instance
|
||||
on hzb_monitor (instance);
|
||||
|
||||
create index idx_hzb_monitor_name
|
||||
on hzb_monitor (name);
|
||||
|
||||
create index index_monitor_bind
|
||||
on hzb_monitor_bind (biz_id);
|
||||
|
||||
create index index_monitor_bin
|
||||
on hzb_monitor_bind (monitor_id);
|
||||
|
||||
create index idx_hzb_param_monitor_id
|
||||
on hzb_param (monitor_id);
|
||||
|
||||
alter table hzb_param
|
||||
add constraint uk_hzb_param_monitor_field unique (monitor_id, field);
|
||||
|
||||
create index idx_hzb_plugin_param_plugin_metadata_id
|
||||
on hzb_plugin_param (plugin_metadata_id);
|
||||
|
||||
alter table hzb_plugin_param
|
||||
add constraint uk_hzb_plugin_param_metadata_field unique (plugin_metadata_id, field);
|
||||
|
||||
create index idx_push_metrics_monitor_id
|
||||
on hzb_push_metrics (monitor_id);
|
||||
|
||||
create index idx_push_metrics_time
|
||||
on hzb_push_metrics (time);
|
||||
|
||||
create index idx_schedule_conversation_id
|
||||
on hzb_sop_schedule (conversation_id);
|
||||
|
||||
create index idx_schedule_enabled_next
|
||||
on hzb_sop_schedule (enabled, next_run_time);
|
||||
|
||||
create index index_incident_component
|
||||
on hzb_status_page_incident_component_bind (incident_id);
|
||||
|
||||
create index idx_incident_component_component_id
|
||||
on hzb_status_page_incident_component_bind (component_id);
|
||||
|
||||
alter table hzb_ai_message
|
||||
add constraint fk_hzb_ai_message_conversation
|
||||
foreign key (conversation_id)
|
||||
references hzb_ai_conversation (id);
|
||||
|
||||
alter table hzb_plugin_item
|
||||
add constraint fk_hzb_plugin_item_metadata
|
||||
foreign key (metadata_id)
|
||||
references hzb_plugin_metadata (id);
|
||||
|
||||
alter table hzb_status_page_incident_content
|
||||
add constraint fk_hzb_incident_content_incident
|
||||
foreign key (incident_id)
|
||||
references hzb_status_page_incident (id);
|
||||
|
||||
CREATE TABLE hzb_entity (
|
||||
id BIGINT PRIMARY KEY COMMENT 'Entity ID',
|
||||
entity_type VARCHAR(32) NOT NULL COMMENT 'Entity type',
|
||||
name VARCHAR(128) NOT NULL COMMENT 'Entity name',
|
||||
display_name VARCHAR(128) COMMENT 'Entity display name',
|
||||
sub_type VARCHAR(128) COMMENT 'Entity subtype from HertzBeat v1 definition',
|
||||
namespace VARCHAR(128) COMMENT 'Namespace',
|
||||
environment VARCHAR(128) COMMENT 'Deployment environment',
|
||||
status VARCHAR(32) NOT NULL COMMENT 'Aggregated entity status',
|
||||
criticality VARCHAR(32) COMMENT 'Entity criticality',
|
||||
owner VARCHAR(128) COMMENT 'Entity owner',
|
||||
additional_owners TEXT COMMENT 'Additional owners json',
|
||||
runbook VARCHAR(512) COMMENT 'Runbook URL or identifier',
|
||||
lifecycle VARCHAR(64) COMMENT 'Entity lifecycle',
|
||||
tier VARCHAR(64) COMMENT 'Entity tier',
|
||||
system_name VARCHAR(128) COMMENT 'Owning system',
|
||||
component_of TEXT COMMENT 'Parent components or systems',
|
||||
components TEXT COMMENT 'Child components that belong to this system',
|
||||
implemented_by TEXT COMMENT 'ImplementedBy references json',
|
||||
api_interface TEXT COMMENT 'API interface definition json',
|
||||
inherit_from VARCHAR(255) COMMENT 'Entity inheritance reference',
|
||||
languages TEXT COMMENT 'Programming languages json',
|
||||
links TEXT COMMENT 'Entity links json',
|
||||
contacts TEXT COMMENT 'Entity contacts json',
|
||||
integrations TEXT COMMENT 'Entity integrations json',
|
||||
extensions TEXT COMMENT 'Entity custom extensions json',
|
||||
hertzbeat TEXT COMMENT 'HertzBeat definition blocks json',
|
||||
source VARCHAR(32) NOT NULL COMMENT 'Entity source',
|
||||
description VARCHAR(512) COMMENT 'Entity description',
|
||||
labels VARCHAR(4096) COMMENT 'Entity labels json',
|
||||
tags TEXT COMMENT 'Entity catalog tags json',
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'Entity workspace boundary',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
modifier VARCHAR(64) COMMENT 'Modifier',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
gmt_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
INDEX idx_hzb_entity_type (entity_type),
|
||||
INDEX idx_hzb_entity_status (status),
|
||||
INDEX idx_hzb_entity_name (name),
|
||||
INDEX idx_hzb_entity_owner (owner),
|
||||
INDEX idx_hzb_entity_workspace (workspace_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_entity_identity (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL COMMENT 'Entity ID',
|
||||
identity_type VARCHAR(32) NOT NULL COMMENT 'Identity source type',
|
||||
identity_key VARCHAR(128) NOT NULL COMMENT 'Identity key',
|
||||
identity_value VARCHAR(512) NOT NULL COMMENT 'Identity value',
|
||||
normalized_value VARCHAR(512) NOT NULL COMMENT 'Normalized identity value',
|
||||
priority INT NOT NULL DEFAULT 40 COMMENT 'Identity priority',
|
||||
primary_identity TINYINT NOT NULL DEFAULT 0 COMMENT 'Whether primary identity',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
modifier VARCHAR(64) COMMENT 'Modifier',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
gmt_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_entity_identity (entity_id, identity_key, normalized_value),
|
||||
INDEX idx_hzb_entity_identity_lookup (identity_key, normalized_value),
|
||||
INDEX idx_hzb_entity_identity_entity (entity_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_entity_monitor_bind (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL COMMENT 'Entity ID',
|
||||
monitor_id BIGINT NOT NULL COMMENT 'Monitor ID',
|
||||
bind_type VARCHAR(32) NOT NULL COMMENT 'Bind type',
|
||||
bind_source VARCHAR(64) NOT NULL COMMENT 'Bind source',
|
||||
status VARCHAR(16) NOT NULL COMMENT 'Bind status',
|
||||
score INT NOT NULL DEFAULT 100 COMMENT 'Bind score',
|
||||
match_context TEXT COMMENT 'Matched identities json',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
modifier VARCHAR(64) COMMENT 'Modifier',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
gmt_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_entity_monitor_bind (entity_id, monitor_id),
|
||||
INDEX idx_hzb_entity_monitor_bind_entity (entity_id),
|
||||
INDEX idx_hzb_entity_monitor_bind_monitor (monitor_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_entity_relation (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
source_entity_id BIGINT NOT NULL COMMENT 'Source entity ID',
|
||||
target_entity_id BIGINT NULL COMMENT 'Target entity ID',
|
||||
target_ref VARCHAR(255) COMMENT 'Target entity reference',
|
||||
relation_type VARCHAR(32) NOT NULL COMMENT 'Relation type',
|
||||
relation_source VARCHAR(32) NOT NULL COMMENT 'Relation source',
|
||||
status VARCHAR(16) NOT NULL COMMENT 'Relation status',
|
||||
score INT NOT NULL DEFAULT 100 COMMENT 'Relation score',
|
||||
description VARCHAR(255) COMMENT 'Relation description',
|
||||
attributes TEXT COMMENT 'Relation attributes json',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
modifier VARCHAR(64) COMMENT 'Modifier',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
gmt_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_entity_relation (source_entity_id, target_entity_id, relation_type),
|
||||
INDEX idx_hzb_entity_relation_source (source_entity_id),
|
||||
INDEX idx_hzb_entity_relation_target (target_entity_id),
|
||||
INDEX idx_hzb_entity_relation_target_ref (target_ref)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_entity_definition_activity (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL COMMENT 'Entity ID',
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'Workspace ID',
|
||||
activity_type VARCHAR(32) NOT NULL COMMENT 'Definition activity type',
|
||||
format VARCHAR(16) NOT NULL COMMENT 'Definition format',
|
||||
status VARCHAR(16) NOT NULL COMMENT 'Activity status',
|
||||
summary VARCHAR(128) NOT NULL COMMENT 'Activity summary',
|
||||
detail VARCHAR(255) COMMENT 'Activity detail',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
INDEX idx_hzb_entity_definition_activity_entity (entity_id),
|
||||
INDEX idx_hzb_entity_definition_activity_workspace_time (workspace_id, gmt_create),
|
||||
INDEX idx_hzb_entity_definition_activity_time (gmt_create)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_entity_governance_state (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
state_scope VARCHAR(32) NOT NULL COMMENT 'Governance scope, such as discovery',
|
||||
state_kind VARCHAR(32) NOT NULL COMMENT 'State kind, such as preset or activity',
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'Workspace ID',
|
||||
state_key VARCHAR(128) NOT NULL COMMENT 'Stable state key',
|
||||
state_name VARCHAR(128) COMMENT 'State display name',
|
||||
status VARCHAR(32) COMMENT 'State status',
|
||||
content TEXT COMMENT 'State JSON content',
|
||||
creator VARCHAR(64) COMMENT 'Creator',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
gmt_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_entity_governance_state_scope_kind_workspace_key (state_scope, state_kind, workspace_id, state_key),
|
||||
INDEX idx_hzb_entity_governance_state_scope_kind (state_scope, state_kind),
|
||||
INDEX idx_hzb_entity_governance_state_scope_kind_workspace (state_scope, state_kind, workspace_id),
|
||||
INDEX idx_hzb_entity_governance_state_update (gmt_update),
|
||||
INDEX idx_hzb_entity_governance_state_creator (creator)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_auth_token (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) COMMENT 'API token name',
|
||||
token_hash VARCHAR(128) NOT NULL COMMENT 'SHA-256 hash of token value',
|
||||
token_mask VARCHAR(64) COMMENT 'Masked token value for display',
|
||||
token_scope VARCHAR(32) NOT NULL DEFAULT 'api-admin' COMMENT 'Token access scope',
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'Token workspace boundary',
|
||||
status TINYINT NOT NULL DEFAULT 0 COMMENT 'Token status, 0 means active',
|
||||
creator VARCHAR(64) COMMENT 'Token creator',
|
||||
gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
expire_time DATETIME NULL COMMENT 'Expire time, null means long-lived',
|
||||
last_used_time DATETIME NULL COMMENT 'Last used time',
|
||||
revoked_time DATETIME NULL COMMENT 'Token revoked time',
|
||||
revoked_by VARCHAR(64) COMMENT 'Token revoker',
|
||||
UNIQUE KEY uk_hzb_auth_token_hash (token_hash),
|
||||
INDEX idx_hzb_auth_token_creator (creator),
|
||||
INDEX idx_hzb_auth_token_scope (token_scope),
|
||||
INDEX idx_hzb_auth_token_workspace (workspace_id),
|
||||
INDEX idx_hzb_auth_token_scope_workspace (token_scope, workspace_id),
|
||||
INDEX idx_hzb_auth_token_status (status),
|
||||
INDEX idx_hzb_auth_token_revoked_by (revoked_by)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_signal_saved_view (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL COMMENT 'Saved view creator',
|
||||
`signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
view_key VARCHAR(128) NOT NULL COMMENT 'Stable saved view key',
|
||||
label VARCHAR(255) NOT NULL COMMENT 'Saved view display label',
|
||||
description VARCHAR(512) COMMENT 'Saved view description',
|
||||
route VARCHAR(2048) NOT NULL COMMENT 'Explorer route snapshot',
|
||||
query_snapshot TEXT COMMENT 'Query-state snapshot JSON',
|
||||
payload TEXT COMMENT 'Additional saved view payload JSON',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_signal_saved_view_signal_key (`signal`, view_key),
|
||||
INDEX idx_hzb_signal_saved_view_signal (`signal`),
|
||||
INDEX idx_hzb_signal_saved_view_update (update_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_signal_dashboard_panel_draft (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL COMMENT 'Panel draft creator',
|
||||
`signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
draft_key VARCHAR(128) NOT NULL COMMENT 'Stable dashboard panel draft key',
|
||||
title VARCHAR(255) NOT NULL COMMENT 'Dashboard panel title',
|
||||
description VARCHAR(512) COMMENT 'Dashboard panel description',
|
||||
visualization VARCHAR(32) NOT NULL COMMENT 'Dashboard panel visualization type',
|
||||
route VARCHAR(2048) NOT NULL COMMENT 'Explorer route snapshot',
|
||||
query_snapshot TEXT COMMENT 'Query-state snapshot JSON',
|
||||
payload TEXT COMMENT 'Additional dashboard panel payload JSON',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_signal_dashboard_panel_draft_creator_signal_key (creator, `signal`, draft_key),
|
||||
INDEX idx_hzb_signal_dashboard_panel_draft_creator_signal (creator, `signal`),
|
||||
INDEX idx_hzb_signal_dashboard_panel_draft_update (update_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_signal_dashboard (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL COMMENT 'Dashboard creator',
|
||||
dashboard_key VARCHAR(128) NOT NULL COMMENT 'Stable dashboard key',
|
||||
title VARCHAR(255) NOT NULL COMMENT 'Dashboard title',
|
||||
description VARCHAR(512) COMMENT 'Dashboard description',
|
||||
tags VARCHAR(512) COMMENT 'Comma-separated dashboard tags',
|
||||
layout TEXT NOT NULL COMMENT 'Dashboard layout JSON',
|
||||
widgets TEXT NOT NULL COMMENT 'Dashboard widgets JSON',
|
||||
variables TEXT COMMENT 'Dashboard variables JSON',
|
||||
panel_map TEXT COMMENT 'Dashboard panel grouping JSON',
|
||||
version VARCHAR(32) COMMENT 'Dashboard schema version',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_signal_dashboard_key (dashboard_key),
|
||||
INDEX idx_hzb_signal_dashboard_update (update_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE hzb_auth_token
|
||||
ADD COLUMN token_audience VARCHAR(32) NULL,
|
||||
ADD COLUMN collector_id VARCHAR(128) NULL,
|
||||
ADD COLUMN allowed_signals VARCHAR(64) NULL,
|
||||
ADD INDEX idx_hzb_auth_token_collector (collector_id);
|
||||
|
||||
ALTER TABLE hzb_collector ADD COLUMN runtime_config TEXT NULL;
|
||||
|
||||
ALTER TABLE hzb_collector ADD COLUMN instrumentation_intake TEXT NULL;
|
||||
|
||||
ALTER TABLE hzb_config ADD COLUMN config_revision VARCHAR(36) NULL;
|
||||
UPDATE hzb_config SET config_revision = UUID() WHERE config_revision IS NULL;
|
||||
ALTER TABLE hzb_config MODIFY COLUMN config_revision VARCHAR(36) NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hzb_account (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password_hash VARCHAR(100) NOT NULL,
|
||||
roles VARCHAR(128) NOT NULL,
|
||||
credential_version BIGINT NOT NULL,
|
||||
disabled BOOLEAN NOT NULL,
|
||||
bootstrap_slot SMALLINT,
|
||||
CONSTRAINT uk_hzb_account_username UNIQUE (username),
|
||||
CONSTRAINT uk_hzb_account_bootstrap UNIQUE (bootstrap_slot)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS hzb_installation (
|
||||
id SMALLINT PRIMARY KEY,
|
||||
installation_fingerprint VARCHAR(64) NOT NULL UNIQUE,
|
||||
complete BOOLEAN NOT NULL
|
||||
);
|
||||
+6
-6
@@ -176,7 +176,7 @@ CREATE TABLE hzb_auth_token (
|
||||
CREATE TABLE hzb_signal_saved_view (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL COMMENT 'Saved view creator',
|
||||
signal VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
`signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
view_key VARCHAR(128) NOT NULL COMMENT 'Stable saved view key',
|
||||
label VARCHAR(255) NOT NULL COMMENT 'Saved view display label',
|
||||
description VARCHAR(512) COMMENT 'Saved view description',
|
||||
@@ -185,15 +185,15 @@ CREATE TABLE hzb_signal_saved_view (
|
||||
payload TEXT COMMENT 'Additional saved view payload JSON',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_signal_saved_view_signal_key (signal, view_key),
|
||||
INDEX idx_hzb_signal_saved_view_signal (signal),
|
||||
UNIQUE KEY uk_hzb_signal_saved_view_signal_key (`signal`, view_key),
|
||||
INDEX idx_hzb_signal_saved_view_signal (`signal`),
|
||||
INDEX idx_hzb_signal_saved_view_update (update_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE hzb_signal_dashboard_panel_draft (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL COMMENT 'Panel draft creator',
|
||||
signal VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
`signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics',
|
||||
draft_key VARCHAR(128) NOT NULL COMMENT 'Stable dashboard panel draft key',
|
||||
title VARCHAR(255) NOT NULL COMMENT 'Dashboard panel title',
|
||||
description VARCHAR(512) COMMENT 'Dashboard panel description',
|
||||
@@ -203,8 +203,8 @@ CREATE TABLE hzb_signal_dashboard_panel_draft (
|
||||
payload TEXT COMMENT 'Additional dashboard panel payload JSON',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Create time',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update time',
|
||||
UNIQUE KEY uk_hzb_signal_dashboard_panel_draft_creator_signal_key (creator, signal, draft_key),
|
||||
INDEX idx_hzb_signal_dashboard_panel_draft_creator_signal (creator, signal),
|
||||
UNIQUE KEY uk_hzb_signal_dashboard_panel_draft_creator_signal_key (creator, `signal`, draft_key),
|
||||
INDEX idx_hzb_signal_dashboard_panel_draft_creator_signal (creator, `signal`),
|
||||
INDEX idx_hzb_signal_dashboard_panel_draft_update (update_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
||||
-- or more contributor license agreements. See the NOTICE file
|
||||
-- distributed with this work for additional information
|
||||
-- regarding copyright ownership. The ASF licenses this file
|
||||
-- to you under the Apache License, Version 2.0 (the
|
||||
-- "License"); you may not use this file except in compliance
|
||||
-- with the License. You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing,
|
||||
-- software distributed under the License is distributed on an
|
||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
-- KIND, either express or implied. See the License for the
|
||||
-- specific language governing permissions and limitations
|
||||
-- under the License.
|
||||
|
||||
ALTER TABLE hzb_signal_saved_view
|
||||
MODIFY COLUMN `signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics';
|
||||
ALTER TABLE hzb_signal_dashboard_panel_draft
|
||||
MODIFY COLUMN `signal` VARCHAR(32) NOT NULL COMMENT 'Signal type: logs, traces, or metrics';
|
||||
+905
@@ -0,0 +1,905 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
-- contributor license agreements. See the NOTICE file distributed with
|
||||
-- this work for additional information regarding copyright ownership.
|
||||
-- The ASF licenses this file to You under the Apache License, Version 2.0.
|
||||
--
|
||||
-- Static V206 schema baseline for provisioning an empty PostgreSQL target.
|
||||
-- Future versioned migrations start at V207 or later.
|
||||
|
||||
create table hzb_ai_conversation (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
title varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_ai_message (
|
||||
conversation_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
role varchar(255),
|
||||
content oid not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_define (
|
||||
enable boolean not null,
|
||||
period integer,
|
||||
times integer,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
datasource varchar(100),
|
||||
name varchar(100) not null,
|
||||
expr varchar(2048),
|
||||
labels varchar(2048),
|
||||
template varchar(2048),
|
||||
annotations varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_define_monitor_bind (
|
||||
alert_define_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_group (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
common_labels varchar(2048),
|
||||
group_key varchar(2048),
|
||||
group_labels varchar(2048),
|
||||
alert_fingerprints TEXT,
|
||||
common_annotations TEXT,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id),
|
||||
constraint unique_group_key unique (group_key)
|
||||
);
|
||||
|
||||
create table hzb_alert_group_converge (
|
||||
enable boolean,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
group_interval bigint,
|
||||
group_wait bigint,
|
||||
id bigint generated by default as identity,
|
||||
repeat_interval bigint,
|
||||
name varchar(100) not null,
|
||||
group_labels varchar(1024),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_inhibit (
|
||||
enable boolean,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(100) not null,
|
||||
equal_labels varchar(2048),
|
||||
source_labels varchar(2048),
|
||||
target_labels varchar(2048),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_silence (
|
||||
enable boolean not null,
|
||||
match_all boolean not null,
|
||||
times integer,
|
||||
type smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
period_end timestamp(6) with time zone,
|
||||
period_start timestamp(6) with time zone,
|
||||
name varchar(100) not null,
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_single (
|
||||
trigger_times integer,
|
||||
active_at bigint,
|
||||
end_at bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
start_at bigint,
|
||||
fingerprint varchar(2048),
|
||||
labels varchar(2048),
|
||||
annotations varchar(4096),
|
||||
content varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id),
|
||||
constraint unique_fingerprint unique (fingerprint)
|
||||
);
|
||||
|
||||
create table hzb_bulletin (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
fields varchar(4096),
|
||||
monitor_ids varchar(4096),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_collector (
|
||||
status smallint not null check ((status>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
ip varchar(255) not null,
|
||||
mode varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
version varchar(255),
|
||||
|
||||
primary key (id),
|
||||
unique (name)
|
||||
);
|
||||
|
||||
create table hzb_collector_monitor_bind (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
collector varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_config (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
|
||||
content varchar(8192),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255) not null,
|
||||
primary key (type)
|
||||
);
|
||||
|
||||
create table hzb_define (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
app varchar(255) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content oid,
|
||||
primary key (app)
|
||||
);
|
||||
|
||||
create table hzb_grafana_dashboard (
|
||||
enabled boolean not null,
|
||||
monitor_id bigint not null,
|
||||
version bigint,
|
||||
folder_uid varchar(255),
|
||||
slug varchar(255),
|
||||
status varchar(255),
|
||||
uid varchar(255),
|
||||
url varchar(255),
|
||||
primary key (monitor_id)
|
||||
);
|
||||
|
||||
create table hzb_history (
|
||||
dou float(53),
|
||||
int32 integer,
|
||||
metric_type smallint,
|
||||
id bigint generated by default as identity,
|
||||
time bigint,
|
||||
str varchar(2048),
|
||||
app varchar(255),
|
||||
metric_labels varchar(5000),
|
||||
metric varchar(255),
|
||||
metrics varchar(255),
|
||||
instance varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_metrics_favorite (
|
||||
create_time timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint not null,
|
||||
creator varchar(255) not null,
|
||||
metrics_name varchar(255) not null,
|
||||
primary key (id),
|
||||
unique (creator, monitor_id, metrics_name)
|
||||
);
|
||||
|
||||
create table hzb_monitor (
|
||||
intervals integer,
|
||||
status smallint not null check ((status<=4) and (status>=0)),
|
||||
type smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint not null,
|
||||
job_id bigint,
|
||||
schedule_type varchar(20),
|
||||
app varchar(100),
|
||||
cron_expression varchar(100),
|
||||
instance varchar(100),
|
||||
name varchar(100),
|
||||
scrape varchar(100),
|
||||
annotations varchar(4096),
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_monitor_bind (
|
||||
biz_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
creator varchar(255),
|
||||
key_str varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_receiver (
|
||||
agent_id integer,
|
||||
lark_receive_type smallint,
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
smn_ak varchar(22),
|
||||
smn_project_id varchar(32),
|
||||
smn_region varchar(32),
|
||||
smn_sk varchar(42),
|
||||
email varchar(100),
|
||||
name varchar(100) not null,
|
||||
phone varchar(100),
|
||||
access_token varchar(300),
|
||||
discord_bot_token varchar(300),
|
||||
discord_channel_id varchar(300),
|
||||
gotify_token varchar(300),
|
||||
hook_auth_token varchar(300),
|
||||
hook_auth_type varchar(300),
|
||||
server_chan_token varchar(300),
|
||||
slack_web_hook_url varchar(300),
|
||||
smn_topic_urn varchar(300),
|
||||
wechat_id varchar(300),
|
||||
hook_url varchar(1000),
|
||||
app_id varchar(255),
|
||||
app_secret varchar(255),
|
||||
chat_id varchar(255),
|
||||
corp_id varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
party_id varchar(255),
|
||||
tag_id varchar(255),
|
||||
tg_bot_token varchar(255),
|
||||
tg_message_thread_id varchar(255),
|
||||
tg_user_id varchar(255),
|
||||
user_id varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_rule (
|
||||
enable boolean not null,
|
||||
filter_all boolean not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
period_end timestamp(6) with time zone,
|
||||
period_start timestamp(6) with time zone,
|
||||
template_id bigint,
|
||||
name varchar(100) not null,
|
||||
template_name varchar(100),
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
receiver_id varchar(255) not null,
|
||||
receiver_name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_template (
|
||||
preset boolean default false,
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(100) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content oid not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_param (
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
constraint uk_hzb_param_monitor_field unique (monitor_id, field)
|
||||
);
|
||||
|
||||
create table hzb_param_define (
|
||||
hide boolean not null,
|
||||
param_limit smallint,
|
||||
required boolean not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(2048),
|
||||
param_options varchar(2048),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
default_value varchar(255),
|
||||
depend varchar(255),
|
||||
field varchar(255),
|
||||
key_alias varchar(255),
|
||||
modifier varchar(255),
|
||||
param_range varchar(255),
|
||||
placeholder varchar(255),
|
||||
type varchar(255),
|
||||
value_alias varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_item (
|
||||
id bigint generated by default as identity,
|
||||
metadata_id bigint,
|
||||
class_identifier varchar(255),
|
||||
type varchar(255) check ((type in ('POST_ALERT','POST_COLLECT'))),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_metadata (
|
||||
enable_status boolean,
|
||||
param_count integer,
|
||||
gmt_create timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
jar_file_path varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_param (
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
plugin_metadata_id bigint not null,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
constraint uk_hzb_plugin_param_metadata_field unique (plugin_metadata_id, field)
|
||||
);
|
||||
|
||||
create table hzb_push_metrics (
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
time bigint,
|
||||
metrics varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_sop_schedule (
|
||||
id bigserial primary key,
|
||||
conversation_id bigint not null,
|
||||
sop_name varchar(64) not null,
|
||||
sop_params varchar(1024),
|
||||
cron_expression varchar(64) not null,
|
||||
enabled boolean default true,
|
||||
last_run_time timestamp,
|
||||
next_run_time timestamp,
|
||||
creator varchar(64),
|
||||
modifier varchar(64),
|
||||
gmt_create timestamp default current_timestamp,
|
||||
gmt_update timestamp default current_timestamp
|
||||
);
|
||||
|
||||
comment on table hzb_sop_schedule is 'Scheduled SOP execution configurations';
|
||||
comment on column hzb_sop_schedule.conversation_id is 'Conversation ID to push results to';
|
||||
comment on column hzb_sop_schedule.sop_name is 'Name of the SOP skill to execute';
|
||||
comment on column hzb_sop_schedule.sop_params is 'SOP execution parameters in JSON format';
|
||||
comment on column hzb_sop_schedule.cron_expression is 'Cron expression for scheduling';
|
||||
comment on column hzb_sop_schedule.enabled is 'Whether the schedule is enabled';
|
||||
comment on column hzb_sop_schedule.last_run_time is 'Last execution time';
|
||||
comment on column hzb_sop_schedule.next_run_time is 'Next scheduled execution time';
|
||||
|
||||
create table hzb_status_page_component (
|
||||
config_state smallint not null,
|
||||
method smallint not null,
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
org_id bigint,
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_history (
|
||||
abnormal integer,
|
||||
normal integer,
|
||||
state smallint not null,
|
||||
unknowing integer,
|
||||
uptime float(53),
|
||||
component_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident (
|
||||
state smallint not null,
|
||||
end_time bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
org_id bigint,
|
||||
start_time bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident_component_bind (
|
||||
component_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
incident_id bigint,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident_content (
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
incident_id bigint,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
message TEXT not null,
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_org (
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
color varchar(255),
|
||||
creator varchar(255),
|
||||
description varchar(255) not null,
|
||||
feedback varchar(255),
|
||||
home varchar(255) not null,
|
||||
logo varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_tag (
|
||||
type smallint check ((type<=3) and (type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
tag_value varchar(2048),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create index idx_message_conversation_id
|
||||
on hzb_ai_message (conversation_id);
|
||||
|
||||
create index idx_alert_define_id
|
||||
on hzb_alert_define_monitor_bind (alert_define_id);
|
||||
|
||||
create index idx_monitor_id
|
||||
on hzb_alert_define_monitor_bind (monitor_id);
|
||||
|
||||
create index idx_name
|
||||
on hzb_alert_group_converge (name);
|
||||
|
||||
create index idx_collector_monitor_collector
|
||||
on hzb_collector_monitor_bind (collector);
|
||||
|
||||
create index idx_collector_monitor_monitor_id
|
||||
on hzb_collector_monitor_bind (monitor_id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
create index idx_hzb_history_instance
|
||||
on hzb_history (instance);
|
||||
|
||||
create index idx_hzb_history_app
|
||||
on hzb_history (app);
|
||||
|
||||
create index idx_hzb_history_metrics
|
||||
on hzb_history (metrics);
|
||||
|
||||
create index idx_hzb_history_metric
|
||||
on hzb_history (metric);
|
||||
|
||||
create index idx_hzb_monitor_app
|
||||
on hzb_monitor (app);
|
||||
|
||||
create index idx_hzb_monitor_instance
|
||||
on hzb_monitor (instance);
|
||||
|
||||
create index idx_hzb_monitor_name
|
||||
on hzb_monitor (name);
|
||||
|
||||
create index index_monitor_bind
|
||||
on hzb_monitor_bind (biz_id);
|
||||
|
||||
create index index_monitor_bin
|
||||
on hzb_monitor_bind (monitor_id);
|
||||
|
||||
create index idx_hzb_param_monitor_id
|
||||
on hzb_param (monitor_id);
|
||||
|
||||
create index idx_hzb_plugin_param_plugin_metadata_id
|
||||
on hzb_plugin_param (plugin_metadata_id);
|
||||
|
||||
create index idx_push_metrics_monitor_id
|
||||
on hzb_push_metrics (monitor_id);
|
||||
|
||||
create index idx_push_metrics_time
|
||||
on hzb_push_metrics (time);
|
||||
|
||||
create index idx_schedule_conversation_id
|
||||
on hzb_sop_schedule (conversation_id);
|
||||
|
||||
create index idx_schedule_enabled_next
|
||||
on hzb_sop_schedule (enabled, next_run_time);
|
||||
|
||||
create index index_incident_component
|
||||
on hzb_status_page_incident_component_bind (incident_id);
|
||||
|
||||
create index idx_incident_component_component_id
|
||||
on hzb_status_page_incident_component_bind (component_id);
|
||||
|
||||
alter table if exists hzb_ai_message
|
||||
add constraint fk_hzb_ai_message_conversation
|
||||
foreign key (conversation_id)
|
||||
references hzb_ai_conversation;
|
||||
|
||||
alter table if exists hzb_plugin_item
|
||||
add constraint fk_hzb_plugin_item_metadata
|
||||
foreign key (metadata_id)
|
||||
references hzb_plugin_metadata;
|
||||
|
||||
alter table if exists hzb_status_page_incident_content
|
||||
add constraint fk_hzb_incident_content_incident
|
||||
foreign key (incident_id)
|
||||
references hzb_status_page_incident;
|
||||
|
||||
CREATE TABLE hzb_entity (
|
||||
id BIGINT PRIMARY KEY,
|
||||
entity_type VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
display_name VARCHAR(128),
|
||||
sub_type VARCHAR(128),
|
||||
namespace VARCHAR(128),
|
||||
environment VARCHAR(128),
|
||||
status VARCHAR(32) NOT NULL,
|
||||
criticality VARCHAR(32),
|
||||
owner VARCHAR(128),
|
||||
additional_owners TEXT,
|
||||
runbook VARCHAR(512),
|
||||
lifecycle VARCHAR(64),
|
||||
tier VARCHAR(64),
|
||||
system_name VARCHAR(128),
|
||||
component_of TEXT,
|
||||
components TEXT,
|
||||
implemented_by TEXT,
|
||||
api_interface TEXT,
|
||||
inherit_from VARCHAR(255),
|
||||
languages TEXT,
|
||||
links TEXT,
|
||||
contacts TEXT,
|
||||
integrations TEXT,
|
||||
extensions TEXT,
|
||||
hertzbeat TEXT,
|
||||
source VARCHAR(32) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
labels VARCHAR(4096),
|
||||
tags TEXT,
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default',
|
||||
creator VARCHAR(64),
|
||||
modifier VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
gmt_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_type ON hzb_entity(entity_type);
|
||||
CREATE INDEX idx_hzb_entity_status ON hzb_entity(status);
|
||||
CREATE INDEX idx_hzb_entity_name ON hzb_entity(name);
|
||||
CREATE INDEX idx_hzb_entity_owner ON hzb_entity(owner);
|
||||
CREATE INDEX idx_hzb_entity_workspace ON hzb_entity(workspace_id);
|
||||
|
||||
CREATE TABLE hzb_entity_identity (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL,
|
||||
identity_type VARCHAR(32) NOT NULL,
|
||||
identity_key VARCHAR(128) NOT NULL,
|
||||
identity_value VARCHAR(512) NOT NULL,
|
||||
normalized_value VARCHAR(512) NOT NULL,
|
||||
priority INT NOT NULL DEFAULT 40,
|
||||
primary_identity BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
creator VARCHAR(64),
|
||||
modifier VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
gmt_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_entity_identity ON hzb_entity_identity(entity_id, identity_key, normalized_value);
|
||||
CREATE INDEX idx_hzb_entity_identity_lookup ON hzb_entity_identity(identity_key, normalized_value);
|
||||
CREATE INDEX idx_hzb_entity_identity_entity ON hzb_entity_identity(entity_id);
|
||||
|
||||
CREATE TABLE hzb_entity_monitor_bind (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL,
|
||||
monitor_id BIGINT NOT NULL,
|
||||
bind_type VARCHAR(32) NOT NULL,
|
||||
bind_source VARCHAR(64) NOT NULL,
|
||||
status VARCHAR(16) NOT NULL,
|
||||
score INT NOT NULL DEFAULT 100,
|
||||
match_context TEXT,
|
||||
creator VARCHAR(64),
|
||||
modifier VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
gmt_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_entity_monitor_bind ON hzb_entity_monitor_bind(entity_id, monitor_id);
|
||||
CREATE INDEX idx_hzb_entity_monitor_bind_entity ON hzb_entity_monitor_bind(entity_id);
|
||||
CREATE INDEX idx_hzb_entity_monitor_bind_monitor ON hzb_entity_monitor_bind(monitor_id);
|
||||
|
||||
CREATE TABLE hzb_entity_relation (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
source_entity_id BIGINT NOT NULL,
|
||||
target_entity_id BIGINT,
|
||||
target_ref VARCHAR(255),
|
||||
relation_type VARCHAR(32) NOT NULL,
|
||||
relation_source VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(16) NOT NULL,
|
||||
score INT NOT NULL DEFAULT 100,
|
||||
description VARCHAR(255),
|
||||
attributes TEXT,
|
||||
creator VARCHAR(64),
|
||||
modifier VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
gmt_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_entity_relation ON hzb_entity_relation(source_entity_id, target_entity_id, relation_type);
|
||||
CREATE INDEX idx_hzb_entity_relation_source ON hzb_entity_relation(source_entity_id);
|
||||
CREATE INDEX idx_hzb_entity_relation_target ON hzb_entity_relation(target_entity_id);
|
||||
CREATE INDEX idx_hzb_entity_relation_target_ref ON hzb_entity_relation(target_ref);
|
||||
|
||||
CREATE TABLE hzb_entity_definition_activity (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
entity_id BIGINT NOT NULL,
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default',
|
||||
activity_type VARCHAR(32) NOT NULL,
|
||||
format VARCHAR(16) NOT NULL,
|
||||
status VARCHAR(16) NOT NULL,
|
||||
summary VARCHAR(128) NOT NULL,
|
||||
detail VARCHAR(255),
|
||||
creator VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_definition_activity_entity
|
||||
ON hzb_entity_definition_activity(entity_id);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_definition_activity_workspace_time
|
||||
ON hzb_entity_definition_activity(workspace_id, gmt_create);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_definition_activity_time
|
||||
ON hzb_entity_definition_activity(gmt_create);
|
||||
|
||||
CREATE TABLE hzb_entity_governance_state (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
state_scope VARCHAR(32) NOT NULL,
|
||||
state_kind VARCHAR(32) NOT NULL,
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default',
|
||||
state_key VARCHAR(128) NOT NULL,
|
||||
state_name VARCHAR(128),
|
||||
status VARCHAR(32),
|
||||
content TEXT,
|
||||
creator VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
gmt_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_entity_governance_state_scope_kind_workspace_key
|
||||
ON hzb_entity_governance_state(state_scope, state_kind, workspace_id, state_key);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_governance_state_scope_kind
|
||||
ON hzb_entity_governance_state(state_scope, state_kind);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_governance_state_scope_kind_workspace
|
||||
ON hzb_entity_governance_state(state_scope, state_kind, workspace_id);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_governance_state_update
|
||||
ON hzb_entity_governance_state(gmt_update);
|
||||
|
||||
CREATE INDEX idx_hzb_entity_governance_state_creator
|
||||
ON hzb_entity_governance_state(creator);
|
||||
|
||||
CREATE TABLE hzb_auth_token (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
token_hash VARCHAR(128) NOT NULL,
|
||||
token_mask VARCHAR(64),
|
||||
token_scope VARCHAR(32) NOT NULL DEFAULT 'api-admin',
|
||||
workspace_id VARCHAR(64) NOT NULL DEFAULT 'default',
|
||||
status SMALLINT NOT NULL DEFAULT 0,
|
||||
creator VARCHAR(64),
|
||||
gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expire_time TIMESTAMP NULL,
|
||||
last_used_time TIMESTAMP NULL,
|
||||
revoked_time TIMESTAMP NULL,
|
||||
revoked_by VARCHAR(64)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_auth_token_hash ON hzb_auth_token(token_hash);
|
||||
CREATE INDEX idx_hzb_auth_token_creator ON hzb_auth_token(creator);
|
||||
CREATE INDEX idx_hzb_auth_token_scope ON hzb_auth_token(token_scope);
|
||||
CREATE INDEX idx_hzb_auth_token_workspace ON hzb_auth_token(workspace_id);
|
||||
CREATE INDEX idx_hzb_auth_token_scope_workspace ON hzb_auth_token(token_scope, workspace_id);
|
||||
CREATE INDEX idx_hzb_auth_token_status ON hzb_auth_token(status);
|
||||
CREATE INDEX idx_hzb_auth_token_revoked_by ON hzb_auth_token(revoked_by);
|
||||
|
||||
CREATE TABLE hzb_signal_saved_view (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL,
|
||||
signal VARCHAR(32) NOT NULL,
|
||||
view_key VARCHAR(128) NOT NULL,
|
||||
label VARCHAR(255) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
route VARCHAR(2048) NOT NULL,
|
||||
query_snapshot TEXT,
|
||||
payload TEXT,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_signal_saved_view_signal_key
|
||||
ON hzb_signal_saved_view(signal, view_key);
|
||||
|
||||
CREATE INDEX idx_hzb_signal_saved_view_signal
|
||||
ON hzb_signal_saved_view(signal);
|
||||
|
||||
CREATE INDEX idx_hzb_signal_saved_view_update
|
||||
ON hzb_signal_saved_view(update_time);
|
||||
|
||||
CREATE TABLE hzb_signal_dashboard_panel_draft (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL,
|
||||
signal VARCHAR(32) NOT NULL,
|
||||
draft_key VARCHAR(128) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
visualization VARCHAR(32) NOT NULL,
|
||||
route VARCHAR(2048) NOT NULL,
|
||||
query_snapshot TEXT,
|
||||
payload TEXT,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_signal_dashboard_panel_draft_creator_signal_key
|
||||
ON hzb_signal_dashboard_panel_draft(creator, signal, draft_key);
|
||||
|
||||
CREATE INDEX idx_hzb_signal_dashboard_panel_draft_creator_signal
|
||||
ON hzb_signal_dashboard_panel_draft(creator, signal);
|
||||
|
||||
CREATE INDEX idx_hzb_signal_dashboard_panel_draft_update
|
||||
ON hzb_signal_dashboard_panel_draft(update_time);
|
||||
|
||||
CREATE TABLE hzb_signal_dashboard (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
creator VARCHAR(255) NOT NULL,
|
||||
dashboard_key VARCHAR(128) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
tags VARCHAR(512),
|
||||
layout TEXT NOT NULL,
|
||||
widgets TEXT NOT NULL,
|
||||
variables TEXT,
|
||||
panel_map TEXT,
|
||||
version VARCHAR(32),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_hzb_signal_dashboard_key
|
||||
ON hzb_signal_dashboard(dashboard_key);
|
||||
|
||||
CREATE INDEX idx_hzb_signal_dashboard_update
|
||||
ON hzb_signal_dashboard(update_time);
|
||||
|
||||
ALTER TABLE hzb_auth_token ADD COLUMN token_audience VARCHAR(32);
|
||||
ALTER TABLE hzb_auth_token ADD COLUMN collector_id VARCHAR(128);
|
||||
ALTER TABLE hzb_auth_token ADD COLUMN allowed_signals VARCHAR(64);
|
||||
CREATE INDEX idx_hzb_auth_token_collector ON hzb_auth_token(collector_id);
|
||||
|
||||
ALTER TABLE hzb_collector ADD COLUMN runtime_config TEXT;
|
||||
|
||||
ALTER TABLE hzb_collector ADD COLUMN instrumentation_intake TEXT;
|
||||
|
||||
ALTER TABLE hzb_config ADD COLUMN config_revision VARCHAR(36);
|
||||
UPDATE hzb_config SET config_revision = gen_random_uuid()::text WHERE config_revision IS NULL;
|
||||
ALTER TABLE hzb_config ALTER COLUMN config_revision SET NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hzb_account (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password_hash VARCHAR(100) NOT NULL,
|
||||
roles VARCHAR(128) NOT NULL,
|
||||
credential_version BIGINT NOT NULL,
|
||||
disabled BOOLEAN NOT NULL,
|
||||
bootstrap_slot SMALLINT,
|
||||
CONSTRAINT uk_hzb_account_username UNIQUE (username),
|
||||
CONSTRAINT uk_hzb_account_bootstrap UNIQUE (bootstrap_slot)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS hzb_installation (
|
||||
id SMALLINT PRIMARY KEY,
|
||||
installation_fingerprint VARCHAR(64) NOT NULL UNIQUE,
|
||||
complete BOOLEAN NOT NULL
|
||||
);
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
||||
-- or more contributor license agreements. See the NOTICE file
|
||||
-- distributed with this work for additional information
|
||||
-- regarding copyright ownership. The ASF licenses this file
|
||||
-- to you under the Apache License, Version 2.0 (the
|
||||
-- "License"); you may not use this file except in compliance
|
||||
-- with the License. You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing,
|
||||
-- software distributed under the License is distributed on an
|
||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
-- KIND, either express or implied. See the License for the
|
||||
-- specific language governing permissions and limitations
|
||||
-- under the License.
|
||||
|
||||
ALTER TABLE hzb_sop_schedule ALTER COLUMN enabled DROP DEFAULT;
|
||||
ALTER TABLE hzb_sop_schedule ALTER COLUMN enabled TYPE BOOLEAN USING enabled <> 0;
|
||||
ALTER TABLE hzb_sop_schedule ALTER COLUMN enabled SET DEFAULT TRUE;
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import org.flywaydb.core.Flyway;
|
||||
|
||||
/** Rebuilds the current schema from an independent V159 fixture and the committed migrations. */
|
||||
final class HistoricalMetadataSchema {
|
||||
|
||||
private static final String FIXTURE = "V159__schema.sql";
|
||||
|
||||
private HistoricalMetadataSchema() {
|
||||
}
|
||||
|
||||
static void rebuild(String jdbcUrl, String username, String password, String vendor)
|
||||
throws SQLException, IOException {
|
||||
Flyway.configure()
|
||||
.dataSource(jdbcUrl, username, password)
|
||||
.locations("classpath:db/migration/" + vendor)
|
||||
.cleanDisabled(false)
|
||||
.load()
|
||||
.clean();
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
|
||||
executeFixture(connection, resource(vendor));
|
||||
}
|
||||
Flyway flyway = Flyway.configure()
|
||||
.dataSource(jdbcUrl, username, password)
|
||||
.locations("classpath:db/migration/" + vendor)
|
||||
.baselineVersion("159")
|
||||
.baselineOnMigrate(true)
|
||||
.cleanDisabled(true)
|
||||
.target("206")
|
||||
.validateMigrationNaming(true)
|
||||
.load();
|
||||
flyway.migrate();
|
||||
flyway.validate();
|
||||
}
|
||||
|
||||
private static void executeFixture(Connection connection, String fixture) throws SQLException {
|
||||
String executable = fixture.replaceAll("(?m)^--.*$", "");
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
for (String sql : executable.split(";")) {
|
||||
if (!sql.isBlank()) {
|
||||
statement.execute(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String resource(String vendor) throws IOException {
|
||||
String path = "/db/historical/" + vendor + '/' + FIXTURE;
|
||||
try (InputStream input = HistoricalMetadataSchema.class.getResourceAsStream(path)) {
|
||||
if (input == null) {
|
||||
throw new IOException("Historical schema fixture is missing: " + path);
|
||||
}
|
||||
return new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Normalized JDBC metadata used to compare two schemas on the same database vendor. */
|
||||
record MetadataSchemaSnapshot(
|
||||
Set<Column> columns,
|
||||
Set<PrimaryKey> primaryKeys,
|
||||
Set<Index> indexes,
|
||||
Set<ForeignKey> foreignKeys) {
|
||||
|
||||
static MetadataSchemaSnapshot capture(Connection connection) throws SQLException {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
Set<String> tables = tables(connection, metadata);
|
||||
Set<Column> columns = new HashSet<>();
|
||||
Set<PrimaryKey> primaryKeys = new HashSet<>();
|
||||
Set<Index> indexes = new HashSet<>();
|
||||
Set<ForeignKey> foreignKeys = new HashSet<>();
|
||||
for (String table : tables) {
|
||||
readColumns(connection, metadata, table, columns);
|
||||
readPrimaryKeys(connection, metadata, table, primaryKeys);
|
||||
readIndexes(connection, metadata, table, indexes);
|
||||
readForeignKeys(connection, metadata, table, foreignKeys);
|
||||
}
|
||||
return new MetadataSchemaSnapshot(columns, primaryKeys, indexes, foreignKeys);
|
||||
}
|
||||
|
||||
private static Set<String> tables(Connection connection, DatabaseMetaData metadata) throws SQLException {
|
||||
Set<String> tables = new HashSet<>();
|
||||
try (ResultSet result = metadata.getTables(connection.getCatalog(), null, "hzb_%", new String[]{"TABLE"})) {
|
||||
while (result.next()) {
|
||||
tables.add(normalize(result.getString("TABLE_NAME")));
|
||||
}
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static void readColumns(
|
||||
Connection connection, DatabaseMetaData metadata, String table, Set<Column> columns) throws SQLException {
|
||||
try (ResultSet result = metadata.getColumns(connection.getCatalog(), null, table, null)) {
|
||||
while (result.next()) {
|
||||
columns.add(new Column(
|
||||
table,
|
||||
normalize(result.getString("COLUMN_NAME")),
|
||||
result.getInt("DATA_TYPE"),
|
||||
normalize(result.getString("TYPE_NAME")),
|
||||
result.getInt("COLUMN_SIZE"),
|
||||
result.getInt("DECIMAL_DIGITS"),
|
||||
result.getInt("NULLABLE"),
|
||||
normalize(result.getString("COLUMN_DEF")),
|
||||
normalize(result.getString("REMARKS")),
|
||||
result.getInt("ORDINAL_POSITION")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readPrimaryKeys(
|
||||
Connection connection, DatabaseMetaData metadata, String table, Set<PrimaryKey> primaryKeys)
|
||||
throws SQLException {
|
||||
try (ResultSet result = metadata.getPrimaryKeys(connection.getCatalog(), null, table)) {
|
||||
while (result.next()) {
|
||||
primaryKeys.add(new PrimaryKey(
|
||||
table,
|
||||
normalize(result.getString("PK_NAME")),
|
||||
result.getShort("KEY_SEQ"),
|
||||
normalize(result.getString("COLUMN_NAME"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readIndexes(
|
||||
Connection connection, DatabaseMetaData metadata, String table, Set<Index> indexes) throws SQLException {
|
||||
Map<String, IndexAccumulator> collected = new HashMap<>();
|
||||
try (ResultSet result = metadata.getIndexInfo(connection.getCatalog(), null, table, false, false)) {
|
||||
while (result.next()) {
|
||||
String name = normalize(result.getString("INDEX_NAME"));
|
||||
String column = normalize(result.getString("COLUMN_NAME"));
|
||||
if (name == null || column == null || result.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) {
|
||||
continue;
|
||||
}
|
||||
String key = name + ':' + result.getBoolean("NON_UNIQUE");
|
||||
collected.computeIfAbsent(key,
|
||||
ignored -> new IndexAccumulator(table, name, !resultBoolean(result, "NON_UNIQUE")))
|
||||
.add(resultShort(result, "ORDINAL_POSITION"), column, normalize(resultString(result, "ASC_OR_DESC")));
|
||||
}
|
||||
}
|
||||
collected.values().stream().map(IndexAccumulator::build).forEach(indexes::add);
|
||||
}
|
||||
|
||||
private static void readForeignKeys(
|
||||
Connection connection, DatabaseMetaData metadata, String table, Set<ForeignKey> foreignKeys)
|
||||
throws SQLException {
|
||||
try (ResultSet result = metadata.getImportedKeys(connection.getCatalog(), null, table)) {
|
||||
while (result.next()) {
|
||||
foreignKeys.add(new ForeignKey(
|
||||
table,
|
||||
normalize(result.getString("FK_NAME")),
|
||||
result.getShort("KEY_SEQ"),
|
||||
normalize(result.getString("FKCOLUMN_NAME")),
|
||||
normalize(result.getString("PKTABLE_NAME")),
|
||||
normalize(result.getString("PKCOLUMN_NAME")),
|
||||
result.getShort("UPDATE_RULE"),
|
||||
result.getShort("DELETE_RULE"),
|
||||
result.getShort("DEFERRABILITY")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean resultBoolean(ResultSet result, String column) {
|
||||
try {
|
||||
return result.getBoolean(column);
|
||||
} catch (SQLException exception) {
|
||||
throw new IllegalStateException("JDBC metadata result is incomplete", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static short resultShort(ResultSet result, String column) {
|
||||
try {
|
||||
return result.getShort(column);
|
||||
} catch (SQLException exception) {
|
||||
throw new IllegalStateException("JDBC metadata result is incomplete", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static String resultString(ResultSet result, String column) {
|
||||
try {
|
||||
return result.getString(column);
|
||||
} catch (SQLException exception) {
|
||||
throw new IllegalStateException("JDBC metadata result is incomplete", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
return value == null ? null : value.toLowerCase(Locale.ROOT).replaceAll("\\s+", " ").trim();
|
||||
}
|
||||
|
||||
record Column(
|
||||
String table,
|
||||
String name,
|
||||
int jdbcType,
|
||||
String typeName,
|
||||
int size,
|
||||
int scale,
|
||||
int nullable,
|
||||
String defaultValue,
|
||||
String remarks,
|
||||
int position) {
|
||||
}
|
||||
|
||||
record PrimaryKey(String table, String name, short position, String column) {
|
||||
}
|
||||
|
||||
record Index(String table, String name, boolean unique, List<IndexColumn> columns) {
|
||||
}
|
||||
|
||||
record IndexColumn(short position, String name, String order) {
|
||||
}
|
||||
|
||||
record ForeignKey(
|
||||
String table,
|
||||
String name,
|
||||
short position,
|
||||
String column,
|
||||
String referencedTable,
|
||||
String referencedColumn,
|
||||
short updateRule,
|
||||
short deleteRule,
|
||||
short deferrability) {
|
||||
}
|
||||
|
||||
private static final class IndexAccumulator {
|
||||
private final String table;
|
||||
private final String name;
|
||||
private final boolean unique;
|
||||
private final List<IndexColumn> columns = new ArrayList<>();
|
||||
|
||||
private IndexAccumulator(String table, String name, boolean unique) {
|
||||
this.table = table;
|
||||
this.name = name;
|
||||
this.unique = unique;
|
||||
}
|
||||
|
||||
void add(short position, String column, String order) {
|
||||
columns.add(new IndexColumn(position, column, order));
|
||||
}
|
||||
|
||||
Index build() {
|
||||
columns.sort(java.util.Comparator.comparingInt(IndexColumn::position));
|
||||
return new Index(table, name, unique, List.copyOf(columns));
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import java.sql.Types;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
|
||||
/** Keeps schema validation compatible with boolean encodings used by the committed MySQL migrations. */
|
||||
public final class MetadataValidationMySqlDialect extends MySQLDialect {
|
||||
|
||||
@Override
|
||||
public boolean equivalentTypes(int firstTypeCode, int secondTypeCode) {
|
||||
if (isBooleanType(firstTypeCode) && isBooleanType(secondTypeCode)) {
|
||||
return true;
|
||||
}
|
||||
return super.equivalentTypes(firstTypeCode, secondTypeCode);
|
||||
}
|
||||
|
||||
private static boolean isBooleanType(int typeCode) {
|
||||
return typeCode == Types.BIT || typeCode == Types.BOOLEAN || typeCode == Types.TINYINT;
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
|
||||
/** Static schema contract for provisioning an empty external metadata database. */
|
||||
class TargetSchemaBaselineResourceTest {
|
||||
|
||||
private static final Pattern CREATE_TABLE = Pattern.compile(
|
||||
"(?im)^\\s*create\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?([a-z][a-z0-9_]*)\\s*\\(");
|
||||
private static final Set<String> MAPPED_TABLES = Set.of(
|
||||
"hzb_account",
|
||||
"hzb_ai_conversation",
|
||||
"hzb_ai_message",
|
||||
"hzb_alert_define",
|
||||
"hzb_alert_define_monitor_bind",
|
||||
"hzb_alert_group",
|
||||
"hzb_alert_group_converge",
|
||||
"hzb_alert_inhibit",
|
||||
"hzb_alert_silence",
|
||||
"hzb_alert_single",
|
||||
"hzb_auth_token",
|
||||
"hzb_bulletin",
|
||||
"hzb_collector",
|
||||
"hzb_collector_monitor_bind",
|
||||
"hzb_config",
|
||||
"hzb_define",
|
||||
"hzb_entity",
|
||||
"hzb_entity_definition_activity",
|
||||
"hzb_entity_governance_state",
|
||||
"hzb_entity_identity",
|
||||
"hzb_entity_monitor_bind",
|
||||
"hzb_entity_relation",
|
||||
"hzb_grafana_dashboard",
|
||||
"hzb_history",
|
||||
"hzb_installation",
|
||||
"hzb_metrics_favorite",
|
||||
"hzb_monitor",
|
||||
"hzb_monitor_bind",
|
||||
"hzb_notice_receiver",
|
||||
"hzb_notice_rule",
|
||||
"hzb_notice_template",
|
||||
"hzb_param",
|
||||
"hzb_param_define",
|
||||
"hzb_plugin_item",
|
||||
"hzb_plugin_metadata",
|
||||
"hzb_plugin_param",
|
||||
"hzb_push_metrics",
|
||||
"hzb_signal_dashboard",
|
||||
"hzb_signal_dashboard_panel_draft",
|
||||
"hzb_signal_saved_view",
|
||||
"hzb_sop_schedule",
|
||||
"hzb_status_page_component",
|
||||
"hzb_status_page_history",
|
||||
"hzb_status_page_incident",
|
||||
"hzb_status_page_incident_component_bind",
|
||||
"hzb_status_page_incident_content",
|
||||
"hzb_status_page_org",
|
||||
"hzb_tag");
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"mysql", "postgresql"})
|
||||
void currentBaselineDeclaresEveryMappedTable(String vendor) throws IOException {
|
||||
String resource = "db/migration/" + vendor + "/B206__current_schema.sql";
|
||||
try (InputStream input = getClass().getClassLoader().getResourceAsStream(resource)) {
|
||||
assertThat(input).as(resource).isNotNull();
|
||||
assertThat(createdTables(new String(input.readAllBytes(), StandardCharsets.UTF_8)))
|
||||
.containsExactlyInAnyOrderElementsOf(MAPPED_TABLES);
|
||||
}
|
||||
MetadataDatabaseKind kind = vendor.equals("mysql")
|
||||
? MetadataDatabaseKind.MYSQL : MetadataDatabaseKind.POSTGRESQL;
|
||||
assertThat(TargetSchemaBaseline.load(kind).expectedTables())
|
||||
.containsExactlyInAnyOrderElementsOf(MAPPED_TABLES);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"mysql", "postgresql"})
|
||||
void historicalFixtureDeclaresImmutableV159Provenance(String vendor) throws IOException {
|
||||
String resource = "db/historical/" + vendor + "/V159__schema.sql";
|
||||
try (InputStream input = getClass().getClassLoader().getResourceAsStream(resource)) {
|
||||
assertThat(input).as(resource).isNotNull();
|
||||
String sql = new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertThat(sql)
|
||||
.contains("Immutable V159 schema fixture for migration-chain tests.")
|
||||
.contains("Do not derive this fixture from the current baseline or later migrations.")
|
||||
.doesNotContain("Static V205 schema baseline", "Future versioned migrations start at V206");
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<String> createdTables(String sql) {
|
||||
Matcher matcher = CREATE_TABLE.matcher(sql.toLowerCase(Locale.ROOT));
|
||||
Set<String> tables = new HashSet<>();
|
||||
while (matcher.find()) {
|
||||
tables.add(matcher.group(1));
|
||||
}
|
||||
return Set.copyOf(tables);
|
||||
}
|
||||
|
||||
static Set<String> mappedTables() {
|
||||
return MAPPED_TABLES;
|
||||
}
|
||||
}
|
||||
+481
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import jakarta.persistence.Entity;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseConfiguration;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.testcontainers.mysql.MySQLContainer;
|
||||
import org.testcontainers.postgresql.PostgreSQLContainer;
|
||||
|
||||
/** Real-database proof for current-version target schema provisioning. */
|
||||
@EnabledIfSystemProperty(named = "hertzbeat.test.database-containers", matches = "true")
|
||||
class TargetSchemaProvisionerDatabaseTest {
|
||||
|
||||
private static final String DATABASE = "hertzbeat";
|
||||
private static final String USERNAME = "hertzbeat";
|
||||
private static final String PASSWORD = "test-only-password";
|
||||
|
||||
@Test
|
||||
void provisionsAndValidatesFreshMysqlSchema() throws Exception {
|
||||
try (MySQLContainer database = new MySQLContainer("mysql:8.4")
|
||||
.withDatabaseName(DATABASE)
|
||||
.withUsername(USERNAME)
|
||||
.withPassword(PASSWORD)
|
||||
.withCommand("--lower-case-table-names=1")) {
|
||||
database.start();
|
||||
assertRejectsFalseEmptyStates(database.getJdbcUrl(), MetadataDatabaseKind.MYSQL);
|
||||
verify(database.getJdbcUrl(), MetadataDatabaseKind.MYSQL,
|
||||
MetadataValidationMySqlDialect.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void provisionsAndValidatesFreshPostgresqlSchema() throws Exception {
|
||||
try (PostgreSQLContainer database = new PostgreSQLContainer("postgres:17.6")
|
||||
.withDatabaseName(DATABASE)
|
||||
.withUsername(USERNAME)
|
||||
.withPassword(PASSWORD)) {
|
||||
database.start();
|
||||
assertRejectsFalseEmptyStates(database.getJdbcUrl(), MetadataDatabaseKind.POSTGRESQL);
|
||||
verify(database.getJdbcUrl(), MetadataDatabaseKind.POSTGRESQL,
|
||||
"org.hibernate.dialect.PostgreSQLDialect");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertRejectsFalseEmptyStates(String jdbcUrl, MetadataDatabaseKind kind) throws Exception {
|
||||
TargetSchemaProvisioner provisioner = new FlywayTargetSchemaProvisioner();
|
||||
MetadataDatabaseConfiguration target =
|
||||
new MetadataDatabaseConfiguration(kind, jdbcUrl, USERNAME, PASSWORD);
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD)) {
|
||||
TargetSchemaBaseline baseline = TargetSchemaBaseline.load(kind);
|
||||
new FlywaySchemaHistory(kind).record(connection, baseline, USERNAME, 0);
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE TABLE hzb_account (id INTEGER NOT NULL PRIMARY KEY)");
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
softly.assertThat(metadataTables(connection)).containsExactly("hzb_account");
|
||||
statement.execute("DROP TABLE hzb_account");
|
||||
statement.execute("DROP TABLE flyway_schema_history");
|
||||
statement.execute("DROP TABLE flyway_schema_contract");
|
||||
statement.execute("CREATE TABLE unrelated_table (id INTEGER NOT NULL PRIMARY KEY)");
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
softly.assertThat(metadataTables(connection)).isEmpty();
|
||||
statement.execute("DROP TABLE unrelated_table");
|
||||
statement.execute("CREATE VIEW hzb_status_page_org AS SELECT 1 AS id");
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
softly.assertThat(metadataTables(connection)).isEmpty();
|
||||
statement.execute("DROP VIEW hzb_status_page_org");
|
||||
}
|
||||
assertRejectsPostgresqlObjects(jdbcUrl, kind, provisioner, target, softly);
|
||||
assertRejectsContractWithoutHistory(jdbcUrl, kind, provisioner, target, softly);
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
private static void assertRejectsContractWithoutHistory(
|
||||
String jdbcUrl,
|
||||
MetadataDatabaseKind kind,
|
||||
TargetSchemaProvisioner provisioner,
|
||||
MetadataDatabaseConfiguration target,
|
||||
SoftAssertions softly) throws Exception {
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD)) {
|
||||
new TargetSchemaContract(kind).record(connection, Set.of());
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute("DROP TABLE flyway_schema_contract");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertRejectsPostgresqlObjects(
|
||||
String jdbcUrl,
|
||||
MetadataDatabaseKind kind,
|
||||
TargetSchemaProvisioner provisioner,
|
||||
MetadataDatabaseConfiguration target,
|
||||
SoftAssertions softly) throws Exception {
|
||||
if (kind != MetadataDatabaseKind.POSTGRESQL) {
|
||||
return;
|
||||
}
|
||||
assertRejectsObject(jdbcUrl, provisioner, target, softly,
|
||||
"CREATE MATERIALIZED VIEW hzb_schema_probe AS SELECT 1 AS id",
|
||||
"DROP MATERIALIZED VIEW hzb_schema_probe");
|
||||
assertRejectsObject(jdbcUrl, provisioner, target, softly,
|
||||
"CREATE SEQUENCE hzb_schema_probe_sequence",
|
||||
"DROP SEQUENCE hzb_schema_probe_sequence");
|
||||
}
|
||||
|
||||
private static void assertRejectsObject(
|
||||
String jdbcUrl,
|
||||
TargetSchemaProvisioner provisioner,
|
||||
MetadataDatabaseConfiguration target,
|
||||
SoftAssertions softly,
|
||||
String createSql,
|
||||
String dropSql) throws Exception {
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute(createSql);
|
||||
}
|
||||
softly.assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
softly.assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute(dropSql);
|
||||
}
|
||||
}
|
||||
|
||||
private static void verify(String jdbcUrl, MetadataDatabaseKind kind, String dialect) throws Exception {
|
||||
MetadataDatabaseConfiguration target =
|
||||
new MetadataDatabaseConfiguration(kind, jdbcUrl, USERNAME, PASSWORD);
|
||||
TargetSchemaProvisioner provisioner = new FlywayTargetSchemaProvisioner();
|
||||
assertProvisioningLogsAreSanitized(provisioner, target);
|
||||
assertCurrentBaselineAllowsAdditionalTable(provisioner, target);
|
||||
assertCurrentBaselineRejectsSchemaCorruption(provisioner, target);
|
||||
|
||||
MetadataSchemaSnapshot baseline;
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD)) {
|
||||
assertThat(metadataTables(connection)).containsExactlyInAnyOrderElementsOf(
|
||||
TargetSchemaBaselineResourceTest.mappedTables());
|
||||
try (Statement statement = connection.createStatement();
|
||||
ResultSet history = statement.executeQuery(
|
||||
"SELECT version, type, success FROM flyway_schema_history ORDER BY installed_rank")) {
|
||||
assertThat(history.next()).isTrue();
|
||||
assertThat(history.getString("version")).isEqualTo("206");
|
||||
assertThat(history.getString("type")).isEqualTo("SQL_BASELINE");
|
||||
assertThat(history.getBoolean("success")).isTrue();
|
||||
assertThat(history.next()).isFalse();
|
||||
}
|
||||
baseline = MetadataSchemaSnapshot.capture(connection);
|
||||
}
|
||||
assertStandardFlywayAcceptsBaseline(jdbcUrl, kind);
|
||||
validateHibernateMappings(jdbcUrl, dialect);
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD)) {
|
||||
replaceEarlyMigrationIndexWithIncorrectDefinition(connection, kind);
|
||||
}
|
||||
HistoricalMetadataSchema.rebuild(jdbcUrl, USERNAME, PASSWORD, kind.value());
|
||||
assertThat(historyRows(jdbcUrl))
|
||||
.extracting(HistoryRow::version)
|
||||
.containsExactly("159", "160", "170", "172", "173", "180", "181",
|
||||
"200", "201", "202", "203", "204", "205", "206");
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD)) {
|
||||
MetadataSchemaSnapshot migrated = MetadataSchemaSnapshot.capture(connection);
|
||||
assertThat(migrated.indexes())
|
||||
.filteredOn(index -> index.table().equals("hzb_monitor")
|
||||
&& index.name().equals("idx_hzb_monitor_app"))
|
||||
.singleElement()
|
||||
.extracting(MetadataSchemaSnapshot.Index::columns)
|
||||
.isEqualTo(List.of(new MetadataSchemaSnapshot.IndexColumn((short) 1, "app", "a")));
|
||||
assertThat(schemaDifferences(baseline, migrated)).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> schemaDifferences(
|
||||
MetadataSchemaSnapshot baseline, MetadataSchemaSnapshot migrated) {
|
||||
List<String> differences = new ArrayList<>();
|
||||
addDifferences(differences, "column", baseline.columns(), migrated.columns());
|
||||
addDifferences(differences, "primary key", baseline.primaryKeys(), migrated.primaryKeys());
|
||||
addDifferences(differences, "index", baseline.indexes(), migrated.indexes());
|
||||
addDifferences(differences, "foreign key", baseline.foreignKeys(), migrated.foreignKeys());
|
||||
return List.copyOf(differences);
|
||||
}
|
||||
|
||||
private static void addDifferences(
|
||||
List<String> differences, String kind, Set<?> baseline, Set<?> migrated) {
|
||||
baseline.stream()
|
||||
.filter(value -> !migrated.contains(value))
|
||||
.map(value -> "baseline-only " + kind + ": " + value)
|
||||
.forEach(differences::add);
|
||||
migrated.stream()
|
||||
.filter(value -> !baseline.contains(value))
|
||||
.map(value -> "migration-only " + kind + ": " + value)
|
||||
.forEach(differences::add);
|
||||
}
|
||||
|
||||
private static void replaceEarlyMigrationIndexWithIncorrectDefinition(
|
||||
Connection connection, MetadataDatabaseKind kind) throws Exception {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
if (kind == MetadataDatabaseKind.MYSQL) {
|
||||
statement.execute("DROP INDEX idx_hzb_monitor_app ON hzb_monitor");
|
||||
} else {
|
||||
statement.execute("DROP INDEX idx_hzb_monitor_app");
|
||||
}
|
||||
statement.execute("CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(name)");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertCurrentBaselineAllowsAdditionalTable(
|
||||
TargetSchemaProvisioner provisioner, MetadataDatabaseConfiguration target) throws Exception {
|
||||
try (Connection connection = DriverManager.getConnection(
|
||||
target.jdbcUrl(), target.username(), target.password());
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE TABLE unrelated_table (id INTEGER NOT NULL PRIMARY KEY)");
|
||||
try {
|
||||
provisioner.provision(target);
|
||||
} finally {
|
||||
statement.execute("DROP TABLE unrelated_table");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertCurrentBaselineRejectsSchemaCorruption(
|
||||
TargetSchemaProvisioner provisioner, MetadataDatabaseConfiguration target) throws Exception {
|
||||
assertCorruptionRejected(provisioner, target,
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_account MODIFY COLUMN username VARCHAR(63) NOT NULL"
|
||||
: "ALTER TABLE hzb_account ALTER COLUMN username TYPE VARCHAR(63)",
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_account MODIFY COLUMN username VARCHAR(64) NOT NULL"
|
||||
: "ALTER TABLE hzb_account ALTER COLUMN username TYPE VARCHAR(64)");
|
||||
assertCorruptionRejected(provisioner, target,
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_account MODIFY COLUMN credential_version INTEGER NOT NULL"
|
||||
: "ALTER TABLE hzb_account ALTER COLUMN credential_version TYPE INTEGER",
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_account MODIFY COLUMN credential_version BIGINT NOT NULL"
|
||||
: "ALTER TABLE hzb_account ALTER COLUMN credential_version TYPE BIGINT");
|
||||
assertCorruptionRejected(provisioner, target,
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "DROP INDEX idx_hzb_monitor_app ON hzb_monitor"
|
||||
: "DROP INDEX idx_hzb_monitor_app",
|
||||
"CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(app)");
|
||||
assertCorruptionRejected(provisioner, target,
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_ai_message DROP FOREIGN KEY fk_hzb_ai_message_conversation"
|
||||
: "ALTER TABLE hzb_ai_message DROP CONSTRAINT fk_hzb_ai_message_conversation",
|
||||
"ALTER TABLE hzb_ai_message ADD CONSTRAINT fk_hzb_ai_message_conversation "
|
||||
+ "FOREIGN KEY (conversation_id) REFERENCES hzb_ai_conversation(id)");
|
||||
assertCorruptionRejected(provisioner, target,
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_ai_message DROP FOREIGN KEY fk_hzb_ai_message_conversation, "
|
||||
+ "ADD CONSTRAINT fk_hzb_ai_message_conversation_cascade "
|
||||
+ "FOREIGN KEY (conversation_id) "
|
||||
+ "REFERENCES hzb_ai_conversation(id) ON DELETE CASCADE"
|
||||
: "ALTER TABLE hzb_ai_message DROP CONSTRAINT fk_hzb_ai_message_conversation, "
|
||||
+ "ADD CONSTRAINT fk_hzb_ai_message_conversation_cascade "
|
||||
+ "FOREIGN KEY (conversation_id) "
|
||||
+ "REFERENCES hzb_ai_conversation(id) ON DELETE CASCADE",
|
||||
target.kind() == MetadataDatabaseKind.MYSQL
|
||||
? "ALTER TABLE hzb_ai_message "
|
||||
+ "DROP FOREIGN KEY fk_hzb_ai_message_conversation_cascade, "
|
||||
+ "ADD CONSTRAINT fk_hzb_ai_message_conversation FOREIGN KEY (conversation_id) "
|
||||
+ "REFERENCES hzb_ai_conversation(id)"
|
||||
: "ALTER TABLE hzb_ai_message "
|
||||
+ "DROP CONSTRAINT fk_hzb_ai_message_conversation_cascade, "
|
||||
+ "ADD CONSTRAINT fk_hzb_ai_message_conversation FOREIGN KEY (conversation_id) "
|
||||
+ "REFERENCES hzb_ai_conversation(id)");
|
||||
}
|
||||
|
||||
private static void assertCorruptionRejected(
|
||||
TargetSchemaProvisioner provisioner,
|
||||
MetadataDatabaseConfiguration target,
|
||||
String corruptSql,
|
||||
String restoreSql) throws Exception {
|
||||
try (Connection connection = DriverManager.getConnection(
|
||||
target.jdbcUrl(), target.username(), target.password());
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute(corruptSql);
|
||||
try {
|
||||
assertThatThrownBy(() -> provisioner.provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception ->
|
||||
assertThat(exception.failure().phase())
|
||||
.isEqualTo(TargetSchemaProvisioningFailure.Phase.PRECONDITION));
|
||||
} finally {
|
||||
statement.execute(restoreSql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertProvisioningLogsAreSanitized(
|
||||
TargetSchemaProvisioner provisioner, MetadataDatabaseConfiguration target) throws Exception {
|
||||
Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
ListAppender<ILoggingEvent> captured = new ListAppender<>();
|
||||
captured.start();
|
||||
root.addAppender(captured);
|
||||
try {
|
||||
provisioner.provision(target);
|
||||
try (Connection connection = DriverManager.getConnection(
|
||||
target.jdbcUrl(), target.username(), target.password())) {
|
||||
TargetSchemaBaseline baseline = TargetSchemaBaseline.load(target.kind());
|
||||
assertThat(new TargetSchemaContract(target.kind()).matches(connection, baseline.expectedTables()))
|
||||
.isTrue();
|
||||
}
|
||||
provisioner.provision(target);
|
||||
} finally {
|
||||
root.detachAppender(captured);
|
||||
captured.stop();
|
||||
}
|
||||
assertThat(captured.list.stream().map(ILoggingEvent::getFormattedMessage).toList().toString())
|
||||
.doesNotContain(target.jdbcUrl(), target.password(), "CREATE TABLE", "INSERT INTO");
|
||||
}
|
||||
|
||||
private static void assertStandardFlywayAcceptsBaseline(String jdbcUrl, MetadataDatabaseKind kind)
|
||||
throws Exception {
|
||||
List<HistoryRow> before = historyRows(jdbcUrl);
|
||||
String vendor = kind == MetadataDatabaseKind.MYSQL ? "mysql" : "postgresql";
|
||||
Flyway flyway = Flyway.configure()
|
||||
.dataSource(jdbcUrl, USERNAME, PASSWORD)
|
||||
.locations("classpath:db/migration/" + vendor)
|
||||
.cleanDisabled(true)
|
||||
.validateMigrationNaming(true)
|
||||
.load();
|
||||
flyway.validate();
|
||||
flyway.migrate();
|
||||
assertThat(historyRows(jdbcUrl)).isEqualTo(before);
|
||||
}
|
||||
|
||||
private static List<HistoryRow> historyRows(String jdbcUrl) throws Exception {
|
||||
List<HistoryRow> rows = new ArrayList<>();
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, USERNAME, PASSWORD);
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet result = statement.executeQuery(
|
||||
"SELECT installed_rank, version, description, type, script, checksum, "
|
||||
+ "installed_by, installed_on, execution_time, success "
|
||||
+ "FROM flyway_schema_history ORDER BY installed_rank")) {
|
||||
while (result.next()) {
|
||||
rows.add(new HistoryRow(
|
||||
result.getInt("installed_rank"),
|
||||
result.getString("version"),
|
||||
result.getString("description"),
|
||||
result.getString("type"),
|
||||
result.getString("script"),
|
||||
result.getInt("checksum"),
|
||||
result.getString("installed_by"),
|
||||
result.getTimestamp("installed_on").toInstant(),
|
||||
result.getInt("execution_time"),
|
||||
result.getBoolean("success")));
|
||||
}
|
||||
}
|
||||
return List.copyOf(rows);
|
||||
}
|
||||
|
||||
private record HistoryRow(
|
||||
int installedRank,
|
||||
String version,
|
||||
String description,
|
||||
String type,
|
||||
String script,
|
||||
int checksum,
|
||||
String installedBy,
|
||||
java.time.Instant installedOn,
|
||||
int executionTime,
|
||||
boolean success) {
|
||||
}
|
||||
|
||||
private static Set<String> metadataTables(Connection connection) throws Exception {
|
||||
Set<String> tables = new HashSet<>();
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
try (ResultSet result = metadata.getTables(connection.getCatalog(), null, "hzb_%", new String[]{"TABLE"})) {
|
||||
while (result.next()) {
|
||||
tables.add(result.getString("TABLE_NAME").toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static void validateHibernateMappings(String jdbcUrl, String dialect) throws Exception {
|
||||
StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder()
|
||||
.applySetting("jakarta.persistence.jdbc.url", jdbcUrl)
|
||||
.applySetting("jakarta.persistence.jdbc.user", USERNAME)
|
||||
.applySetting("jakarta.persistence.jdbc.password", PASSWORD)
|
||||
.applySetting("hibernate.dialect", dialect)
|
||||
.applySetting("hibernate.physical_naming_strategy",
|
||||
"org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy")
|
||||
.applySetting("hibernate.hbm2ddl.auto", "validate");
|
||||
StandardServiceRegistry registry = registryBuilder.build();
|
||||
try {
|
||||
MetadataSources sources = new MetadataSources(registry);
|
||||
ClassPathScanningCandidateComponentProvider scanner =
|
||||
new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
|
||||
scanner.findCandidateComponents("org.apache.hertzbeat").stream()
|
||||
.map(definition -> definition.getBeanClassName())
|
||||
.map(TargetSchemaProvisionerDatabaseTest::loadClass)
|
||||
.forEach(sources::addAnnotatedClass);
|
||||
try (SessionFactory ignored = sources.buildMetadata().buildSessionFactory()) {
|
||||
assertThat(ignored.getMetamodel().getEntities()).hasSize(48);
|
||||
}
|
||||
} finally {
|
||||
StandardServiceRegistryBuilder.destroy(registry);
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> loadClass(String className) {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException exception) {
|
||||
throw new IllegalStateException("Mapped entity class is unavailable", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.manager.setup.workflow;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.DriverPropertyInfo;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseConfiguration;
|
||||
import org.apache.hertzbeat.manager.setup.api.SetupApiContract.MetadataDatabaseKind;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TargetSchemaProvisionerMetadataFailureTest {
|
||||
|
||||
@Test
|
||||
void metadataProviderFailureIsSanitizedAtProvisioningBoundary() throws Exception {
|
||||
String jdbcUrl = "jdbc:metadata-failure://private.example.test/hertzbeat?password=secret-value";
|
||||
TargetSchemaBaseline baseline = TargetSchemaBaseline.load(MetadataDatabaseKind.MYSQL);
|
||||
Connection connection = currentSchemaConnection(baseline);
|
||||
Driver driver = new TestConnectionDriver(jdbcUrl, connection);
|
||||
DriverManager.registerDriver(driver);
|
||||
try {
|
||||
MetadataDatabaseConfiguration target = new MetadataDatabaseConfiguration(
|
||||
MetadataDatabaseKind.MYSQL, jdbcUrl, "operator", "secret-value");
|
||||
|
||||
assertThatThrownBy(() -> new FlywayTargetSchemaProvisioner().provision(target))
|
||||
.isInstanceOfSatisfying(TargetSchemaProvisioningException.class, exception -> {
|
||||
assertThat(exception.failure()).isEqualTo(new TargetSchemaProvisioningFailure(
|
||||
TargetSchemaProvisioningFailure.Phase.PRECONDITION,
|
||||
TargetSchemaBaseline.VERSION,
|
||||
"58000",
|
||||
777));
|
||||
assertThat(exception).hasNoCause();
|
||||
assertThat(exception.getMessage())
|
||||
.doesNotContain(jdbcUrl, "secret-value", "raw metadata diagnostic");
|
||||
});
|
||||
} finally {
|
||||
DriverManager.deregisterDriver(driver);
|
||||
}
|
||||
}
|
||||
|
||||
private static Connection currentSchemaConnection(TargetSchemaBaseline baseline) throws Exception {
|
||||
Connection connection = mock(Connection.class);
|
||||
DatabaseMetaData metadata = mock(DatabaseMetaData.class);
|
||||
Statement historyStatement = mock(Statement.class);
|
||||
ResultSet tables = tableRows(baseline);
|
||||
ResultSet history = historyRow(baseline);
|
||||
when(connection.getMetaData()).thenReturn(metadata);
|
||||
when(connection.createStatement()).thenReturn(historyStatement);
|
||||
when(metadata.getTables(isNull(), isNull(), anyString(), any(String[].class)))
|
||||
.thenReturn(tables);
|
||||
when(historyStatement.executeQuery(anyString())).thenReturn(history);
|
||||
when(metadata.getColumns(isNull(), isNull(), anyString(), isNull()))
|
||||
.thenThrow(new SQLException("raw metadata diagnostic", "58000", 777));
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static ResultSet tableRows(TargetSchemaBaseline baseline) throws Exception {
|
||||
List<String> tables = new ArrayList<>(baseline.expectedTables());
|
||||
tables.add("flyway_schema_history");
|
||||
tables.add(TargetSchemaContract.TABLE);
|
||||
AtomicInteger row = new AtomicInteger(-1);
|
||||
ResultSet result = mock(ResultSet.class);
|
||||
when(result.next()).thenAnswer(ignored -> row.incrementAndGet() < tables.size());
|
||||
when(result.getString("TABLE_NAME")).thenAnswer(ignored -> tables.get(row.get()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ResultSet historyRow(TargetSchemaBaseline baseline) throws Exception {
|
||||
ResultSet result = mock(ResultSet.class);
|
||||
when(result.next()).thenReturn(true, false);
|
||||
when(result.getInt("installed_rank")).thenReturn(1);
|
||||
when(result.getString("version")).thenReturn(TargetSchemaBaseline.VERSION);
|
||||
when(result.getString("type")).thenReturn(TargetSchemaBaseline.TYPE);
|
||||
when(result.getString("script")).thenReturn(TargetSchemaBaseline.SCRIPT);
|
||||
when(result.getInt("checksum")).thenReturn(baseline.checksum());
|
||||
when(result.getBoolean("success")).thenReturn(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
private record TestConnectionDriver(String acceptedUrl, Connection connection) implements Driver {
|
||||
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) {
|
||||
return acceptsURL(url) ? connection : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsURL(String url) {
|
||||
return acceptedUrl.equals(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
|
||||
return new DriverPropertyInfo[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcCompliant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() {
|
||||
return Logger.getAnonymousLogger();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,593 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
-- contributor license agreements. See the NOTICE file distributed with
|
||||
-- this work for additional information regarding copyright ownership.
|
||||
-- The ASF licenses this file to You under the Apache License, Version 2.0.
|
||||
--
|
||||
-- Immutable V159 schema fixture for migration-chain tests.
|
||||
-- Do not derive this fixture from the current baseline or later migrations.
|
||||
|
||||
create table hzb_ai_conversation (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
title varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_ai_message (
|
||||
conversation_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
role varchar(255),
|
||||
content longtext not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_define (
|
||||
enable bit not null,
|
||||
period integer,
|
||||
times integer,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
app varchar(255),
|
||||
metric varchar(255),
|
||||
field varchar(255),
|
||||
preset bit,
|
||||
priority integer,
|
||||
tags varchar(255),
|
||||
datasource varchar(100),
|
||||
name varchar(100) not null,
|
||||
expr varchar(2048),
|
||||
labels varchar(2048),
|
||||
template varchar(2048),
|
||||
annotations varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_define_monitor_bind (
|
||||
alert_define_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_group (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
common_labels varchar(2048),
|
||||
group_key varchar(2048) character set ascii,
|
||||
group_labels varchar(2048),
|
||||
alert_fingerprints varchar(255),
|
||||
common_annotations varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_group_converge (
|
||||
enable bit,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
group_interval bigint,
|
||||
group_wait bigint,
|
||||
id bigint not null auto_increment,
|
||||
repeat_interval bigint,
|
||||
name varchar(100) not null,
|
||||
group_labels varchar(1024),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_inhibit (
|
||||
enable bit,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(100) not null,
|
||||
equal_labels varchar(2048),
|
||||
source_labels varchar(2048),
|
||||
target_labels varchar(2048),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_silence (
|
||||
enable bit not null,
|
||||
match_all bit not null,
|
||||
times integer,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
period_end datetime(6),
|
||||
period_start datetime(6),
|
||||
name varchar(100) not null,
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_alert_single (
|
||||
trigger_times integer,
|
||||
active_at bigint,
|
||||
end_at bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
start_at bigint,
|
||||
fingerprint varchar(2048) character set ascii,
|
||||
labels varchar(2048),
|
||||
annotations varchar(4096),
|
||||
content varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_bulletin (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
fields varchar(4096),
|
||||
monitor_ids varchar(4096),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_collector (
|
||||
status tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
ip varchar(255) not null,
|
||||
mode varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
version varchar(255),
|
||||
|
||||
primary key (id),
|
||||
check ((status>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_collector_monitor_bind (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
collector varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_config (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
|
||||
content varchar(8192),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255) not null,
|
||||
primary key (type)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_define (
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
app varchar(255) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content longtext,
|
||||
primary key (app)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_grafana_dashboard (
|
||||
enabled bit not null,
|
||||
monitor_id bigint not null,
|
||||
version bigint,
|
||||
folder_uid varchar(255),
|
||||
slug varchar(255),
|
||||
status varchar(255),
|
||||
uid varchar(255),
|
||||
url varchar(255),
|
||||
primary key (monitor_id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_history (
|
||||
dou float(53),
|
||||
int32 integer,
|
||||
metric_type tinyint,
|
||||
id bigint not null auto_increment,
|
||||
time bigint,
|
||||
str varchar(2048),
|
||||
app varchar(255),
|
||||
instance varchar(5000),
|
||||
metric varchar(255),
|
||||
metrics varchar(255),
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_metrics_favorite (
|
||||
create_time datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint not null,
|
||||
creator varchar(255) not null,
|
||||
metrics_name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_monitor (
|
||||
intervals integer,
|
||||
status tinyint not null,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null,
|
||||
job_id bigint,
|
||||
schedule_type varchar(20),
|
||||
app varchar(100),
|
||||
cron_expression varchar(100),
|
||||
host varchar(100),
|
||||
name varchar(100),
|
||||
scrape varchar(100),
|
||||
annotations varchar(4096),
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id),
|
||||
check ((status<=4) and (status>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_monitor_bind (
|
||||
biz_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
creator varchar(255),
|
||||
key_str varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_receiver (
|
||||
agent_id integer,
|
||||
lark_receive_type tinyint,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
smn_ak varchar(22),
|
||||
smn_project_id varchar(32),
|
||||
smn_region varchar(32),
|
||||
smn_sk varchar(42),
|
||||
email varchar(100),
|
||||
name varchar(100) not null,
|
||||
phone varchar(100),
|
||||
access_token varchar(300),
|
||||
discord_bot_token varchar(300),
|
||||
discord_channel_id varchar(300),
|
||||
gotify_token varchar(300),
|
||||
hook_auth_token varchar(300),
|
||||
hook_auth_type varchar(300),
|
||||
server_chan_token varchar(300),
|
||||
slack_web_hook_url varchar(300),
|
||||
smn_topic_urn varchar(300),
|
||||
wechat_id varchar(300),
|
||||
hook_url varchar(1000),
|
||||
app_id varchar(255),
|
||||
app_secret varchar(255),
|
||||
chat_id varchar(255),
|
||||
corp_id varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
party_id varchar(255),
|
||||
tag_id varchar(255),
|
||||
tg_bot_token varchar(255),
|
||||
tg_message_thread_id varchar(255),
|
||||
tg_user_id varchar(255),
|
||||
user_id varchar(255),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_rule (
|
||||
enable bit not null,
|
||||
filter_all bit not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
period_end datetime(6),
|
||||
period_start datetime(6),
|
||||
template_id bigint,
|
||||
name varchar(100) not null,
|
||||
template_name varchar(100),
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
receiver_id varchar(255) not null,
|
||||
receiver_name varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_notice_template (
|
||||
preset boolean default false,
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(100) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content text not null,
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_param (
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_param_define (
|
||||
hide bit not null,
|
||||
param_limit smallint,
|
||||
required bit not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
name varchar(2048),
|
||||
param_options varchar(2048),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
default_value varchar(255),
|
||||
depend varchar(255),
|
||||
field varchar(255),
|
||||
key_alias varchar(255),
|
||||
modifier varchar(255),
|
||||
param_range varchar(255),
|
||||
placeholder varchar(255),
|
||||
type varchar(255),
|
||||
value_alias varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_item (
|
||||
id bigint not null auto_increment,
|
||||
metadata_id bigint,
|
||||
class_identifier varchar(255),
|
||||
type enum ('POST_ALERT','POST_COLLECT'),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_metadata (
|
||||
enable_status bit,
|
||||
param_count integer,
|
||||
gmt_create datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
creator varchar(255),
|
||||
jar_file_path varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_plugin_param (
|
||||
type tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
plugin_metadata_id bigint not null,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
check ((type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_push_metrics (
|
||||
id bigint not null auto_increment,
|
||||
monitor_id bigint,
|
||||
time bigint,
|
||||
metrics varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_component (
|
||||
config_state tinyint not null,
|
||||
method tinyint not null,
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
org_id bigint,
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_history (
|
||||
abnormal integer,
|
||||
normal integer,
|
||||
state tinyint not null,
|
||||
unknowing integer,
|
||||
uptime float(53),
|
||||
component_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident (
|
||||
state tinyint not null,
|
||||
end_time bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
org_id bigint,
|
||||
start_time bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident_component_bind (
|
||||
component_id bigint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
incident_id bigint,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_incident_content (
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
incident_id bigint,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
message varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_status_page_org (
|
||||
state tinyint not null,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
color varchar(255),
|
||||
creator varchar(255),
|
||||
description varchar(255) not null,
|
||||
feedback varchar(255),
|
||||
home varchar(255) not null,
|
||||
logo varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table hzb_tag (
|
||||
type tinyint,
|
||||
gmt_create datetime(6),
|
||||
gmt_update datetime(6),
|
||||
id bigint not null auto_increment,
|
||||
tag_value varchar(2048),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id),
|
||||
check ((type<=3) and (type>=0))
|
||||
) engine=InnoDB;
|
||||
|
||||
|
||||
create index idx_message_conversation_id
|
||||
on hzb_ai_message (conversation_id);
|
||||
|
||||
create index index_alert_define_monitor
|
||||
on hzb_alert_define_monitor_bind (alert_define_id, monitor_id);
|
||||
|
||||
alter table hzb_alert_group
|
||||
add constraint unique_group_key unique (group_key);
|
||||
|
||||
create index idx_name
|
||||
on hzb_alert_group_converge (name);
|
||||
|
||||
alter table hzb_alert_single
|
||||
add constraint unique_fingerprint unique (fingerprint);
|
||||
|
||||
alter table hzb_collector
|
||||
add constraint uk_hzb_collector_name unique (name);
|
||||
|
||||
create index index_collector_monitor
|
||||
on hzb_collector_monitor_bind (collector, monitor_id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
create index history_query_index
|
||||
on hzb_history (monitor_id, app, metrics, metric);
|
||||
|
||||
alter table hzb_metrics_favorite
|
||||
add constraint uk_hzb_metrics_favorite unique (creator, monitor_id, metrics_name);
|
||||
|
||||
create index monitor_query_index
|
||||
on hzb_monitor (app, host, name);
|
||||
|
||||
create index index_monitor_bin
|
||||
on hzb_monitor_bind (monitor_id);
|
||||
|
||||
create index idx_hzb_param_monitor_id
|
||||
on hzb_param (monitor_id);
|
||||
|
||||
alter table hzb_param
|
||||
add constraint uk_hzb_param_monitor_field unique (monitor_id, field);
|
||||
|
||||
create index idx_hzb_plugin_param_plugin_metadata_id
|
||||
on hzb_plugin_param (plugin_metadata_id);
|
||||
|
||||
alter table hzb_plugin_param
|
||||
add constraint uk_hzb_plugin_param_metadata_field unique (plugin_metadata_id, field);
|
||||
|
||||
create index push_query_index
|
||||
on hzb_push_metrics (monitor_id, time);
|
||||
|
||||
create index index_incident_component
|
||||
on hzb_status_page_incident_component_bind (incident_id);
|
||||
|
||||
alter table hzb_ai_message
|
||||
add constraint fk_hzb_ai_message_conversation
|
||||
foreign key (conversation_id)
|
||||
references hzb_ai_conversation (id);
|
||||
|
||||
alter table hzb_plugin_item
|
||||
add constraint fk_hzb_plugin_item_metadata
|
||||
foreign key (metadata_id)
|
||||
references hzb_plugin_metadata (id);
|
||||
|
||||
alter table hzb_status_page_incident_content
|
||||
add constraint fk_hzb_incident_content_incident
|
||||
foreign key (incident_id)
|
||||
references hzb_status_page_incident (id);
|
||||
@@ -0,0 +1,573 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
-- contributor license agreements. See the NOTICE file distributed with
|
||||
-- this work for additional information regarding copyright ownership.
|
||||
-- The ASF licenses this file to You under the Apache License, Version 2.0.
|
||||
--
|
||||
-- Immutable V159 schema fixture for migration-chain tests.
|
||||
-- Do not derive this fixture from the current baseline or later migrations.
|
||||
|
||||
create table hzb_ai_conversation (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
title varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_ai_message (
|
||||
conversation_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
role varchar(255),
|
||||
content oid not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_define (
|
||||
enable boolean not null,
|
||||
period integer,
|
||||
times integer,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
app varchar(255),
|
||||
metric varchar(255),
|
||||
field varchar(255),
|
||||
preset boolean,
|
||||
priority integer,
|
||||
tags varchar(255),
|
||||
datasource varchar(100),
|
||||
name varchar(100) not null,
|
||||
expr varchar(2048),
|
||||
labels varchar(2048),
|
||||
template varchar(2048),
|
||||
annotations varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_define_monitor_bind (
|
||||
alert_define_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_group (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
common_labels varchar(2048),
|
||||
group_key varchar(2048),
|
||||
group_labels varchar(2048),
|
||||
alert_fingerprints varchar(255),
|
||||
common_annotations varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id),
|
||||
constraint unique_group_key unique (group_key)
|
||||
);
|
||||
|
||||
create table hzb_alert_group_converge (
|
||||
enable boolean,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
group_interval bigint,
|
||||
group_wait bigint,
|
||||
id bigint generated by default as identity,
|
||||
repeat_interval bigint,
|
||||
name varchar(100) not null,
|
||||
group_labels varchar(1024),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_inhibit (
|
||||
enable boolean,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(100) not null,
|
||||
equal_labels varchar(2048),
|
||||
source_labels varchar(2048),
|
||||
target_labels varchar(2048),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_silence (
|
||||
enable boolean not null,
|
||||
match_all boolean not null,
|
||||
times integer,
|
||||
type smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
period_end timestamp(6) with time zone,
|
||||
period_start timestamp(6) with time zone,
|
||||
name varchar(100) not null,
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_alert_single (
|
||||
trigger_times integer,
|
||||
active_at bigint,
|
||||
end_at bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
start_at bigint,
|
||||
fingerprint varchar(2048),
|
||||
labels varchar(2048),
|
||||
annotations varchar(4096),
|
||||
content varchar(4096),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
status varchar(255),
|
||||
primary key (id),
|
||||
constraint unique_fingerprint unique (fingerprint)
|
||||
);
|
||||
|
||||
create table hzb_bulletin (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
fields varchar(4096),
|
||||
monitor_ids varchar(4096),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_collector (
|
||||
status smallint not null check ((status>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
ip varchar(255) not null,
|
||||
mode varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
version varchar(255),
|
||||
|
||||
primary key (id),
|
||||
unique (name)
|
||||
);
|
||||
|
||||
create table hzb_collector_monitor_bind (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
collector varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_config (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
|
||||
content varchar(8192),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
type varchar(255) not null,
|
||||
primary key (type)
|
||||
);
|
||||
|
||||
create table hzb_define (
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
app varchar(255) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content oid,
|
||||
primary key (app)
|
||||
);
|
||||
|
||||
create table hzb_grafana_dashboard (
|
||||
enabled boolean not null,
|
||||
monitor_id bigint not null,
|
||||
version bigint,
|
||||
folder_uid varchar(255),
|
||||
slug varchar(255),
|
||||
status varchar(255),
|
||||
uid varchar(255),
|
||||
url varchar(255),
|
||||
primary key (monitor_id)
|
||||
);
|
||||
|
||||
create table hzb_history (
|
||||
dou float(53),
|
||||
int32 integer,
|
||||
metric_type smallint,
|
||||
id bigint generated by default as identity,
|
||||
time bigint,
|
||||
str varchar(2048),
|
||||
app varchar(255),
|
||||
instance varchar(5000),
|
||||
metric varchar(255),
|
||||
metrics varchar(255),
|
||||
monitor_id bigint,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_metrics_favorite (
|
||||
create_time timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint not null,
|
||||
creator varchar(255) not null,
|
||||
metrics_name varchar(255) not null,
|
||||
primary key (id),
|
||||
unique (creator, monitor_id, metrics_name)
|
||||
);
|
||||
|
||||
create table hzb_monitor (
|
||||
intervals integer,
|
||||
status smallint not null check ((status<=4) and (status>=0)),
|
||||
type smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint not null,
|
||||
job_id bigint,
|
||||
schedule_type varchar(20),
|
||||
app varchar(100),
|
||||
cron_expression varchar(100),
|
||||
host varchar(100),
|
||||
name varchar(100),
|
||||
scrape varchar(100),
|
||||
annotations varchar(4096),
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_monitor_bind (
|
||||
biz_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
creator varchar(255),
|
||||
key_str varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_receiver (
|
||||
agent_id integer,
|
||||
lark_receive_type smallint,
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
smn_ak varchar(22),
|
||||
smn_project_id varchar(32),
|
||||
smn_region varchar(32),
|
||||
smn_sk varchar(42),
|
||||
email varchar(100),
|
||||
name varchar(100) not null,
|
||||
phone varchar(100),
|
||||
access_token varchar(300),
|
||||
discord_bot_token varchar(300),
|
||||
discord_channel_id varchar(300),
|
||||
gotify_token varchar(300),
|
||||
hook_auth_token varchar(300),
|
||||
hook_auth_type varchar(300),
|
||||
server_chan_token varchar(300),
|
||||
slack_web_hook_url varchar(300),
|
||||
smn_topic_urn varchar(300),
|
||||
wechat_id varchar(300),
|
||||
hook_url varchar(1000),
|
||||
app_id varchar(255),
|
||||
app_secret varchar(255),
|
||||
chat_id varchar(255),
|
||||
corp_id varchar(255),
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
party_id varchar(255),
|
||||
tag_id varchar(255),
|
||||
tg_bot_token varchar(255),
|
||||
tg_message_thread_id varchar(255),
|
||||
tg_user_id varchar(255),
|
||||
user_id varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_rule (
|
||||
enable boolean not null,
|
||||
filter_all boolean not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
period_end timestamp(6) with time zone,
|
||||
period_start timestamp(6) with time zone,
|
||||
template_id bigint,
|
||||
name varchar(100) not null,
|
||||
template_name varchar(100),
|
||||
labels varchar(2048),
|
||||
creator varchar(255),
|
||||
days varchar(255),
|
||||
modifier varchar(255),
|
||||
receiver_id varchar(255) not null,
|
||||
receiver_name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_notice_template (
|
||||
preset boolean default false,
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(100) not null,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
content oid not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_param (
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
constraint uk_hzb_param_monitor_field unique (monitor_id, field)
|
||||
);
|
||||
|
||||
create table hzb_param_define (
|
||||
hide boolean not null,
|
||||
param_limit smallint,
|
||||
required boolean not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
name varchar(2048),
|
||||
param_options varchar(2048),
|
||||
app varchar(255),
|
||||
creator varchar(255),
|
||||
default_value varchar(255),
|
||||
depend varchar(255),
|
||||
field varchar(255),
|
||||
key_alias varchar(255),
|
||||
modifier varchar(255),
|
||||
param_range varchar(255),
|
||||
placeholder varchar(255),
|
||||
type varchar(255),
|
||||
value_alias varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_item (
|
||||
id bigint generated by default as identity,
|
||||
metadata_id bigint,
|
||||
class_identifier varchar(255),
|
||||
type varchar(255) check ((type in ('POST_ALERT','POST_COLLECT'))),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_metadata (
|
||||
enable_status boolean,
|
||||
param_count integer,
|
||||
gmt_create timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
creator varchar(255),
|
||||
jar_file_path varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_plugin_param (
|
||||
type smallint not null check ((type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
plugin_metadata_id bigint not null,
|
||||
field varchar(100) not null,
|
||||
param_value varchar(8126),
|
||||
primary key (id),
|
||||
constraint uk_hzb_plugin_param_metadata_field unique (plugin_metadata_id, field)
|
||||
);
|
||||
|
||||
create table hzb_push_metrics (
|
||||
id bigint generated by default as identity,
|
||||
monitor_id bigint,
|
||||
time bigint,
|
||||
metrics varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_component (
|
||||
config_state smallint not null,
|
||||
method smallint not null,
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
org_id bigint,
|
||||
labels varchar(4096),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_history (
|
||||
abnormal integer,
|
||||
normal integer,
|
||||
state smallint not null,
|
||||
unknowing integer,
|
||||
uptime float(53),
|
||||
component_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident (
|
||||
state smallint not null,
|
||||
end_time bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
org_id bigint,
|
||||
start_time bigint,
|
||||
creator varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident_component_bind (
|
||||
component_id bigint,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
incident_id bigint,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_incident_content (
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
incident_id bigint,
|
||||
timestamp bigint,
|
||||
creator varchar(255),
|
||||
message varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_status_page_org (
|
||||
state smallint not null,
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
color varchar(255),
|
||||
creator varchar(255),
|
||||
description varchar(255) not null,
|
||||
feedback varchar(255),
|
||||
home varchar(255) not null,
|
||||
logo varchar(255) not null,
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hzb_tag (
|
||||
type smallint check ((type<=3) and (type>=0)),
|
||||
gmt_create timestamp(6),
|
||||
gmt_update timestamp(6),
|
||||
id bigint generated by default as identity,
|
||||
tag_value varchar(2048),
|
||||
creator varchar(255),
|
||||
description varchar(255),
|
||||
modifier varchar(255),
|
||||
name varchar(255) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create index idx_message_conversation_id
|
||||
on hzb_ai_message (conversation_id);
|
||||
|
||||
create index index_alert_define_monitor
|
||||
on hzb_alert_define_monitor_bind (alert_define_id, monitor_id);
|
||||
|
||||
create index idx_name
|
||||
on hzb_alert_group_converge (name);
|
||||
|
||||
create index index_collector_monitor
|
||||
on hzb_collector_monitor_bind (collector, monitor_id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
create index history_query_index
|
||||
on hzb_history (monitor_id, app, metrics, metric);
|
||||
|
||||
create index monitor_query_index
|
||||
on hzb_monitor (app, host, name);
|
||||
|
||||
create index index_monitor_bin
|
||||
on hzb_monitor_bind (monitor_id);
|
||||
|
||||
create index idx_hzb_param_monitor_id
|
||||
on hzb_param (monitor_id);
|
||||
|
||||
create index idx_hzb_plugin_param_plugin_metadata_id
|
||||
on hzb_plugin_param (plugin_metadata_id);
|
||||
|
||||
create index push_query_index
|
||||
on hzb_push_metrics (monitor_id, time);
|
||||
|
||||
create index index_incident_component
|
||||
on hzb_status_page_incident_component_bind (incident_id);
|
||||
|
||||
alter table if exists hzb_ai_message
|
||||
add constraint fk_hzb_ai_message_conversation
|
||||
foreign key (conversation_id)
|
||||
references hzb_ai_conversation;
|
||||
|
||||
alter table if exists hzb_plugin_item
|
||||
add constraint fk_hzb_plugin_item_metadata
|
||||
foreign key (metadata_id)
|
||||
references hzb_plugin_metadata;
|
||||
|
||||
alter table if exists hzb_status_page_incident_content
|
||||
add constraint fk_hzb_incident_content_incident
|
||||
foreign key (incident_id)
|
||||
references hzb_status_page_incident;
|
||||
Reference in New Issue
Block a user