Skip to content

Commit b2c8fa5

Browse files
committed
api,server,schema,plugin,client: logs web server
This feature enables administrators to view management server logs directly in the UI through a dedicated API call. It leverages a Netty-based websocket server to stream logs in real time, offering an efficient way to monitor and debug server operations. Note that the plugin is disabled by default and must be enabled manually. Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 2dfe6a6 commit b2c8fa5

File tree

46 files changed

+2780
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2780
-28
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public class ApiConstants {
9090
public static final String CONVERT_INSTANCE_HOST_ID = "convertinstancehostid";
9191
public static final String CONVERT_INSTANCE_STORAGE_POOL_ID = "convertinstancepoolid";
9292
public static final String ENABLED_REVOCATION_CHECK = "enabledrevocationcheck";
93+
public static final String CONTEXT_ID = "contextid";
9394
public static final String CONTROLLER = "controller";
9495
public static final String CONTROLLER_UNIT = "controllerunit";
9596
public static final String COPY_IMAGE_TAGS = "copyimagetags";
@@ -119,12 +120,15 @@ public class ApiConstants {
119120
public static final String CN = "cn";
120121
public static final String COMMAND = "command";
121122
public static final String CMD_EVENT_TYPE = "cmdeventtype";
123+
public static final String CLIENT_ADDRESS = "clientaddress";
122124
public static final String COMPONENT = "component";
125+
public static final String CONNECTED = "connected";
123126
public static final String CPU_CORE_PER_SOCKET = "cpucorepersocket";
124127
public static final String CPU_NUMBER = "cpunumber";
125128
public static final String CPU_SPEED = "cpuspeed";
126129
public static final String CPU_LOAD_AVERAGE = "cpuloadaverage";
127130
public static final String CREATED = "created";
131+
public static final String CREATOR_ADDRESS = "creatoraddress";
128132
public static final String CTX_ACCOUNT_ID = "ctxaccountid";
129133
public static final String CTX_DETAILS = "ctxDetails";
130134
public static final String CTX_USER_ID = "ctxuserid";
@@ -140,6 +144,7 @@ public class ApiConstants {
140144
public static final String ENCRYPT_FORMAT = "encryptformat";
141145
public static final String ENCRYPT_ROOT = "encryptroot";
142146
public static final String ENCRYPTION_SUPPORTED = "encryptionsupported";
147+
public static final String FILTERS = "filters";
143148
public static final String MIN_IOPS = "miniops";
144149
public static final String MAX_IOPS = "maxiops";
145150
public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve";
@@ -1191,6 +1196,8 @@ public class ApiConstants {
11911196
public static final String WEBHOOK_ID = "webhookid";
11921197
public static final String WEBHOOK_NAME = "webhookname";
11931198

1199+
public static final String WEBSOCKET = "websocket";
1200+
11941201
public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
11951202
public static final String MOUNT_OPTIONS = "mountopts";
11961203

@@ -1207,6 +1214,8 @@ public class ApiConstants {
12071214
public static final String OBJECT_STORAGE_LIMIT = "objectstoragelimit";
12081215
public static final String OBJECT_STORAGE_TOTAL = "objectstoragetotal";
12091216

1217+
public static final String LOGS_WEB_SERVER_ENABLED = "logswebserverenabled";
1218+
12101219
public static final String PARAMETER_DESCRIPTION_ACTIVATION_RULE = "Quota tariff's activation rule. It can receive a JS script that results in either " +
12111220
"a boolean or a numeric value: if it results in a boolean value, the tariff value will be applied according to the result; if it results in a numeric value, the " +
12121221
"numeric value will be applied; if the result is neither a boolean nor a numeric value, the tariff will not be applied. If the rule is not informed, the tariff " +

api/src/main/java/org/apache/cloudstack/api/BaseResponse.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ public abstract class BaseResponse implements ResponseObject {
3232
@Param(description = "the current status of the latest async job acting on this object")
3333
private Integer jobStatus;
3434

35+
@SerializedName(ApiConstants.CONTEXT_ID)
36+
@Param(description = "the ID of the executing context")
37+
private String contextId;
38+
3539
public BaseResponse() {
3640
}
3741

@@ -83,4 +87,14 @@ public Integer getJobStatus() {
8387
public void setJobStatus(Integer jobStatus) {
8488
this.jobStatus = jobStatus;
8589
}
90+
91+
@Override
92+
public String getContextId() {
93+
return contextId;
94+
}
95+
96+
@Override
97+
public void setContextId(String contextId) {
98+
this.contextId = contextId;
99+
}
86100
}

api/src/main/java/org/apache/cloudstack/api/ResponseObject.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ public interface ResponseObject {
7676
*/
7777
void setJobStatus(Integer jobStatus);
7878

79+
String getContextId();
80+
void setContextId(String contextId);
81+
7982
public enum ResponseView {
8083
Full,
8184
Restricted

api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void execute() {
7272
response.setInstancesDisksStatsRetentionTime((Integer) capabilities.get(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_TIME));
7373
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
7474
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
75+
response.setLogsWebServerEnabled((Boolean)capabilities.get(ApiConstants.LOGS_WEB_SERVER_ENABLED));
7576
response.setObjectName("capability");
7677
response.setResponseName(getCommandName());
7778
this.setResponseObject(response);

api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public class CapabilitiesResponse extends BaseResponse {
136136
@Param(description = "the min Ram size for the service offering used by the shared filesystem instance", since = "4.20.0")
137137
private Integer sharedFsVmMinRamSize;
138138

139+
@SerializedName(ApiConstants.LOGS_WEB_SERVER_ENABLED)
140+
@Param(description = "true if Logs Web Server plugin is enabled, false otherwise", since = "4.21.0")
141+
private boolean logsWebServerEnabled;
142+
139143
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
140144
this.securityGroupsEnabled = securityGroupsEnabled;
141145
}
@@ -247,4 +251,8 @@ public void setSharedFsVmMinCpuCount(Integer sharedFsVmMinCpuCount) {
247251
public void setSharedFsVmMinRamSize(Integer sharedFsVmMinRamSize) {
248252
this.sharedFsVmMinRamSize = sharedFsVmMinRamSize;
249253
}
254+
255+
public void setLogsWebServerEnabled(boolean logsWebServerEnabled) {
256+
this.logsWebServerEnabled = logsWebServerEnabled;
257+
}
250258
}

client/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@
246246
<artifactId>cloud-plugin-user-two-factor-authenticator-staticpin</artifactId>
247247
<version>${project.version}</version>
248248
</dependency>
249+
<dependency>
250+
<groupId>org.apache.cloudstack</groupId>
251+
<artifactId>cloud-plugin-logs-web-server</artifactId>
252+
<version>${project.version}</version>
253+
</dependency>
249254
<dependency>
250255
<groupId>org.apache.cloudstack</groupId>
251256
<artifactId>cloud-plugin-metrics</artifactId>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.cloudstack.util;
19+
20+
import com.fasterxml.jackson.core.JsonProcessingException;
21+
import com.fasterxml.jackson.databind.ObjectMapper;
22+
import javax.persistence.AttributeConverter;
23+
import javax.persistence.Converter;
24+
import java.io.IOException;
25+
import java.util.List;
26+
27+
@Converter
28+
public class StringListJsonConverter implements AttributeConverter<List<String>, String> {
29+
30+
private static final ObjectMapper mapper = new ObjectMapper();
31+
32+
@Override
33+
public String convertToDatabaseColumn(List<String> attribute) {
34+
try {
35+
return attribute == null ? null : mapper.writeValueAsString(attribute);
36+
} catch (JsonProcessingException e) {
37+
throw new IllegalArgumentException("Error converting list to JSON", e);
38+
}
39+
}
40+
41+
@Override
42+
public List<String> convertToEntityAttribute(String dbData) {
43+
try {
44+
return dbData == null ? null : mapper.readValue(dbData, List.class);
45+
} catch (IOException e) {
46+
throw new IllegalArgumentException("Error converting JSON to list", e);
47+
}
48+
}
49+
}
50+

engine/schema/src/main/resources/META-INF/db/schema-42010to42100-cleanup.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@
1818
--;
1919
-- Schema upgrade cleanup from 4.20.1.0 to 4.21.0.0
2020
--;
21+
22+
DROP TABLE IF EXISTS `cloud`.`logs_web_session`;

engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,18 @@ WHERE rp.rule = 'quotaStatement'
3737
AND NOT EXISTS(SELECT 1 FROM cloud.role_permissions rp_ WHERE rp.role_id = rp_.role_id AND rp_.rule = 'quotaCreditsList');
3838

3939
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.host', 'last_mgmt_server_id', 'bigint unsigned DEFAULT NULL COMMENT "last management server this host is connected to" AFTER `mgmt_server_id`');
40+
41+
CREATE TABLE IF NOT EXISTS `cloud`.`logs_web_session` (
42+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
43+
`uuid` varchar(40) NOT NULL COMMENT 'UUID generated for the session',
44+
`filter` varchar(64) DEFAULT NULL COMMENT 'Filter keyword for the session',
45+
`created` datetime NOT NULL COMMENT 'When the session was created',
46+
`domain_id` bigint(20) unsigned NOT NULL COMMENT 'Domain of the account who generated the session',
47+
`account_id` bigint(20) unsigned NOT NULL COMMENT 'Account who generated the session',
48+
`creator_address` VARCHAR(45) DEFAULT NULL COMMENT 'Address of the creator of the session',
49+
`connections` int unsigned NOT NULL DEFAULT 0 COMMENT 'Number of connections for the session',
50+
`connected_time` datetime DEFAULT NULL COMMENT 'When the session was connected',
51+
`client_address` VARCHAR(45) DEFAULT NULL COMMENT 'Address of the client that connected to the session',
52+
`removed` datetime COMMENT 'When the session was removed/used',
53+
CONSTRAINT `uc_logs_web_session__uuid` UNIQUE (`uuid`)
54+
);

plugins/logs-web-server/pom.xml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
<artifactId>cloud-plugin-logs-web-server</artifactId>
23+
<name>Apache CloudStack Plugin - Logs Web Server</name>
24+
<parent>
25+
<groupId>org.apache.cloudstack</groupId>
26+
<artifactId>cloudstack-plugins</artifactId>
27+
<version>4.21.0.0-SNAPSHOT</version>
28+
<relativePath>../pom.xml</relativePath>
29+
</parent>
30+
<dependencies>
31+
<dependency>
32+
<groupId>org.apache.cloudstack</groupId>
33+
<artifactId>cloud-api</artifactId>
34+
<version>${project.version}</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>io.netty</groupId>
38+
<artifactId>netty-all</artifactId>
39+
</dependency>
40+
</dependencies>
41+
</project>

0 commit comments

Comments
 (0)