Skip to content

Commit 6bf5881

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

2 files changed

Lines changed: 93 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: 69 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,74 @@ 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+
return existing;
347+
}
348+
349+
@Test(expected = InvalidParameterValueException.class)
350+
public void testValidateExistingHostLocationImmutableRejectsZoneChange() {
351+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
352+
StartupCommand startup = Mockito.mock(StartupCommand.class);
353+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
354+
resourceManager.validateExistingHostLocationImmutable(existing, false, 2L, 10L, 100L, startup);
355+
}
356+
357+
@Test(expected = InvalidParameterValueException.class)
358+
public void testValidateExistingHostLocationImmutableRejectsPodChange() {
359+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
360+
StartupCommand startup = Mockito.mock(StartupCommand.class);
361+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
362+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 11L, 100L, startup);
363+
}
364+
365+
@Test(expected = InvalidParameterValueException.class)
366+
public void testValidateExistingHostLocationImmutableRejectsClusterChange() {
367+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
368+
StartupCommand startup = Mockito.mock(StartupCommand.class);
369+
when(startup.getPrivateIpAddress()).thenReturn("10.10.10.10");
370+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 101L, startup);
371+
}
372+
373+
@Test
374+
public void testValidateExistingHostLocationImmutableAllowsSameTupleReconnect() {
375+
HostVO existing = mockExistingRoutingHost(1L, 10L, 100L);
376+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 100L, null);
377+
}
378+
379+
@Test
380+
public void testValidateExistingHostLocationImmutableAllowsNewHost() {
381+
HostVO existing = mockExistingRoutingHost(2L, 20L, 200L);
382+
resourceManager.validateExistingHostLocationImmutable(existing, true, 1L, 10L, 100L, null);
383+
}
384+
385+
@Test
386+
public void testValidateExistingHostLocationImmutableSkipsNonRoutingHost() {
387+
HostVO existing = Mockito.mock(HostVO.class);
388+
when(existing.getType()).thenReturn(Host.Type.SecondaryStorageVM);
389+
resourceManager.validateExistingHostLocationImmutable(existing, false, 1L, 10L, 100L, null);
390+
}
391+
392+
@Test
393+
public void testValidateExistingHostLocationImmutableSkipsPartialLocationRow() {
394+
HostVO existing = Mockito.mock(HostVO.class);
395+
when(existing.getType()).thenReturn(Host.Type.Routing);
396+
when(existing.getDataCenterId()).thenReturn(1L);
397+
when(existing.getPodId()).thenReturn(null);
398+
when(existing.getClusterId()).thenReturn(null);
399+
resourceManager.validateExistingHostLocationImmutable(existing, false, 2L, 10L, 100L, null);
400+
}
401+
402+
@Test
403+
public void testValidateExistingHostLocationImmutableSkipsNullExistingHost() {
404+
resourceManager.validateExistingHostLocationImmutable(null, false, 2L, 10L, 100L, null);
405+
}
406+
338407
@Test
339408
public void testGetHostCredentials() {
340409
Ternary<String, String, String> credentials = resourceManager.getHostCredentials(host);

0 commit comments

Comments
 (0)