Skip to content

Commit 860267f

Browse files
author
Rohit Yadav
authored
Merge pull request #19 from shapeblue/kvm-host-without-storage
APPLE-272: Host Connects Without Storage
2 parents 033f87d + a4848c1 commit 860267f

File tree

3 files changed

+168
-2
lines changed

3 files changed

+168
-2
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.manager;
18+
19+
import com.cloud.agent.Listener;
20+
import com.cloud.agent.api.Answer;
21+
import com.cloud.agent.api.ReadyCommand;
22+
import com.cloud.agent.api.StartupCommand;
23+
import com.cloud.agent.api.StartupRoutingCommand;
24+
import com.cloud.exception.ConnectionException;
25+
import com.cloud.host.HostVO;
26+
import com.cloud.host.Status;
27+
import com.cloud.host.dao.HostDao;
28+
import com.cloud.utils.Pair;
29+
import org.junit.Assert;
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
import org.mockito.Mockito;
33+
34+
import java.util.ArrayList;
35+
36+
public class AgentManagerImplTest {
37+
38+
private HostDao hostDao;
39+
private Listener storagePoolMonitor;
40+
private AgentAttache attache;
41+
private AgentManagerImpl mgr = Mockito.spy(new AgentManagerImpl());
42+
private HostVO host;
43+
private StartupCommand[] cmds;
44+
45+
@Before
46+
public void setUp() throws Exception {
47+
host = new HostVO("some-Uuid");
48+
host.setDataCenterId(1L);
49+
cmds = new StartupCommand[]{new StartupRoutingCommand()};
50+
attache = new ConnectedAgentAttache(null, 1L, "kvm-attache", null, false);
51+
52+
hostDao = Mockito.mock(HostDao.class);
53+
storagePoolMonitor = Mockito.mock(Listener.class);
54+
55+
mgr._hostDao = hostDao;
56+
mgr._hostMonitors = new ArrayList<>();
57+
mgr._hostMonitors.add(new Pair<>(0, storagePoolMonitor));
58+
}
59+
60+
@Test
61+
public void testNotifyMonitorsOfConnectionNormal() throws ConnectionException {
62+
Mockito.when(hostDao.findById(Mockito.anyLong())).thenReturn(host);
63+
Mockito.doNothing().when(storagePoolMonitor).processConnect(Mockito.eq(host), Mockito.eq(cmds[0]), Mockito.eq(false));
64+
Mockito.doReturn(true).when(mgr).handleDisconnectWithoutInvestigation(Mockito.any(attache.getClass()), Mockito.any(Status.Event.class), Mockito.anyBoolean(), Mockito.anyBoolean());
65+
Mockito.doReturn(Mockito.mock(Answer.class)).when(mgr).easySend(Mockito.anyLong(), Mockito.any(ReadyCommand.class));
66+
Mockito.doReturn(true).when(mgr).agentStatusTransitTo(Mockito.eq(host), Mockito.eq(Status.Event.Ready), Mockito.anyLong());
67+
68+
final AgentAttache agentAttache = mgr.notifyMonitorsOfConnection(attache, cmds, false);
69+
Assert.assertTrue(agentAttache.isReady()); // Agent is in UP state
70+
}
71+
72+
@Test
73+
public void testNotifyMonitorsOfConnectionWhenStoragePoolConnectionHostFailure() throws ConnectionException {
74+
ConnectionException connectionException = new ConnectionException(true, "storage pool could not be connected on host");
75+
Mockito.when(hostDao.findById(Mockito.anyLong())).thenReturn(host);
76+
Mockito.doThrow(connectionException).when(storagePoolMonitor).processConnect(Mockito.eq(host), Mockito.eq(cmds[0]), Mockito.eq(false));
77+
Mockito.doReturn(true).when(mgr).handleDisconnectWithoutInvestigation(Mockito.any(attache.getClass()), Mockito.any(Status.Event.class), Mockito.anyBoolean(), Mockito.anyBoolean());
78+
try {
79+
mgr.notifyMonitorsOfConnection(attache, cmds, false);
80+
Assert.fail("Connection Exception was expected");
81+
} catch (ConnectionException e) {
82+
Assert.assertEquals(e.getMessage(), connectionException.getMessage());
83+
}
84+
Mockito.verify(mgr, Mockito.times(1)).handleDisconnectWithoutInvestigation(Mockito.any(attache.getClass()), Mockito.eq(Status.Event.AgentDisconnected), Mockito.eq(true), Mockito.eq(true));
85+
}
86+
}

