Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions conf/db/zsv/V5.1.0__schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,19 @@ SET src.`type` = IF(ldap.serverType IN ('OpenLdap', 'WindowsAD'), ldap.serverTyp
WHERE src.`type` = 'ldap';

CALL INSERT_COLUMN('ThirdPartyAccountSourceVO', 'updateAccountStrategies', 'varchar(255)', 0, '', 'createAccountStrategy');

-- Feature: Log Server | ZSV-12254

CREATE TABLE IF NOT EXISTS `zstack`.`LogServerVO` (
`uuid` varchar(32) NOT NULL UNIQUE,
`name` varchar(255) NOT NULL,
`description` varchar(2048) NULL,
`category` varchar(255) NOT NULL,
`type` varchar(255) NOT NULL,
`level` varchar(255) NULL,
`state` varchar(255) NOT NULL DEFAULT 'Enabled',
`configuration` text NOT NULL,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

避免将敏感配置明文存储在 configuration 字段。

configuration 使用 text NOT NULL 会把日志服务器配置整体落库;若包含如密码/令牌等敏感项,将形成明文泄露面(备份、审计导出、SQL 日志)。建议将密钥类字段拆分为单独加密存储(或至少入库前加密、出参脱敏),并避免在 Inventory/日志中直接回传原文。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conf/db/zsv/V5.1.0__schema.sql` at line 50, The schema currently defines the
`configuration` column as text NOT NULL which stores full server configs in
plaintext; change this by identifying sensitive keys within `configuration` and
either: (a) extract those keys into dedicated columns (e.g., `api_key`,
`password`, `token`) and store them encrypted at rest (use your app's encryption
service or DB encryption functions) with appropriate NOT NULL/NULL constraints,
or (b) keep a single `configuration` column but ensure the application encrypts
it before INSERT/UPDATE and decrypts only when needed, plus add DB-level
comments/constraints to enforce that `configuration` is stored encrypted and
ensure SELECTs used by Inventory/log APIs strip or mask sensitive fields. Ensure
the migration updates the table to add new encrypted columns and a migration
path to move and remove plaintext data from the `configuration` text field.

`lastOpDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '1999-12-31 23:59:59',
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1 change: 1 addition & 0 deletions conf/persistence.xml
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,6 @@
<class>org.zstack.softwarePackage.header.SoftwarePackageVO</class>
<class>org.zstack.header.vm.metadata.VmMetadataDirtyVO</class>
<class>org.zstack.header.vm.metadata.VmMetadataFlushStateVO</class>
<class>org.zstack.log.server.LogServerVO</class>
</persistence-unit>
</persistence>
5 changes: 5 additions & 0 deletions core/src/main/java/org/zstack/core/log/LogGlobalConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.zstack.core.log;

import org.zstack.core.config.GlobalConfig;
import org.zstack.core.config.GlobalConfigDef;
import org.zstack.core.config.GlobalConfigDefinition;
import org.zstack.core.config.GlobalConfigValidation;

Expand All @@ -13,4 +14,8 @@ public class LogGlobalConfig {

@GlobalConfigValidation
public static GlobalConfig LOG_DELETE_ACCUMULATED_FILE_SIZE = new GlobalConfig(CATEGORY, "log.delete.accumulatedFileSize");

@GlobalConfigValidation(numberGreaterThan = 1)
@GlobalConfigDef(defaultValue = "30", type = Long.class, description = "sync custom log configuration interval")
public static GlobalConfig SYNC_CUSTOM_LOG_CONFIGURATION_TASK_INTERVAL = new GlobalConfig(CATEGORY, "log.syncCustomLogConfigurationTaskInterval");
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class SdkDataStructureGenerator implements SdkTemplate {
dstToSrc.sort()

SdkFile f = new SdkFile()
f.subPath = "org/zstack/sdk"
f.fileName = "SourceClassMap.java"
f.content = """package org.zstack.sdk;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public Result throwExceptionIfError() {
@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String type;

@Param(required = false, validValues = {"OFF","FATAL","ERROR","WARN","INFO","DEBUG","TRACE","ALL"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String level;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String configuration;

Expand Down
122 changes: 122 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/AddLogServerAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class AddLogServerAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.AddLogServerResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
);
}

return this;
}
}

@Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String name;

@Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String description;

@Param(required = true, validValues = {"ManagementNodeLog","PlatformOperationLog"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String category;

@Param(required = true, validValues = {"Log4j2","FluentBit"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String type;

@Param(required = false, validValues = {"OFF","FATAL","ERROR","WARN","INFO","DEBUG","TRACE","ALL"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String level;

@Param(required = true, maxLength = 8192, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String configuration;

@Param(required = false)
public java.lang.String resourceUuid;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.util.List tagUuids;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.AddLogServerResult value = res.getResult(org.zstack.sdk.AddLogServerResult.class);
ret.value = value == null ? new org.zstack.sdk.AddLogServerResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "POST";
info.path = "/log/servers";
info.needSession = true;
info.needPoll = true;
info.parameterName = "params";
return info;
}

}
14 changes: 14 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/AddLogServerResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.sdk;

import org.zstack.sdk.LogServerInventory;

public class AddLogServerResult {
public LogServerInventory inventory;
public void setInventory(LogServerInventory inventory) {
this.inventory = inventory;
}
public LogServerInventory getInventory() {
return this.inventory;
}

}
101 changes: 101 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/DeleteLogServerAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class DeleteLogServerAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.DeleteLogServerResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
);
}

return this;
}
}

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String uuid;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.DeleteLogServerResult value = res.getResult(org.zstack.sdk.DeleteLogServerResult.class);
ret.value = value == null ? new org.zstack.sdk.DeleteLogServerResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "DELETE";
info.path = "/log/servers";
info.needSession = true;
info.needPoll = true;
info.parameterName = "";
return info;
}

}
7 changes: 7 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/DeleteLogServerResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.zstack.sdk;



public class DeleteLogServerResult {

}
6 changes: 6 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/LogCategory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.zstack.sdk;

public enum LogCategory {
ManagementNodeLog,
PlatformOperationLog,
}
12 changes: 12 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/LogLevel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.zstack.sdk;

public enum LogLevel {
OFF,
FATAL,
ERROR,
WARN,
INFO,
DEBUG,
TRACE,
ALL,
}
Loading