Java tutorial
/* * This program is part of Autonomiccs "autonomic-platform", * an open source autonomic cloud computing management platform. * Copyright (C) 2016 Autonomiccs, Inc. * * Licensed to the Autonomiccs, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The Autonomiccs, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with 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. */ package br.com.autonomiccs.autonomic.administration.plugin.hypervisors.xenserver; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import org.apache.xmlrpc.XmlRpcException; import org.springframework.stereotype.Component; import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.xenserver.resource.XenServerConnectionPool; import com.cloud.utils.exception.CloudRuntimeException; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Host; import com.xensource.xenapi.Pool; import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.XenAPIException; import br.com.autonomiccs.autonomic.administration.plugin.hypervisors.HypervisorHost; import br.com.autonomiccs.autonomic.plugin.common.services.HostService; import br.com.autonomiccs.autonomic.plugin.common.utils.HostUtils; import br.com.autonomiccs.autonomic.plugin.common.utils.ShellCommandUtils; import br.com.autonomiccs.autonomic.plugin.common.utils.ThreadUtils; @Component public class XenHypervisor implements HypervisorHost { protected static final String FIND_ARP_FOR_HOST_COMMAND = "arp -n %s"; protected static final String REGEX_GET_ARP_FROM_ARP_COMMAND_OUTPUT = ".+([A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}).+"; protected XenServerConnectionPool connPool = XenServerConnectionPool.getInstance(); protected final Pattern compileRegexToGetArp = Pattern.compile(REGEX_GET_ARP_FROM_ARP_COMMAND_OUTPUT); @Inject protected ThreadUtils threadUtils; @Inject protected HostUtils hostUtils; @Inject protected ShellCommandUtils shellCommandUtils; @Inject protected HostService hostService; /** * This method shuts down the given host. It checks if the host to be powered off is the * master, if yes then changes the master to be another host in the cluster. * * @note this method can be executed only after the * {@link HostService#loadHostDetails(HostVO)} method. */ @Override public void shutdownHost(HostVO hostVo) { String privateMacAddress = getHostPrivateMacAddress(hostVo); hostService.updateHostPrivaceMacAddress(hostVo, privateMacAddress); Connection conn = getConnection(hostVo); String hostToDeactivatedUuid = hostVo.getGuid(); try { Host master = getMasterHost(conn); changeMasterIfNeeded(conn, master, hostToDeactivatedUuid); Host host = Host.getByUuid(conn, hostToDeactivatedUuid); String hostAddress = host.getAddress(conn); disableAndShutdownHost(conn, host); do { threadUtils.sleepThread(3); } while (hostUtils.isHostReachable(hostAddress)); } catch (Exception e) { throw new CloudRuntimeException( String.format("Could not shut down host [uuid=%s]", hostToDeactivatedUuid), e); } } protected String getHostPrivateMacAddress(HostVO hostVo) { String returnOfArpCommand = shellCommandUtils .executeCommand(String.format(FIND_ARP_FOR_HOST_COMMAND, hostVo.getPrivateIpAddress())); Matcher matcher = compileRegexToGetArp.matcher(returnOfArpCommand); if (matcher.find()) { return matcher.group(1); } throw new CloudRuntimeException( String.format("Could not find host [name=%s, privateAddress=%s] private mac address.", hostVo.getName(), hostVo.getPrivateIpAddress())); } /** * It disables the host (using {@link Host#disable(Connection)}) and shuts it down * using the {@link Host#shutdown(Connection)} method. */ protected void disableAndShutdownHost(Connection conn, Host host) throws BadServerResponse, XenAPIException, XmlRpcException { host.disable(conn); host.shutdown(conn); } /** * If the pool has more than one host and the * host to be powered off is the master, it changes the master using * {@link #changePoolMasterHost(Connection, String)}. */ protected void changeMasterIfNeeded(Connection conn, Host master, String hostUuid) throws BadServerResponse, XenAPIException, XmlRpcException { if (hostUuid.equals(master.getUuid(conn)) && !isLastHostOnPool(conn)) { changePoolMasterHost(conn, hostUuid); waitChangePoolMasterHost(master, conn, hostUuid); } } /** * Returns true if the pool has exactly one {@link Host}. */ protected boolean isLastHostOnPool(Connection conn) throws BadServerResponse, XenAPIException, XmlRpcException { return Host.getAll(conn).size() == 1; } /** * Returns the {@link Host} that is the current master of this pool. */ protected Host getMasterHost(Connection conn) throws BadServerResponse, XenAPIException, XmlRpcException { Iterator<Pool> poolIterator = Pool.getAll(conn).iterator(); if (poolIterator.hasNext()) { return poolIterator.next().getMaster(conn); } throw new CloudRuntimeException("Could not find master server for pool."); } /** * The new master will be selected with no specific criteria. */ protected void changePoolMasterHost(Connection conn, String hostUuid) throws BadServerResponse, XenAPIException, XmlRpcException { for (Host host : Host.getAll(conn)) { if (hostUuid.equals(host.getUuid(conn))) { continue; } if (hostUtils.isHostReachable(host.getAddress(conn))) { Pool.designateNewMaster(conn, host); return; } } } /** * Waits until the master of the pool changes, given a total of 90 tries, * each taking 3 seconds of wait. */ protected void waitChangePoolMasterHost(Host master, Connection conn, String hostUuid) throws BadServerResponse, XenAPIException, XmlRpcException { int count = 0; while (hostUuid.equals(master.getUuid(conn))) { threadUtils.sleepThread(3); count++; if (count > 90) { throw new CloudRuntimeException(String.format( "Could not shut down host [uuid=%s]; It was not possible to assign a new master to its pool", hostUuid)); } } } /** * Get connection with the * {@link XenServerConnectionPool#getConnect(String, String, Queue)}, * passing the host uuid, pool, ip, username, password and wait time. */ protected Connection getConnection(HostVO host) { Map<String, String> params = host.getDetails(); String username = getUsername(params); Queue<String> password = getPassword(params); return connPool.getConnect(host.getPrivateIpAddress(), username, password); } /** * Returns the host user name. */ protected String getUsername(Map<String, String> params) { return params.get("username"); } /** * Returns the host password. */ protected Queue<String> getPassword(Map<String, String> params) { Queue<String> password = new LinkedList<>(); password.add(params.get("password")); return password; } /** * It returns true if the given {@link com.cloud.hypervisor.Hypervisor.HypervisorType} is equals * to {@link com.cloud.hypervisor.Hypervisor.HypervisorType#XenServer}. */ @Override public boolean supportsHypervisor(HypervisorType hypervisorType) { return HypervisorType.XenServer.equals(hypervisorType); } }