server/src/com/cloud/storage/listener/StoragePoolMonitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ public void processConnect(Host host, StartupCommand cmd, boolean forRebalance)
9999
}
100100

101101
Long hostId = host.getId();
102-
s_logger.debug("Host " + hostId + " connected, sending down storage pool information ...");
102+
s_logger.debug("Host " + hostId + " connected, connecting host to shared pool id " + pool.getId() + " and sending storage pool information ...");
103103
try {
104104
_storageManager.connectHostToSharedPool(hostId, pool.getId());
105105
_storageManager.createCapacityEntry(pool.getId());
106106
} catch (Exception e) {
107-
s_logger.warn("Unable to connect host " + hostId + " to pool " + pool + " due to " + e.toString(), e);
107+
throw new ConnectionException(true, "Unable to connect host " + hostId + " to storage pool id " + pool.getId() + " due to " + e.toString(), e);
108108
}
109109
}
110110
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.storage.listener;
18+
19+
import com.cloud.agent.api.StartupRoutingCommand;
20+
import com.cloud.exception.ConnectionException;
21+
import com.cloud.exception.StorageUnavailableException;
22+
import com.cloud.host.HostVO;
23+
import com.cloud.hypervisor.Hypervisor;
24+
import com.cloud.storage.ScopeType;
25+
import com.cloud.storage.StorageManagerImpl;
26+
import com.cloud.storage.StoragePoolStatus;
27+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
28+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
29+
import org.junit.Before;
30+
import org.junit.Test;
31+
import org.mockito.Mockito;
32+
33+
import java.util.Collections;
34+
35+
public class StoragePoolMonitorTest {
36+
37+
private StorageManagerImpl storageManager;
38+
private PrimaryDataStoreDao poolDao;
39+
private StoragePoolMonitor storagePoolMonitor;
40+
private HostVO host;
41+
private StoragePoolVO pool;
42+
private StartupRoutingCommand cmd;
43+
44+
@Before
45+
public void setUp() throws Exception {
46+
storageManager = Mockito.mock(StorageManagerImpl.class);
47+
poolDao = Mockito.mock(PrimaryDataStoreDao.class);
48+
49+
storagePoolMonitor = new StoragePoolMonitor(storageManager, poolDao);
50+
host = new HostVO("some-uuid");
51+
pool = new StoragePoolVO();
52+
pool.setScope(ScopeType.CLUSTER);
53+
pool.setStatus(StoragePoolStatus.Up);
54+
pool.setId(123L);
55+
cmd = new StartupRoutingCommand();
56+
cmd.setHypervisorType(Hypervisor.HypervisorType.KVM);
57+
}
58+
59+
@Test
60+
public void testProcessConnectStoragePoolNormal() throws Exception {
61+
Mockito.when(poolDao.listBy(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
62+
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class))).thenReturn(Collections.<StoragePoolVO>emptyList());
63+
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
64+
65+
storagePoolMonitor.processConnect(host, cmd, false);
66+
67+
Mockito.verify(storageManager, Mockito.times(1)).connectHostToSharedPool(Mockito.eq(host.getId()), Mockito.eq(pool.getId()));
68+
Mockito.verify(storageManager, Mockito.times(1)).createCapacityEntry(Mockito.eq(pool.getId()));
69+
}
70+
71+
@Test(expected = ConnectionException.class)
72+
public void testProcessConnectStoragePoolFailureOnHost() throws Exception {
73+
Mockito.when(poolDao.listBy(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
74+
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class))).thenReturn(Collections.<StoragePoolVO>emptyList());
75+
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
76+
Mockito.doThrow(new StorageUnavailableException("unable to mount storage", 123L)).when(storageManager).connectHostToSharedPool(Mockito.anyLong(), Mockito.anyLong());
77+
78+
storagePoolMonitor.processConnect(host, cmd, false);
79+
}
80+
}

0 commit comments

Comments
 (0)