From 0343cb79c330b6f6bc74fb9fcbfa86ea8625b1e7 Mon Sep 17 00:00:00 2001 From: frank Date: Thu, 22 Sep 2011 14:42:05 -0700 Subject: [PATCH] Bug 11522 - New agent manager replace simulateStart with createHostAndAgent --- .../agent/manager/MockAgentManagerImpl.java | 4 +- api/src/com/cloud/host/Host.java | 4 + core/src/com/cloud/host/HostVO.java | 18 +- server/src/com/cloud/agent/AgentManager.java | 29 +-- .../cloud/agent/manager/AgentManagerImpl.java | 178 +++++++------- .../baremetal/BareMetalPingServiceImpl.java | 5 +- .../baremetal/ExternalDhcpManagerImpl.java | 4 +- .../network/ExternalNetworkManagerImpl.java | 6 +- .../com/cloud/network/F5BigIpManagerImpl.java | 2 +- .../cloud/network/JuniperSrxManagerImpl.java | 5 +- .../network/NetworkUsageManagerImpl.java | 4 +- .../com/cloud/resource/ResourceManager.java | 9 + .../cloud/resource/ResourceManagerImpl.java | 230 +++++++++++++++++- 13 files changed, 381 insertions(+), 117 deletions(-) mode change 100644 => 100755 agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java mode change 100644 => 100755 server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java mode change 100644 => 100755 server/src/com/cloud/network/ExternalNetworkManagerImpl.java mode change 100644 => 100755 server/src/com/cloud/network/F5BigIpManagerImpl.java mode change 100644 => 100755 server/src/com/cloud/network/JuniperSrxManagerImpl.java mode change 100644 => 100755 server/src/com/cloud/network/NetworkUsageManagerImpl.java diff --git a/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java b/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java old mode 100644 new mode 100755 index 5fcdff62648..fda42027ca4 --- a/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java +++ b/agent-simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java @@ -34,6 +34,7 @@ import com.cloud.host.Host.Type; import com.cloud.resource.AgentResourceBase; import com.cloud.resource.AgentRoutingResource; import com.cloud.resource.AgentStorageResource; +import com.cloud.resource.ResourceManager; import com.cloud.simulator.MockHost; import com.cloud.simulator.MockHostVO; import com.cloud.simulator.MockVMVO; @@ -56,6 +57,7 @@ public class MockAgentManagerImpl implements MockAgentManager { @Inject SimulatorManager _simulatorMgr = null; @Inject AgentManager _agentMgr = null; @Inject MockStorageManager _storageMgr = null; + @Inject ResourceManager _resourceMgr; private SecureRandom random; private Map _resources = new ConcurrentHashMap(); private ThreadPoolExecutor _executor; @@ -270,7 +272,7 @@ public class MockAgentManagerImpl implements MockAgentManager { } Map details = new HashMap(); - _agentMgr.addHost(this.dcId, storageResource, Type.SecondaryStorageVM, details); + _resourceMgr.addHost(this.dcId, storageResource, Type.SecondaryStorageVM, details); _resources.put(this.guid, storageResource); } diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index a938c41a7d5..4eb0cc9d61a 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -20,6 +20,7 @@ package com.cloud.host; import java.util.Date; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.resource.ResourceState; import com.cloud.utils.fsm.StateObject; @@ -202,4 +203,7 @@ public interface Host extends StateObject { String getHypervisorVersion(); + boolean isInMaintenanceStates(); + + ResourceState getResourceState(); } diff --git a/core/src/com/cloud/host/HostVO.java b/core/src/com/cloud/host/HostVO.java index 20f6d3c8fe9..d4a57ac3766 100755 --- a/core/src/com/cloud/host/HostVO.java +++ b/core/src/com/cloud/host/HostVO.java @@ -38,6 +38,7 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.resource.ResourceState; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; @@ -130,6 +131,10 @@ public class HostVO implements Host { @Column(name="allocation_state", nullable=false) @Enumerated(value=EnumType.STRING) private HostAllocationState hostAllocationState; + + @Column(name="resource_state", nullable=false) + @Enumerated(value=EnumType.STRING) + private ResourceState resourceState; @Column(name="hypervisor_version") private String hypervisorVersion; @@ -700,5 +705,16 @@ public class HostVO implements Host { public Long getHostId() { // TODO Auto-generated method stub return null; - } + } + + @Override + public ResourceState getResourceState() { + return resourceState; + } + + @Override + public boolean isInMaintenanceStates() { + return (getResourceState() == ResourceState.Maintenance || getResourceState() == ResourceState.ErrorInMaintenance + || getResourceState() == ResourceState.PrepareForMaintenace); + } } diff --git a/server/src/com/cloud/agent/AgentManager.java b/server/src/com/cloud/agent/AgentManager.java index 838c9b56174..af71fcb9341 100755 --- a/server/src/com/cloud/agent/AgentManager.java +++ b/server/src/com/cloud/agent/AgentManager.java @@ -23,6 +23,7 @@ import java.util.Set; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.StartupCommand; import com.cloud.agent.manager.AgentAttache; import com.cloud.agent.manager.Commands; import com.cloud.api.commands.UpdateHostPasswordCmd; @@ -30,6 +31,7 @@ import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.PodCluster; import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConnectionException; import com.cloud.exception.OperationTimedoutException; import com.cloud.host.Host; import com.cloud.host.Host.Type; @@ -53,6 +55,12 @@ public interface AgentManager extends Manager { Continue, Stop } + public enum TapAgentsAction { + Add, + Del, + Contains, + } + /** * easy send method that returns null if there's any errors. It handles all exceptions. * @@ -187,17 +195,6 @@ public interface AgentManager extends Manager { List listByPod(long podId); - /** - * Adds a new host - * - * @param zoneId - * @param resource - * @param hostType - * @param hostDetails - * @return new Host - */ - public Host addHost(long zoneId, ServerResource resource, Type hostType, Map hostDetails); - /** * Deletes a host * @@ -250,8 +247,6 @@ public interface AgentManager extends Manager { void notifyAnswersToMonitors(long agentId, long seq, Answer[] answers); - AgentAttache simulateStart(Long id, ServerResource resource, Map details, boolean old, List hostTags, String allocationState, boolean forRebalance) throws IllegalArgumentException; - boolean updateHostPassword(UpdateHostPasswordCmd upasscmd); long sendToSecStorage(HostVO ssHost, Command cmd, Listener listener); @@ -261,5 +256,11 @@ public interface AgentManager extends Manager { HostVO getSSAgent(HostVO ssHost); void updateStatus(HostVO host, Event event); - + + /* working as a lock while agent is being loaded */ + public boolean tapLoadingAgents(Long hostId, TapAgentsAction action); + + public AgentAttache createAttacheForDirectConnect(HostVO host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException; + + public boolean agentStatusTransitTo(HostVO host, Status.Event e, long msId); } diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index e67c0bdaf99..d576d8d43e9 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -117,6 +117,8 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.kvm.resource.KvmDummyResourceBase; import com.cloud.network.IPAddressVO; import com.cloud.network.dao.IPAddressDao; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; import com.cloud.resource.ServerResource; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Storage; @@ -147,6 +149,8 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.HypervisorVersionChangedException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.utils.nio.HandlerFactory; @@ -255,6 +259,10 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { protected AgentMonitor _monitor = null; protected ExecutorService _executor; + + protected StateMachine2 _statusStateMachine = Status.getStateMachine(); + + @Inject ResourceManager _resourceMgr; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -1275,12 +1283,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { } if (forRebalance) { - AgentAttache attache = simulateStart(host.getId(), resource, host.getDetails(), false, null, null, true); - if (attache == null) { - return false; - } else { - return true; - } + Host h = _resourceMgr.createHostAndAgent(host.getId(), resource, host.getDetails(), false, null, null, true); + return (h == null ? false : true); } else { _executor.execute(new SimulateStartTask(host.getId(), resource, host.getDetails(), null)); return true; @@ -1288,69 +1292,32 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { } @Override - public AgentAttache simulateStart(Long id, ServerResource resource, Map details, boolean old, List hostTags, String allocationState, boolean forRebalance) throws IllegalArgumentException { - HostVO host = null; - if (id != null) { - synchronized (_loadingAgents) { - s_logger.debug("Adding to loading agents " + id); - _loadingAgents.add(id); - } + public AgentAttache createAttacheForDirectConnect(HostVO host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) + throws ConnectionException { + if (resource instanceof DummySecondaryStorageResource || resource instanceof KvmDummyResourceBase) { + return new DummyAttache(this, host.getId(), false); } - AgentAttache attache = null; - StartupCommand[] cmds = null; - try { - if (id != null) { - host = _hostDao.findById(id); - if (!_hostDao.directConnect(host, _nodeId)) { - s_logger.info("MS " + host.getManagementServerId() + " is loading " + host); - return null; - } - } - - cmds = resource.initialize(); - if (cmds == null) { - s_logger.info("Unable to fully initialize the agent because no StartupCommands are returned"); - return null; - } - - if (host != null) { - if (!_hostDao.directConnect(host, _nodeId)) { - host = _hostDao.findById(id); - s_logger.info("MS " + host.getManagementServerId() + " is loading " + host + " after it has been initialized."); - return null; - } - } - - if (s_logger.isDebugEnabled()) { - new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); - } - try { - attache = handleDirectConnect(resource, cmds, details, old, hostTags, allocationState, forRebalance); - } catch (IllegalArgumentException ex) { - s_logger.warn("Unable to connect due to ", ex); - throw ex; - } catch (Exception e) { - s_logger.warn("Unable to connect due to ", e); - } - - } finally { - if (id != null) { - synchronized (_loadingAgents) { - _loadingAgents.remove(id); - } - } - if (attache == null) { - if (cmds != null) { - resource.disconnected(); - } - if (host != null) { - _hostDao.updateStatus(host, Event.AgentDisconnected, _nodeId); - } - } + + s_logger.debug("create DirectAgentAttache for " + host.getId()); + DirectAgentAttache attache = new DirectAgentAttache(this, host.getId(), resource, host.isInMaintenanceStates(), this); + + AgentAttache old = null; + synchronized (_agents) { + old = _agents.put(host.getId(), attache); } - return attache; + if (old != null) { + old.disconnect(Status.Removed); + } + + StartupAnswer[] answers = new StartupAnswer[cmds.length]; + for (int i = 0; i < answers.length; i++) { + answers[i] = new StartupAnswer(cmds[i], attache.getId(), _pingInterval); + } + attache.process(answers); + + return notifyMonitorsOfConnection(attache, cmds, forRebalance); } - + @Override public boolean stop() { if (_monitor != null) { @@ -1758,26 +1725,6 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { } } - @Override - public Host addHost(long zoneId, ServerResource resource, Type hostType, Map hostDetails) { - // Check if the zone exists in the system - if (_dcDao.findById(zoneId) == null) { - throw new InvalidParameterValueException("Can't find zone with id " + zoneId); - } - - Map details = hostDetails; - String guid = details.get("guid"); - List currentHosts = _hostDao.listBy(hostType, zoneId); - for (HostVO currentHost : currentHosts) { - if (currentHost.getGuid().equals(guid)) { - return currentHost; - } - } - - AgentAttache attache = simulateStart(null, resource, hostDetails, true, null, null, false); - return _hostDao.findById(attache.getId()); - } - public HostVO createHost(final StartupCommand startup, ServerResource resource, Map details, boolean directFirst, List hostTags, String allocationState) throws IllegalArgumentException { Host.Type type = null; @@ -2207,7 +2154,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { if (s_logger.isDebugEnabled()) { s_logger.debug("Simulating start for resource " + resource.getName() + " id " + id); } - simulateStart(id, resource, details, false, null, null, false); + + _resourceMgr.createHostAndAgent(id, resource, details, false, null, null, false); } catch (Exception e) { s_logger.warn("Unable to simulate start on resource " + id + " name " + resource.getName(), e); } finally { @@ -2447,4 +2395,60 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { protected AgentManagerImpl() { } + @Override + public boolean tapLoadingAgents(Long hostId, TapAgentsAction action) { + synchronized (_loadingAgents) { + if (action == TapAgentsAction.Add) { + _loadingAgents.add(hostId); + } else if (action == TapAgentsAction.Del) { + _loadingAgents.remove(hostId); + } else if (action == TapAgentsAction.Contains) { + return _loadingAgents.contains(hostId); + } else { + throw new CloudRuntimeException("Unkonwn TapAgentsAction " + action); + } + } + return true; + } + + private boolean isAgentEventAllowedByResourceState(HostVO host, Status.Event event) { + ResourceState state = host.getResourceState(); + boolean allow = true; + if (state == ResourceState.Enabled) { + + } else if (state == ResourceState.Disabled) { + if (event == Status.Event.AgentConnected) { + allow = false; + } + } else if (state == ResourceState.Unmanaged) { + if (event == Status.Event.AgentConnected) { + allow = false; + } + } else if (state == ResourceState.PrepareForMaintenace) { + + } else if (state == ResourceState.Maintenance) { + + } else { + throw new CloudRuntimeException("Unknown resource state " + state); + } + + return allow; + } + + @Override + public boolean agentStatusTransitTo(HostVO host, Status.Event e, long msId) { + if (!isAgentEventAllowedByResourceState(host, e)) { + s_logger.debug(String.format("Cannot proceed agent event %1$s because it is not allowed by current resource state %2$s fort host %3$s", e, host.getResourceState(), host.getId())); + return false; + } + + host.setManagementServerId(msId); + try { + return _statusStateMachine.transitTo(host, e, host.getId(), _hostDao); + } catch (NoTransitionException e1) { + s_logger.debug("Cannot transit agent status with event " + e + " for host " + host.getId() + ", mangement server id is " + msId); + throw new CloudRuntimeException("Cannot transit agent status with event " + e + " for host " + host.getId() + ", mangement server id is " + msId + "," + e1.getMessage()); + } + } + } diff --git a/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java b/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java old mode 100644 new mode 100755 index 1878b305f9e..579e7047823 --- a/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java +++ b/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java @@ -39,8 +39,10 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.host.HostVO; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ServerResource; import com.cloud.uservm.UserVm; +import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; @@ -51,6 +53,7 @@ import com.cloud.vm.VirtualMachineProfile; @Local(value=PxeServerService.class) public class BareMetalPingServiceImpl extends BareMetalPxeServiceBase implements PxeServerService { private static final Logger s_logger = Logger.getLogger(BareMetalPingServiceImpl.class); + @Inject ResourceManager _resourceMgr; @Override public Host addPxeServer(PxeServerProfile profile) { @@ -122,7 +125,7 @@ public class BareMetalPingServiceImpl extends BareMetalPxeServiceBase implements throw new CloudRuntimeException("Unsupport PXE server type:" + profile.getType()); } - Host pxeServer = _agentMgr.addHost(zoneId, resource, Host.Type.PxeServer, params); + Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.PxeServer, params); if (pxeServer == null) { throw new CloudRuntimeException("Cannot add PXE server as a host"); } diff --git a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java b/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java index 0d6ddfff729..5ba62fce8e2 100755 --- a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java +++ b/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java @@ -59,6 +59,7 @@ import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ServerResource; import com.cloud.utils.component.Inject; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -81,6 +82,7 @@ public class ExternalDhcpManagerImpl implements ExternalDhcpManager { @Inject AgentManager _agentMgr; @Inject HostPodDao _podDao; @Inject UserVmDao _userVmDao; + @Inject ResourceManager _resourceMgr; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -159,7 +161,7 @@ public class ExternalDhcpManagerImpl implements ExternalDhcpManager { throw new CloudRuntimeException(e.getMessage()); } - Host dhcpServer = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalDhcp, params); + Host dhcpServer = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalDhcp, params); if (dhcpServer == null) { throw new CloudRuntimeException("Cannot add external Dhcp server as a host"); } diff --git a/server/src/com/cloud/network/ExternalNetworkManagerImpl.java b/server/src/com/cloud/network/ExternalNetworkManagerImpl.java old mode 100644 new mode 100755 index 64d6b3f122e..c43718c708f --- a/server/src/com/cloud/network/ExternalNetworkManagerImpl.java +++ b/server/src/com/cloud/network/ExternalNetworkManagerImpl.java @@ -93,6 +93,7 @@ import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ServerResource; import com.cloud.server.api.response.ExternalFirewallResponse; import com.cloud.server.api.response.ExternalLoadBalancerResponse; @@ -147,6 +148,7 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { @Inject VpnUserDao _vpnUsersDao; @Inject InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; @Inject AccountManager _accountMgr; + @Inject ResourceManager _resourceMgr; ScheduledExecutorService _executor; int _externalNetworkStatsInterval; @@ -285,7 +287,7 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { throw new CloudRuntimeException(e.getMessage()); } - Host host = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalLoadBalancer, hostDetails); + Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalLoadBalancer, hostDetails); if (host != null) { if (deviceType.equalsIgnoreCase(ExternalNetworkDeviceType.F5BigIP.getName())) { zone.setLoadBalancerProvider(Network.Provider.F5BigIp.getName()); @@ -630,7 +632,7 @@ public class ExternalNetworkManagerImpl implements ExternalNetworkManager { throw new CloudRuntimeException(e.getMessage()); } - Host externalFirewall = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails); + Host externalFirewall = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails); if (externalFirewall != null) { zone.setFirewallProvider(Network.Provider.JuniperSRX.getName()); zone.setUserDataProvider(Network.Provider.DhcpServer.getName()); diff --git a/server/src/com/cloud/network/F5BigIpManagerImpl.java b/server/src/com/cloud/network/F5BigIpManagerImpl.java old mode 100644 new mode 100755 index 28781e618e0..6af33ba4526 --- a/server/src/com/cloud/network/F5BigIpManagerImpl.java +++ b/server/src/com/cloud/network/F5BigIpManagerImpl.java @@ -141,7 +141,7 @@ public class F5BigIpManagerImpl extends ExternalNetworkManagerImpl implements Ex throw new CloudRuntimeException(e.getMessage()); } - Host host = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalLoadBalancer, hostDetails); + Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalLoadBalancer, hostDetails); if (host != null) { zone.setLoadBalancerProvider(Network.Provider.F5BigIp.getName()); _dcDao.update(zone.getId(), zone); diff --git a/server/src/com/cloud/network/JuniperSrxManagerImpl.java b/server/src/com/cloud/network/JuniperSrxManagerImpl.java old mode 100644 new mode 100755 index a461826b2a1..f8712e6db20 --- a/server/src/com/cloud/network/JuniperSrxManagerImpl.java +++ b/server/src/com/cloud/network/JuniperSrxManagerImpl.java @@ -43,6 +43,7 @@ import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; import com.cloud.server.api.response.ExternalFirewallResponse; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -78,6 +79,8 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements ConfigurationManager _configMgr; @Inject AccountManager _accountMgr; + @Inject + ResourceManager _resourceMgr; private static final org.apache.log4j.Logger s_logger = Logger.getLogger(JuniperSrxManagerImpl.class); @@ -184,7 +187,7 @@ public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements throw new CloudRuntimeException(e.getMessage()); } - Host externalFirewall = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails); + Host externalFirewall = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails); if (externalFirewall != null) { zone.setFirewallProvider(Network.Provider.JuniperSRX.getName()); zone.setUserDataProvider(Network.Provider.DhcpServer.getName()); diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java old mode 100644 new mode 100755 index d2a98f4caf5..e5172e5a838 --- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java +++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java @@ -66,6 +66,7 @@ import com.cloud.network.Network.GuestIpType; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.resource.TrafficSentinelResource; +import com.cloud.resource.ResourceManager; import com.cloud.server.api.response.TrafficMonitorResponse; import com.cloud.usage.UsageIPAddressVO; import com.cloud.user.AccountManager; @@ -104,6 +105,7 @@ public class NetworkUsageManagerImpl implements NetworkUsageManager { @Inject HostDetailsDao _detailsDao; @Inject AccountManager _accountMgr; @Inject NetworkDao _networksDao = null; + @Inject ResourceManager _resourceMgr; ScheduledExecutorService _executor; int _networkStatsInterval; protected SearchBuilder AllocatedIpSearch; @@ -161,7 +163,7 @@ public class NetworkUsageManagerImpl implements NetworkUsageManager { hostDetails.put("url", cmd.getUrl()); hostDetails.put("last_collection", ""+System.currentTimeMillis()); - Host trafficMonitor = _agentMgr.addHost(zoneId, resource, Host.Type.TrafficMonitor, hostDetails); + Host trafficMonitor = _resourceMgr.addHost(zoneId, resource, Host.Type.TrafficMonitor, hostDetails); return trafficMonitor; } diff --git a/server/src/com/cloud/resource/ResourceManager.java b/server/src/com/cloud/resource/ResourceManager.java index 3ef2f17348d..f9b4f469c55 100755 --- a/server/src/com/cloud/resource/ResourceManager.java +++ b/server/src/com/cloud/resource/ResourceManager.java @@ -17,7 +17,11 @@ */ package com.cloud.resource; +import java.util.List; +import java.util.Map; + import com.cloud.host.Host; +import com.cloud.host.Host.Type; /** * ResourceManager manages how physical resources are organized within the @@ -45,4 +49,9 @@ public interface ResourceManager { public void registerResourceStateAdapter(String name, ResourceStateAdapter adapter); public void unregisterResourceStateAdapter(String name); + + public Host createHostAndAgent(Long hostId, ServerResource resource, Map details, boolean old, List hostTags, + String allocationState, boolean forRebalance); + + public Host addHost(long zoneId, ServerResource resource, Type hostType, Map hostDetails); } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 8ee661d5449..74f61baa070 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -33,8 +33,10 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; +import com.cloud.agent.AgentManager.TapAgentsAction; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.manager.AgentAttache; +import com.cloud.agent.transport.Request; import com.cloud.api.commands.AddClusterCmd; import com.cloud.api.commands.AddHostCmd; import com.cloud.api.commands.AddSecondaryStorageCmd; @@ -58,6 +60,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.host.Host; import com.cloud.host.Host.HostAllocationState; +import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; @@ -85,6 +88,7 @@ import com.cloud.utils.component.Manager; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; @Local({ ResourceManager.class, ResourceService.class }) public class ResourceManagerImpl implements ResourceManager, ResourceService, Manager { @@ -364,9 +368,9 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma break; } - AgentAttache attache = _agentMgr.simulateStart(null, resource, entry.getValue(), true, null, null, false); - if (attache != null) { - hosts.add(_hostDao.findById(attache.getId())); + HostVO host = (HostVO)createHostAndAgent(resource, entry.getValue(), true, null, null, false); + if (host != null) { + hosts.add(host); } discoverer.postDiscovery(hosts, _nodeId); } @@ -585,9 +589,10 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma } return null; } - AgentAttache attache = _agentMgr.simulateStart(null, resource, entry.getValue(), true, hostTags, allocationState, false); - if (attache != null) { - hosts.add(_hostDao.findById(attache.getId())); + + HostVO host = (HostVO)createHostAndAgent(resource, entry.getValue(), true, hostTags, allocationState, false); + if (host != null) { + hosts.add(host); } discoverer.postDiscovery(hosts, _nodeId); @@ -1030,6 +1035,217 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma return result; } } - + private boolean checkCIDR(HostPodVO pod, String serverPrivateIP, String serverPrivateNetmask) { + if (serverPrivateIP == null) { + return true; + } + // Get the CIDR address and CIDR size + String cidrAddress = pod.getCidrAddress(); + long cidrSize = pod.getCidrSize(); + + // If the server's private IP address is not in the same subnet as the + // pod's CIDR, return false + String cidrSubnet = NetUtils.getCidrSubNet(cidrAddress, cidrSize); + String serverSubnet = NetUtils.getSubNet(serverPrivateIP, serverPrivateNetmask); + if (!cidrSubnet.equals(serverSubnet)) { + return false; + } + + // If the server's private netmask is less inclusive than the pod's CIDR + // netmask, return false + String cidrNetmask = NetUtils.getCidrSubNet("255.255.255.255", cidrSize); + long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); + long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask); + if (serverNetmaskNumeric > cidrNetmaskNumeric) { + return false; + } + return true; + } + + protected HostVO createHostVO(StartupCommand[] cmds, ServerResource resource, Map details, List hostTags, + ResourceStateAdapter.Event stateEvent) { + StartupCommand startup = cmds[0]; + HostVO host = _hostDao.findByGuid(startup.getGuid()); + if (host == null) { + host = _hostDao.findByGuid(startup.getGuidWithoutResource()); + } + if (host == null) { + host = new HostVO(startup.getGuid()); + host.setResource(resource.getClass().getName()); + host = _hostDao.persist(host); + } + // TODO: we don't allow to set ResourceState here? + + String dataCenter = startup.getDataCenter(); + String pod = startup.getPod(); + String cluster = startup.getCluster(); + + if (pod != null && dataCenter != null && pod.equalsIgnoreCase("default") && dataCenter.equalsIgnoreCase("default")) { + List pods = _podDao.listAllIncludingRemoved(); + for (HostPodVO hpv : pods) { + if (checkCIDR(hpv, startup.getPrivateIpAddress(), startup.getPrivateNetmask())) { + pod = hpv.getName(); + dataCenter = _dcDao.findById(hpv.getDataCenterId()).getName(); + break; + } + } + } + + long dcId = -1; + DataCenterVO dc = _dcDao.findByName(dataCenter); + if (dc == null) { + try { + dcId = Long.parseLong(dataCenter); + dc = _dcDao.findById(dcId); + } catch (final NumberFormatException e) { + } + } + if (dc == null) { + throw new IllegalArgumentException("Host " + startup.getPrivateIpAddress() + " sent incorrect data center: " + dataCenter); + } + dcId = dc.getId(); + + HostPodVO p = _podDao.findByName(pod, dcId); + if (p == null) { + try { + final long podId = Long.parseLong(pod); + p = _podDao.findById(podId); + } catch (final NumberFormatException e) { + } + } + /* + * ResourceStateAdapter is responsible for throwing Exception if Pod is + * null and non-null is required. for example, XcpServerDiscoever. + * Others, like PxeServer, ExternalFireware don't require Pod + */ + Long podId = (p == null ? null : p.getId()); + + Long clusterId = null; + if (cluster != null) { + try { + clusterId = Long.valueOf(cluster); + } catch (NumberFormatException e) { + ClusterVO c = _clusterDao.findBy(cluster, podId); + if (c == null) { + c = new ClusterVO(dcId, podId, cluster); + c = _clusterDao.persist(c); + } + clusterId = c.getId(); + } + } + + host.setDataCenterId(dc.getId()); + host.setPodId(podId); + host.setClusterId(clusterId); + host.setPrivateIpAddress(startup.getPrivateIpAddress()); + host.setPrivateNetmask(startup.getPrivateNetmask()); + host.setPrivateMacAddress(startup.getPrivateMacAddress()); + host.setPublicIpAddress(startup.getPublicIpAddress()); + host.setPublicMacAddress(startup.getPublicMacAddress()); + host.setPublicNetmask(startup.getPublicNetmask()); + host.setStorageIpAddress(startup.getStorageIpAddress()); + host.setStorageMacAddress(startup.getStorageMacAddress()); + host.setStorageNetmask(startup.getStorageNetmask()); + host.setVersion(startup.getVersion()); + host.setName(startup.getName()); + host.setManagementServerId(_nodeId); + host.setStorageUrl(startup.getIqn()); + host.setLastPinged(System.currentTimeMillis() >> 10); + host.setHostTags(hostTags); + host.setDetails(details); + if (startup.getStorageIpAddressDeux() != null) { + host.setStorageIpAddressDeux(startup.getStorageIpAddressDeux()); + host.setStorageMacAddressDeux(startup.getStorageMacAddressDeux()); + host.setStorageNetmaskDeux(startup.getStorageNetmaskDeux()); + } + + host = (HostVO) dispatchToStateAdapters(stateEvent, true, host, cmds, resource, details, hostTags); + _hostDao.update(host.getId(), host); + /* Agent goes to Connecting status */ + _agentMgr.agentStatusTransitTo(host, Status.Event.AgentConnected, _nodeId); + return host; + } + + private Host createHostAndAgent(ServerResource resource, Map details, boolean old, List hostTags, String allocationState, + boolean forRebalance) { + HostVO host = null; + AgentAttache attache = null; + StartupCommand[] cmds = null; + + try { + cmds = resource.initialize(); + if (cmds == null) { + s_logger.info("Unable to fully initialize the agent because no StartupCommands are returned"); + return null; + } + + if (s_logger.isDebugEnabled()) { + new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); + } + + if (old) { + StartupCommand firstCmd = cmds[0]; + host = _hostDao.findByGuid(firstCmd.getGuid()); + if (host == null) { + host = _hostDao.findByGuid(firstCmd.getGuidWithoutResource()); + } + if (host != null && host.getRemoved() == null) { + s_logger.debug("Found the host " + host.getId() + " by guid: " + firstCmd.getGuid() + ", old host reconnected as new"); + return null; + } + } + + host = createHostVO(cmds, resource, details, hostTags, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT); + if (host != null) { + attache = _agentMgr.createAttacheForDirectConnect(host, cmds, resource, forRebalance); + /* reload myself from database */ + host = _hostDao.findById(host.getId()); + } + } catch (Exception e) { + s_logger.warn("Unable to connect due to ", e); + } finally { + if (attache == null) { + if (cmds != null) { + resource.disconnected(); + } + + if (host != null) { + /* Change agent status to Alert */ + _agentMgr.agentStatusTransitTo(host, Status.Event.AgentDisconnected, _nodeId); + } + } + } + + return host; + } + + @Override + public Host createHostAndAgent(Long hostId, ServerResource resource, Map details, boolean old, List hostTags, + String allocationState, boolean forRebalance) { + _agentMgr.tapLoadingAgents(hostId, TapAgentsAction.Add); + Host host = createHostAndAgent(resource, details, old, hostTags, allocationState, forRebalance); + _agentMgr.tapLoadingAgents(hostId, TapAgentsAction.Del); + return host; + } + + @Override + public Host addHost(long zoneId, ServerResource resource, Type hostType, Map hostDetails) { + // Check if the zone exists in the system + if (_dcDao.findById(zoneId) == null) { + throw new InvalidParameterValueException("Can't find zone with id " + zoneId); + } + + Map details = hostDetails; + String guid = details.get("guid"); + List currentHosts = _hostDao.listBy(hostType, zoneId); + for (HostVO currentHost : currentHosts) { + if (currentHost.getGuid().equals(guid)) { + return currentHost; + } + } + + return createHostAndAgent(resource, hostDetails, true, null, null, false); + } + }