// Copyright 2012 Citrix Systems, Inc. Licensed under the // Apache License, Version 2.0 (the "License"); you may not use this // file except in compliance with the License. Citrix Systems, Inc. // reserves all rights not expressly granted by the License. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.hypervisor; import java.util.List; import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.StartupCommandProcessor; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.manager.authn.AgentAuthnException; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ZoneConfig; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DcDetailVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DcDetailsDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.exception.ConnectionException; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; /** * Creates a host record and supporting records such as pod and ip address * */ @Local(value=StartupCommandProcessor.class) public class CloudZonesStartupProcessor implements StartupCommandProcessor { private static final Logger s_logger = Logger.getLogger(CloudZonesStartupProcessor.class); @Inject ClusterDao _clusterDao = null; @Inject ConfigurationDao _configDao = null; @Inject DataCenterDao _zoneDao = null; @Inject HostDao _hostDao = null; @Inject HostPodDao _podDao = null; @Inject DcDetailsDao _zoneDetailsDao = null; @Inject AgentManager _agentManager = null; @Inject ConfigurationManager _configurationManager = null; long _nodeId = -1; @Override public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { _agentManager.registerForInitialConnects(this, false); if (_nodeId == -1) { // FIXME: We really should not do this like this. It should be done // at config time and is stored as a config variable. _nodeId = MacAddress.getMacAddress().toLong(); } return true; } @Override public String getName() { return getClass().getName(); } @Override public boolean start() { return true; } @Override public boolean stop() { return true; } @Override public boolean processInitialConnect(StartupCommand[] cmd) throws ConnectionException { StartupCommand startup = cmd[0]; if (startup instanceof StartupRoutingCommand) { return processHostStartup((StartupRoutingCommand)startup); } else if (startup instanceof StartupStorageCommand ){ return processStorageStartup((StartupStorageCommand)startup); } return false; } protected boolean processHostStartup(StartupRoutingCommand startup) throws ConnectionException{ /* boolean found = false; Type type = Host.Type.Routing; final Map<String, String> hostDetails = startup.getHostDetails(); HostVO server = _hostDao.findByGuid(startup.getGuid()); if (server == null) { server = _hostDao.findByGuid(startup.getGuidWithoutResource()); } if (server != null && server.getRemoved() == null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found the host " + server.getId() + " by guid: " + startup.getGuid()); } found = true; } else { server = new HostVO(startup.getGuid()); } server.setDetails(hostDetails); try { updateComputeHost(server, startup, type); } catch (AgentAuthnException e) { throw new ConnectionException(true, "Failed to authorize host, invalid configuration", e); } if (!found) { server.setHostAllocationState(Host.HostAllocationState.Enabled); server = _hostDao.persist(server); } else { if (!_hostDao.connect(server, _nodeId)) { throw new CloudRuntimeException( "Agent cannot connect because the current state is " + server.getStatus().toString()); } s_logger.info("Old " + server.getType().toString() + " host reconnected w/ id =" + server.getId()); } */ return true; } protected void updateComputeHost(final HostVO host, final StartupCommand startup, final Host.Type type) throws AgentAuthnException { String zoneToken = startup.getDataCenter(); if(zoneToken == null){ s_logger.warn("No Zone Token passed in, cannot not find zone for the agent"); throw new AgentAuthnException("No Zone Token passed in, cannot not find zone for agent"); } DataCenterVO zone = _zoneDao.findByToken(zoneToken); if (zone == null) { zone = _zoneDao.findByName(zoneToken); if(zone == null){ try { long zoneId = Long.parseLong(zoneToken); zone = _zoneDao.findById(zoneId); if (zone == null) { throw new AgentAuthnException("Could not find zone for agent with token " + zoneToken); } } catch (NumberFormatException nfe) { throw new AgentAuthnException("Could not find zone for agent with token " + zoneToken); } } } if(s_logger.isDebugEnabled()){ s_logger.debug("Successfully loaded the DataCenter from the zone token passed in "); } long zoneId = zone.getId(); DcDetailVO maxHostsInZone = _zoneDetailsDao.findDetail(zoneId, ZoneConfig.MaxHosts.key()); if(maxHostsInZone != null){ long maxHosts = new Long(maxHostsInZone.getValue()).longValue(); long currentCountOfHosts = _hostDao.countRoutingHostsByDataCenter(zoneId); if(s_logger.isDebugEnabled()){ s_logger.debug("Number of hosts in Zone:"+ currentCountOfHosts + ", max hosts limit: "+ maxHosts); } if(currentCountOfHosts >= maxHosts){ throw new AgentAuthnException("Number of running Routing hosts in the Zone:"+ zone.getName() +" is already at the max limit:"+maxHosts+", cannot start one more host"); } } HostPodVO pod = null; if(startup.getPrivateIpAddress() == null){ s_logger.warn("No private IP address passed in for the agent, cannot not find pod for agent"); throw new AgentAuthnException("No private IP address passed in for the agent, cannot not find pod for agent"); } if(startup.getPrivateNetmask() == null){ s_logger.warn("No netmask passed in for the agent, cannot not find pod for agent"); throw new AgentAuthnException("No netmask passed in for the agent, cannot not find pod for agent"); } if(host.getPodId() != null){ if(s_logger.isDebugEnabled()){ s_logger.debug("Pod is already created for this agent, looks like agent is reconnecting..."); } pod = _podDao.findById(host.getPodId()); if(!checkCIDR(type, pod, startup.getPrivateIpAddress(), startup.getPrivateNetmask())){ pod = null; if(s_logger.isDebugEnabled()){ s_logger.debug("Subnet of Pod does not match the subnet of the agent, not using this Pod: "+host.getPodId()); } }else{ updatePodNetmaskIfNeeded(pod, startup.getPrivateNetmask()); } } if(pod == null){ if(s_logger.isDebugEnabled()){ s_logger.debug("Trying to detect the Pod to use from the agent's ip address and netmask passed in "); } //deduce pod boolean podFound = false; List<HostPodVO> podsInZone = _podDao.listByDataCenterId(zoneId); for (HostPodVO hostPod : podsInZone) { if (checkCIDR(type, hostPod, startup.getPrivateIpAddress(), startup.getPrivateNetmask())) { pod = hostPod; //found the default POD having the same subnet. updatePodNetmaskIfNeeded(pod, startup.getPrivateNetmask()); podFound = true; break; } } if (!podFound) { if(s_logger.isDebugEnabled()){ s_logger.debug("Creating a new Pod since no default Pod found that matches the agent's ip address and netmask passed in "); } if(startup.getGatewayIpAddress() == null){ s_logger.warn("No Gateway IP address passed in for the agent, cannot create a new pod for the agent"); throw new AgentAuthnException("No Gateway IP address passed in for the agent, cannot create a new pod for the agent"); } //auto-create a new pod, since pod matching the agent's ip is not found String podName = "POD-"+ (podsInZone.size()+1); try{ String gateway = startup.getGatewayIpAddress(); String cidr = NetUtils.getCidrFromGatewayAndNetmask(gateway, startup.getPrivateNetmask()); String[] cidrPair = cidr.split("\\/"); String cidrAddress = cidrPair[0]; long cidrSize = Long.parseLong(cidrPair[1]); String startIp = NetUtils.getIpRangeStartIpFromCidr(cidrAddress, cidrSize); String endIp = NetUtils.getIpRangeEndIpFromCidr(cidrAddress, cidrSize); pod = _configurationManager.createPod(-1, podName, zoneId, gateway, cidr, startIp, endIp, null, true); }catch (Exception e) { // no longer tolerate exception during the cluster creation phase throw new CloudRuntimeException("Unable to create new Pod " + podName + " in Zone: " + zoneId, e); } } } final StartupRoutingCommand scc = (StartupRoutingCommand) startup; ClusterVO cluster = null; if(host.getClusterId() != null){ if(s_logger.isDebugEnabled()){ s_logger.debug("Cluster is already created for this agent, looks like agent is reconnecting..."); } cluster = _clusterDao.findById(host.getClusterId()); } if(cluster == null){ //auto-create cluster - assume one host per cluster String clusterName = "Cluster-" + startup.getPrivateIpAddress(); ClusterVO existingCluster = _clusterDao.findBy(clusterName, pod.getId()); if (existingCluster != null) { cluster = existingCluster; } else { if(s_logger.isDebugEnabled()){ s_logger.debug("Creating a new Cluster for this agent with name: "+clusterName + " in Pod: " +pod.getId() +", in Zone:"+zoneId); } cluster = new ClusterVO(zoneId, pod.getId(), clusterName); cluster.setHypervisorType(scc.getHypervisorType().toString()); try { cluster = _clusterDao.persist(cluster); } catch (Exception e) { // no longer tolerate exception during the cluster creation phase throw new CloudRuntimeException("Unable to create cluster " + clusterName + " in pod " + pod.getId() + " and data center " + zoneId, e); } } } if(s_logger.isDebugEnabled()){ s_logger.debug("Detected Zone: "+zoneId+", Pod: " +pod.getId() +", Cluster:" +cluster.getId()); } host.setDataCenterId(zone.getId()); host.setPodId(pod.getId()); host.setClusterId(cluster.getId()); 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.setType(type); host.setStorageUrl(startup.getIqn()); host.setLastPinged(System.currentTimeMillis() >> 10); host.setCaps(scc.getCapabilities()); host.setCpus(scc.getCpus()); host.setTotalMemory(scc.getMemory()); host.setSpeed(scc.getSpeed()); HypervisorType hyType = scc.getHypervisorType(); host.setHypervisorType(hyType); host.setHypervisorVersion(scc.getHypervisorVersion()); } private boolean checkCIDR(Host.Type type, 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; } return true; } private void updatePodNetmaskIfNeeded(HostPodVO pod, String agentNetmask){ // If the server's private netmask is less inclusive than the pod's CIDR // netmask, update cidrSize of the default POD //(reason: we are maintaining pods only for internal accounting.) long cidrSize = pod.getCidrSize(); String cidrNetmask = NetUtils .getCidrSubNet("255.255.255.255", cidrSize); long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); long serverNetmaskNumeric = NetUtils.ip2Long(agentNetmask);// if (serverNetmaskNumeric > cidrNetmaskNumeric) { //update pod's cidrsize int newCidrSize = new Long(NetUtils.getCidrSize(agentNetmask)).intValue(); pod.setCidrSize(newCidrSize); _podDao.update(pod.getId(), pod); } } protected boolean processStorageStartup(StartupStorageCommand startup) throws ConnectionException{ /* if (startup.getResourceType() != Storage.StorageResourceType.LOCAL_SECONDARY_STORAGE) { return false; } boolean found = false; Type type = Host.Type.LocalSecondaryStorage; final Map<String, String> hostDetails = startup.getHostDetails(); HostVO server = _hostDao.findByGuid(startup.getGuid()); if (server == null) { server = _hostDao.findByGuid(startup.getGuidWithoutResource()); } if (server != null && server.getRemoved() == null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found the host " + server.getId() + " by guid: " + startup.getGuid()); } found = true; } else { server = new HostVO(startup.getGuid()); } server.setDetails(hostDetails); try { updateSecondaryHost(server, startup, type); } catch (AgentAuthnException e) { throw new ConnectionException(true, "Failed to authorize host, invalid configuration", e); } if (!found) { server.setHostAllocationState(Host.HostAllocationState.Enabled); server = _hostDao.persist(server); } else { if (!_hostDao.connect(server, _nodeId)) { throw new CloudRuntimeException( "Agent cannot connect because the current state is " + server.getStatus().toString()); } s_logger.info("Old " + server.getType().toString() + " host reconnected w/ id =" + server.getId()); } */ return true; } protected void updateSecondaryHost(final HostVO host, final StartupStorageCommand startup, final Host.Type type) throws AgentAuthnException { String zoneToken = startup.getDataCenter(); if(zoneToken == null){ s_logger.warn("No Zone Token passed in, cannot not find zone for the agent"); throw new AgentAuthnException("No Zone Token passed in, cannot not find zone for agent"); } DataCenterVO zone = _zoneDao.findByToken(zoneToken); if (zone == null) { zone = _zoneDao.findByName(zoneToken); if(zone == null){ try { long zoneId = Long.parseLong(zoneToken); zone = _zoneDao.findById(zoneId); if (zone == null) { throw new AgentAuthnException("Could not find zone for agent with token " + zoneToken); } } catch (NumberFormatException nfe) { throw new AgentAuthnException("Could not find zone for agent with token " + zoneToken); } } } if(s_logger.isDebugEnabled()){ s_logger.debug("Successfully loaded the DataCenter from the zone token passed in "); } HostPodVO pod = findPod(startup, zone.getId(), Host.Type.Routing); //yes, routing Long podId = null; if (pod != null) { s_logger.debug("Found pod " + pod.getName() + " for the secondary storage host " + startup.getName()); podId = pod.getId(); } host.setDataCenterId(zone.getId()); host.setPodId(podId); host.setClusterId(null); 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.setType(type); host.setStorageUrl(startup.getIqn()); host.setLastPinged(System.currentTimeMillis() >> 10); host.setCaps(null); host.setCpus(null); host.setTotalMemory(0); host.setSpeed(null); host.setParent(startup.getParent()); host.setTotalSize(startup.getTotalSize()); host.setHypervisorType(HypervisorType.None); if (startup.getNfsShare() != null) { host.setStorageUrl(startup.getNfsShare()); } } private HostPodVO findPod(StartupCommand startup, long zoneId, Host.Type type) { HostPodVO pod = null; List<HostPodVO> podsInZone = _podDao.listByDataCenterId(zoneId); for (HostPodVO hostPod : podsInZone) { if (checkCIDR(type, hostPod, startup.getPrivateIpAddress(), startup.getPrivateNetmask())) { pod = hostPod; //found the default POD having the same subnet. updatePodNetmaskIfNeeded(pod, startup.getPrivateNetmask()); break; } } return pod; } }