| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF 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 com.cloud.hypervisor.kvm.resource; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import com.cloud.agent.properties.AgentProperties; |
| import com.cloud.agent.properties.AgentPropertiesFileHandler; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.logging.log4j.LogManager; |
| import org.libvirt.Connect; |
| import org.libvirt.Library; |
| import org.libvirt.LibvirtException; |
| |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.hypervisor.Hypervisor.HypervisorType; |
| |
| public class LibvirtConnection { |
| protected static Logger LOGGER = LogManager.getLogger(LibvirtConnection.class); |
| static private Map<String, Connect> s_connections = new HashMap<String, Connect>(); |
| |
| static private Connect s_connection; |
| static private String s_hypervisorURI; |
| static private Thread libvirtEventThread; |
| |
| static public Connect getConnection() throws LibvirtException { |
| return getConnection(s_hypervisorURI); |
| } |
| |
| static synchronized public Connect getConnection(String hypervisorURI) throws LibvirtException { |
| LOGGER.debug("Looking for libvirtd connection at: " + hypervisorURI); |
| Connect conn = s_connections.get(hypervisorURI); |
| |
| if (conn == null) { |
| LOGGER.info("No existing libvirtd connection found. Opening a new one"); |
| |
| setupEventListener(); |
| conn = new Connect(hypervisorURI, false); |
| LOGGER.debug("Successfully connected to libvirt at: " + hypervisorURI); |
| s_connections.put(hypervisorURI, conn); |
| } else { |
| try { |
| conn.getVersion(); |
| } catch (LibvirtException e) { |
| LOGGER.error("Connection with libvirtd is broken: " + e.getMessage()); |
| |
| try { |
| conn.close(); |
| } catch (LibvirtException closeEx) { |
| LOGGER.debug("Ignoring error while trying to close broken connection:" + closeEx.getMessage()); |
| } |
| |
| LOGGER.debug("Opening a new libvirtd connection to: " + hypervisorURI); |
| setupEventListener(); |
| conn = new Connect(hypervisorURI, false); |
| s_connections.put(hypervisorURI, conn); |
| } |
| } |
| |
| return conn; |
| } |
| |
| static public Connect getConnectionByVmName(String vmName) throws LibvirtException { |
| HypervisorType[] hypervisors = new HypervisorType[] {HypervisorType.KVM, Hypervisor.HypervisorType.LXC}; |
| |
| for (HypervisorType hypervisor : hypervisors) { |
| try { |
| Connect conn = LibvirtConnection.getConnectionByType(hypervisor.toString()); |
| if (conn.domainLookupByName(vmName) != null) { |
| return conn; |
| } |
| } catch (Exception e) { |
| LOGGER.debug("Can not find " + hypervisor.toString() + " connection for Instance: " + vmName + ", continuing."); |
| } |
| } |
| |
| LOGGER.warn("Can not find a connection for Instance " + vmName + ". Assuming the default connection."); |
| // return the default connection |
| return getConnection(); |
| } |
| |
| static public Connect getConnectionByType(String hypervisorType) throws LibvirtException { |
| return getConnection(getHypervisorURI(hypervisorType)); |
| } |
| |
| static void initialize(String hypervisorURI) { |
| s_hypervisorURI = hypervisorURI; |
| } |
| |
| static String getHypervisorURI(String hypervisorType) { |
| String uri = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HYPERVISOR_URI); |
| if (uri != null) { |
| return uri; |
| } |
| |
| if ("LXC".equalsIgnoreCase(hypervisorType)) { |
| return "lxc:///"; |
| } |
| |
| return "qemu:///system"; |
| } |
| |
| /** |
| * Set up Libvirt event handling and polling. This is not specific to a connection object instance, but needs |
| * to be done prior to creating connections. See the Libvirt documentation for virEventRegisterDefaultImpl and |
| * virEventRunDefaultImpl or the libvirt-java Library Javadoc for more information. |
| * @throws LibvirtException |
| */ |
| private static synchronized void setupEventListener() throws LibvirtException { |
| if (!AgentPropertiesFileHandler.getPropertyValue(AgentProperties.LIBVIRT_EVENTS_ENABLED)) { |
| LOGGER.debug("Libvirt event listening is disabled, not setting up event loop"); |
| return; |
| } |
| |
| if (libvirtEventThread == null || !libvirtEventThread.isAlive()) { |
| // Registers a default event loop, must be called before connecting to hypervisor |
| Library.initEventLoop(); |
| libvirtEventThread = new Thread(() -> { |
| while (true) { |
| try { |
| // This blocking call contains a loop of its own that will process events until the event loop is stopped or exception is thrown. |
| Library.runEventLoop(); |
| } catch (LibvirtException e) { |
| LOGGER.error("LibvirtException was thrown in event loop: ", e); |
| } catch (InterruptedException e) { |
| LOGGER.error("Libvirt event loop was interrupted: ", e); |
| } |
| } |
| }); |
| |
| // Process events in separate thread. Failure to run event loop regularly will cause connections to close due to keepalive timeout. |
| libvirtEventThread.setDaemon(true); |
| libvirtEventThread.start(); |
| } |
| } |
| } |