From 620d389d1717b26b09dcdf8893a0749e2d1cd600 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 11 Mar 2026 19:20:47 +0100 Subject: [PATCH 1/6] There is a set of TO classes with renamed fields, which makes impossible to correctly communicate between Management Servers and Agents --- .../transport/compat/AbstractTOAdaptor.java | 127 ++++++++++++++++++ .../agent/transport/compat/DiskTOAdaptor.java | 28 ++++ .../compat/MigrateCommandAdaptor.java | 28 ++++ .../transport/compat/NetworkTOAdaptor.java | 28 ++++ .../compat/VirtualMachineTOAdaptor.java | 29 ++++ .../java/com/cloud/serializer/GsonHelper.java | 13 ++ 6 files changed, 253 insertions(+) create mode 100644 core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java create mode 100644 core/src/main/java/com/cloud/agent/transport/compat/DiskTOAdaptor.java create mode 100644 core/src/main/java/com/cloud/agent/transport/compat/MigrateCommandAdaptor.java create mode 100644 core/src/main/java/com/cloud/agent/transport/compat/NetworkTOAdaptor.java create mode 100644 core/src/main/java/com/cloud/agent/transport/compat/VirtualMachineTOAdaptor.java diff --git a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java new file mode 100644 index 000000000000..558b249e4756 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java @@ -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. +package com.cloud.agent.transport.compat; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.SecStorageFirewallCfgCommand; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.transport.ArrayTypeAdaptor; +import com.cloud.agent.transport.InterfaceTypeAdaptor; +import com.cloud.agent.transport.LoggingExclusionStrategy; +import com.cloud.agent.transport.Request; +import com.cloud.agent.transport.StoragePoolTypeAdaptor; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.storage.Storage; +import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.reflect.TypeToken; +import org.apache.cloudstack.transport.HypervisorTypeAdaptor; +import org.apache.log4j.Logger; + +import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * JSON serializer adapter for transport classes (com.cloud.agent.api.to.*) that ensures backward compatibility + * with older Agent versions due to rename of the fields + * (see https://github.com/shapeblue/cloudstack-apple/pull/532/changes) + */ + +public class AbstractTOAdaptor implements JsonSerializer { + private static final Logger s_logger = Logger.getLogger(AbstractTOAdaptor.class); + private static final Gson gson; + + static { + GsonBuilder gsonBuilder = new GsonBuilder(); + gson = setDefaultGsonConfig(gsonBuilder); + GsonBuilder loggerBuilder = new GsonBuilder(); + loggerBuilder.disableHtmlEscaping(); + loggerBuilder.setExclusionStrategies(new LoggingExclusionStrategy(s_logger)); + } + + private Map fieldMappings; + + protected AbstractTOAdaptor(String... fields) { + this.fieldMappings = new LinkedHashMap<>(); + for (int i = 0; i + 1 < fields.length; i += 2) { + String sourceField = fields[i]; + String destinationField = fields[i + 1]; + // skip empty fields + if (StringUtils.isBlank(sourceField) || StringUtils.isBlank(destinationField)) { + continue; + } + this.fieldMappings.put(sourceField, destinationField); + } + if (this.fieldMappings.isEmpty()) { + throw new CloudRuntimeException("Field mappings must not be empty"); + } + } + + private static Gson setDefaultGsonConfig(GsonBuilder builder) { + builder.setVersion(1.5); + InterfaceTypeAdaptor dsAdaptor = new InterfaceTypeAdaptor(); + builder.registerTypeAdapter(DataStoreTO.class, dsAdaptor); + InterfaceTypeAdaptor dtAdaptor = new InterfaceTypeAdaptor(); + builder.registerTypeAdapter(DataTO.class, dtAdaptor); + ArrayTypeAdaptor cmdAdaptor = new ArrayTypeAdaptor(); + builder.registerTypeAdapter(Command[].class, cmdAdaptor); + ArrayTypeAdaptor ansAdaptor = new ArrayTypeAdaptor(); + builder.registerTypeAdapter(Answer[].class, ansAdaptor); + builder.registerTypeAdapter(new TypeToken>() { + }.getType(), new Request.PortConfigListTypeAdaptor()); + builder.registerTypeAdapter(new TypeToken>() { + }.getType(), new Request.NwGroupsCommandTypeAdaptor()); + builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor()); + builder.registerTypeAdapter(Hypervisor.HypervisorType.class, new HypervisorTypeAdaptor()); + + Gson gson = builder.create(); + dsAdaptor.initGson(gson); + dtAdaptor.initGson(gson); + cmdAdaptor.initGson(gson); + ansAdaptor.initGson(gson); + return gson; + } + + @Override + public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { + if (src == null) { + return null; + } + JsonObject obj = gson.toJsonTree(src).getAsJsonObject(); + if (obj != null) { + for (Map.Entry field : fieldMappings.entrySet()) { + String sourceField = field.getKey(); + String destinationField = field.getValue(); + if (obj.has(sourceField)) { + obj.add(destinationField, obj.get(sourceField)); + } + } + } + return obj; + } +} diff --git a/core/src/main/java/com/cloud/agent/transport/compat/DiskTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/DiskTOAdaptor.java new file mode 100644 index 000000000000..6b45529de05f --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/compat/DiskTOAdaptor.java @@ -0,0 +1,28 @@ +// 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 com.cloud.agent.transport.compat; + +import com.cloud.agent.api.to.DiskTO; + +/** + * See {@link AbstractTOAdaptor}. + */ +public class DiskTOAdaptor extends AbstractTOAdaptor { + public DiskTOAdaptor() { + super("details", "_details"); + } +} diff --git a/core/src/main/java/com/cloud/agent/transport/compat/MigrateCommandAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/MigrateCommandAdaptor.java new file mode 100644 index 000000000000..ddac8afe5975 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/compat/MigrateCommandAdaptor.java @@ -0,0 +1,28 @@ +// 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 com.cloud.agent.transport.compat; + +import com.cloud.agent.api.MigrateCommand; + +/** + * See {@link AbstractTOAdaptor}. + */ +public class MigrateCommandAdaptor extends AbstractTOAdaptor { + public MigrateCommandAdaptor() { + super("destinationIp", "destIp", "windows", "isWindows", "virtualMachine", "vmTO"); + } +} diff --git a/core/src/main/java/com/cloud/agent/transport/compat/NetworkTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/NetworkTOAdaptor.java new file mode 100644 index 000000000000..01b0cdb4cdf9 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/compat/NetworkTOAdaptor.java @@ -0,0 +1,28 @@ +// 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 com.cloud.agent.transport.compat; + +import com.cloud.agent.api.to.NetworkTO; + +/** + * See {@link AbstractTOAdaptor}. + */ +public class NetworkTOAdaptor extends AbstractTOAdaptor { + public NetworkTOAdaptor() { + super("securityGroupEnabled", "isSecurityGroupEnabled"); + } +} diff --git a/core/src/main/java/com/cloud/agent/transport/compat/VirtualMachineTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/VirtualMachineTOAdaptor.java new file mode 100644 index 000000000000..24a8c02a59c5 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/compat/VirtualMachineTOAdaptor.java @@ -0,0 +1,29 @@ +// 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 com.cloud.agent.transport.compat; + +import com.cloud.agent.api.to.VirtualMachineTO; + +/** + * See {@link AbstractTOAdaptor}. + */ +public class VirtualMachineTOAdaptor extends AbstractTOAdaptor { + + public VirtualMachineTOAdaptor() { + super("details", "params"); + } +} diff --git a/core/src/main/java/com/cloud/serializer/GsonHelper.java b/core/src/main/java/com/cloud/serializer/GsonHelper.java index 7de98c08b7e0..2cc247cc10dc 100644 --- a/core/src/main/java/com/cloud/serializer/GsonHelper.java +++ b/core/src/main/java/com/cloud/serializer/GsonHelper.java @@ -21,6 +21,14 @@ import java.util.List; +import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.NetworkTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.transport.compat.DiskTOAdaptor; +import com.cloud.agent.transport.compat.MigrateCommandAdaptor; +import com.cloud.agent.transport.compat.NetworkTOAdaptor; +import com.cloud.agent.transport.compat.VirtualMachineTOAdaptor; import com.cloud.hypervisor.Hypervisor; import org.apache.cloudstack.transport.HypervisorTypeAdaptor; import org.apache.logging.log4j.Logger; @@ -78,6 +86,11 @@ public static Gson setDefaultGsonConfig(GsonBuilder builder) { }.getType(), new NwGroupsCommandTypeAdaptor()); builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor()); builder.registerTypeAdapter(Hypervisor.HypervisorType.class, new HypervisorTypeAdaptor()); + // added for compatibility purposes, remove after all Agents migrate to the new version + builder.registerTypeAdapter(VirtualMachineTO.class, new VirtualMachineTOAdaptor()); + builder.registerTypeAdapter(DiskTO.class, new DiskTOAdaptor()); + builder.registerTypeAdapter(NetworkTO.class, new NetworkTOAdaptor()); + builder.registerTypeAdapter(MigrateCommand.class, new MigrateCommandAdaptor()); Gson gson = builder.create(); dsAdaptor.initGson(gson); dtAdaptor.initGson(gson); From e8c2037d41bbbe0e304be5ff1b67d6b45347525d Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 15 Jul 2026 16:47:38 +0200 Subject: [PATCH 2/6] fix logger --- .../cloud/agent/transport/compat/AbstractTOAdaptor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java index 558b249e4756..9dc448bf4368 100644 --- a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java +++ b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java @@ -39,7 +39,8 @@ import com.google.gson.JsonSerializer; import com.google.gson.reflect.TypeToken; import org.apache.cloudstack.transport.HypervisorTypeAdaptor; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import java.lang.reflect.Type; import java.util.LinkedHashMap; @@ -53,7 +54,7 @@ */ public class AbstractTOAdaptor implements JsonSerializer { - private static final Logger s_logger = Logger.getLogger(AbstractTOAdaptor.class); + private static final Logger LOGGER = LogManager.getLogger(AbstractTOAdaptor.class); private static final Gson gson; static { @@ -61,7 +62,7 @@ public class AbstractTOAdaptor implements JsonSerializer { gson = setDefaultGsonConfig(gsonBuilder); GsonBuilder loggerBuilder = new GsonBuilder(); loggerBuilder.disableHtmlEscaping(); - loggerBuilder.setExclusionStrategies(new LoggingExclusionStrategy(s_logger)); + loggerBuilder.setExclusionStrategies(new LoggingExclusionStrategy(LOGGER)); } private Map fieldMappings; From 44ddaefd1fea9aa2bcf6faa4659d02a1615774f7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 16 Jul 2026 15:44:07 +0200 Subject: [PATCH 3/6] Apply suggestion from Daman --- .../com/cloud/agent/transport/compat/AbstractTOAdaptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java index 9dc448bf4368..9121ac3f8d71 100644 --- a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java +++ b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java @@ -50,7 +50,7 @@ /** * JSON serializer adapter for transport classes (com.cloud.agent.api.to.*) that ensures backward compatibility * with older Agent versions due to rename of the fields - * (see https://github.com/shapeblue/cloudstack-apple/pull/532/changes) + * (see https://github.com/apache/cloudstack/pull/10514) */ public class AbstractTOAdaptor implements JsonSerializer { From 15b39f4fd1d4d587388c18badf1eb205ba15f20a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 16 Jul 2026 15:44:59 +0200 Subject: [PATCH 4/6] Apply suggestion from Daman 2 --- .../java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java index 9121ac3f8d71..d37ee9eb48bf 100644 --- a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java +++ b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java @@ -52,7 +52,6 @@ * with older Agent versions due to rename of the fields * (see https://github.com/apache/cloudstack/pull/10514) */ - public class AbstractTOAdaptor implements JsonSerializer { private static final Logger LOGGER = LogManager.getLogger(AbstractTOAdaptor.class); private static final Gson gson; From 8a811d5bd37f137d751e615d882cf425b423c848 Mon Sep 17 00:00:00 2001 From: Daman Arora Date: Tue, 28 Jul 2026 12:12:11 -0400 Subject: [PATCH 5/6] Fix nested TO renaming, log redaction and cleanup in compat TypeAdaptors AbstractTOAdaptor built its own private Gson to run the pre-rename serialization step through, which meant it never honoured the LoggingExclusionStrategy the enclosing Gson (GsonHelper's logging instance) was configured with, so fields marked @LogLevel(Off) (e.g. VirtualMachineTO.vncPassword) leaked in plaintext when logged. It also had no adapters for the sibling compat TOs, so nested TOs (disks/nics inside a VirtualMachineTO, or a VirtualMachineTO inside a MigrateCommand) kept their new field names instead of being renamed for backward compatibility with older Agents. AbstractTOAdaptor no longer owns a Gson at all: it takes one via initGson(), mirroring the existing InterfaceTypeAdaptor pattern. GsonHelper.setDefaultGsonConfig now wires each compat adaptor's delegate Gson incrementally off the same builder, snapshotting it via builder.create() right before each adaptor registers itself, so every adaptor's delegate carries its sibling adaptors (for correct nested renaming) without ever routing back into itself and recursing forever. NetworkTO is now registered via registerTypeHierarchyAdapter since VirtualMachineTO.nics is declared as NicTO[] (a NetworkTO subclass) and was never matched by the previous exact-type registration. This also removes AbstractTOAdaptor's now-unused loggerBuilder/LOGGER and its duplicate copy of GsonHelper.setDefaultGsonConfig, and replaces a dead null check (getAsJsonObject() never returns null) with a real isJsonObject() check. Added RequestTest#testCompatFieldRenamingNestedTOs covering a StartCommand and a MigrateCommand with nested disks/nics, asserting old field names appear at every nesting level on the wire and that vncPassword never appears in the logging serialization. Co-Authored-By: Claude Sonnet 5 --- .../transport/compat/AbstractTOAdaptor.java | 71 ++------- .../java/com/cloud/serializer/GsonHelper.java | 39 ++++- .../cloud/agent/transport/RequestTest.java | 148 +++++++++++++++--- 3 files changed, 177 insertions(+), 81 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java index d37ee9eb48bf..ed5630183ead 100644 --- a/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java +++ b/core/src/main/java/com/cloud/agent/transport/compat/AbstractTOAdaptor.java @@ -16,54 +16,33 @@ // under the License. package com.cloud.agent.transport.compat; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.SecStorageFirewallCfgCommand; -import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DataTO; -import com.cloud.agent.transport.ArrayTypeAdaptor; -import com.cloud.agent.transport.InterfaceTypeAdaptor; -import com.cloud.agent.transport.LoggingExclusionStrategy; -import com.cloud.agent.transport.Request; -import com.cloud.agent.transport.StoragePoolTypeAdaptor; -import com.cloud.hypervisor.Hypervisor; -import com.cloud.storage.Storage; -import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.exception.CloudRuntimeException; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import com.google.gson.reflect.TypeToken; -import org.apache.cloudstack.transport.HypervisorTypeAdaptor; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; import java.lang.reflect.Type; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; /** * JSON serializer adapter for transport classes (com.cloud.agent.api.to.*) that ensures backward compatibility * with older Agent versions due to rename of the fields * (see https://github.com/apache/cloudstack/pull/10514) + * + * This class does not build its own Gson instance: doing so would silently drop whichever exclusion + * strategy (e.g. log redaction) and sibling compat adaptors (for nested TOs) the enclosing Gson was + * configured with. Instead, whoever registers an instance of this class into a GsonBuilder is + * responsible for also calling {@link #initGson(Gson)} with a Gson that (a) carries that same + * exclusion strategy and (b) has adapters registered for any nested TO types that also need field + * renaming, but not for this adaptor's own type (to avoid infinite recursion). See + * {@link com.cloud.serializer.GsonHelper#setDefaultGsonConfig(com.google.gson.GsonBuilder)}. */ public class AbstractTOAdaptor implements JsonSerializer { - private static final Logger LOGGER = LogManager.getLogger(AbstractTOAdaptor.class); - private static final Gson gson; - - static { - GsonBuilder gsonBuilder = new GsonBuilder(); - gson = setDefaultGsonConfig(gsonBuilder); - GsonBuilder loggerBuilder = new GsonBuilder(); - loggerBuilder.disableHtmlEscaping(); - loggerBuilder.setExclusionStrategies(new LoggingExclusionStrategy(LOGGER)); - } - + private Gson gson; private Map fieldMappings; protected AbstractTOAdaptor(String... fields) { @@ -82,29 +61,8 @@ protected AbstractTOAdaptor(String... fields) { } } - private static Gson setDefaultGsonConfig(GsonBuilder builder) { - builder.setVersion(1.5); - InterfaceTypeAdaptor dsAdaptor = new InterfaceTypeAdaptor(); - builder.registerTypeAdapter(DataStoreTO.class, dsAdaptor); - InterfaceTypeAdaptor dtAdaptor = new InterfaceTypeAdaptor(); - builder.registerTypeAdapter(DataTO.class, dtAdaptor); - ArrayTypeAdaptor cmdAdaptor = new ArrayTypeAdaptor(); - builder.registerTypeAdapter(Command[].class, cmdAdaptor); - ArrayTypeAdaptor ansAdaptor = new ArrayTypeAdaptor(); - builder.registerTypeAdapter(Answer[].class, ansAdaptor); - builder.registerTypeAdapter(new TypeToken>() { - }.getType(), new Request.PortConfigListTypeAdaptor()); - builder.registerTypeAdapter(new TypeToken>() { - }.getType(), new Request.NwGroupsCommandTypeAdaptor()); - builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor()); - builder.registerTypeAdapter(Hypervisor.HypervisorType.class, new HypervisorTypeAdaptor()); - - Gson gson = builder.create(); - dsAdaptor.initGson(gson); - dtAdaptor.initGson(gson); - cmdAdaptor.initGson(gson); - ansAdaptor.initGson(gson); - return gson; + public void initGson(Gson gson) { + this.gson = gson; } @Override @@ -112,8 +70,9 @@ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext con if (src == null) { return null; } - JsonObject obj = gson.toJsonTree(src).getAsJsonObject(); - if (obj != null) { + JsonElement tree = gson.toJsonTree(src); + if (tree.isJsonObject()) { + JsonObject obj = tree.getAsJsonObject(); for (Map.Entry field : fieldMappings.entrySet()) { String sourceField = field.getKey(); String destinationField = field.getValue(); @@ -122,6 +81,6 @@ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext con } } } - return obj; + return tree; } } diff --git a/core/src/main/java/com/cloud/serializer/GsonHelper.java b/core/src/main/java/com/cloud/serializer/GsonHelper.java index 2cc247cc10dc..7fcfb28f983c 100644 --- a/core/src/main/java/com/cloud/serializer/GsonHelper.java +++ b/core/src/main/java/com/cloud/serializer/GsonHelper.java @@ -86,11 +86,42 @@ public static Gson setDefaultGsonConfig(GsonBuilder builder) { }.getType(), new NwGroupsCommandTypeAdaptor()); builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor()); builder.registerTypeAdapter(Hypervisor.HypervisorType.class, new HypervisorTypeAdaptor()); + // added for compatibility purposes, remove after all Agents migrate to the new version - builder.registerTypeAdapter(VirtualMachineTO.class, new VirtualMachineTOAdaptor()); - builder.registerTypeAdapter(DiskTO.class, new DiskTOAdaptor()); - builder.registerTypeAdapter(NetworkTO.class, new NetworkTOAdaptor()); - builder.registerTypeAdapter(MigrateCommand.class, new MigrateCommandAdaptor()); + // + // Each compat adaptor below needs a "base" Gson to run its own reflective (pre-rename) + // serialization through, so that nested TOs are renamed too and the exclusion strategy set + // on `builder` (e.g. log redaction) is honoured consistently at every nesting level. That base + // Gson is built incrementally off the same builder, snapshotted (via builder.create()) just + // before each adaptor's own type is registered on it, so it carries every sibling adaptor it + // can nest without ever routing back into itself and recursing forever. + DiskTOAdaptor diskAdaptor = new DiskTOAdaptor(); + NetworkTOAdaptor netAdaptor = new NetworkTOAdaptor(); + VirtualMachineTOAdaptor vmAdaptor = new VirtualMachineTOAdaptor(); + MigrateCommandAdaptor migrateAdaptor = new MigrateCommandAdaptor(); + + // DiskTO and NetworkTO don't nest any other compat TO, so the plain config built so far is + // already the correct base Gson for them. + Gson leafDelegateGson = builder.create(); + diskAdaptor.initGson(leafDelegateGson); + netAdaptor.initGson(leafDelegateGson); + + // VirtualMachineTO nests DiskTO[] and NicTO[] (NicTO extends NetworkTO), so its base Gson needs + // Disk/Network adapters too. registerTypeHierarchyAdapter is used for NetworkTO so that the + // NicTO[]-declared "nics" field is matched via its supertype. + builder.registerTypeAdapter(DiskTO.class, diskAdaptor); + builder.registerTypeHierarchyAdapter(NetworkTO.class, netAdaptor); + Gson vmDelegateGson = builder.create(); + vmAdaptor.initGson(vmDelegateGson); + + // MigrateCommand nests a VirtualMachineTO, so its base Gson needs the VirtualMachineTO adapter + // (which already renames the nested disks/nics above). + builder.registerTypeAdapter(VirtualMachineTO.class, vmAdaptor); + Gson migrateDelegateGson = builder.create(); + migrateAdaptor.initGson(migrateDelegateGson); + + builder.registerTypeAdapter(MigrateCommand.class, migrateAdaptor); + Gson gson = builder.create(); dsAdaptor.initGson(gson); dtAdaptor.initGson(gson); diff --git a/core/src/test/java/com/cloud/agent/transport/RequestTest.java b/core/src/test/java/com/cloud/agent/transport/RequestTest.java index 0fe42c7cede8..80df0219c4fc 100644 --- a/core/src/test/java/com/cloud/agent/transport/RequestTest.java +++ b/core/src/test/java/com/cloud/agent/transport/RequestTest.java @@ -20,10 +20,11 @@ package com.cloud.agent.transport; import java.nio.ByteBuffer; +import java.util.HashMap; import junit.framework.TestCase; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; import org.junit.Assert; import org.mockito.Mockito; @@ -35,19 +36,28 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.GetHostStatsCommand; import com.cloud.agent.api.GetVolumeStatsCommand; +import com.cloud.agent.api.MigrateCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; +import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.UpdateHostPasswordCommand; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NfsTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.transport.Request.Version; import com.cloud.exception.UnsupportedVersionException; +import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.serializer.GsonHelper; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.template.VirtualMachineTemplate; +import com.cloud.template.VirtualMachineTemplate.BootloaderType; +import com.cloud.vm.VirtualMachine; /** * @@ -57,22 +67,47 @@ */ public class RequestTest extends TestCase { - protected Logger logger = LogManager.getLogger(getClass()); + private static final Logger s_logger = Logger.getLogger(RequestTest.class); public void testSerDeser() { - logger.info("Testing serializing and deserializing works as expected"); + s_logger.info("Testing serializing and deserializing works as expected"); - logger.info("UpdateHostPasswordCommand should have two parameters that doesn't show in logging"); + s_logger.info("UpdateHostPasswordCommand should have two parameters that doesn't show in logging"); UpdateHostPasswordCommand cmd1 = new UpdateHostPasswordCommand("abc", "def"); - logger.info("SecStorageFirewallCfgCommand has a context map that shouldn't show up in debug level"); + s_logger.info("SecStorageFirewallCfgCommand has a context map that shouldn't show up in debug level"); SecStorageFirewallCfgCommand cmd2 = new SecStorageFirewallCfgCommand(); - logger.info("GetHostStatsCommand should not show up at all in debug level"); + s_logger.info("GetHostStatsCommand should not show up at all in debug level"); GetHostStatsCommand cmd3 = new GetHostStatsCommand("hostguid", "hostname", 101); cmd2.addPortConfig("abc", "24", true, "eth0"); cmd2.addPortConfig("127.0.0.1", "44", false, "eth1"); Request sreq = new Request(2, 3, new Command[] {cmd1, cmd2, cmd3}, true, true); sreq.setSequence(892403717); + Logger logger = Logger.getLogger(GsonHelper.class); + Level level = logger.getLevel(); + + logger.setLevel(Level.DEBUG); + String log = sreq.log("Debug", true, Level.DEBUG); + assert (log.contains(UpdateHostPasswordCommand.class.getSimpleName())); + assert (log.contains(SecStorageFirewallCfgCommand.class.getSimpleName())); + assert (!log.contains(GetHostStatsCommand.class.getSimpleName())); + assert (!log.contains("username")); + assert (!log.contains("password")); + + logger.setLevel(Level.TRACE); + log = sreq.log("Trace", true, Level.TRACE); + assert (log.contains(UpdateHostPasswordCommand.class.getSimpleName())); + assert (log.contains(SecStorageFirewallCfgCommand.class.getSimpleName())); + assert (log.contains(GetHostStatsCommand.class.getSimpleName())); + assert (!log.contains("username")); + assert (!log.contains("password")); + + logger.setLevel(Level.INFO); + log = sreq.log("Info", true, Level.INFO); + assert (log == null); + + logger.setLevel(level); + byte[] bytes = sreq.getBytes(); assert Request.getSequence(bytes) == 892403717; @@ -83,9 +118,9 @@ public void testSerDeser() { try { creq = Request.parse(bytes); } catch (ClassNotFoundException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } assert creq != null : "Couldn't get the request back"; @@ -101,9 +136,9 @@ public void testSerDeser() { try { sresp = Response.parse(bytes); } catch (ClassNotFoundException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } assert sresp != null : "Couldn't get the response back"; @@ -112,7 +147,7 @@ public void testSerDeser() { } public void testSerDeserTO() { - logger.info("Testing serializing and deserializing interface TO works as expected"); + s_logger.info("Testing serializing and deserializing interface TO works as expected"); NfsTO nfs = new NfsTO("nfs://192.168.56.10/opt/storage/secondary", DataStoreRole.Image); // SecStorageSetupCommand cmd = new SecStorageSetupCommand(nfs, "nfs://192.168.56.10/opt/storage/secondary", null); @@ -130,9 +165,9 @@ public void testSerDeserTO() { try { creq = Request.parse(bytes); } catch (ClassNotFoundException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - logger.error("Unable to parse bytes: ", e); + s_logger.error("Unable to parse bytes: ", e); } assert creq != null : "Couldn't get the request back"; @@ -142,7 +177,7 @@ public void testSerDeserTO() { } public void testDownload() { - logger.info("Testing Download answer"); + s_logger.info("Testing Download answer"); VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class); Mockito.when(template.getId()).thenReturn(1L); Mockito.when(template.getFormat()).thenReturn(ImageFormat.QCOW2); @@ -167,7 +202,7 @@ public void testDownload() { } public void testCompress() { - logger.info("testCompress"); + s_logger.info("testCompress"); int len = 800000; ByteBuffer inputBuffer = ByteBuffer.allocate(len); for (int i = 0; i < len; i++) { @@ -176,7 +211,7 @@ public void testCompress() { inputBuffer.limit(len); ByteBuffer compressedBuffer = ByteBuffer.allocate(len); compressedBuffer = Request.doCompress(inputBuffer, len); - logger.info("compressed length: " + compressedBuffer.limit()); + s_logger.info("compressed length: " + compressedBuffer.limit()); ByteBuffer decompressedBuffer = ByteBuffer.allocate(len); decompressedBuffer = Request.doDecompress(compressedBuffer, len); for (int i = 0; i < len; i++) { @@ -186,6 +221,77 @@ public void testCompress() { } } + public void testLogging() { + s_logger.info("Testing Logging"); + GetHostStatsCommand cmd3 = new GetHostStatsCommand("hostguid", "hostname", 101); + Request sreq = new Request(2, 3, new Command[] {cmd3}, true, true); + sreq.setSequence(1); + Logger logger = Logger.getLogger(GsonHelper.class); + Level level = logger.getLevel(); + + logger.setLevel(Level.DEBUG); + String log = sreq.log("Debug", true, Level.DEBUG); + assert (log == null); + + log = sreq.log("Debug", false, Level.DEBUG); + assert (log != null); + + logger.setLevel(Level.TRACE); + log = sreq.log("Trace", true, Level.TRACE); + assert (log.contains(GetHostStatsCommand.class.getSimpleName())); + s_logger.debug(log); + + logger.setLevel(level); + } + + public void testCompatFieldRenamingNestedTOs() { + s_logger.info("Testing that renamed fields are restored on nested TOs too, for backward compatibility with older Agents"); + + DiskTO diskTO = new DiskTO(); + diskTO.setDetails(new HashMap()); + + NicTO nicTO = new NicTO(); + nicTO.setSecurityGroupEnabled(true); + + VirtualMachineTO vmTO = new VirtualMachineTO(1, "i-2-3-VM", VirtualMachine.Type.User, 1, 512, 512L * 1024 * 1024, 512L * 1024 * 1024, + BootloaderType.HVM, "Other PV (64-bit)", true, true, "vncpassword123"); + vmTO.setDetails(new HashMap()); + vmTO.setDisks(new DiskTO[] {diskTO}); + vmTO.setNics(new NicTO[] {nicTO}); + + Host host = Mockito.mock(Host.class); + Mockito.when(host.getPrivateIpAddress()).thenReturn("10.1.1.1"); + StartCommand startCmd = new StartCommand(vmTO, host, false); + + Request startReq = new Request(1, 1, startCmd, true); + String startWireJson = GsonHelper.getGson().toJson(new Command[] {startCmd}); + assert startWireJson.contains("\"params\"") : "VirtualMachineTO.details should be serialized under its old name 'params'"; + assert startWireJson.contains("\"_details\"") : "nested DiskTO.details should be serialized under its old name '_details'"; + assert startWireJson.contains("\"isSecurityGroupEnabled\"") : "nested NicTO.securityGroupEnabled should be serialized under its old name 'isSecurityGroupEnabled'"; + assert startWireJson.contains("vncpassword123") : "wire serialization should still contain the real vncPassword value"; + + Logger gsonLogger = Logger.getLogger(GsonHelper.class); + Level gsonLoggerLevel = gsonLogger.getLevel(); + gsonLogger.setLevel(Level.TRACE); + String startLogJson; + try { + startLogJson = startReq.log("Trace", true, Level.TRACE); + } finally { + gsonLogger.setLevel(gsonLoggerLevel); + } + assert startLogJson.contains("\"isSecurityGroupEnabled\"") : "renamed fields should still show up in the logging serialization"; + assert !startLogJson.contains("vncpassword123") : "logging serialization should never contain the plaintext vncPassword value"; + + MigrateCommand migrateCmd = new MigrateCommand("i-2-3-VM", "10.1.1.2", true, vmTO, false); + String migrateWireJson = GsonHelper.getGson().toJson(new Command[] {migrateCmd}); + assert migrateWireJson.contains("\"destIp\"") : "MigrateCommand.destinationIp should be serialized under its old name 'destIp'"; + assert migrateWireJson.contains("\"isWindows\"") : "MigrateCommand.windows should be serialized under its old name 'isWindows'"; + assert migrateWireJson.contains("\"vmTO\"") : "MigrateCommand.virtualMachine should be serialized under its old name 'vmTO'"; + assert migrateWireJson.contains("\"params\"") : "VirtualMachineTO nested in MigrateCommand should still be renamed"; + assert migrateWireJson.contains("\"_details\"") : "DiskTO nested inside the VirtualMachineTO nested in MigrateCommand should still be renamed"; + assert migrateWireJson.contains("\"isSecurityGroupEnabled\"") : "NicTO nested inside the VirtualMachineTO nested in MigrateCommand should still be renamed"; + } + protected void compareRequest(Request req1, Request req2) { assert req1.getSequence() == req2.getSequence(); assert req1.getAgentId() == req2.getAgentId(); @@ -204,24 +310,24 @@ protected void compareRequest(Request req1, Request req2) { } public void testGoodCommand() { - logger.info("Testing good Command"); + s_logger.info("Testing good Command"); String content = "[{\"com.cloud.agent.api.GetVolumeStatsCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); - logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); + s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); assert cmds[0].getClass().equals(GetVolumeStatsCommand.class); } public void testBadCommand() { - logger.info("Testing Bad Command"); + s_logger.info("Testing Bad Command"); String content = "[{\"com.cloud.agent.api.SomeJunkCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); - logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); + s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); assert cmds[0].getClass().equals(BadCommand.class); } From 5efe316ddf438fed048ade1f3e9ad1ace56f1e9a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 3 Aug 2026 14:24:22 +0200 Subject: [PATCH 6/6] fix logger --- .../cloud/agent/transport/RequestTest.java | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/core/src/test/java/com/cloud/agent/transport/RequestTest.java b/core/src/test/java/com/cloud/agent/transport/RequestTest.java index 80df0219c4fc..aa6842359ace 100644 --- a/core/src/test/java/com/cloud/agent/transport/RequestTest.java +++ b/core/src/test/java/com/cloud/agent/transport/RequestTest.java @@ -23,8 +23,9 @@ import java.util.HashMap; import junit.framework.TestCase; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.junit.Assert; import org.mockito.Mockito; @@ -67,23 +68,23 @@ */ public class RequestTest extends TestCase { - private static final Logger s_logger = Logger.getLogger(RequestTest.class); + private static final Logger logger = LogManager.getLogger(RequestTest.class); public void testSerDeser() { - s_logger.info("Testing serializing and deserializing works as expected"); + logger.info("Testing serializing and deserializing works as expected"); - s_logger.info("UpdateHostPasswordCommand should have two parameters that doesn't show in logging"); + logger.info("UpdateHostPasswordCommand should have two parameters that doesn't show in logging"); UpdateHostPasswordCommand cmd1 = new UpdateHostPasswordCommand("abc", "def"); - s_logger.info("SecStorageFirewallCfgCommand has a context map that shouldn't show up in debug level"); + logger.info("SecStorageFirewallCfgCommand has a context map that shouldn't show up in debug level"); SecStorageFirewallCfgCommand cmd2 = new SecStorageFirewallCfgCommand(); - s_logger.info("GetHostStatsCommand should not show up at all in debug level"); + logger.info("GetHostStatsCommand should not show up at all in debug level"); GetHostStatsCommand cmd3 = new GetHostStatsCommand("hostguid", "hostname", 101); cmd2.addPortConfig("abc", "24", true, "eth0"); cmd2.addPortConfig("127.0.0.1", "44", false, "eth1"); Request sreq = new Request(2, 3, new Command[] {cmd1, cmd2, cmd3}, true, true); sreq.setSequence(892403717); - Logger logger = Logger.getLogger(GsonHelper.class); + Logger logger = LogManager.getLogger(GsonHelper.class); Level level = logger.getLevel(); logger.setLevel(Level.DEBUG); @@ -118,9 +119,9 @@ public void testSerDeser() { try { creq = Request.parse(bytes); } catch (ClassNotFoundException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } assert creq != null : "Couldn't get the request back"; @@ -136,9 +137,9 @@ public void testSerDeser() { try { sresp = Response.parse(bytes); } catch (ClassNotFoundException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } assert sresp != null : "Couldn't get the response back"; @@ -147,7 +148,7 @@ public void testSerDeser() { } public void testSerDeserTO() { - s_logger.info("Testing serializing and deserializing interface TO works as expected"); + logger.info("Testing serializing and deserializing interface TO works as expected"); NfsTO nfs = new NfsTO("nfs://192.168.56.10/opt/storage/secondary", DataStoreRole.Image); // SecStorageSetupCommand cmd = new SecStorageSetupCommand(nfs, "nfs://192.168.56.10/opt/storage/secondary", null); @@ -165,9 +166,9 @@ public void testSerDeserTO() { try { creq = Request.parse(bytes); } catch (ClassNotFoundException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } catch (UnsupportedVersionException e) { - s_logger.error("Unable to parse bytes: ", e); + logger.error("Unable to parse bytes: ", e); } assert creq != null : "Couldn't get the request back"; @@ -177,7 +178,7 @@ public void testSerDeserTO() { } public void testDownload() { - s_logger.info("Testing Download answer"); + logger.info("Testing Download answer"); VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class); Mockito.when(template.getId()).thenReturn(1L); Mockito.when(template.getFormat()).thenReturn(ImageFormat.QCOW2); @@ -202,7 +203,7 @@ public void testDownload() { } public void testCompress() { - s_logger.info("testCompress"); + logger.info("testCompress"); int len = 800000; ByteBuffer inputBuffer = ByteBuffer.allocate(len); for (int i = 0; i < len; i++) { @@ -211,7 +212,7 @@ public void testCompress() { inputBuffer.limit(len); ByteBuffer compressedBuffer = ByteBuffer.allocate(len); compressedBuffer = Request.doCompress(inputBuffer, len); - s_logger.info("compressed length: " + compressedBuffer.limit()); + logger.info("compressed length: " + compressedBuffer.limit()); ByteBuffer decompressedBuffer = ByteBuffer.allocate(len); decompressedBuffer = Request.doDecompress(compressedBuffer, len); for (int i = 0; i < len; i++) { @@ -222,11 +223,11 @@ public void testCompress() { } public void testLogging() { - s_logger.info("Testing Logging"); + logger.info("Testing Logging"); GetHostStatsCommand cmd3 = new GetHostStatsCommand("hostguid", "hostname", 101); Request sreq = new Request(2, 3, new Command[] {cmd3}, true, true); sreq.setSequence(1); - Logger logger = Logger.getLogger(GsonHelper.class); + Logger logger = LogManager.getLogger(GsonHelper.class); Level level = logger.getLevel(); logger.setLevel(Level.DEBUG); @@ -239,13 +240,13 @@ public void testLogging() { logger.setLevel(Level.TRACE); log = sreq.log("Trace", true, Level.TRACE); assert (log.contains(GetHostStatsCommand.class.getSimpleName())); - s_logger.debug(log); + logger.debug(log); logger.setLevel(level); } public void testCompatFieldRenamingNestedTOs() { - s_logger.info("Testing that renamed fields are restored on nested TOs too, for backward compatibility with older Agents"); + logger.info("Testing that renamed fields are restored on nested TOs too, for backward compatibility with older Agents"); DiskTO diskTO = new DiskTO(); diskTO.setDetails(new HashMap()); @@ -270,7 +271,7 @@ public void testCompatFieldRenamingNestedTOs() { assert startWireJson.contains("\"isSecurityGroupEnabled\"") : "nested NicTO.securityGroupEnabled should be serialized under its old name 'isSecurityGroupEnabled'"; assert startWireJson.contains("vncpassword123") : "wire serialization should still contain the real vncPassword value"; - Logger gsonLogger = Logger.getLogger(GsonHelper.class); + Logger gsonLogger = LogManager.getLogger(GsonHelper.class); Level gsonLoggerLevel = gsonLogger.getLevel(); gsonLogger.setLevel(Level.TRACE); String startLogJson; @@ -310,24 +311,24 @@ protected void compareRequest(Request req1, Request req2) { } public void testGoodCommand() { - s_logger.info("Testing good Command"); + logger.info("Testing good Command"); String content = "[{\"com.cloud.agent.api.GetVolumeStatsCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); - s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); + logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); assert cmds[0].getClass().equals(GetVolumeStatsCommand.class); } public void testBadCommand() { - s_logger.info("Testing Bad Command"); + logger.info("Testing Bad Command"); String content = "[{\"com.cloud.agent.api.SomeJunkCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); - s_logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); + logger.debug("Command class = " + cmds[0].getClass().getSimpleName()); assert cmds[0].getClass().equals(BadCommand.class); }