chore: import upstream snapshot with attribution
MCP Bash Server CI / Test MCP Bash Server (dev) (push) Has been cancelled
MCP Bash Server CI / Test MCP Bash Server (release) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:11:39 +08:00
commit c8cebdfeee
4654 changed files with 626756 additions and 0 deletions
@@ -0,0 +1,41 @@
/*
* 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.startup;
import org.apache.hertzbeat.common.config.VirtualThreadProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
/**
* Dedicated {@code @Async} executor configuration.
*/
@Configuration(proxyBeanMethods = false)
public class AsyncConfig {
@Bean(name = "taskExecutor", destroyMethod = "close")
public SimpleAsyncTaskExecutor taskExecutor(VirtualThreadProperties virtualThreadProperties) {
VirtualThreadProperties.AsyncProperties asyncProperties = virtualThreadProperties.async();
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("async-worker-");
executor.setVirtualThreads(virtualThreadProperties.enabled() && asyncProperties.enabled());
executor.setConcurrencyLimit(asyncProperties.concurrencyLimit());
executor.setRejectTasksWhenLimitReached(asyncProperties.rejectWhenLimitReached());
executor.setTaskTerminationTimeout(asyncProperties.taskTerminationTimeout());
return executor;
}
}
@@ -0,0 +1,57 @@
/*
* 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.startup;
import jakarta.annotation.PostConstruct;
import org.apache.hertzbeat.manager.nativex.HertzbeatRuntimeHintsRegistrar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* HertzBeat main application startup class.
* This class replaces the original Manager class as the main entry point for HertzBeat application.
*/
@SpringBootApplication
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = {"org.apache.hertzbeat"})
@EntityScan(basePackages = {"org.apache.hertzbeat"})
@ComponentScan(basePackages = {"org.apache.hertzbeat"})
@ConfigurationPropertiesScan(basePackages = {"org.apache.hertzbeat"})
@ImportRuntimeHints(HertzbeatRuntimeHintsRegistrar.class)
@EnableAsync
@EnableScheduling
public class HertzBeatApplication {
public static void main(String[] args) {
SpringApplication.run(HertzBeatApplication.class, args);
}
@PostConstruct
public void init() {
// Set JNDI object factory filter for security
System.setProperty("jdk.jndi.object.factoriesFilter", "!com.zaxxer.hikari.HikariJNDIFactory");
}
}
@@ -0,0 +1,223 @@
# 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.
server:
port: ${random.int[10000,19999]}
spring:
datasource:
driver-class-name: org.h2.Driver
username: sa
password: 123456
url: jdbc:h2:./data/test;MODE=MYSQL
hikari:
max-lifetime: 120000
jpa:
show-sql: false
database: h2
hibernate:
ddl-auto: create-drop
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
format_sql: true
flyway:
enabled: false
mail:
host: smtp.exmail.qq.com
username: example@tancloud.cn
password: example
port: 465
default-encoding: UTF-8
properties:
mail:
smtp:
socketFactoryClass: javax.net.ssl.SSLSocketFactory
ssl:
enable: true
debug: false
common:
queue:
type: memory
warehouse:
store:
duckdb:
enabled: true
expire-time: 90d
store-path: data/history.duckdb
victoria-metrics:
enabled: false
url: http://localhost:8428
username: root
password: root
insert:
buffer-size: 100
flush-interval: 3
compression:
enabled: false
cluster:
enabled: false
select:
url: http://localhost:8481
username: root
password: root
insert:
url: http://localhost:8480
username: root
password: root
buffer-size: 1000
flush-interval: 3
td-engine:
enabled: false
driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
url: jdbc:TAOS-RS://127.0.0.1:6041/hertzbeat
username: root
password: taosdata
greptime:
enabled: false
grpc-endpoints: localhost:4001
http-endpoint: http://localhost:4000
database: public
username: greptime
password: greptime
iot-db:
enabled: false
host: 127.0.0.1
rpc-port: 6667
username: root
password: root
query-timeout-in-ms: -1
expire-time: '7776000000'
influxdb:
enabled: false
server-url: http://127.0.0.1:8086
username: root
password: root
expire-time: '30d'
replication: 1
# store real-time metrics data, enable only one below
real-time:
memory:
enabled: true
init-size: 16
redis:
enabled: false
# redis mode: single, sentinel, cluster. Default is single
mode: single
# separate each address with comma when using cluster mode, eg: 127.0.0.1:6379,127.0.0.1:6380
address: 127.0.0.1:6379
# enter master name when using sentinel mode
masterName: mymaster
password: 123456
# redis db index, default: DB0
db: 0
alerter:
# custom console url
console-url: https://console.tancloud.io
# we work
we-work-webhook-url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=
# ding ding talk
ding-talk-webhook-url: https://oapi.dingtalk.com/robot/send?access_token=
# fei shu fly book
fly-book-webhook-url: https://open.feishu.cn/open-apis/bot/v2/hook/
# telegram
telegram-webhook-url: https://api.telegram.org/bot%s/sendMessage
# discord
discord-webhook-url: https://discord.com/api/v9/channels/%s/messages
# serverChan
server-chan-webhook-url: https://sctapi.ftqq.com/%s.send
# gotify
gotify-webhook-url: http://127.0.0.1/message?token=%s
# alert inhibit ttl unit ms, default 14400000(4 hours)
inhibit:
ttl: 14400000
sms:
enable: false
type: tencent
tencent:
secret-id:
secret-key:
app-id:
sign-name:
template-id:
alibaba:
access-key-id:
access-key-secret:
sign-name:
template-code:
unisms:
# auth-mode: simple or hmac
auth-mode: simple
access-key-id: YOUR_ACCESS_KEY_ID
# hmac mode need to fill in access-key-secret
access-key-secret: YOUR_ACCESS_KEY_SECRET
signature: YOUR_SMS_SIGNATURE
template-id: YOUR_TEMPLATE_ID
smslocal:
api-key: YOUR_API_KEY_HERE
aws:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
twilio:
account-sid: YOUR_ACCOUNT_SID
auth-token: YOUR_AUTH_TOKEN
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
port: 1158
grafana:
enabled: false
url: http://127.0.0.1:3000
expose-url: http://127.0.0.1:3000
username: admin
password: admin
hertzbeat:
vthreads:
enabled: true
common:
mode: UNBOUNDED_VT
collector:
mode: LIMIT_AND_REJECT
manager:
mode: LIMIT_AND_REJECT
max-concurrent-jobs: 10
alerter:
notify:
mode: LIMIT_AND_REJECT
max-concurrent-jobs: 64
periodic-max-concurrent-jobs: 10
log-worker:
max-concurrent-jobs: 10
queue-capacity: 1000
reduce:
max-concurrent-jobs: 2
window-evaluator:
max-concurrent-jobs: 2
notify-max-concurrent-per-channel: 4
warehouse:
mode: UNBOUNDED_VT
async:
enabled: true
concurrency-limit: 256
reject-when-limit-reached: true
task-termination-timeout: 5000
@@ -0,0 +1,375 @@
# 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.
server:
port: 1157
spring:
application:
name: ${HOSTNAME:@hertzbeat@}${PID}
profiles:
active: prod
ai:
mcp:
server:
enabled: true
stdio: false
protocol: streamable
streamable-http:
mcp-endpoint: /api/mcp
name: hertzbeat-mcp-server
version: 1.0.0
type: SYNC
mvc:
static-path-pattern: /**
jackson:
default-property-inclusion: ALWAYS
web:
resources:
static-locations:
- classpath:/dist/
- classpath:../dist/
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
management:
health:
mail:
enabled: off
endpoints:
web:
exposure:
include:
- 'metrics'
- 'health'
- 'prometheus'
access:
default: read_only
endpoint:
prometheus:
access: read_only
metrics:
tags:
application: ${spring.application.name}
environment: ${spring.profiles.active}
prometheus:
metrics:
export:
enabled: true
sureness:
container: jakarta_servlet
auths:
- digest
- basic
- jwt
jwt:
secret: 'CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R
LnfKefTjsIfJLBa2YkhEqEGtcHDTNe4CU6+9
8tVt4bisXQ13rbN0oxhUZR73M6EByXIO+SV5
dKhaX0csgOCTlCxq20yhmUea6H6JIpSE2Rwp'
---
spring:
config:
activate:
on-profile: prod
datasource:
driver-class-name: org.h2.Driver
username: sa
password: 123456
url: jdbc:h2:./data/hertzbeat;MODE=MYSQL
hikari:
max-lifetime: 120000
jpa:
show-sql: false
database: h2
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
format_sql: true
flyway:
enabled: true
clean-disabled: true
baseline-on-migrate: true
baseline-version: 1
locations:
- classpath:db/migration/{vendor}
mail:
# Mail server address, eg: qq-mailbox is smtp.qq.com, qq-exmail is smtp.exmail.qq.com
host: smtp.qq.com
username: tancloud@qq.com
# Attention this is not email account password, this requires an email authorization code
password: your-password
# Mailbox smtp server port, eg: qq-mailbox is 465, qq-exmail is 587
port: 465
properties:
mail:
smtp:
socketFactoryClass: javax.net.ssl.SSLSocketFactory
ssl:
enable: true
starttls:
enable: false
common:
queue:
# memory, kafka, redis
type: memory
# properties when queue type is kafka
kafka:
servers: 127.0.0.1:9092
metrics-data-topic: async-metrics-data
metrics-data-to-storage-topic: metrics-data-to-storage-topic
service-discovery-data-topic: service-discovery-data
alerts-data-topic: async-alerts-data
log-entry-data-topic: async-log-entry-data
log-entry-data-to-storage-topic: log-entry-data-to-storage-topic
redis:
redis-host: 127.0.0.1
redis-port: 6379
metrics-data-queue-name-for-service-discovery: service_discovery
metrics-data-queue-name-to-persistent-storage: metrics:to_persistent_storage
metrics-data-queue-name-to-alerter: metrics:to_alerter
metrics-data-queue-name-to-real-time-storage: metrics:to_realtime_storage
alerts-data-queue-name: alerts
log-entry-queue-name: log:to_alerter
log-entry-to-storage-queue-name: log:to_storage
warehouse:
store:
# store history metrics data, enable only one below
duckdb:
enabled: true
# The maximum retention time for history records, after which records will be deleted
expire-time: 90d
store-path: data/history.duckdb
victoria-metrics:
# Standalone mode toggle — must be set to false when using cluster mode
enabled: false
url: http://localhost:8428
username: root
password: root
insert:
buffer-size: 100
flush-interval: 3
compression:
enabled: false
cluster:
enabled: false
select:
url: http://localhost:8481
username: root
password: root
insert:
url: http://localhost:8480
username: root
password: root
buffer-size: 1000
flush-interval: 3
td-engine:
enabled: false
driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
url: jdbc:TAOS-RS://localhost:6041/hertzbeat
username: root
password: taosdata
greptime:
enabled: false
grpc-endpoints: localhost:4001
http-endpoint: http://localhost:4000
# if you config other database name, you should create them first
database: public
username: greptime
password: greptime
questdb:
enabled: false
url: localhost:9000
username: admin
password: quest
iot-db:
enabled: false
host: 127.0.0.1
rpc-port: 6667
username: root
password: root
query-timeout-in-ms: -1
# data expire time, unit:ms, default '7776000000'(90 days, -1:never expire)
expire-time: '7776000000'
influxdb:
enabled: false
server-url: http://127.0.0.1:8086
username: root
password: root
expire-time: '30d'
replication: 1
doris:
enabled: false
url: jdbc:mysql://127.0.0.1:9030
username: root
password:
table-config:
enable-partition: false
partition-time-unit: DAY
partition-retention-days: 30
partition-future-days: 3
buckets: 8
replication-num: 1
pool-config:
minimum-idle: 5
maximum-pool-size: 20
connection-timeout: 30000
write-config:
# Write mode: jdbc (default, suitable for small/medium scale) or stream (high throughput)
write-mode: jdbc
# JDBC mode: batch size and flush interval
batch-size: 1000
flush-interval: 5
# Stream Load mode configuration (only used when write-mode: stream)
stream-load-config:
# Doris FE HTTP port for Stream Load API
http-port: :8030
# Stream load timeout in seconds
timeout: 60
# Max batch size in bytes for stream load (10MB default)
max-bytes-per-batch: 10485760
# Redirect policy in complex networks: direct/public/private, empty means Doris default
redirect-policy: ""
# store real-time metrics data, enable only one below
real-time:
memory:
enabled: true
init-size: 16
redis:
enabled: false
# redis mode: single, sentinel, cluster. Default is single
mode: single
# separate each address with comma when using cluster mode, eg: 127.0.0.1:6379,127.0.0.1:6380
address: 127.0.0.1:6379
# enter master name when using sentinel mode
masterName: mymaster
password: 123456
# redis db index, default: DB0
db: 0
alerter:
# custom console url
console-url: https://console.tancloud.io
# we work
we-work-webhook-url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=
# ding ding talk
ding-talk-webhook-url: https://oapi.dingtalk.com/robot/send?access_token=
# fei shu fly book
fly-book-webhook-url: https://open.feishu.cn/open-apis/bot/v2/hook/
# telegram
telegram-webhook-url: https://api.telegram.org/bot%s/sendMessage
# discord
discord-webhook-url: https://discord.com/api/v9/channels/%s/messages
# serverChan
server-chan-webhook-url: https://sctapi.ftqq.com/%s.send
# gotify
gotify-webhook-url: http://127.0.0.1/message?token=%s
# alert inhibit ttl unit ms, default 14400000(4 hours)
inhibit:
ttl: 14400000
sms:
enable: false
type: tencent
tencent:
secret-id:
secret-key:
app-id:
sign-name:
template-id:
alibaba:
access-key-id:
access-key-secret:
sign-name:
template-code:
unisms:
# auth-mode: simple or hmac
auth-mode: simple
access-key-id: YOUR_ACCESS_KEY_ID
# hmac mode need to fill in access-key-secret
access-key-secret: YOUR_ACCESS_KEY_SECRET
signature: YOUR_SMS_SIGNATURE
template-id: YOUR_TEMPLATE_ID
smslocal:
api-key: YOUR_API_KEY_HERE
aws:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
twilio:
account-sid: YOUR_ACCOUNT_SID
auth-token: YOUR_AUTH_TOKEN
twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
port: 1158
grafana:
enabled: false
url: http://127.0.0.1:3000
expose-url: http://127.0.0.1:3000
username: admin
password: admin
hertzbeat:
collector:
mysql:
# MySQL-compatible query engine routing for MySQL, MariaDB, OceanBase, and TiDB SQL metrics.
# auto : prefer JDBC only when mysql-connector-j is available from ext-lib, otherwise use the built-in query engine
# jdbc : always use JDBC
# r2dbc : always use the built-in query engine
query-engine: ${HERTZBEAT_COLLECTOR_MYSQL_QUERY_ENGINE:auto}
# Optional virtual-thread overrides. Remove this whole block to use built-in defaults.
vthreads:
enabled: true
common:
mode: UNBOUNDED_VT
collector:
mode: LIMIT_AND_REJECT
manager:
mode: LIMIT_AND_REJECT
max-concurrent-jobs: 10
alerter:
notify:
mode: LIMIT_AND_REJECT
max-concurrent-jobs: 64
periodic-max-concurrent-jobs: 10
log-worker:
max-concurrent-jobs: 10
queue-capacity: 1000
reduce:
max-concurrent-jobs: 2
window-evaluator:
max-concurrent-jobs: 2
notify-max-concurrent-per-channel: 4
warehouse:
mode: UNBOUNDED_VT
async:
enabled: true
concurrency-limit: 256
reject-when-limit-reached: true
task-termination-timeout: 5000
@@ -0,0 +1,5 @@
_ _ _ ____ _
| | | | ___ _ __| |_ ___| __ ) ___ __ _| |_
| |_| |/ _ \ '__| __|_ / _ \ / _ \/ _` | __| Profile: ${spring.profiles.active}
| _ | __/ | | |_ / /| |_) | __/ (_| | |_ Name: ${spring.application.name} Port: ${server.port} Pid: ${pid}
|_| |_|\___|_| \__/___|____/ \___|\__,_|\__| https://hertzbeat.apache.org/
@@ -0,0 +1,30 @@
-- 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.
-- ensure every sql can rerun without error
ALTER TABLE HZB_PARAM ADD COLUMN IF NOT EXISTS "value" VARCHAR(255);
UPDATE HZB_PARAM SET param_value = "value" WHERE "value" IS NOT NULL AND param_value IS NULL;
ALTER TABLE HZB_PARAM DROP COLUMN "value";
ALTER TABLE HZB_TAG ADD COLUMN IF NOT EXISTS "value" VARCHAR(255);
UPDATE HZB_TAG SET tag_value = "value" WHERE "value" IS NOT NULL AND tag_value IS NULL;
ALTER TABLE HZB_TAG DROP COLUMN "value";
ALTER TABLE HZB_STATUS_PAGE_HISTORY ADD COLUMN IF NOT EXISTS "unknown" integer;
UPDATE HZB_STATUS_PAGE_HISTORY SET unknowing = "unknown" WHERE "unknown" IS NOT NULL AND unknowing IS NULL;
ALTER TABLE HZB_STATUS_PAGE_HISTORY DROP COLUMN "unknown";
@@ -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.
-- ensure every sql can rerun without error
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS app VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN app;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS metric VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN metric;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS field VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN field;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS preset boolean;
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN preset;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS priority integer;
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN priority;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS tags VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN tags;
@@ -0,0 +1,24 @@
-- 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.
-- ensure every sql can rerun without error
-- Modify common_annotations column to TEXT (H2 TEXT is equivalent to CLOB)
ALTER TABLE HZB_ALERT_GROUP ALTER COLUMN common_annotations CLOB;
-- Modify alert_fingerprints column to TEXT (H2 TEXT is equivalent to CLOB)
ALTER TABLE HZB_ALERT_GROUP ALTER COLUMN alert_fingerprints CLOB;
@@ -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.
-- ensure every sql can rerun without error
-- Modify message column to TEXT (H2 TEXT is equivalent to CLOB)
ALTER TABLE HZB_STATUS_PAGE_INCIDENT_CONTENT ALTER COLUMN message CLOB;
@@ -0,0 +1,609 @@
-- 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.
-- ensure every sql can rerun without error
-- Update type from 'realtime' to 'realtime_metric'
UPDATE HZB_ALERT_DEFINE
SET type = 'realtime_metric'
WHERE type = 'realtime';
-- Update type from 'periodic' to 'periodic_metric'
UPDATE HZB_ALERT_DEFINE
SET type = 'periodic_metric'
WHERE type = 'periodic';
-- Rename host to instance
CREATE ALIAS RENAME_HOST_TO_INSTANCE AS $$
void renameHostToInstance(java.sql.Connection conn) throws java.sql.SQLException {
boolean instanceExists = false;
boolean hostExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getColumns(null, null, "HZB_MONITOR", "INSTANCE")) {
if (rs.next()) instanceExists = true;
}
try (java.sql.ResultSet rs = conn.getMetaData().getColumns(null, null, "HZB_MONITOR", "HOST")) {
if (rs.next()) hostExists = true;
}
try (java.sql.Statement stmt = conn.createStatement()) {
if (instanceExists) {
if (hostExists) {
stmt.execute("UPDATE HZB_MONITOR SET instance = host WHERE instance IS NULL");
stmt.execute("ALTER TABLE HZB_MONITOR DROP COLUMN host");
}
} else {
if (hostExists) {
stmt.execute("ALTER TABLE HZB_MONITOR ALTER COLUMN host RENAME TO instance");
}
}
}
}
$$;
CALL RENAME_HOST_TO_INSTANCE();
DROP ALIAS RENAME_HOST_TO_INSTANCE;
-- Update instance with port
UPDATE HZB_MONITOR m
SET instance = CONCAT(instance, ':', (SELECT param_value FROM HZB_PARAM p WHERE p.monitor_id = m.id AND p.field = 'port'))
WHERE EXISTS (SELECT 1 FROM HZB_PARAM p WHERE p.monitor_id = m.id AND p.field = 'port' AND p.param_value IS NOT NULL AND p.param_value != '')
AND instance NOT LIKE CONCAT('%:', (SELECT param_value FROM HZB_PARAM p WHERE p.monitor_id = m.id AND p.field = 'port'));
-- Migrate history table
CREATE ALIAS MIGRATE_HISTORY_TABLE AS $$
void migrateHistoryTable(java.sql.Connection conn) throws java.sql.SQLException {
boolean monitorIdExists = false;
boolean metricLabelsExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getColumns(null, null, "HZB_HISTORY", "MONITOR_ID")) {
if (rs.next()) monitorIdExists = true;
}
try (java.sql.ResultSet rs = conn.getMetaData().getColumns(null, null, "HZB_HISTORY", "METRIC_LABELS")) {
if (rs.next()) metricLabelsExists = true;
}
if (monitorIdExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
if (!metricLabelsExists) {
stmt.execute("ALTER TABLE HZB_HISTORY ALTER COLUMN instance RENAME TO metric_labels");
stmt.execute("ALTER TABLE HZB_HISTORY ALTER COLUMN metric_labels SET DATA TYPE VARCHAR(5000)");
stmt.execute("ALTER TABLE HZB_HISTORY ADD COLUMN instance VARCHAR(255)");
} else {
stmt.execute("UPDATE HZB_HISTORY SET metric_labels = instance WHERE metric_labels IS NULL");
stmt.execute("UPDATE HZB_HISTORY SET instance = NULL");
stmt.execute("ALTER TABLE HZB_HISTORY ALTER COLUMN instance SET DATA TYPE VARCHAR(255)");
}
stmt.execute("UPDATE HZB_HISTORY h SET instance = (SELECT m.instance FROM HZB_MONITOR m WHERE m.id = h.monitor_id) WHERE h.monitor_id IS NOT NULL");
stmt.execute("ALTER TABLE HZB_HISTORY DROP COLUMN monitor_id");
}
}
}
$$;
CALL MIGRATE_HISTORY_TABLE();
DROP ALIAS MIGRATE_HISTORY_TABLE;
-- ========================================
-- hzb_alert_define_monitor_bind table
-- ========================================
CREATE ALIAS UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES AS $$
void updateAlertDefineMonitorBindIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_ALERT_DEFINE_MONITOR_BIND", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_ALERT_DEFINE_MONITOR_BIND", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("INDEX_ALERT_DEFINE_MONITOR".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX INDEX_ALERT_DEFINE_MONITOR");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new indexes if not exist
boolean alertDefineIdIndexExists = false;
boolean monitorIdIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_ALERT_DEFINE_MONITOR_BIND", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_ALERT_DEFINE_ID".equalsIgnoreCase(indexName)) {
alertDefineIdIndexExists = true;
}
if ("IDX_MONITOR_ID".equalsIgnoreCase(indexName)) {
monitorIdIndexExists = true;
}
}
}
if (!alertDefineIdIndexExists) {
stmt.execute("CREATE INDEX IDX_ALERT_DEFINE_ID ON HZB_ALERT_DEFINE_MONITOR_BIND(ALERT_DEFINE_ID)");
}
if (!monitorIdIndexExists) {
stmt.execute("CREATE INDEX IDX_MONITOR_ID ON HZB_ALERT_DEFINE_MONITOR_BIND(MONITOR_ID)");
}
}
}
}
$$;
CALL UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES();
DROP ALIAS UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES;
-- ========================================
-- hzb_collector_monitor_bind table
-- ========================================
CREATE ALIAS UPDATE_COLLECTOR_MONITOR_BIND_INDEXES AS $$
void updateCollectorMonitorBindIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_COLLECTOR_MONITOR_BIND", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_COLLECTOR_MONITOR_BIND", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("INDEX_COLLECTOR_MONITOR".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX INDEX_COLLECTOR_MONITOR");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new indexes if not exist
boolean collectorIndexExists = false;
boolean monitorIdIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_COLLECTOR_MONITOR_BIND", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_COLLECTOR_MONITOR_COLLECTOR".equalsIgnoreCase(indexName)) {
collectorIndexExists = true;
}
if ("IDX_COLLECTOR_MONITOR_MONITOR_ID".equalsIgnoreCase(indexName)) {
monitorIdIndexExists = true;
}
}
}
if (!collectorIndexExists) {
stmt.execute("CREATE INDEX IDX_COLLECTOR_MONITOR_COLLECTOR ON HZB_COLLECTOR_MONITOR_BIND(COLLECTOR)");
}
if (!monitorIdIndexExists) {
stmt.execute("CREATE INDEX IDX_COLLECTOR_MONITOR_MONITOR_ID ON HZB_COLLECTOR_MONITOR_BIND(MONITOR_ID)");
}
}
}
}
$$;
CALL UPDATE_COLLECTOR_MONITOR_BIND_INDEXES();
DROP ALIAS UPDATE_COLLECTOR_MONITOR_BIND_INDEXES;
-- ========================================
-- hzb_monitor table
-- ========================================
CREATE ALIAS UPDATE_MONITOR_INDEXES AS $$
void updateMonitorIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_MONITOR", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_MONITOR", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("MONITOR_QUERY_INDEX".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX MONITOR_QUERY_INDEX");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new indexes if not exist
boolean appIndexExists = false;
boolean instanceIndexExists = false;
boolean nameIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_MONITOR", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_HZB_MONITOR_APP".equalsIgnoreCase(indexName)) {
appIndexExists = true;
}
if ("IDX_HZB_MONITOR_INSTANCE".equalsIgnoreCase(indexName)) {
instanceIndexExists = true;
}
if ("IDX_HZB_MONITOR_NAME".equalsIgnoreCase(indexName)) {
nameIndexExists = true;
}
}
}
if (!appIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_MONITOR_APP ON HZB_MONITOR(APP)");
}
if (!instanceIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_MONITOR_INSTANCE ON HZB_MONITOR(INSTANCE)");
}
if (!nameIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_MONITOR_NAME ON HZB_MONITOR(NAME)");
}
}
}
}
$$;
CALL UPDATE_MONITOR_INDEXES();
DROP ALIAS UPDATE_MONITOR_INDEXES;
-- ========================================
-- hzb_monitor_bind table
-- ========================================
CREATE ALIAS UPDATE_MONITOR_BIND_INDEXES AS $$
void updateMonitorBindIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_MONITOR_BIND", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Create new index if not exist
boolean bindIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_MONITOR_BIND", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("INDEX_MONITOR_BIND".equalsIgnoreCase(indexName)) {
bindIndexExists = true;
}
}
}
if (!bindIndexExists) {
stmt.execute("CREATE INDEX INDEX_MONITOR_BIND ON HZB_MONITOR_BIND(BIZ_ID)");
}
}
}
}
$$;
CALL UPDATE_MONITOR_BIND_INDEXES();
DROP ALIAS UPDATE_MONITOR_BIND_INDEXES;
-- ========================================
-- hzb_status_page_incident_component_bind table
-- Special handling: component_id might have auto-created index from FK
-- ========================================
CREATE ALIAS UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES AS $$
void updateStatusPageIncidentComponentBindIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Check if component_id column already has any index
boolean hasComponentIdIndex = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND", false, false)) {
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
if (columnName != null && "COMPONENT_ID".equalsIgnoreCase(columnName)) {
hasComponentIdIndex = true;
break;
}
}
}
// Create index on component_id only if no index exists on this column
if (!hasComponentIdIndex) {
stmt.execute("CREATE INDEX IDX_INCIDENT_COMPONENT_COMPONENT_ID ON HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND(COMPONENT_ID)");
}
}
}
}
$$;
CALL UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES();
DROP ALIAS UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES;
-- ========================================
-- hzb_push_metrics table
-- ========================================
CREATE ALIAS UPDATE_PUSH_METRICS_INDEXES AS $$
void updatePushMetricsIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_PUSH_METRICS", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PUSH_METRICS", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("PUSH_QUERY_INDEX".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX PUSH_QUERY_INDEX");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new indexes if not exist
boolean monitorIdIndexExists = false;
boolean timeIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PUSH_METRICS", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_PUSH_METRICS_MONITOR_ID".equalsIgnoreCase(indexName)) {
monitorIdIndexExists = true;
}
if ("IDX_PUSH_METRICS_TIME".equalsIgnoreCase(indexName)) {
timeIndexExists = true;
}
}
}
if (!monitorIdIndexExists) {
stmt.execute("CREATE INDEX IDX_PUSH_METRICS_MONITOR_ID ON HZB_PUSH_METRICS(MONITOR_ID)");
}
if (!timeIndexExists) {
stmt.execute("CREATE INDEX IDX_PUSH_METRICS_TIME ON HZB_PUSH_METRICS(TIME)");
}
}
}
}
$$;
CALL UPDATE_PUSH_METRICS_INDEXES();
DROP ALIAS UPDATE_PUSH_METRICS_INDEXES;
-- ========================================
-- hzb_history table
-- ========================================
CREATE ALIAS UPDATE_HISTORY_INDEXES AS $$
void updateHistoryIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_HISTORY", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_HISTORY", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("HISTORY_QUERY_INDEX".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX HISTORY_QUERY_INDEX");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new indexes if not exist
boolean instanceIndexExists = false;
boolean appIndexExists = false;
boolean metricsIndexExists = false;
boolean metricIndexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_HISTORY", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_HZB_HISTORY_INSTANCE".equalsIgnoreCase(indexName)) {
instanceIndexExists = true;
}
if ("IDX_HZB_HISTORY_APP".equalsIgnoreCase(indexName)) {
appIndexExists = true;
}
if ("IDX_HZB_HISTORY_METRICS".equalsIgnoreCase(indexName)) {
metricsIndexExists = true;
}
if ("IDX_HZB_HISTORY_METRIC".equalsIgnoreCase(indexName)) {
metricIndexExists = true;
}
}
}
if (!instanceIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_HISTORY_INSTANCE ON HZB_HISTORY(INSTANCE)");
}
if (!appIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_HISTORY_APP ON HZB_HISTORY(APP)");
}
if (!metricsIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_HISTORY_METRICS ON HZB_HISTORY(METRICS)");
}
if (!metricIndexExists) {
stmt.execute("CREATE INDEX IDX_HZB_HISTORY_METRIC ON HZB_HISTORY(METRIC)");
}
}
}
}
$$;
CALL UPDATE_HISTORY_INDEXES();
DROP ALIAS UPDATE_HISTORY_INDEXES;
-- ========================================
-- hzb_param table
-- ========================================
CREATE ALIAS UPDATE_PARAM_TABLE_INDEXES AS $$
void updateParamTableIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_PARAM", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PARAM", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_HZB_PARAM_MONITOR_ID".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX IDX_HZB_PARAM_MONITOR_ID");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new index if not exist
boolean indexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PARAM", false, false)) {
while (rs.next()) {
if ("IDX_HZB_PARAM_MONITOR_ID".equalsIgnoreCase(rs.getString("INDEX_NAME"))) {
indexExists = true;
break;
}
}
}
if (!indexExists) {
stmt.execute("CREATE INDEX IDX_HZB_PARAM_MONITOR_ID ON HZB_PARAM(MONITOR_ID)");
}
// Drop old unique constraint if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PARAM", true, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if (indexName != null && indexName.equalsIgnoreCase("UK_HZB_PARAM_MONITOR_FIELD")) {
stmt.execute("DROP INDEX UK_HZB_PARAM_MONITOR_FIELD");
break;
}
}
} catch (Exception e) {
// Constraint may not exist, continue
}
// Create new unique constraint if not exist
boolean constraintExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PARAM", true, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if (indexName != null && indexName.equalsIgnoreCase("UK_HZB_PARAM_MONITOR_FIELD")) {
constraintExists = true;
break;
}
}
}
if (!constraintExists) {
stmt.execute("CREATE UNIQUE INDEX UK_HZB_PARAM_MONITOR_FIELD ON HZB_PARAM(MONITOR_ID, FIELD)");
}
}
}
}
$$;
CALL UPDATE_PARAM_TABLE_INDEXES();
DROP ALIAS UPDATE_PARAM_TABLE_INDEXES;
-- ========================================
-- hzb_plugin_param table
-- ========================================
CREATE ALIAS UPDATE_PLUGIN_PARAM_TABLE_INDEXES AS $$
void updatePluginParamTableIndexes(java.sql.Connection conn) throws java.sql.SQLException {
boolean tableExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null, "HZB_PLUGIN_PARAM", null)) {
if (rs.next()) tableExists = true;
}
if (tableExists) {
try (java.sql.Statement stmt = conn.createStatement()) {
// Drop old index if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PLUGIN_PARAM", false, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if ("IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID".equalsIgnoreCase(indexName)) {
stmt.execute("DROP INDEX IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID");
break;
}
}
} catch (Exception e) {
// Index may not exist, continue
}
// Create new index if not exist
boolean indexExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PLUGIN_PARAM", false, false)) {
while (rs.next()) {
if ("IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID".equalsIgnoreCase(rs.getString("INDEX_NAME"))) {
indexExists = true;
break;
}
}
}
if (!indexExists) {
stmt.execute("CREATE INDEX IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID ON HZB_PLUGIN_PARAM(PLUGIN_METADATA_ID)");
}
// Drop old unique constraint if exists
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PLUGIN_PARAM", true, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if (indexName != null && indexName.equalsIgnoreCase("UK_HZB_PLUGIN_PARAM_METADATA_FIELD")) {
stmt.execute("DROP INDEX UK_HZB_PLUGIN_PARAM_METADATA_FIELD");
break;
}
}
} catch (Exception e) {
// Constraint may not exist, continue
}
// Create new unique constraint if not exist
boolean constraintExists = false;
try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null, null, "HZB_PLUGIN_PARAM", true, false)) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
if (indexName != null && indexName.equalsIgnoreCase("UK_HZB_PLUGIN_PARAM_METADATA_FIELD")) {
constraintExists = true;
break;
}
}
}
if (!constraintExists) {
stmt.execute("CREATE UNIQUE INDEX UK_HZB_PLUGIN_PARAM_METADATA_FIELD ON HZB_PLUGIN_PARAM(PLUGIN_METADATA_ID, FIELD)");
}
}
}
}
$$;
CALL UPDATE_PLUGIN_PARAM_TABLE_INDEXES();
DROP ALIAS UPDATE_PLUGIN_PARAM_TABLE_INDEXES;
@@ -0,0 +1,52 @@
-- 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.
-- 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.
-- Scheduled SOP execution configurations
CREATE TABLE IF NOT EXISTS hzb_sop_schedule (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
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'
);
CREATE INDEX IF NOT EXISTS idx_schedule_conversation_id ON hzb_sop_schedule(conversation_id);
CREATE INDEX IF NOT EXISTS idx_schedule_enabled_next ON hzb_sop_schedule(enabled, next_run_time);
@@ -0,0 +1,35 @@
-- 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.
-- ensure every sql can rerun without error
-- for to hertzbeat v1.6.0 upgrade in mysql, user need run this by themself, ignore for non-upgrading -> 1.6.0 users
# UPDATE hzb_param SET param_value = `value` WHERE `value` IS NOT NULL AND param_value IS NULL;
# ALTER TABLE hzb_param DROP COLUMN `value`;
# commit;
#
# UPDATE hzb_tag SET tag_value = `value` WHERE `value` IS NOT NULL AND tag_value IS NULL;
# ALTER TABLE hzb_tag DROP COLUMN `value`;
# commit;
#
# UPDATE hzb_status_page_history SET unknowing = `unknown` WHERE `unknown` IS NOT NULL AND unknowing IS NULL;
# ALTER TABLE hzb_status_page_history DROP COLUMN `unknown`;
# commit;
#
# ALTER TABLE `hertzbeat`.`hzb_notice_rule` MODIFY COLUMN `receiver_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL AFTER `receiver_id`;
# commit;
@@ -0,0 +1,70 @@
-- 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.
-- ensure every sql can rerun without error
-- add repair table sql
REPAIR TABLE HZB_ALERT_DEFINE;
DELIMITER //
CREATE PROCEDURE AddOrDropColumns()
BEGIN
DECLARE col_exists INT;
-- Drop 'app' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='app';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN app;
END IF;
-- Drop 'metric' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='metric';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN metric;
END IF;
-- Drop 'field' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='field';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN field;
END IF;
-- Drop 'preset' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='preset';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN preset;
END IF;
-- Drop 'priority' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='priority';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN priority;
END IF;
-- Drop 'tags' column if it exists
SELECT COUNT(*) INTO col_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='HZB_ALERT_DEFINE' AND COLUMN_NAME='tags';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN tags;
END IF;
END //
DELIMITER ;
CALL AddOrDropColumns();
DROP PROCEDURE IF EXISTS AddOrDropColumns;
commit;
@@ -0,0 +1,64 @@
-- 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.
-- ensure every sql can rerun without error
-- Modify hzb_alert_group table columns to TEXT type to resolve MySQL row size limit issue
DELIMITER //
CREATE PROCEDURE ModifyGroupAlertColumns()
BEGIN
DECLARE table_exists INT;
DECLARE col_exists INT;
-- Check if the table exists
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'HZB_ALERT_GROUP';
IF table_exists = 1 THEN
-- Check and modify common_annotations column to TEXT
SELECT COUNT(*) INTO col_exists
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'HZB_ALERT_GROUP'
AND COLUMN_NAME = 'common_annotations'
AND DATA_TYPE != 'text';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_GROUP MODIFY COLUMN common_annotations TEXT;
END IF;
-- Check and modify alert_fingerprints column to TEXT
SELECT COUNT(*) INTO col_exists
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'HZB_ALERT_GROUP'
AND COLUMN_NAME = 'alert_fingerprints'
AND DATA_TYPE != 'text';
IF col_exists = 1 THEN
ALTER TABLE HZB_ALERT_GROUP MODIFY COLUMN alert_fingerprints TEXT;
END IF;
END IF;
END //
DELIMITER ;
CALL ModifyGroupAlertColumns();
DROP PROCEDURE IF EXISTS ModifyGroupAlertColumns;
COMMIT;
@@ -0,0 +1,50 @@
-- 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.
-- ensure every sql can rerun without error
-- Modify hzb_status_page_incident_content table columns to TEXT type to resolve MySQL row size limit issue
DELIMITER //
CREATE PROCEDURE ModifyStatusIncidentContentColumns()
BEGIN
DECLARE table_exists INT;
DECLARE col_exists INT;
-- Check if the table exists
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'HZB_STATUS_PAGE_INCIDENT_CONTENT';
IF table_exists = 1 THEN
-- Check and modify message column to TEXT
SELECT COUNT(*) INTO col_exists
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'HZB_STATUS_PAGE_INCIDENT_CONTENT'
AND COLUMN_NAME = 'message'
AND DATA_TYPE != 'text';
IF col_exists = 1 THEN
ALTER TABLE HZB_STATUS_PAGE_INCIDENT_CONTENT MODIFY COLUMN message TEXT;
END IF;
END IF;
END //
DELIMITER ;
CALL ModifyStatusIncidentContentColumns();
DROP PROCEDURE IF EXISTS ModifyStatusIncidentContentColumns;
COMMIT;
@@ -0,0 +1,556 @@
-- 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.
-- ensure every sql can rerun without error
-- Update hzb_alert_define table type column to support log monitoring
DELIMITER //
CREATE PROCEDURE UpdateAlertDefineColumns()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_alert_define';
IF table_exists = 1 THEN
UPDATE hzb_alert_define
SET type = 'realtime_metric'
WHERE type = 'realtime';
UPDATE hzb_alert_define
SET type = 'periodic_metric'
WHERE type = 'periodic';
END IF;
END //
DELIMITER ;
CALL UpdateAlertDefineColumns();
DROP PROCEDURE IF EXISTS UpdateAlertDefineColumns;
-- Rename host to instance
DELIMITER //
CREATE PROCEDURE RenameHostToInstance()
BEGIN
DECLARE instance_exists INT;
DECLARE host_exists INT;
SELECT COUNT(*) INTO instance_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor' AND COLUMN_NAME = 'instance';
SELECT COUNT(*) INTO host_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor' AND COLUMN_NAME = 'host';
IF instance_exists > 0 THEN
IF host_exists > 0 THEN
SET @sql_update = 'UPDATE hzb_monitor SET instance = host WHERE instance IS NULL';
PREPARE stmt_update FROM @sql_update;
EXECUTE stmt_update;
DEALLOCATE PREPARE stmt_update;
SET @sql_drop = 'ALTER TABLE hzb_monitor DROP COLUMN host';
PREPARE stmt_drop FROM @sql_drop;
EXECUTE stmt_drop;
DEALLOCATE PREPARE stmt_drop;
END IF;
ELSE
IF host_exists > 0 THEN
SET @sql_change = 'ALTER TABLE hzb_monitor CHANGE host instance VARCHAR(100)';
PREPARE stmt_change FROM @sql_change;
EXECUTE stmt_change;
DEALLOCATE PREPARE stmt_change;
END IF;
END IF;
END //
DELIMITER ;
CALL RenameHostToInstance();
DROP PROCEDURE IF EXISTS RenameHostToInstance;
-- Update instance with port
UPDATE hzb_monitor m
INNER JOIN hzb_param p ON m.id = p.monitor_id AND p.field = 'port'
SET m.instance = CONCAT(m.instance, ':', p.param_value)
WHERE m.instance IS NOT NULL AND p.param_value IS NOT NULL AND p.param_value != ''
AND m.instance NOT LIKE CONCAT('%:', p.param_value);
-- Migrate history table
DELIMITER //
CREATE PROCEDURE MigrateHistoryTable()
BEGIN
DECLARE monitor_id_exists INT;
DECLARE metric_labels_exists INT;
SELECT COUNT(*) INTO monitor_id_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_history' AND COLUMN_NAME = 'monitor_id';
SELECT COUNT(*) INTO metric_labels_exists FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_history' AND COLUMN_NAME = 'metric_labels';
IF monitor_id_exists > 0 THEN
IF metric_labels_exists = 0 THEN
SET @sql_rename = 'ALTER TABLE hzb_history CHANGE instance metric_labels VARCHAR(5000)';
PREPARE stmt_rename FROM @sql_rename;
EXECUTE stmt_rename;
DEALLOCATE PREPARE stmt_rename;
SET @sql_add = 'ALTER TABLE hzb_history ADD COLUMN instance VARCHAR(255)';
PREPARE stmt_add FROM @sql_add;
EXECUTE stmt_add;
DEALLOCATE PREPARE stmt_add;
ELSE
UPDATE hzb_history SET metric_labels = instance WHERE metric_labels IS NULL;
UPDATE hzb_history SET instance = NULL;
SET @sql_resize = 'ALTER TABLE hzb_history MODIFY COLUMN instance VARCHAR(255)';
PREPARE stmt_resize FROM @sql_resize;
EXECUTE stmt_resize;
DEALLOCATE PREPARE stmt_resize;
END IF;
UPDATE hzb_history h JOIN hzb_monitor m ON h.monitor_id = m.id SET h.instance = m.instance;
SET @sql_drop = 'ALTER TABLE hzb_history DROP COLUMN monitor_id';
PREPARE stmt_drop FROM @sql_drop;
EXECUTE stmt_drop;
DEALLOCATE PREPARE stmt_drop;
END IF;
END //
DELIMITER ;
CALL MigrateHistoryTable();
DROP PROCEDURE IF EXISTS MigrateHistoryTable;
-- ========================================
-- hzb_alert_define_monitor_bind table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateAlertDefineMonitorBindIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_alert_define_monitor_bind';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
AND INDEX_NAME = 'index_alert_define_monitor') THEN
SET @drop_sql = 'DROP INDEX index_alert_define_monitor ON hzb_alert_define_monitor_bind';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
AND INDEX_NAME = 'idx_alert_define_id') THEN
CREATE INDEX idx_alert_define_id ON hzb_alert_define_monitor_bind(alert_define_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
AND INDEX_NAME = 'idx_monitor_id') THEN
CREATE INDEX idx_monitor_id ON hzb_alert_define_monitor_bind(monitor_id);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateAlertDefineMonitorBindIndexes();
DROP PROCEDURE IF EXISTS UpdateAlertDefineMonitorBindIndexes;
-- ========================================
-- hzb_collector_monitor_bind table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateCollectorMonitorBindIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_collector_monitor_bind';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_collector_monitor_bind'
AND INDEX_NAME = 'index_collector_monitor') THEN
SET @drop_sql = 'DROP INDEX index_collector_monitor ON hzb_collector_monitor_bind';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_collector_monitor_bind'
AND INDEX_NAME = 'idx_collector_monitor_collector') THEN
CREATE INDEX idx_collector_monitor_collector ON hzb_collector_monitor_bind(collector);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_collector_monitor_bind'
AND INDEX_NAME = 'idx_collector_monitor_monitor_id') THEN
CREATE INDEX idx_collector_monitor_monitor_id ON hzb_collector_monitor_bind(monitor_id);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateCollectorMonitorBindIndexes();
DROP PROCEDURE IF EXISTS UpdateCollectorMonitorBindIndexes;
-- ========================================
-- hzb_monitor table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateMonitorIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_monitor'
AND INDEX_NAME = 'monitor_query_index') THEN
SET @drop_sql = 'DROP INDEX monitor_query_index ON hzb_monitor';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_monitor'
AND INDEX_NAME = 'idx_hzb_monitor_app') THEN
CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(app);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_monitor'
AND INDEX_NAME = 'idx_hzb_monitor_instance') THEN
CREATE INDEX idx_hzb_monitor_instance ON hzb_monitor(instance);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_monitor'
AND INDEX_NAME = 'idx_hzb_monitor_name') THEN
CREATE INDEX idx_hzb_monitor_name ON hzb_monitor(name);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateMonitorIndexes();
DROP PROCEDURE IF EXISTS UpdateMonitorIndexes;
-- ========================================
-- hzb_monitor_bind table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateMonitorBindIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor_bind';
IF table_exists = 1 THEN
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_monitor_bind'
AND INDEX_NAME = 'index_monitor_bind') THEN
CREATE INDEX index_monitor_bind ON hzb_monitor_bind(biz_id);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateMonitorBindIndexes();
DROP PROCEDURE IF EXISTS UpdateMonitorBindIndexes;
-- ========================================
-- hzb_status_page_incident_component_bind table
-- Special handling: component_id might have auto-created index from FK
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateStatusPageIncidentComponentBindIndexes()
BEGIN
DECLARE table_exists INT;
DECLARE component_id_has_index INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_status_page_incident_component_bind';
IF table_exists = 1 THEN
-- Check if component_id column already has any index (including auto-created by FK)
SELECT COUNT(*) INTO component_id_has_index
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_status_page_incident_component_bind'
AND COLUMN_NAME = 'component_id'
AND INDEX_NAME != 'PRIMARY';
-- Create index on component_id only if no index exists on this column
IF component_id_has_index = 0 THEN
CREATE INDEX idx_incident_component_component_id ON hzb_status_page_incident_component_bind(component_id);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateStatusPageIncidentComponentBindIndexes();
DROP PROCEDURE IF EXISTS UpdateStatusPageIncidentComponentBindIndexes;
-- ========================================
-- hzb_push_metrics table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdatePushMetricsIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_push_metrics';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_push_metrics'
AND INDEX_NAME = 'push_query_index') THEN
SET @drop_sql = 'DROP INDEX push_query_index ON hzb_push_metrics';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_push_metrics'
AND INDEX_NAME = 'idx_push_metrics_monitor_id') THEN
CREATE INDEX idx_push_metrics_monitor_id ON hzb_push_metrics(monitor_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_push_metrics'
AND INDEX_NAME = 'idx_push_metrics_time') THEN
CREATE INDEX idx_push_metrics_time ON hzb_push_metrics(time);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdatePushMetricsIndexes();
DROP PROCEDURE IF EXISTS UpdatePushMetricsIndexes;
-- ========================================
-- hzb_history table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateHistoryIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_history';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_history'
AND INDEX_NAME = 'history_query_index') THEN
SET @drop_sql = 'DROP INDEX history_query_index ON hzb_history';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_history'
AND INDEX_NAME = 'idx_hzb_history_instance') THEN
CREATE INDEX idx_hzb_history_instance ON hzb_history(instance);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_history'
AND INDEX_NAME = 'idx_hzb_history_app') THEN
CREATE INDEX idx_hzb_history_app ON hzb_history(app);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_history'
AND INDEX_NAME = 'idx_hzb_history_metrics') THEN
CREATE INDEX idx_hzb_history_metrics ON hzb_history(metrics);
END IF;
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_history'
AND INDEX_NAME = 'idx_hzb_history_metric') THEN
CREATE INDEX idx_hzb_history_metric ON hzb_history(metric);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateHistoryIndexes();
DROP PROCEDURE IF EXISTS UpdateHistoryIndexes;
-- ========================================
-- hzb_param table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdateParamTableIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_param';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_param'
AND INDEX_NAME = 'idx_hzb_param_monitor_id') THEN
SET @drop_sql = 'DROP INDEX idx_hzb_param_monitor_id ON hzb_param';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_param'
AND INDEX_NAME = 'idx_hzb_param_monitor_id') THEN
CREATE INDEX idx_hzb_param_monitor_id ON hzb_param(monitor_id);
END IF;
-- Drop old unique constraint if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_param'
AND CONSTRAINT_TYPE = 'UNIQUE'
AND CONSTRAINT_NAME = 'uk_hzb_param_monitor_field') THEN
SET @drop_sql = 'ALTER TABLE hzb_param DROP INDEX uk_hzb_param_monitor_field';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new unique constraint if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_param'
AND CONSTRAINT_TYPE = 'UNIQUE'
AND CONSTRAINT_NAME = 'uk_hzb_param_monitor_field') THEN
ALTER TABLE hzb_param
ADD CONSTRAINT uk_hzb_param_monitor_field
UNIQUE (monitor_id, field);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdateParamTableIndexes();
DROP PROCEDURE IF EXISTS UpdateParamTableIndexes;
-- ========================================
-- hzb_plugin_param table
-- ========================================
DELIMITER //
CREATE PROCEDURE UpdatePluginParamTableIndexes()
BEGIN
DECLARE table_exists INT;
SELECT COUNT(*) INTO table_exists
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_plugin_param';
IF table_exists = 1 THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_plugin_param'
AND INDEX_NAME = 'idx_hzb_plugin_param_plugin_metadata_id') THEN
SET @drop_sql = 'DROP INDEX idx_hzb_plugin_param_plugin_metadata_id ON hzb_plugin_param';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_plugin_param'
AND INDEX_NAME = 'idx_hzb_plugin_param_plugin_metadata_id') THEN
CREATE INDEX idx_hzb_plugin_param_plugin_metadata_id ON hzb_plugin_param(plugin_metadata_id);
END IF;
-- Drop old unique constraint if exists
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_plugin_param'
AND CONSTRAINT_TYPE = 'UNIQUE'
AND CONSTRAINT_NAME = 'uk_hzb_plugin_param_metadata_field') THEN
SET @drop_sql = 'ALTER TABLE hzb_plugin_param DROP INDEX uk_hzb_plugin_param_metadata_field';
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
-- Create new unique constraint if not exist
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hzb_plugin_param'
AND CONSTRAINT_TYPE = 'UNIQUE'
AND CONSTRAINT_NAME = 'uk_hzb_plugin_param_metadata_field') THEN
ALTER TABLE hzb_plugin_param
ADD CONSTRAINT uk_hzb_plugin_param_metadata_field
UNIQUE (plugin_metadata_id, field);
END IF;
END IF;
END //
DELIMITER ;
CALL UpdatePluginParamTableIndexes();
DROP PROCEDURE IF EXISTS UpdatePluginParamTableIndexes;
COMMIT;
@@ -0,0 +1,51 @@
-- 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.
-- 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.
-- Scheduled SOP execution configurations
CREATE TABLE hzb_sop_schedule (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
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',
INDEX idx_schedule_conversation_id (conversation_id),
INDEX idx_schedule_enabled_next (enabled, next_run_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@@ -0,0 +1,32 @@
-- 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.
-- ensure every sql can rerun without error
ALTER TABLE HZB_PARAM ADD COLUMN IF NOT EXISTS value VARCHAR(255);
UPDATE HZB_PARAM SET param_value = value WHERE value IS NOT NULL AND param_value IS NULL;
ALTER TABLE HZB_PARAM DROP COLUMN value;
ALTER TABLE HZB_TAG ADD COLUMN IF NOT EXISTS value VARCHAR(255);
UPDATE HZB_TAG SET tag_value = value WHERE value IS NOT NULL AND tag_value IS NULL;
ALTER TABLE HZB_TAG DROP COLUMN value;
ALTER TABLE HZB_STATUS_PAGE_HISTORY ADD COLUMN IF NOT EXISTS unknown integer;
UPDATE HZB_STATUS_PAGE_HISTORY SET unknowing = unknown WHERE unknown IS NOT NULL AND unknowing IS NULL;
ALTER TABLE HZB_STATUS_PAGE_HISTORY DROP COLUMN unknown;
commit;
@@ -0,0 +1,38 @@
-- 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.
-- ensure every sql can rerun without error
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS app VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN app;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS metric VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN metric;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS field VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN field;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS preset boolean;
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN preset;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS priority integer;
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN priority;
ALTER TABLE HZB_ALERT_DEFINE ADD COLUMN IF NOT EXISTS tags VARCHAR(255);
ALTER TABLE HZB_ALERT_DEFINE DROP COLUMN tags;
commit;
@@ -0,0 +1,25 @@
-- 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.
-- ensure every sql can rerun without error
-- Modify hzb_alert_group table columns to TEXT type to resolve row size limit issue
ALTER TABLE HZB_ALERT_GROUP ALTER COLUMN common_annotations TYPE TEXT;
ALTER TABLE HZB_ALERT_GROUP ALTER COLUMN alert_fingerprints TYPE TEXT;
commit;
@@ -0,0 +1,24 @@
-- 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.
-- ensure every sql can rerun without error
-- Modify message column to TEXT
ALTER TABLE HZB_STATUS_PAGE_INCIDENT_CONTENT ALTER COLUMN message TYPE TEXT;
commit;
@@ -0,0 +1,301 @@
-- 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.
-- ensure every sql can rerun without error
-- Update type from 'realtime' to 'realtime_metric'
UPDATE HZB_ALERT_DEFINE
SET type = 'realtime_metric'
WHERE type = 'realtime';
-- Update type from 'periodic' to 'periodic_metric'
UPDATE HZB_ALERT_DEFINE
SET type = 'periodic_metric'
WHERE type = 'periodic';
-- Rename host to instance
DO $$
BEGIN
IF EXISTS(SELECT * FROM information_schema.columns WHERE table_name = 'hzb_monitor' AND column_name = 'instance') THEN
IF EXISTS(SELECT * FROM information_schema.columns WHERE table_name = 'hzb_monitor' AND column_name = 'host') THEN
EXECUTE 'UPDATE HZB_MONITOR SET instance = host WHERE instance IS NULL';
EXECUTE 'ALTER TABLE HZB_MONITOR DROP COLUMN host';
END IF;
ELSE
IF EXISTS(SELECT * FROM information_schema.columns WHERE table_name = 'hzb_monitor' AND column_name = 'host') THEN
EXECUTE 'ALTER TABLE HZB_MONITOR RENAME COLUMN host TO instance';
END IF;
END IF;
END $$;
-- Update instance with port
UPDATE HZB_MONITOR m
SET instance = m.instance || ':' || p.param_value
FROM HZB_PARAM p
WHERE m.id = p.monitor_id AND p.field = 'port' AND p.param_value IS NOT NULL AND p.param_value != ''
AND m.instance NOT LIKE ('%:' || p.param_value);
-- Migrate history table
DO $$
BEGIN
IF EXISTS(SELECT * FROM information_schema.columns WHERE table_name = 'hzb_history' AND column_name = 'monitor_id') THEN
IF NOT EXISTS(SELECT * FROM information_schema.columns WHERE table_name = 'hzb_history' AND column_name = 'metric_labels') THEN
ALTER TABLE hzb_history RENAME COLUMN instance TO metric_labels;
ALTER TABLE hzb_history ALTER COLUMN metric_labels TYPE VARCHAR(5000);
ALTER TABLE hzb_history ADD COLUMN instance VARCHAR(255);
ELSE
UPDATE hzb_history SET metric_labels = instance WHERE metric_labels IS NULL;
UPDATE hzb_history SET instance = NULL;
ALTER TABLE hzb_history ALTER COLUMN instance TYPE VARCHAR(255);
END IF;
UPDATE hzb_history h
SET instance = m.instance
FROM hzb_monitor m
WHERE h.monitor_id = m.id;
ALTER TABLE hzb_history DROP COLUMN monitor_id;
END IF;
END $$;
-- ========================================
-- hzb_alert_define_monitor_bind table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_alert_define_monitor_bind') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_alert_define_monitor_bind' AND indexname = 'index_alert_define_monitor') THEN
DROP INDEX IF EXISTS index_alert_define_monitor;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_alert_define_monitor_bind' AND indexname = 'idx_alert_define_id') THEN
CREATE INDEX idx_alert_define_id ON hzb_alert_define_monitor_bind(alert_define_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_alert_define_monitor_bind' AND indexname = 'idx_monitor_id') THEN
CREATE INDEX idx_monitor_id ON hzb_alert_define_monitor_bind(monitor_id);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_collector_monitor_bind table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_collector_monitor_bind') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_collector_monitor_bind' AND indexname = 'index_collector_monitor') THEN
DROP INDEX IF EXISTS index_collector_monitor;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_collector_monitor_bind' AND indexname = 'idx_collector_monitor_collector') THEN
CREATE INDEX idx_collector_monitor_collector ON hzb_collector_monitor_bind(collector);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_collector_monitor_bind' AND indexname = 'idx_collector_monitor_monitor_id') THEN
CREATE INDEX idx_collector_monitor_monitor_id ON hzb_collector_monitor_bind(monitor_id);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_monitor table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_monitor') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor' AND indexname = 'monitor_query_index') THEN
DROP INDEX IF EXISTS monitor_query_index;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor' AND indexname = 'idx_hzb_monitor_app') THEN
CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(app);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor' AND indexname = 'idx_hzb_monitor_instance') THEN
CREATE INDEX idx_hzb_monitor_instance ON hzb_monitor(instance);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor' AND indexname = 'idx_hzb_monitor_name') THEN
CREATE INDEX idx_hzb_monitor_name ON hzb_monitor(name);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_monitor_bind table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_monitor_bind') THEN
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor_bind' AND indexname = 'index_monitor_bind') THEN
CREATE INDEX index_monitor_bind ON hzb_monitor_bind(biz_id);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_status_page_incident_component_bind table
-- Special handling: component_id might have auto-created index from FK
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_status_page_incident_component_bind') THEN
-- Check if component_id column already has any index, create if not
IF NOT EXISTS (
SELECT 1 FROM pg_indexes
WHERE tablename = 'hzb_status_page_incident_component_bind'
AND indexdef LIKE '%component_id%'
AND indexname NOT LIKE '%_pkey'
) THEN
CREATE INDEX idx_incident_component_component_id ON hzb_status_page_incident_component_bind(component_id);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_push_metrics table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_push_metrics') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_push_metrics' AND indexname = 'push_query_index') THEN
DROP INDEX IF EXISTS push_query_index;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_push_metrics' AND indexname = 'idx_push_metrics_monitor_id') THEN
CREATE INDEX idx_push_metrics_monitor_id ON hzb_push_metrics(monitor_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_push_metrics' AND indexname = 'idx_push_metrics_time') THEN
CREATE INDEX idx_push_metrics_time ON hzb_push_metrics(time);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_history table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_history') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history' AND indexname = 'history_query_index') THEN
DROP INDEX IF EXISTS history_query_index;
END IF;
-- Create new indexes if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history' AND indexname = 'idx_hzb_history_instance') THEN
CREATE INDEX idx_hzb_history_instance ON hzb_history(instance);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history' AND indexname = 'idx_hzb_history_app') THEN
CREATE INDEX idx_hzb_history_app ON hzb_history(app);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history' AND indexname = 'idx_hzb_history_metrics') THEN
CREATE INDEX idx_hzb_history_metrics ON hzb_history(metrics);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history' AND indexname = 'idx_hzb_history_metric') THEN
CREATE INDEX idx_hzb_history_metric ON hzb_history(metric);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_param table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_param') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_param' AND indexname = 'idx_hzb_param_monitor_id') THEN
DROP INDEX IF EXISTS idx_hzb_param_monitor_id;
END IF;
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_param' AND indexname = 'idx_hzb_param_monitor_id') THEN
CREATE INDEX idx_hzb_param_monitor_id ON hzb_param(monitor_id);
END IF;
-- Drop old unique constraint if exists
IF EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE table_name = 'hzb_param'
AND constraint_type = 'UNIQUE'
AND constraint_name = 'uk_hzb_param_monitor_field') THEN
ALTER TABLE hzb_param DROP CONSTRAINT IF EXISTS uk_hzb_param_monitor_field;
END IF;
-- Create new unique constraint if not exist
IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE table_name = 'hzb_param'
AND constraint_type = 'UNIQUE'
AND constraint_name = 'uk_hzb_param_monitor_field') THEN
ALTER TABLE hzb_param
ADD CONSTRAINT uk_hzb_param_monitor_field
UNIQUE (monitor_id, field);
END IF;
END IF;
END $$;
-- ========================================
-- hzb_plugin_param table
-- ========================================
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'hzb_plugin_param') THEN
-- Drop old index if exists
IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_plugin_param' AND indexname = 'idx_hzb_plugin_param_plugin_metadata_id') THEN
DROP INDEX IF EXISTS idx_hzb_plugin_param_plugin_metadata_id;
END IF;
-- Create new index if not exist
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_plugin_param' AND indexname = 'idx_hzb_plugin_param_plugin_metadata_id') THEN
CREATE INDEX idx_hzb_plugin_param_plugin_metadata_id ON hzb_plugin_param(plugin_metadata_id);
END IF;
-- Drop old unique constraint if exists
IF EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE table_name = 'hzb_plugin_param'
AND constraint_type = 'UNIQUE'
AND constraint_name = 'uk_hzb_plugin_param_metadata_field') THEN
ALTER TABLE hzb_plugin_param DROP CONSTRAINT IF EXISTS uk_hzb_plugin_param_metadata_field;
END IF;
-- Create new unique constraint if not exist
IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE table_name = 'hzb_plugin_param'
AND constraint_type = 'UNIQUE'
AND constraint_name = 'uk_hzb_plugin_param_metadata_field') THEN
ALTER TABLE hzb_plugin_param
ADD CONSTRAINT uk_hzb_plugin_param_metadata_field
UNIQUE (plugin_metadata_id, field);
END IF;
END IF;
END $$;
COMMIT;
@@ -0,0 +1,61 @@
-- 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.
-- 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.
-- Scheduled SOP execution configurations
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 SMALLINT DEFAULT 1,
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 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);
@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<configuration scan="true">
<springProperty scope="context" name="application_name" source="spring.application.name" defaultValue="server"/>
<!-- Output logs to ConsoleAppender -->
<appender name="CONSOLE_RAW" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="ConsoleAppender" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>512</queueSize>
<includeCallerData>true</includeCallerData>
<appender-ref ref="CONSOLE_RAW"/>
</appender>
<appender name="SystemOutFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- Logger rolling policy, by date and by size -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Archived log file path. %d{yyyy-MM-dd} specifies date format, %i specifies index -->
<fileNamePattern>logs/${application_name}-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
<!-- Log retention duration -->
<maxHistory>7</maxHistory>
<!-- Maximum size of log retention -->
<totalSizeCap>5GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<!-- Besides logging by day, log files cannot exceed 200M, if exceeded, log files will start from index 0 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- Append mode for logging -->
<append>true</append>
<!-- Log file format -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<appender name="ErrOutFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/${application_name}-%d{yyyy-MM-dd}-error.%i.log.zip</fileNamePattern>
<!-- Log retention duration -->
<maxHistory>7</maxHistory>
<!-- Maximum size of log retention -->
<totalSizeCap>5GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- Append mode for logging -->
<append>true</append>
<!-- Log file format -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- This log file records error and above levels -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<!-- OpenTelemetry Appender for shipping logs to GrepTimeDB -->
<appender name="OpenTelemetryAppender" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
<!-- Capture source code information (class name, method name, line number) -->
<captureCodeAttributes>true</captureCodeAttributes>
<!-- Capture MDC context values -->
<captureMdcAttributes>
<pattern>.*</pattern>
</captureMdcAttributes>
<!-- Capture experimental attributes like exception details -->
<captureExperimentalAttributes>true</captureExperimentalAttributes>
<!-- Capture marker attributes -->
<captureMarkerAttribute>true</captureMarkerAttribute>
<!-- Capture logger context attributes -->
<captureLoggerContext>true</captureLoggerContext>
</appender>
<!-- Settings for this logger: for example, all output logs under the org.springframework package must be at level info or above to be output! -->
<!-- This can avoid outputting many common debug information of the spring framework! -->
<logger name="org.springframework" level="info"/>
<logger name="org.json" level="error"/>
<logger name="io.netty" level="info"/>
<logger name="org.slf4j" level="info"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.hibernate" level="info"/>
<logger name="org.apache.http" level="info"/>
<logger name="com.zaxxer" level="info"/>
<logger name="springfox" level="info"/>
<logger name="org.mongodb" level="warn"/>
<logger name="io.greptime" level="warn"/>
<logger name="org.apache.kafka" level="warn"/>
<logger name="io.opentelemetry" level="info"/>
<!-- Production environment configuration -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="OpenTelemetryAppender"/>
</root>
<!-- North log -->
<Logger name="com.obs.services.AbstractClient" level="OFF"
additivity="false">
</Logger>
<!-- South log -->
<Logger name="com.obs.services.internal.RestStorageService" level="OFF"
additivity="false">
</Logger>
<!-- Access log -->
<Logger name="com.obs.log.AccessLogger" level="OFF"
additivity="false">
</Logger>
</springProfile>
<!-- Development environment configuration -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="OpenTelemetryAppender"/>
</root>
</springProfile>
<!-- Development environment configuration -->
<springProfile name="mysql">
<root level="INFO">
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="OpenTelemetryAppender"/>
</root>
</springProfile>
<!-- Development environment configuration -->
<springProfile name="pg">
<root level="INFO">
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="SystemOutFileAppender"/>
<appender-ref ref="ErrOutFileAppender"/>
<appender-ref ref="OpenTelemetryAppender"/>
</root>
</springProfile>
</configuration>
@@ -0,0 +1,127 @@
# 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.
## -- sureness.yml account source -- ##
# config the resource restful api that need auth protection, base rbac
# rule: api===method===role
# eg: /api/v1/source1===get===[admin] means /api/v2/host===post support role[admin] access.
# eg: /api/v1/source2===get===[] means /api/v1/source2===get can not access by any role.
resourceRole:
- /api/account/auth/refresh===post===[admin,user,guest]
- /api/apps/**===get===[admin,user,guest]
- /api/monitor/**===get===[admin,user,guest]
- /api/monitor/**===post===[admin,user]
- /api/monitor/**===put===[admin,user]
- /api/monitor/**===delete==[admin]
- /api/monitors/**===get===[admin,user,guest]
- /api/monitors/**===post===[admin,user]
- /api/monitors/**===put===[admin,user]
- /api/monitors/**===delete===[admin]
- /api/alert/**===get===[admin,user,guest]
- /api/alert/**===post===[admin,user]
- /api/alert/**===put===[admin,user]
- /api/alert/**===delete===[admin]
- /api/alerts/**===get===[admin,user,guest]
- /api/alerts/**===post===[admin,user]
- /api/alerts/**===put===[admin,user]
- /api/alerts/**===delete===[admin]
- /api/notice/**===get===[admin,user,guest]
- /api/notice/**===post===[admin,user]
- /api/notice/**===put===[admin,user]
- /api/notice/**===delete===[admin]
- /api/tag/**===get===[admin,user,guest]
- /api/tag/**===post===[admin,user]
- /api/tag/**===put===[admin,user]
- /api/tag/**===delete===[admin]
- /api/summary/**===get===[admin,user,guest]
- /api/summary/**===post===[admin,user]
- /api/summary/**===put===[admin,user]
- /api/summary/**===delete===[admin]
- /api/collector/**===get===[admin,user,guest]
- /api/collector/**===post===[admin,user]
- /api/collector/**===put===[admin,user]
- /api/collector/**===delete===[admin]
- /api/status/page/**===get===[admin,user,guest]
- /api/status/page/**===post===[admin,user]
- /api/status/page/**===put===[admin,user]
- /api/status/page/**===delete===[admin]
- /api/grafana/**===get===[admin,user,guest]
- /api/grafana/**===post===[admin,user]
- /api/grafana/**===put===[admin,user]
- /api/grafana/**===delete===[admin]
- /api/bulletin/**===get===[admin,user,guest]
- /api/bulletin/**===post===[admin,user]
- /api/bulletin/**===put===[admin,user]
- /api/bulletin/**===delete===[admin]
- /api/mcp/**===get===[admin]
- /api/mcp/**===post===[admin]
- /api/chat/**===get===[admin,user]
- /api/chat/**===post===[admin]
- /api/logs/ingest/**===post===[admin,user]
- /api/account/token===get===[admin]
- /api/account/token/**===post===[admin]
- /api/account/token/**===delete===[admin]
# config the resource restful api that need bypass auth protection
# rule: api===method
# eg: /api/v1/source3===get means /api/v1/source3===get can be access by anyone, no need auth.
excludedResource:
- /api/alert/sse/**===*
- /api/logs/sse/**===*
- /api/account/auth/**===*
- /api/i18n/**===get
- /api/apps/hierarchy===get
- /api/push/**===*
- /api/status/page/public/**===*
- /api/manager/sse/**===*
# web ui resource
- /===get
- /assets/**===get
- /dashboard/**===get
- /monitors/**===get
- /alert/**===get
- /account/**===get
- /setting/**===get
- /passport/**===get
- /status/**===get
- /log/**===get
- /**/*.html===get
- /**/*.js===get
- /**/*.css===get
- /**/*.ico===get
- /**/*.ttf===get
- /**/*.png===get
- /**/*.gif===get
- /**/*.jpg===get
- /**/*.svg===get
- /**/*.json===get
- /**/*.woff===get
- /**/*.eot===get
# swagger ui resource
- /swagger-resources/**===get
- /v2/api-docs===get
- /v3/api-docs===get
# h2 database
- /h2-console/**===*
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
# eg: admin has role [admin,user], password is hertzbeat
# eg: tom has role [user], password is hertzbeat
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
account:
- appId: admin
credential: hertzbeat
role: [admin]
@@ -0,0 +1,30 @@
/*
* 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.startup;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
/**
* Abstract Integration Test for Spring.
*/
@ActiveProfiles("test")
@SpringBootTest(classes = HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AbstractSpringIntegrationTest {
}
@@ -0,0 +1,88 @@
/*
* 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.startup;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hertzbeat.common.config.VirtualThreadProperties;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskRejectedException;
/**
* Tests for {@link AsyncConfig}.
*/
class AsyncConfigTest {
private final AsyncConfig asyncConfig = new AsyncConfig();
@Test
void taskExecutorRunsAsyncTasksOnVirtualThreads() throws Exception {
VirtualThreadProperties properties = new VirtualThreadProperties();
try (SimpleAsyncTaskExecutor executor = asyncConfig.taskExecutor(properties)) {
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean virtualThread = new AtomicBoolean(false);
executor.execute(() -> {
virtualThread.set(Thread.currentThread().isVirtual());
latch.countDown();
});
assertTrue(latch.await(5, TimeUnit.SECONDS));
assertTrue(virtualThread.get());
}
}
@Test
void taskExecutorRejectsWhenConcurrencyLimitReached() throws Exception {
VirtualThreadProperties properties = new VirtualThreadProperties(
true,
VirtualThreadProperties.PoolProperties.collectorDefaults(),
VirtualThreadProperties.PoolProperties.commonDefaults(),
VirtualThreadProperties.PoolProperties.managerDefaults(),
VirtualThreadProperties.AlerterProperties.defaults(),
VirtualThreadProperties.PoolProperties.warehouseDefaults(),
new VirtualThreadProperties.AsyncProperties(true, 1, true, 5000L));
try (SimpleAsyncTaskExecutor executor = asyncConfig.taskExecutor(properties)) {
CountDownLatch started = new CountDownLatch(1);
CountDownLatch release = new CountDownLatch(1);
executor.execute(() -> {
started.countDown();
try {
release.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
assertTrue(started.await(5, TimeUnit.SECONDS));
try {
assertThrows(TaskRejectedException.class, () -> executor.execute(() -> {
}));
} finally {
release.countDown();
}
}
}
}
@@ -0,0 +1,110 @@
/*
* 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.startup;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import jakarta.annotation.Resource;
import org.apache.hertzbeat.alert.AlerterProperties;
import org.apache.hertzbeat.alert.AlerterWorkerPool;
import org.apache.hertzbeat.alert.calculate.realtime.MetricsRealTimeAlertCalculator;
import org.apache.hertzbeat.alert.controller.AlertDefineController;
import org.apache.hertzbeat.alert.controller.AlertDefinesController;
import org.apache.hertzbeat.alert.controller.AlertsController;
import org.apache.hertzbeat.alert.service.impl.AlertDefineServiceImpl;
import org.apache.hertzbeat.alert.service.impl.AlertServiceImpl;
import org.apache.hertzbeat.collector.collect.database.JdbcSpiLoader;
import org.apache.hertzbeat.collector.collect.http.promethus.PrometheusParseCreator;
import org.apache.hertzbeat.collector.collect.strategy.CollectStrategyFactory;
import org.apache.hertzbeat.collector.dispatch.CommonDispatcher;
import org.apache.hertzbeat.collector.dispatch.DispatchProperties;
import org.apache.hertzbeat.collector.dispatch.MetricsCollectorQueue;
import org.apache.hertzbeat.collector.dispatch.WorkerPool;
import org.apache.hertzbeat.collector.dispatch.entrance.internal.CollectJobService;
import org.apache.hertzbeat.collector.timer.TimerDispatcher;
import org.apache.hertzbeat.collector.dispatch.unit.impl.DataSizeConvert;
import org.apache.hertzbeat.common.config.CommonConfig;
import org.apache.hertzbeat.common.config.CommonProperties;
import org.apache.hertzbeat.common.queue.impl.InMemoryCommonDataQueue;
import org.apache.hertzbeat.common.support.SpringContextHolder;
import org.apache.hertzbeat.alert.service.impl.TencentSmsClientImpl;
import org.apache.hertzbeat.warehouse.WarehouseWorkerPool;
import org.apache.hertzbeat.warehouse.controller.MetricsDataController;
import org.apache.hertzbeat.warehouse.store.history.tsdb.iotdb.IotDbDataStorage;
import org.apache.hertzbeat.warehouse.store.history.tsdb.tdengine.TdEngineDataStorage;
import org.apache.hertzbeat.warehouse.store.realtime.memory.MemoryDataStorage;
import org.apache.hertzbeat.warehouse.store.realtime.redis.RedisDataStorage;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
/**
* Manager Test
*
* @version 2.1
*/
class ContextTest extends AbstractSpringIntegrationTest {
@Resource
private ApplicationContext ctx;
@Test
void testAutoImport() {
// test alert module
assertNotNull(ctx.getBean(AlertDefineServiceImpl.class));
assertNotNull(ctx.getBean(AlertServiceImpl.class));
assertNotNull(ctx.getBean(AlertDefineController.class));
assertNotNull(ctx.getBean(AlerterWorkerPool.class));
assertNotNull(ctx.getBean(AlerterProperties.class));
assertNotNull(ctx.getBean(MetricsRealTimeAlertCalculator.class));
assertNotNull(ctx.getBean(AlertsController.class));
assertNotNull(ctx.getBean(AlertDefinesController.class));
// test collector module
assertNotNull(ctx.getBean(TimerDispatcher.class));
assertNotNull(ctx.getBean(CommonDispatcher.class));
assertNotNull(ctx.getBean(DispatchProperties.class));
assertNotNull(ctx.getBean(MetricsCollectorQueue.class));
assertNotNull(ctx.getBean(WorkerPool.class));
assertNotNull(ctx.getBean(CollectJobService.class));
assertNotNull(ctx.getBean(JdbcSpiLoader.class));
assertNotNull(ctx.getBean(PrometheusParseCreator.class));
assertNotNull(ctx.getBean(DataSizeConvert.class));
assertNotNull(ctx.getBean(CollectStrategyFactory.class));
// test common module
assertNotNull(ctx.getBean(CommonProperties.class));
assertNotNull(ctx.getBean(CommonConfig.class));
assertNotNull(ctx.getBean(InMemoryCommonDataQueue.class));
// condition on common.sms.tencent.app-id
assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(TencentSmsClientImpl.class));
assertNotNull(ctx.getBean(SpringContextHolder.class));
// test warehouse module
assertNotNull(ctx.getBean(WarehouseWorkerPool.class));
// default DataStorage is RealTimeMemoryDataStorage
assertNotNull(ctx.getBean(MemoryDataStorage.class));
assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(RedisDataStorage.class));
assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(TdEngineDataStorage.class));
assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getBean(IotDbDataStorage.class));
assertNotNull(ctx.getBean(MetricsDataController.class));
}
}
@@ -0,0 +1,185 @@
/*
* 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.startup;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.AlertDefineMonitorBind;
import org.apache.hertzbeat.common.entity.manager.CollectorMonitorBind;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.common.entity.manager.MonitorBind;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.StatusPageIncidentComponentBind;
import org.apache.hertzbeat.common.entity.push.PushMetrics;
import org.apache.hertzbeat.common.entity.warehouse.History;
import org.apache.hertzbeat.manager.pojo.dto.PluginParam;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Integration test for validating that entity indexes are actually created in the database.
* This test uses H2 in-memory database to verify DDL generation and index creation.
*/
@Slf4j
@SpringBootTest(classes = HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test")
@TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1",
"spring.datasource.driver-class-name=org.h2.Driver",
"spring.jpa.show-sql=false"
})
@DisplayName("Entity Index Creation Integration Test")
class EntityIndexIntegrationTest {
@Autowired
private DataSource dataSource;
public List<Class<?>> entities = List.of(
AlertDefineMonitorBind.class,
CollectorMonitorBind.class,
Monitor.class,
MonitorBind.class,
Param.class,
StatusPageIncidentComponentBind.class,
PushMetrics.class,
History.class,
PluginParam.class
);
@Test
@DisplayName("All entity indexes should be created in database")
public void testAllEntityIndexes() throws SQLException {
for (Class<?> entity : entities) {
List<ExpectedIndex> expectedIndexes = parseExpectedIndexes(entity);
if (expectedIndexes.isEmpty()) {
continue;
}
Map<String, IndexMeta> actual = getIndexes(expectedIndexes.get(0).tableName());
for (ExpectedIndex expected : expectedIndexes) {
assertIndexExists(expected, actual);
}
}
}
private List<ExpectedIndex> parseExpectedIndexes(Class<?> entityClass) {
Table table = entityClass.getAnnotation(Table.class);
if (table == null) {
return List.of();
}
String tableName = table.name().toUpperCase();
List<ExpectedIndex> result = new ArrayList<>();
for (Index idx : table.indexes()) {
Set<String> columns = Arrays.stream(idx.columnList().split(","))
.map(String::trim)
.map(String::toUpperCase)
.collect(Collectors.toSet());
result.add(new ExpectedIndex(tableName, columns, false));
}
for (UniqueConstraint uc : table.uniqueConstraints()) {
Set<String> columns = Arrays.stream(uc.columnNames())
.map(String::toUpperCase).collect(Collectors.toSet());
result.add(new ExpectedIndex(tableName, columns, true));
}
return result;
}
private void assertIndexExists(ExpectedIndex expected, Map<String, IndexMeta> actualIndexes) {
boolean found = actualIndexes.values().stream().filter(idx -> !expected.unique || idx.unique).anyMatch(idx -> idx.columns.containsAll(expected.columns));
assertTrue(found, "Expected index not found. Table=" + expected.tableName + ", columns=" + expected.columns + ", unique=" + expected.unique + ", actual=" + actualIndexes);
}
private Map<String, IndexMeta> getIndexes(String tableName) throws SQLException {
Map<String, IndexMeta> indexes = new HashMap<>();
String sql = """
SELECT
INDEX_NAME,
COLUMN_NAME,
IS_UNIQUE
FROM INFORMATION_SCHEMA.INDEX_COLUMNS
WHERE TABLE_NAME = ?
""";
try (Connection conn = dataSource.getConnection(); var ps = conn.prepareStatement(sql)) {
ps.setString(1, tableName.toUpperCase());
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String indexName = rs.getString("INDEX_NAME");
String column = rs.getString("COLUMN_NAME");
boolean unique = rs.getBoolean("IS_UNIQUE");
if ("PRIMARY".equalsIgnoreCase(indexName)) {
continue;
}
indexes.computeIfAbsent(indexName, k -> new IndexMeta(unique)).columns.add(column.toUpperCase());
}
}
}
return indexes;
}
static class IndexMeta {
final boolean unique;
final Set<String> columns = new HashSet<>();
IndexMeta(boolean unique) {
this.unique = unique;
}
}
record ExpectedIndex(String tableName, Set<String> columns, boolean unique) {
}
@TestConfiguration
static class TestConfig {
@Bean
public WebProperties webProperties() {
return new WebProperties();
}
}
}
@@ -0,0 +1,54 @@
/*
* 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.startup;
import static org.junit.jupiter.api.Assertions.fail;
import io.netty.channel.ChannelOption;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;
/**
* Guards the startup runtime against Reactor Netty / Netty mismatches that only show up when a client loop
* is created for MySQL R2DBC collection.
*/
class ReactorNettyCompatibilityTest {
@Test
void reactorNettyClientLoopCanBeCreated() {
Connection connection = null;
try {
connection = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
.host("127.0.0.1")
.port(9)
.connect()
.onErrorResume(throwable -> Mono.empty())
.block(Duration.ofSeconds(3));
} catch (NoClassDefFoundError error) {
fail("Startup runtime is missing a Reactor Netty dependency needed by MySQL R2DBC collection", error);
} finally {
if (connection != null) {
connection.disposeNow();
}
}
}
}
@@ -0,0 +1,116 @@
/*
* 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.startup;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.time.Duration;
import org.apache.hertzbeat.collector.mysql.r2dbc.MysqlR2dbcConnectionFactoryProvider;
import org.apache.hertzbeat.collector.mysql.r2dbc.MysqlR2dbcQueryExecutor;
import org.apache.hertzbeat.collector.mysql.r2dbc.QueryOptions;
import org.apache.hertzbeat.collector.mysql.r2dbc.QueryResult;
import org.apache.hertzbeat.collector.mysql.r2dbc.ResultSetMapper;
import org.apache.hertzbeat.collector.mysql.r2dbc.SqlGuard;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;
/**
* Verifies that the startup runtime can execute a real MySQL R2DBC query.
*/
class StartupMysqlR2dbcCompatibilityTest {
private static final String DATABASE = "hzb";
private static final String USERNAME = "test";
private static final String PASSWORD = "test123";
private static final String ROOT_PASSWORD = "root123";
private GenericContainer<?> container;
@AfterEach
void tearDown() {
if (container != null) {
container.stop();
container = null;
}
}
@Test
void shouldExecuteMysqlQueryOnStartupRuntimeClasspath() throws Exception {
container = new GenericContainer<>(DockerImageName.parse("mysql:8.0.36"))
.withExposedPorts(3306)
.withEnv("MYSQL_DATABASE", DATABASE)
.withEnv("MYSQL_USER", USERNAME)
.withEnv("MYSQL_PASSWORD", PASSWORD)
.withEnv("MYSQL_ROOT_PASSWORD", ROOT_PASSWORD)
.waitingFor(Wait.forListeningPort());
container.start();
awaitTcpLoginReady();
MysqlR2dbcQueryExecutor executor = new MysqlR2dbcQueryExecutor(
new MysqlR2dbcConnectionFactoryProvider(),
new ResultSetMapper(),
new SqlGuard());
QueryOptions options = QueryOptions.builder()
.host(container.getHost())
.port(container.getMappedPort(3306))
.database(DATABASE)
.username(USERNAME)
.password(PASSWORD)
.timeout(Duration.ofSeconds(8))
.build();
QueryResult result = executor.execute("SELECT 1 AS ok", options);
assertFalse(result.hasError(), () -> "Unexpected query error: " + result.getError());
assertEquals(1, result.getRowCount());
assertEquals("1", result.getRows().getFirst().getFirst());
}
private void awaitTcpLoginReady() throws Exception {
long deadline = System.currentTimeMillis() + 30_000L;
while (System.currentTimeMillis() < deadline) {
try {
var result = container.execInContainer("sh", "-lc",
mysqlCliCommand("SELECT 1"));
if (result.getExitCode() == 0) {
return;
}
} catch (Exception ignored) {
// Wait for the MySQL entrypoint to finish bootstrapping and switch to the final TCP listener.
}
Thread.sleep(1000);
}
throw new IllegalStateException("Timed out waiting for MySQL TCP login to become ready");
}
private String mysqlCliCommand(String sql) {
return String.join(" ",
"CLIENT=$(command -v mysql || command -v mariadb)",
"&&",
"$CLIENT --protocol=TCP -h127.0.0.1 -P3306",
"-u" + USERNAME,
"-p" + PASSWORD,
DATABASE,
"-e",
"\"" + sql.replace("\"", "\\\"") + "\"");
}
}
@@ -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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import jakarta.annotation.Resource;
import org.apache.hertzbeat.common.entity.manager.Collector;
import org.apache.hertzbeat.manager.dao.CollectorDao;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Test case for {@link CollectorDao}
*/
@Transactional
public class CollectorDaoTest extends AbstractSpringIntegrationTest {
@Resource
private CollectorDao collectorDao;
@BeforeEach
void setUp() {
Collector creator = Collector.builder()
.id(1L)
.name("test")
.mode("public")
.status((byte) 1)
.ip("192.34.5.43")
.creator("tom")
.build();
creator = collectorDao.save(creator);
assertNotNull(creator);
}
@AfterEach
public void deleteAll() {
collectorDao.deleteAll();
}
@Test
public void deleteCollectorByName() {
collectorDao.deleteCollectorByName("test");
}
@Test
public void findCollectorByName() {
assertTrue(collectorDao.findCollectorByName("test").isPresent());
}
@Test
public void findCollectorsByNameIn(){
assertFalse(collectorDao.findCollectorsByNameIn(List.of("test")).isEmpty());
}
}
@@ -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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hertzbeat.common.entity.manager.Label;
import org.apache.hertzbeat.base.dao.LabelDao;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* Test case for {@link LabelDao}
*/
@Transactional
class LabelDaoTest extends AbstractSpringIntegrationTest {
@Resource
private LabelDao labelDao;
@BeforeEach
void setUp() {
Label tag = Label.builder()
.name("mock tag")
.tagValue("mock value")
.type((byte) 1)
.creator("mock creator")
.modifier("mock modifier")
.gmtCreate(LocalDateTime.now())
.gmtUpdate(LocalDateTime.now())
.build();
tag = labelDao.saveAndFlush(tag);
assertNotNull(tag);
}
@AfterEach
void tearDown() {
labelDao.deleteAll();
}
@Test
void deleteTagsByIdIn() {
List<Label> tagList = labelDao.findAll();
assertNotNull(tagList);
assertFalse(tagList.isEmpty());
Set<Long> ids = tagList.stream().map(Label::getId).collect(Collectors.toSet());
assertDoesNotThrow(() -> labelDao.deleteLabelsByIdIn(ids));
tagList = labelDao.findAll();
assertNotNull(tagList);
assertTrue(tagList.isEmpty());
}
}
@@ -0,0 +1,221 @@
/*
* 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.startup.dao;
import jakarta.annotation.Resource;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.apache.hertzbeat.common.entity.manager.MetricsFavorite;
import org.apache.hertzbeat.manager.dao.MetricsFavoriteDao;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Test case for {@link MetricsFavoriteDao}
*/
@Transactional
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MetricsFavoriteDaoTest extends AbstractSpringIntegrationTest {
@Resource
private MetricsFavoriteDao metricsFavoriteDao;
@PersistenceContext
private EntityManager entityManager;
private MetricsFavorite testFavorite1;
private MetricsFavorite testFavorite2;
private MetricsFavorite testFavorite3;
private final String testCreator1 = "user1";
private final String testCreator2 = "user2";
private final Long testMonitorId1 = 1L;
private final Long testMonitorId2 = 2L;
private final String testMetricsName1 = "cpu";
private final String testMetricsName2 = "memory";
@BeforeEach
void setUp() {
testFavorite1 = MetricsFavorite.builder()
.creator(testCreator1)
.monitorId(testMonitorId1)
.metricsName(testMetricsName1)
.createTime(LocalDateTime.now())
.build();
testFavorite2 = MetricsFavorite.builder()
.creator(testCreator1)
.monitorId(testMonitorId1)
.metricsName(testMetricsName2)
.createTime(LocalDateTime.now())
.build();
testFavorite3 = MetricsFavorite.builder()
.creator(testCreator2)
.monitorId(testMonitorId2)
.metricsName(testMetricsName1)
.createTime(LocalDateTime.now())
.build();
}
@Test
void testSaveAndFindById() {
MetricsFavorite saved = metricsFavoriteDao.saveAndFlush(testFavorite1);
assertNotNull(saved.getId());
Optional<MetricsFavorite> found = metricsFavoriteDao.findById(saved.getId());
assertTrue(found.isPresent());
assertEquals(testCreator1, found.get().getCreator());
assertEquals(testMonitorId1, found.get().getMonitorId());
assertEquals(testMetricsName1, found.get().getMetricsName());
}
@Test
void testFindByCreatorAndMonitorIdAndMetricsName() {
metricsFavoriteDao.saveAndFlush(testFavorite1);
Optional<MetricsFavorite> found = metricsFavoriteDao
.findByCreatorAndMonitorIdAndMetricsName(testCreator1, testMonitorId1, testMetricsName1);
assertTrue(found.isPresent());
assertEquals(testCreator1, found.get().getCreator());
assertEquals(testMonitorId1, found.get().getMonitorId());
assertEquals(testMetricsName1, found.get().getMetricsName());
}
@Test
void testFindByCreatorAndMonitorIdAndMetricsNameNotFound() {
Optional<MetricsFavorite> found = metricsFavoriteDao.findByCreatorAndMonitorIdAndMetricsName("nonexistent", 999L, "nonexistent");
assertFalse(found.isPresent());
}
@Test
void testFindByCreatorAndMonitorId() {
metricsFavoriteDao.saveAndFlush(testFavorite1);
metricsFavoriteDao.saveAndFlush(testFavorite2);
metricsFavoriteDao.saveAndFlush(testFavorite3);
List<MetricsFavorite> found = metricsFavoriteDao.findByCreatorAndMonitorId(testCreator1, testMonitorId1);
assertNotNull(found);
assertEquals(2, found.size());
assertTrue(found.stream().allMatch(f -> f.getCreator().equals(testCreator1)));
assertTrue(found.stream().allMatch(f -> f.getMonitorId().equals(testMonitorId1)));
assertTrue(found.stream().anyMatch(f -> f.getMetricsName().equals(testMetricsName1)));
assertTrue(found.stream().anyMatch(f -> f.getMetricsName().equals(testMetricsName2)));
}
@Test
void testFindByCreatorAndMonitorIdEmptyResult() {
List<MetricsFavorite> found = metricsFavoriteDao.findByCreatorAndMonitorId("nonexistent", 999L);
assertNotNull(found);
assertTrue(found.isEmpty());
}
@Test
void testDeleteByUserIdAndMonitorIdAndMetricsName() {
MetricsFavorite saved = metricsFavoriteDao.saveAndFlush(testFavorite1);
assertTrue(metricsFavoriteDao.findById(saved.getId()).isPresent());
metricsFavoriteDao.deleteByUserIdAndMonitorIdAndMetricsName(testCreator1, testMonitorId1, testMetricsName1);
entityManager.flush();
entityManager.clear();
assertFalse(metricsFavoriteDao.findById(saved.getId()).isPresent());
}
@Test
void testDeleteByUserIdAndMonitorIdAndMetricsNameNotExists() {
// When - Should not throw exception even if record doesn't exist
assertDoesNotThrow(() -> {
metricsFavoriteDao.deleteByUserIdAndMonitorIdAndMetricsName("nonexistent", 999L, "nonexistent");
});
}
@Test
void testDeleteFavoritesByMonitorIdIn() {
MetricsFavorite saved1 = metricsFavoriteDao.saveAndFlush(testFavorite1);
MetricsFavorite saved2 = metricsFavoriteDao.saveAndFlush(testFavorite2);
MetricsFavorite saved3 = metricsFavoriteDao.saveAndFlush(testFavorite3);
assertEquals(3, metricsFavoriteDao.findAll().size());
Set<Long> monitorIds = Set.of(testMonitorId1, testMonitorId2);
metricsFavoriteDao.deleteFavoritesByMonitorIdIn(monitorIds);
entityManager.flush();
entityManager.clear();
assertEquals(0, metricsFavoriteDao.findAll().size());
assertFalse(metricsFavoriteDao.findById(saved1.getId()).isPresent());
assertFalse(metricsFavoriteDao.findById(saved2.getId()).isPresent());
assertFalse(metricsFavoriteDao.findById(saved3.getId()).isPresent());
}
@Test
void testDeleteFavoritesByMonitorIdInPartialDelete() {
MetricsFavorite saved1 = metricsFavoriteDao.saveAndFlush(testFavorite1);
MetricsFavorite saved3 = metricsFavoriteDao.saveAndFlush(testFavorite3);
Set<Long> monitorIds = Set.of(testMonitorId1);
metricsFavoriteDao.deleteFavoritesByMonitorIdIn(monitorIds);
entityManager.flush();
entityManager.clear();
assertEquals(1, metricsFavoriteDao.findAll().size());
assertFalse(metricsFavoriteDao.findById(saved1.getId()).isPresent());
assertTrue(metricsFavoriteDao.findById(saved3.getId()).isPresent());
}
@Test
void testDeleteFavoritesByMonitorIdInNonExistentIds() {
metricsFavoriteDao.saveAndFlush(testFavorite1);
Set<Long> nonExistentIds = Set.of(999L, 1000L);
metricsFavoriteDao.deleteFavoritesByMonitorIdIn(nonExistentIds);
assertEquals(1, metricsFavoriteDao.findAll().size());
}
@Test
void testUniqueConstraint() {
metricsFavoriteDao.saveAndFlush(testFavorite1);
MetricsFavorite duplicate = MetricsFavorite.builder()
.creator(testCreator1)
.monitorId(testMonitorId1)
.metricsName(testMetricsName1)
.createTime(LocalDateTime.now()).build();
assertThrows(Throwable.class, () -> {
metricsFavoriteDao.saveAndFlush(duplicate);
});
}
}
@@ -0,0 +1,124 @@
/*
* 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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import jakarta.annotation.Resource;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.manager.dao.MonitorDao;
import org.apache.hertzbeat.manager.pojo.dto.AppCount;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* Test case for {@link MonitorDao}
*/
@Transactional
class MonitorDaoTest extends AbstractSpringIntegrationTest {
@Resource
private MonitorDao monitorDao;
@BeforeEach
void setUp() {
Monitor monitor = Monitor.builder()
.id(1L)
.jobId(2L)
.app("jvm")
.name("jvm_test")
.instance("192.34.5.43:8989")
.status((byte) 1)
.build();
monitor = monitorDao.saveAndFlush(monitor);
assertNotNull(monitor);
}
@AfterEach
void tearDown() {
monitorDao.deleteAll();
}
@Test
void deleteAllByIdIn() {
Set<Long> ids = new HashSet<>();
ids.add(1L);
assertDoesNotThrow(() -> monitorDao.deleteAllByIdIn(ids));
}
@Test
void findMonitorsByIdIn() {
Set<Long> ids = new HashSet<>();
ids.add(1L);
List<Monitor> monitors = monitorDao.findMonitorsByIdIn(ids);
assertNotNull(monitors);
assertEquals(1, monitors.size());
}
@Test
void findMonitorsByAppEquals() {
List<Monitor> monitors = monitorDao.findMonitorsByAppEquals("jvm");
assertNotNull(monitors);
assertEquals(1, monitors.size());
monitors = monitorDao.findMonitorsByAppEquals("mysql");
assertTrue(monitors.isEmpty());
}
@Test
void findMonitorsByStatusNotInAndJobIdNotNull() {
List<Byte> bytes = Arrays.asList((byte) 2, (byte) 3);
List<Monitor> monitors = monitorDao.findMonitorsByStatusNotInAndJobIdNotNull(bytes);
assertNotNull(monitors);
assertEquals(1, monitors.size());
}
@Test
void findMonitorByNameEquals() {
Optional<Monitor> monitorOptional = monitorDao.findMonitorByNameEquals("jvm_test");
assertTrue(monitorOptional.isPresent());
}
@Test
void findAppsStatusCount() {
List<AppCount> appCounts = monitorDao.findAppsStatusCount();
assertNotNull(appCounts);
assertFalse(appCounts.isEmpty());
}
@Test
void updateMonitorStatus() {
Optional<Monitor> monitorOptional = monitorDao.findById(1L);
assertTrue(monitorOptional.isPresent());
assertEquals((byte) 1, monitorOptional.get().getStatus());
monitorDao.updateMonitorStatus(1L, (byte) 0);
monitorOptional = monitorDao.findById(1L);
assertTrue(monitorOptional.isPresent());
assertEquals((byte) 0, monitorOptional.get().getStatus());
}
}
@@ -0,0 +1,90 @@
/*
* 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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import org.apache.hertzbeat.alert.dao.NoticeRuleDao;
import org.apache.hertzbeat.common.entity.alerter.NoticeRule;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* Test case for {@link NoticeRuleDao}
*/
@Transactional
class NoticeRuleDaoTest extends AbstractSpringIntegrationTest {
@Resource
private NoticeRuleDao noticeRuleDao;
@BeforeEach
void setUp() {
// insert notice rule with enable = true
NoticeRule enabled = NoticeRule.builder()
.name("mock notice rule")
.enable(true)
.filterAll(true)
.gmtCreate(LocalDateTime.now())
.gmtUpdate(LocalDateTime.now())
.modifier("mock")
.creator("mock")
.receiverId(List.of(1L))
.receiverName(List.of("mock receiver"))
.templateId(1L)
.receiverName(List.of("mock template"))
.build();
enabled = noticeRuleDao.saveAndFlush(enabled);
assertNotNull(enabled);
// insert notice rule with enable = false
NoticeRule disabled = NoticeRule.builder()
.name("mock notice rule disabled")
.enable(false)
.filterAll(true)
.gmtCreate(LocalDateTime.now())
.gmtUpdate(LocalDateTime.now())
.modifier("mock")
.creator("mock")
.receiverId(List.of(1L))
.receiverName(List.of("mock receiver"))
.templateId(1L)
.receiverName(List.of("mock template"))
.build();
disabled = noticeRuleDao.saveAndFlush(disabled);
assertNotNull(disabled);
}
@AfterEach
void tearDown() {
noticeRuleDao.deleteAll();
}
@Test
void findNoticeRulesByEnableTrue() {
List<NoticeRule> enabledList = noticeRuleDao.findNoticeRulesByEnableTrue();
assertNotNull(enabledList);
assertEquals(1, enabledList.size());
}
}
@@ -0,0 +1,120 @@
/*
* 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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.manager.dao.ParamDao;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* Test case for {@link ParamDao}
*/
@Transactional
class ParamDaoTest extends AbstractSpringIntegrationTest {
@Resource
private ParamDao paramDao;
@BeforeEach
void setUp() {
Param param = Param.builder()
.field("mock field")
.paramValue("mock value")
.gmtCreate(LocalDateTime.now())
.gmtUpdate(LocalDateTime.now())
.monitorId(1L)
.type((byte) 1)
.build();
param = paramDao.saveAndFlush(param);
assertNotNull(param);
}
@AfterEach
void tearDown() {
paramDao.deleteAll();
}
@Test
void findParamsByMonitorId() {
List<Param> paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(1L, paramList.size());
}
@Test
void deleteParamsByMonitorId() {
// make sure params size is correct
List<Param> paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(1L, paramList.size());
// delete params by monitor id when monitor id is wrong
paramDao.deleteParamsByMonitorId(2L);
paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(1L, paramList.size());
// delete params by monitor id when monitor id is true
paramDao.deleteParamsByMonitorId(1L);
paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(0L, paramList.size());
}
@Test
void deleteParamsByMonitorIdIn() {
// make sure params size is correct
List<Param> paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(1L, paramList.size());
// delete params by monitor id when monitor id is wrong
Set<Long> ids = new HashSet<>();
ids.add(2L);
paramDao.deleteParamsByMonitorIdIn(ids);
paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(1L, paramList.size());
// delete params by monitor id when monitor id is true
ids.add(1L);
paramDao.deleteParamsByMonitorId(1L);
paramList = paramDao.findParamsByMonitorId(1L);
assertNotNull(paramList);
assertEquals(0L, paramList.size());
}
}
@@ -0,0 +1,78 @@
/*
* 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.startup.dao;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import jakarta.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.dao.ParamDefineDao;
import org.apache.hertzbeat.startup.AbstractSpringIntegrationTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* Test case for {@link ParamDefineDao}
*/
@Transactional
class ParamDefineDaoTest extends AbstractSpringIntegrationTest {
@Resource
private ParamDefineDao paramDefineDao;
@BeforeEach
void setUp() {
ParamDefine paramDefine = ParamDefine.builder()
.app("mock app")
.field("mock field")
.defaultValue("mock default value")
.limit((short) 1)
.keyAlias("mock key alias")
.valueAlias("mock value alias")
.options(Collections.emptyList())
.range("mock range")
.name(new HashMap<>())
.hide(true)
.required(true)
.type("mock type")
.placeholder("mock placeholder")
.creator("mock creator")
.modifier("mock modifier")
.build();
paramDefine = paramDefineDao.saveAndFlush(paramDefine);
assertNotNull(paramDefine);
}
@AfterEach
void tearDown() {
paramDefineDao.deleteAll();
}
@Test
void findParamDefinesByApp() {
List<ParamDefine> paramDefineList = paramDefineDao.findParamDefinesByApp("mock app");
assertNotNull(paramDefineList);
assertEquals(1, paramDefineList.size());
}
}