Skip to content

Commit 2f64bcd

Browse files
committed
Don't allow adding of existing host to another zone, pod or cluster
1 parent a7c2a05 commit 2f64bcd

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

server/src/main/java/com/cloud/resource/ResourceManagerImpl.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Locale;
3333
import java.util.Map;
34+
import java.util.Objects;
3435
import java.util.Random;
3536
import java.util.stream.Collectors;
3637

@@ -2281,6 +2282,27 @@ private HostVO getNewHost(StartupCommand[] startupCommands) {
22812282
return null;
22822283
}
22832284

2285+
protected void validateExistingHostLocationImmutable(final HostVO host, final boolean newHost,
2286+
final long dcId, final Long podId, final Long clusterId, final StartupCommand startup) {
2287+
if (newHost || host == null || host.getType() != Host.Type.Routing) {
2288+
return;
2289+
}
2290+
final Long existingDcId = host.getDataCenterId();
2291+
final Long existingPodId = host.getPodId();
2292+
final Long existingClusterId = host.getClusterId();
2293+
if (existingDcId == null || existingPodId == null || existingClusterId == null) {
2294+
return;
2295+
}
2296+
if (existingDcId == dcId && Objects.equals(existingPodId, podId) && Objects.equals(existingClusterId, clusterId)) {
2297+
return;
2298+
}
2299+
final String identity = host.getUuid() != null ? host.getUuid() : host.getGuid();
2300+
final String ip = startup != null ? startup.getPrivateIpAddress() : "unknown";
2301+
throw new InvalidParameterValueException(String.format(
2302+
"Host %s (ip: %s) is already registered in [zone: %d, pod: %d, cluster: %d] and cannot be re-added or reconnected with [zone: %d, pod: %s, cluster: %s]. Zone, pod and cluster of an existing host are immutable.",
2303+
identity, ip, existingDcId, existingPodId, existingClusterId, dcId, podId, clusterId));
2304+
}
2305+
22842306
protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map<String, String> details, List<String> hostTags,
22852307
final ResourceStateAdapter.Event stateEvent) {
22862308
boolean newHost = false;
@@ -2356,6 +2378,8 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource
23562378
}
23572379
}
23582380

2381+
validateExistingHostLocationImmutable(host, newHost, dcId, podId, clusterId, startup);
2382+
23592383
host.setDataCenterId(dc.getId());
23602384
host.setPodId(podId);
23612385
host.setClusterId(clusterId);

server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.cloud.resource;
1919

2020
import com.cloud.agent.AgentManager;
21+
import com.cloud.agent.api.StartupCommand;
2122
import com.cloud.agent.api.GetVncPortAnswer;
2223
import com.cloud.agent.api.GetVncPortCommand;
2324
import com.cloud.capacity.dao.CapacityDao;
@@ -335,6 +336,75 @@ public void testGetHostCredentialsMissingParameter() {
335336
resourceManager.getHostCredentials(host);
336337
}
337338

339+
private HostVO mockExistingRoutingHost(long dcId, Long podId, Long clusterId) {
340+
HostVO existing = Mockito.mock(HostVO.class);
341+
when(existing.getType()).thenReturn(Host.Type.Routing);
342+
when(existing.getDataCenterId()).thenReturn(dcId);
343+
when(existing.getPodId()).thenReturn(podId);
344+
when(existing.getClusterId()).thenReturn(clusterId);
345+
when(existing.getUuid()).thenReturn("host-uuid");
346+
when(existing.getGuid()).thenReturn("host-guid");
347+
return existing;
348+
}
349+
350+
@Test(expected = InvalidParameterValueException.class)
351+
public void testValidateExistingHostLocationImmutableRejectsZoneChange() {
352+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
353+
StartupCommand startup = Mockito.mock(StartupCommand.class);
354+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
355+
resourceManager.validateExistingHostLocationImmutable(existing, false, 2L, 10L, 100L, startup);
356+
}
357+
358+
@Test(expected = InvalidParameterValueException.class)
359+
public void testValidateExistingHostLocationImmutableRejectsPodChange() {
360+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
361+
StartupCommand startup = Mockito.mock(StartupCommand.class);
362+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
363+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 11L, 100L, startup);
364+
}
365+
366+
@Test(expected = InvalidParameterValueException.class)
367+
public void testValidateExistingHostLocationImmutableRejectsClusterChange() {
368+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
369+
StartupCommand startup = Mockito.mock(StartupCommand.class);
370+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
371+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 101L, startup);
372+
}
373+
374+
@Test
375+
public void testValidateExistingHostLocationImmutableAllowsSameTupleReconnect() {
376+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
377+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 100L, null);
378+
}
379+
380+
@Test
381+
public void testValidateExistingHostLocationImmutableAllowsNewHost() {
382+
HostVO existing = mockExistingRoutingHost(2L, 20L, 200L);
383+
resourceManager.validateExistingHostLocationImmutable(existing, true, 1L, 10L, 100L, null);
384+
}
385+
386+
@Test
387+
public void testValidateExistingHostLocationImmutableSkipsNonRoutingHost() {
388+
HostVO existing = Mockito.mock(HostVO.class);
389+
when(existing.getType()).thenReturn(Host.Type.SecondaryStorageVM);
390+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 100L, null);
391+
}
392+
393+
@Test
394+
public void testValidateExistingHostLocationImmutableSkipsPartialLocationRow() {
395+
HostVO existing = Mockito.mock(HostVO.class);
396+
when(existing.getType()).thenReturn(Host.Type.Routing);
397+
when(existing.getDataCenterId()).thenReturn(1L);
398+
when(existing.getPodId()).thenReturn(null);
399+
when(existing.getClusterId()).thenReturn(null);
400+
resourceManager.validateExistingHostLocationImmutable(existing, false, 2L, 10L, 100L, null);
401+
}
402+
403+
@Test
404+
public void testValidateExistingHostLocationImmutableSkipsNullExistingHost() {
405+
resourceManager.validateExistingHostLocationImmutable(null, false, 2L, 10L, 100L, null);
406+
}
407+
338408
@Test
339409
public void testGetHostCredentials() {
340410
Ternary<String, String, String> credentials = resourceManager.getHostCredentials(host);

0 commit comments

Comments
 (0)