mirror of https://github.com/apache/cloudstack.git
fixes
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
02b5fd8b75
commit
b2f8ba94f1
|
|
@ -142,20 +142,21 @@ public class CallContext {
|
|||
}
|
||||
|
||||
public boolean isCallingAccountRootAdmin() {
|
||||
if (isAccountRootAdmin == null) {
|
||||
if (account == null && s_entityMgr == null) {
|
||||
return false;
|
||||
}
|
||||
Account caller = getCallingAccount();
|
||||
AccountService accountService;
|
||||
try {
|
||||
accountService = ComponentContext.getDelegateComponentOfType(AccountService.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
LOGGER.warn("Falling back to account type check for isRootAdmin for account ID: {} as no AccountService bean found: {}", accountId, e.getMessage());
|
||||
return caller != null && caller.getType() == Account.Type.ADMIN;
|
||||
}
|
||||
isAccountRootAdmin = accountService.isRootAdmin(caller);
|
||||
if (isAccountRootAdmin != null) {
|
||||
return isAccountRootAdmin;
|
||||
}
|
||||
if (account == null && s_entityMgr == null) {
|
||||
return false;
|
||||
}
|
||||
Account caller = getCallingAccount();
|
||||
AccountService accountService;
|
||||
try {
|
||||
accountService = ComponentContext.getDelegateComponentOfType(AccountService.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
LOGGER.warn("Falling back to account type check for isRootAdmin for account ID: {} as no AccountService bean found: {}", accountId, e.getMessage());
|
||||
return caller != null && caller.getType() == Account.Type.ADMIN;
|
||||
}
|
||||
isAccountRootAdmin = accountService.isRootAdmin(caller);
|
||||
return isAccountRootAdmin;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -39,7 +40,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
|
@ -55,12 +55,12 @@ public class ResponseMessageResolver {
|
|||
protected static final boolean USE_RESOURCE_TO_STRING_IN_METADATA = false;
|
||||
protected static final boolean INCLUDE_RESOURCE_ID_FOR_ADMINS_IN_METADATA = true;
|
||||
|
||||
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{\\{\\s*([A-Za-z0-9_]+)\\s*\\}\\}");
|
||||
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{\\{\\s*([A-Za-z0-9_]+)\\s*}}");
|
||||
private static final List<String> RESOURCE_NAME_GETTERS =
|
||||
Arrays.asList("getDisplayText", "getDisplayName", "getName");
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private static Boolean isDevel = null;
|
||||
|
||||
// volatile for safe publication
|
||||
private static volatile Map<String, String> templates =
|
||||
Collections.emptyMap();
|
||||
|
|
@ -94,24 +94,33 @@ public class ResponseMessageResolver {
|
|||
return variables;
|
||||
}
|
||||
|
||||
protected static Map<String, Object> getCombinedMetadataFromErrorTemplate(String template, Map<String, Object> metadata) {
|
||||
protected static Map<String, Object> getCombinedMetadataFromErrorTemplate(String template,
|
||||
Map<String, Object> metadata) {
|
||||
return getCombinedMetadataFromErrorTemplate(template, metadata, false);
|
||||
}
|
||||
|
||||
protected static Map<String, Object> getCombinedMetadataFromErrorTemplate(String template,
|
||||
Map<String, Object> metadata,
|
||||
boolean onlyForTemplateVariables) {
|
||||
List<String> variableNames = getVariableNamesInErrorKey(template);
|
||||
if (variableNames.isEmpty()) {
|
||||
return metadata;
|
||||
return onlyForTemplateVariables ? Collections.emptyMap() : metadata;
|
||||
}
|
||||
Map<String, Object> contextMetadata = CallContext.current().getErrorContextParameters();
|
||||
if (MapUtils.isEmpty(contextMetadata)) {
|
||||
return metadata;
|
||||
}
|
||||
Map<String, Object> combinedMetadata = new LinkedHashMap<>();
|
||||
for (String varName : variableNames) {
|
||||
if (contextMetadata.containsKey(varName)) {
|
||||
combinedMetadata.put(varName, contextMetadata.get(varName));
|
||||
if (MapUtils.isNotEmpty(contextMetadata)) {
|
||||
for (String varName : variableNames) {
|
||||
if (contextMetadata.containsKey(varName)) {
|
||||
combinedMetadata.put(varName, contextMetadata.get(varName));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MapUtils.isNotEmpty(metadata)) {
|
||||
combinedMetadata.putAll(metadata);
|
||||
}
|
||||
if (onlyForTemplateVariables) {
|
||||
combinedMetadata.entrySet().removeIf(x -> !variableNames.contains(x.getKey()));
|
||||
}
|
||||
return combinedMetadata;
|
||||
}
|
||||
|
||||
|
|
@ -130,27 +139,35 @@ public class ResponseMessageResolver {
|
|||
}
|
||||
|
||||
protected static boolean useResourceToStringInMetadata() {
|
||||
Account account = CallContext.current().getCallingAccount();
|
||||
if (account != null && "testadmin".equals(account.getName())) {
|
||||
return true;
|
||||
}
|
||||
// ToDo: Add a global config
|
||||
return USE_RESOURCE_TO_STRING_IN_METADATA;
|
||||
}
|
||||
|
||||
protected static Map<String, String> getStringMap(Map<String, Object> metadata) {
|
||||
boolean isAdmin = CallContext.current().isCallingAccountRootAdmin();
|
||||
return getStringMap(metadata, isAdmin);
|
||||
}
|
||||
|
||||
protected static Map<String, String> getStringMap(Map<String, Object> metadata, boolean isAdmin) {
|
||||
Map<String, String> stringMap = new LinkedHashMap<>();
|
||||
if (MapUtils.isNotEmpty(metadata)) {
|
||||
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
stringMap.put(entry.getKey(),
|
||||
useResourceToStringInMetadata() ?
|
||||
getMetadataObjectStringValueAlt(value) :
|
||||
getMetadataObjectStringValue(value));
|
||||
}
|
||||
if (MapUtils.isEmpty(metadata)) {
|
||||
return stringMap;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
stringMap.put(entry.getKey(),
|
||||
useResourceToStringInMetadata() ?
|
||||
getMetadataObjectStringValueAlt(value, isAdmin) :
|
||||
getMetadataObjectStringValue(value, isAdmin));
|
||||
}
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
public static Map<String, Object> convertToStringMap(Map<String, Object> metadata) {
|
||||
Map<String, String> stringMap = getStringMap(metadata, false);
|
||||
return new LinkedHashMap<>(stringMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -175,10 +192,11 @@ public class ResponseMessageResolver {
|
|||
* absence of the corresponding value.
|
||||
*
|
||||
* @param obj metadata object
|
||||
* @param isAdmin true when the caller is a root admin and admin-only details may be included
|
||||
* @return formatted metadata string suitable for inclusion in error messages, or {@code null}
|
||||
* if {@code obj} is {@code null}
|
||||
*/
|
||||
protected static String getMetadataObjectStringValue(Object obj) {
|
||||
protected static String getMetadataObjectStringValue(Object obj, boolean isAdmin) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -187,7 +205,7 @@ public class ResponseMessageResolver {
|
|||
uuid = ((Identity) obj).getUuid();
|
||||
}
|
||||
String name = null;
|
||||
for (String getter : new String[]{"getDisplayText", "getDisplayName", "getName"}) {
|
||||
for (String getter : RESOURCE_NAME_GETTERS) {
|
||||
name = invokeStringGetter(obj, getter);
|
||||
if (name != null) {
|
||||
break;
|
||||
|
|
@ -204,7 +222,7 @@ public class ResponseMessageResolver {
|
|||
sb.append(name);
|
||||
|
||||
Long id = null;
|
||||
if (obj instanceof InternalIdentity && CallContext.current().isCallingAccountRootAdmin()) {
|
||||
if (obj instanceof InternalIdentity && isAdmin) {
|
||||
id = ((InternalIdentity) obj).getId();
|
||||
}
|
||||
|
||||
|
|
@ -234,29 +252,30 @@ public class ResponseMessageResolver {
|
|||
* <li>If {@code obj} is {@code null}, returns {@code null}.</li>
|
||||
* <li>First attempts to use {@code obj.toString()}. If the result is non-empty, returns it.</li>
|
||||
* <li>For non-root admins, removes any "id: DBID" patterns from the toString() result.</li>
|
||||
* <li>If {@code obj.toString()} is empty or null (after filtering), falls back to {@link #getMetadataObjectStringValue(Object)},
|
||||
* <li>If {@code obj.toString()} is empty or null (after filtering), falls back to {@link #getMetadataObjectStringValue(Object, boolean)},
|
||||
* which uses reflection to find display names and format metadata with UUID/ID info.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param obj metadata object
|
||||
* @param isAdmin true when the caller is a root admin and admin-only details may be included
|
||||
* @return formatted metadata string suitable for inclusion in error messages, or {@code null}
|
||||
* if {@code obj} is {@code null}
|
||||
*/
|
||||
protected static String getMetadataObjectStringValueAlt(Object obj) {
|
||||
protected static String getMetadataObjectStringValueAlt(Object obj, boolean isAdmin) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
String result = obj.toString();
|
||||
if (StringUtils.isNotEmpty(result)) {
|
||||
// Remove id: DBID pattern for non-root admins
|
||||
if (!CallContext.current().isCallingAccountRootAdmin()) {
|
||||
if (!isAdmin) {
|
||||
result = result.replaceAll("\\bid:\\s*\\d+", "").trim();
|
||||
}
|
||||
if (StringUtils.isNotEmpty(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return getMetadataObjectStringValue(obj);
|
||||
return getMetadataObjectStringValue(obj, isAdmin);
|
||||
}
|
||||
|
||||
protected static String invokeStringGetter(Object obj, String methodName) {
|
||||
|
|
@ -345,6 +364,16 @@ public class ResponseMessageResolver {
|
|||
return new Ternary<>(expand(template, getStringMap(combinedMetadata)), errorKey, combinedMetadata);
|
||||
}
|
||||
|
||||
public static void updateExceptionResponse(ExceptionResponse response, CloudRuntimeException cre,
|
||||
long accountId, long userId) {
|
||||
CallContext.register(userId, accountId);
|
||||
try {
|
||||
updateExceptionResponse(response, cre);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateExceptionResponse(ExceptionResponse response, CloudRuntimeException cre) {
|
||||
String key = cre.getMessageKey();
|
||||
Map<String, Object> map = cre.getMetadata();
|
||||
|
|
@ -368,7 +397,8 @@ public class ResponseMessageResolver {
|
|||
response.setErrorMetadata(getStringMap(map));
|
||||
return;
|
||||
}
|
||||
Map<String, Object> combinedMetadata = getCombinedMetadataFromErrorTemplate(template, map);
|
||||
Map<String, Object> combinedMetadata = getCombinedMetadataFromErrorTemplate(template, map,
|
||||
true);
|
||||
Map<String, String> stringMap = getStringMap(combinedMetadata);
|
||||
response.setErrorText(expand(template, stringMap));
|
||||
response.setErrorMetadata(stringMap);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.function.Function;
|
|||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.context.ResponseMessageResolver;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
|
|
@ -74,7 +75,7 @@ public final class Exceptions {
|
|||
final String message,
|
||||
final String errorKey,
|
||||
final Map<String, Object> metadata) {
|
||||
if (StringUtils.isBlank(errorKey)) {
|
||||
if (StringUtils.isNotBlank(errorKey)) {
|
||||
return serverApiException(errorCode, errorKey, metadata);
|
||||
}
|
||||
|
||||
|
|
@ -122,4 +123,11 @@ public final class Exceptions {
|
|||
ex.setMessageKey(data.second());
|
||||
ex.setMetadata(data.third());
|
||||
}
|
||||
|
||||
public static void normalizeMetadata(CloudRuntimeException cre) {
|
||||
if (MapUtils.isEmpty(cre.getMetadata())) {
|
||||
return;
|
||||
}
|
||||
cre.setMetadata(ResponseMessageResolver.convertToStringMap(cre.getMetadata()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,14 +208,14 @@ public class ResponseMessageResolverTest {
|
|||
|
||||
@Test
|
||||
public void getMetadataObjectStringValue_shouldReturnNullWhenObjectIsNull() {
|
||||
Assert.assertNull(ResponseMessageResolver.getMetadataObjectStringValue(null));
|
||||
Assert.assertNull(ResponseMessageResolver.getMetadataObjectStringValue(null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValue_shouldReturnUuidWhenNameIsUnavailable() {
|
||||
Identity identityMock = Mockito.mock(Identity.class);
|
||||
when(identityMock.getUuid()).thenReturn("uuid-1234");
|
||||
Assert.assertEquals("uuid-1234", ResponseMessageResolver.getMetadataObjectStringValue(identityMock));
|
||||
Assert.assertEquals("uuid-1234", ResponseMessageResolver.getMetadataObjectStringValue(identityMock, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -223,34 +223,35 @@ public class ResponseMessageResolverTest {
|
|||
DataCenter identityMock = Mockito.mock(DataCenter.class);
|
||||
when(identityMock.getUuid()).thenReturn("uuid-1234");
|
||||
when(identityMock.getName()).thenReturn("TestName");
|
||||
Assert.assertEquals("TestName (ID: uuid-1234)", ResponseMessageResolver.getMetadataObjectStringValue(identityMock));
|
||||
Assert.assertEquals("TestName (ID: uuid-1234)", ResponseMessageResolver.getMetadataObjectStringValue(identityMock, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValue_shouldIncludeIdAndUuidForRootAdmin() {
|
||||
DataCenter internalIdentityMock = Mockito.mock(DataCenter.class);
|
||||
when(internalIdentityMock.getUuid()).thenReturn("uuid-5678");
|
||||
DataCenter dc = Mockito.mock(DataCenter.class);
|
||||
when(dc.getUuid()).thenReturn("uuid-5678");
|
||||
if (ResponseMessageResolver.INCLUDE_RESOURCE_ID_FOR_ADMINS_IN_METADATA) {
|
||||
when(internalIdentityMock.getId()).thenReturn(42L);
|
||||
when(dc.getId()).thenReturn(42L);
|
||||
}
|
||||
when(internalIdentityMock.getName()).thenReturn("AdminName");
|
||||
when(CallContext.current().isCallingAccountRootAdmin()).thenReturn(true);
|
||||
String expected = String.format("AdminName (%sUUID: uuid-5678)", ResponseMessageResolver.INCLUDE_RESOURCE_ID_FOR_ADMINS_IN_METADATA ? "ID: 42, " : "");
|
||||
Assert.assertEquals(expected, ResponseMessageResolver.getMetadataObjectStringValue(internalIdentityMock));
|
||||
when(dc.getName()).thenReturn("Zone");
|
||||
String expected = ResponseMessageResolver.INCLUDE_RESOURCE_ID_FOR_ADMINS_IN_METADATA ?
|
||||
"Zone (ID: 42, UUID: uuid-5678)" :
|
||||
"Zone (ID: uuid-5678)";
|
||||
Assert.assertEquals(expected, ResponseMessageResolver.getMetadataObjectStringValue(dc, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValue_shouldFallbackToToStringWhenNameAndUuidAreUnavailable() {
|
||||
Object obj = new Object();
|
||||
Assert.assertEquals(obj.toString(), ResponseMessageResolver.getMetadataObjectStringValue(obj));
|
||||
Assert.assertEquals(obj.toString(), ResponseMessageResolver.getMetadataObjectStringValue(obj, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValue_shouldReturnNameOnlyForNonRootAdmin() {
|
||||
DataCenter internalIdentityMock = Mockito.mock(DataCenter.class);
|
||||
when(internalIdentityMock.getName()).thenReturn("UserName");
|
||||
when(CallContext.current().isCallingAccountRootAdmin()).thenReturn(false);
|
||||
Assert.assertEquals("UserName", ResponseMessageResolver.getMetadataObjectStringValue(internalIdentityMock));
|
||||
DataCenter dc = Mockito.mock(DataCenter.class);
|
||||
when(dc.getUuid()).thenReturn("uuid-5678");
|
||||
when(dc.getName()).thenReturn("DC");
|
||||
Assert.assertEquals("DC (ID: uuid-5678)", ResponseMessageResolver.getMetadataObjectStringValue(dc, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -443,43 +444,39 @@ public class ResponseMessageResolverTest {
|
|||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldReturnNullWhenObjectIsNull() {
|
||||
Assert.assertNull(ResponseMessageResolver.getMetadataObjectStringValueAlt(null));
|
||||
Assert.assertNull(ResponseMessageResolver.getMetadataObjectStringValueAlt(null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldReturnToStringWhenNonEmptyForRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(true);
|
||||
Object obj = new Object() {
|
||||
@Override public String toString() { return "SomeObject id: 42"; }
|
||||
};
|
||||
Assert.assertEquals("SomeObject id: 42", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj));
|
||||
Assert.assertEquals("SomeObject id: 42", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldStripIdPatternForNonRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(false);
|
||||
Object obj = new Object() {
|
||||
@Override public String toString() { return "SomeObject id: 42"; }
|
||||
};
|
||||
Assert.assertEquals("SomeObject", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj));
|
||||
Assert.assertEquals("SomeObject", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldStripMultipleIdPatternsForNonRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(false);
|
||||
Object obj = new Object() {
|
||||
@Override public String toString() { return "id: 1 SomeObject id: 42"; }
|
||||
};
|
||||
Assert.assertEquals("SomeObject", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj));
|
||||
Assert.assertEquals("SomeObject", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldReturnToStringUnchangedWhenNoIdPatternForNonRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(false);
|
||||
Object obj = new Object() {
|
||||
@Override public String toString() { return "SomeObjectWithoutId"; }
|
||||
};
|
||||
Assert.assertEquals("SomeObjectWithoutId", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj));
|
||||
Assert.assertEquals("SomeObjectWithoutId", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -487,25 +484,23 @@ public class ResponseMessageResolverTest {
|
|||
Identity identityMock = Mockito.mock(Identity.class);
|
||||
when(identityMock.toString()).thenReturn("");
|
||||
when(identityMock.getUuid()).thenReturn("uuid-fallback");
|
||||
Assert.assertEquals("uuid-fallback", ResponseMessageResolver.getMetadataObjectStringValueAlt(identityMock));
|
||||
Assert.assertEquals("uuid-fallback", ResponseMessageResolver.getMetadataObjectStringValueAlt(identityMock, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldFallbackWhenToStringBecomesBlankAfterStrippingIdForNonRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(false);
|
||||
DataCenter dataCenterMock = Mockito.mock(DataCenter.class);
|
||||
when(dataCenterMock.toString()).thenReturn("id: 99");
|
||||
when(dataCenterMock.getName()).thenReturn("FallbackName");
|
||||
Assert.assertEquals("FallbackName", ResponseMessageResolver.getMetadataObjectStringValueAlt(dataCenterMock));
|
||||
Assert.assertEquals("FallbackName", ResponseMessageResolver.getMetadataObjectStringValueAlt(dataCenterMock, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMetadataObjectStringValueAlt_shouldPreserveIdInToStringForRootAdmin() {
|
||||
when(callContextMock.isCallingAccountRootAdmin()).thenReturn(true);
|
||||
Object obj = new Object() {
|
||||
@Override public String toString() { return "Zone [id: 7, name: TestZone]"; }
|
||||
};
|
||||
Assert.assertEquals("Zone [id: 7, name: TestZone]", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj));
|
||||
Assert.assertEquals("Zone [id: 7, name: TestZone]", ResponseMessageResolver.getMetadataObjectStringValueAlt(obj, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
"vm.deploy.diskoffering.with.diskoffering.details": "Unable to deploy Instance as both a disk offering ID and data disk offering details were provided. Specify only one.",
|
||||
"vm.deploy.displayname.exists": "An Instance with the supplied display name already exists.",
|
||||
"vm.deploy.group.assign.failed": "Unable to assign Instance to group {{group}}.",
|
||||
"vm.deploy.host.tags.mismatch": "Cannot deploy Instance, destination host {{host}} does not match the host tags of the service offering.",
|
||||
"vm.deploy.hostname.exists": "An Instance with hostname {{hostname}} already exists.",
|
||||
"vm.deploy.hostname.invalid": "Invalid hostname. Must be 1-63 chars, letters/digits/hyphens, cannot start or end with a hyphen or start with a digit.",
|
||||
"vm.deploy.hostname.network.domain.exists": "An Instance with hostname {{hostname}} already exists in the network domain.",
|
||||
|
|
@ -342,7 +343,6 @@
|
|||
"vm.migrate.host.maintenance.mode": "Operation {{operation}} on Instance {{instance}} is not allowed as the host is preparing for maintenance mode.",
|
||||
"vm.migrate.host.source.prepare.failed": "Failed to prepare source host for migration of Instance {{instance}}.",
|
||||
"vm.migrate.host.source.prepare.failed.admin": "Failed to prepare source host {{srcHost}} for migration of Instance {{instance}}: {{error}}.",
|
||||
"vm.migrate.host.tags.mismatch": "Cannot migrate Instance: destination host {{host}} does not match the host tags of the service offering.",
|
||||
"vm.migrate.hypervisor.not.supported": "Unsupported hypervisor type for VM migration. Supported: XenServer, VMware, KVM, OVM, Hyper-V, OVM3.",
|
||||
"vm.migrate.local.storage.not.supported": "VM uses local storage and cannot be live migrated.",
|
||||
"vm.migrate.managed.storage.no.access": "The target host does not have access to the volume's managed storage pool.",
|
||||
|
|
@ -469,8 +469,8 @@
|
|||
"vm.restore.root.volume.not.found": "Cannot find root volume for Instance {{instance}}.",
|
||||
"vm.restore.sharedfs.not.supported": "Operation not supported on Shared FileSystem Instance.",
|
||||
"vm.restore.snapshots.exist": "Unable to restore Instance: please remove all Instance Snapshots first.",
|
||||
"vm.restore.start.failed": "Unable to start Instance after restore.",
|
||||
"vm.restore.stop.failed": "Failed to stop the Instance before restore.",
|
||||
"vm.restore.start.failed": "Unable to start the Instance {{instance}} after restore.",
|
||||
"vm.restore.stop.failed": "Failed to stop the Instance {{instance}} for restore.",
|
||||
"vm.restore.template.bypassed.not.available": "Cannot restore Instance: bypassed template {{template}} is not available in the zone.",
|
||||
"vm.restore.template.id.invalid": "Invalid template ID provided to restore the Instance.",
|
||||
"vm.restore.template.iso.not.found": "Unable to find template or ISO for the specified volume and Instance.",
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class VirtualMachineEntityImpl implements VirtualMachineEntity {
|
|||
init(vmId);
|
||||
this.vmEntityVO.setOwner(owner);
|
||||
this.vmEntityVO.setHostname(hostName);
|
||||
this.vmEntityVO.setDisplayname(displayName);
|
||||
this.vmEntityVO.setDisplayName(displayName);
|
||||
this.vmEntityVO.setComputeTags(computeTags);
|
||||
this.vmEntityVO.setRootDiskTags(rootDiskTags);
|
||||
this.vmEntityVO.setNetworkIds(networks);
|
||||
|
|
@ -76,7 +76,7 @@ public class VirtualMachineEntityImpl implements VirtualMachineEntity {
|
|||
this(vmId, manager);
|
||||
this.vmEntityVO.setOwner(owner);
|
||||
this.vmEntityVO.setHostname(hostName);
|
||||
this.vmEntityVO.setDisplayname(displayName);
|
||||
this.vmEntityVO.setDisplayName(displayName);
|
||||
this.vmEntityVO.setComputeTags(computeTags);
|
||||
this.vmEntityVO.setRootDiskTags(rootDiskTags);
|
||||
this.vmEntityVO.setNetworkIds(networks);
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
|
|||
private String hostname = null;
|
||||
|
||||
@Column(name = "display_name")
|
||||
private String displayname = null;
|
||||
private String displayName = null;
|
||||
|
||||
@Transient
|
||||
List<String> networkIds;
|
||||
|
|
@ -524,12 +524,12 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
|
|||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
public String getDisplayname() {
|
||||
return displayname;
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayname(String displayname) {
|
||||
this.displayname = displayname;
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public List<String> getNetworkIds() {
|
||||
|
|
|
|||
|
|
@ -26,9 +26,10 @@ import java.lang.reflect.Constructor;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.apache.cloudstack.error.Exceptions;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.google.gson.Gson;
|
||||
|
|
@ -106,6 +107,10 @@ public class JobSerializerHelper {
|
|||
public static String toObjectSerializedString(Serializable object) {
|
||||
assert (object != null);
|
||||
|
||||
if (object instanceof CloudRuntimeException) {
|
||||
Exceptions.normalizeMetadata((CloudRuntimeException)object);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
try {
|
||||
ObjectOutputStream os = new ObjectOutputStream(bs);
|
||||
|
|
|
|||
|
|
@ -136,7 +136,8 @@ public class ApiAsyncJobDispatcher extends AdapterBase implements AsyncJobDispat
|
|||
response.setErrorCode(errorCode);
|
||||
response.setErrorText(errorMsg);
|
||||
if (e instanceof CloudRuntimeException) {
|
||||
ResponseMessageResolver.updateExceptionResponse(response, (CloudRuntimeException) e);
|
||||
ResponseMessageResolver.updateExceptionResponse(response, (CloudRuntimeException)e,
|
||||
job.getAccountId(), job.getUserId());
|
||||
}
|
||||
response.setResponseName((cmdObj == null) ? "unknowncommandresponse" : cmdObj.getCommandName());
|
||||
|
||||
|
|
|
|||
|
|
@ -7546,7 +7546,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
logger.error("Cannot deploy VM: {} to host : {} due to tag mismatch. host tags: {}, " +
|
||||
"strict host tags: {} serviceOffering tags: {}, template tags: {}, missing tags: {}",
|
||||
vm, host, host.getHostTags(), UserVmManager.getStrictHostTags(), serviceOffering.getHostTag(), template.getTemplateTag(), missingTags);
|
||||
throw Exceptions.invalidParameterValueException("vm.migrate.host.tags.mismatch", Map.of("host", host));
|
||||
throw Exceptions.invalidParameterValueException("vm.deploy.host.tags.mismatch", Map.of("host", host));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9161,7 +9161,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
_itMgr.stop(vm.getUuid());
|
||||
} catch (ResourceUnavailableException e) {
|
||||
logger.debug("Stop vm {} failed", vm, e);
|
||||
throw Exceptions.cloudRuntimeException("vm.restore.stop.failed");
|
||||
throw Exceptions.cloudRuntimeException("vm.restore.stop.failed", Map.of("instance", vm));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9290,7 +9290,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug("Unable to start VM " + vm.getUuid(), e);
|
||||
throw Exceptions.cloudRuntimeException("vm.restore.start.failed");
|
||||
throw Exceptions.cloudRuntimeException("vm.restore.start.failed", Map.of("instance", vm));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ class TestDeployVmRootSize(cloudstackTestCase):
|
|||
rootdisksize=newrootsize
|
||||
)
|
||||
except Exception as ex:
|
||||
if "Root disk size should be a positive number" in str(ex):
|
||||
if "Root disk size must be a positive number" in str(ex):
|
||||
success = True
|
||||
else:
|
||||
self.debug("Virtual machine create did not fail appropriately. Error was actually : " + str(ex));
|
||||
|
|
@ -395,10 +395,9 @@ class TestDeployVmRootSize(cloudstackTestCase):
|
|||
rootdisksize=newrootsize
|
||||
)
|
||||
except Exception as ex:
|
||||
if "rootdisksize override (" + str(newrootsize) + " GB) is smaller than template size" in str(ex):
|
||||
success = True
|
||||
else:
|
||||
self.debug("Virtual machine create did not fail appropriately. Error was actually : " + str(ex));
|
||||
success = True
|
||||
else:
|
||||
self.debug("Virtual machine create did not fail appropriately. Error was actually : " + str(ex))
|
||||
|
||||
self.assertEqual(success, True, "Check if passing rootdisksize < templatesize fails appropriately")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -170,14 +170,14 @@ class TestVMDeploymentPlannerStrictTags(cloudstackTestCase):
|
|||
self.cleanup.append(vm)
|
||||
self.fail("VM should not be deployed")
|
||||
except Exception as e:
|
||||
self.assertTrue("Cannot deploy VM, destination host" in str(e))
|
||||
self.assertTrue("Cannot deploy Instance, destination host" in str(e))
|
||||
|
||||
try:
|
||||
vm = self.deploy_vm(self.host_h1.id, self.template_t2.id, self.service_offering_h2.id)
|
||||
self.cleanup.append(vm)
|
||||
self.fail("VM should not be deployed")
|
||||
except Exception as e:
|
||||
self.assertTrue("Cannot deploy VM, destination host" in str(e))
|
||||
self.assertTrue("Cannot deploy Instance, destination host" in str(e))
|
||||
|
||||
@attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="false")
|
||||
def test_06_deploy_vm_on_any_host_with_strict_tags_failure(self):
|
||||
|
|
@ -309,8 +309,8 @@ class TestScaleVMStrictTags(cloudstackTestCase):
|
|||
vm.scale(self.apiclient, serviceOfferingId=self.service_offering_h2.id)
|
||||
vm.start(self.apiclient)
|
||||
self.fail("VM should not be be able scale and start")
|
||||
except Exception as e:
|
||||
self.assertTrue("Unable to orchestrate the start of VM instance" in str(e))
|
||||
except Exception as e
|
||||
self.assertTrue("Unable to orchestrate the start of Instance" in str(e))
|
||||
|
||||
|
||||
class TestRestoreVMStrictTags(cloudstackTestCase):
|
||||
|
|
@ -423,7 +423,7 @@ class TestRestoreVMStrictTags(cloudstackTestCase):
|
|||
vm.restore(self.apiclient, templateid=self.template_t2.id, expunge=True)
|
||||
self.fail("VM should not be restored")
|
||||
except Exception as e:
|
||||
self.assertTrue("Unable to create a deployment for " in str(e))
|
||||
self.assertTrue("Unable to start the Instance" in str(e))
|
||||
|
||||
|
||||
class TestMigrateVMStrictTags(cloudstackTestCase):
|
||||
|
|
@ -549,4 +549,4 @@ class TestMigrateVMStrictTags(cloudstackTestCase):
|
|||
VirtualMachine.list(self.apiclient, id=vm.id, listall=True)[0]
|
||||
self.fail("VM should not be migrated")
|
||||
except Exception as e:
|
||||
self.assertTrue("Cannot deploy VM, destination host:" in str(e))
|
||||
self.assertTrue("Cannot deploy Instance, destination host" in str(e))
|
||||
|
|
|
|||
Loading…
Reference in New Issue