blob: a31637b60deb376e878a9723269e25d85ad74840 [file] [log] [blame]
// 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.hyperv.manager;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.cloud.configuration.Config;
import com.cloud.storage.JavaStorageLayer;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.FileUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.VMInstanceDao;
public class HypervManagerImpl implements HypervManager {
protected Logger logger = LogManager.getLogger(getClass());
private String name;
private int runLevel;
private Map<String, Object> params;
private int _timeout;
Random _rand = new Random(System.currentTimeMillis());
Map<String, String> _storageMounts = new HashMap<String, String>();
StorageLayer _storage;
@Inject ConfigurationDao _configDao;
@Inject DataStoreManager _dataStoreMgr;
@Inject VMInstanceDao _vminstanceDao;
@Inject NicDao _nicDao;
int _routerExtraPublicNics = 2;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
if (params != null) {
String value = (String)params.get("scripts.timeout");
_timeout = NumbersUtil.parseInt(value, 30) * 1000;
_storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey);
}
if (_storage == null) {
_storage = new JavaStorageLayer();
_storage.configure("StorageLayer", params);
}
_routerExtraPublicNics = NumbersUtil.parseInt(_configDao.getValue(Config.RouterExtraPublicNics.key()), 2);
return true;
}
@Override
public boolean start() {
startupCleanup(getMountParent());
return true;
}
@Override
public boolean stop() {
shutdownCleanup();
return true;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setConfigParams(Map<String, Object> params) {
this.params = params;
}
@Override
public Map<String, Object> getConfigParams() {
return params;
}
@Override
public int getRunLevel() {
return runLevel;
}
@Override
public void setRunLevel(int level) {
runLevel = level;
}
@Override
public String prepareSecondaryStorageStore(long zoneId) {
String secondaryStorageUri = getSecondaryStorageStoreUrl(zoneId);
if (secondaryStorageUri == null) {
logger.debug("Secondary storage uri for dc " + zoneId + " couldn't be obtained");
} else {
prepareSecondaryStorageStore(secondaryStorageUri);
}
return secondaryStorageUri;
}
private String getSecondaryStorageStoreUrl(long zoneId) {
String secUrl = null;
DataStore secStore = _dataStoreMgr.getImageStoreWithFreeCapacity(zoneId);
if (secStore != null) {
secUrl = secStore.getUri();
}
if (secUrl == null) {
logger.warn("Secondary storage uri couldn't be retrieved");
}
return secUrl;
}
private void prepareSecondaryStorageStore(String storageUrl) {
String mountPoint = getMountPoint(storageUrl);
GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm");
try {
if (lock.lock(3600)) {
try {
File patchFolder = new File(mountPoint + "/systemvm");
if (!patchFolder.exists()) {
if (!patchFolder.mkdirs()) {
String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString();
logger.error(msg);
throw new CloudRuntimeException(msg);
}
}
File srcIso = getSystemVMPatchIsoFile();
File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore());
if (!destIso.exists()) {
logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " +
srcIso.getAbsolutePath() + ", destination: " + destIso.getAbsolutePath());
try {
FileUtil.copyfile(srcIso, destIso);
} catch (IOException e) {
logger.error("Unexpected exception ", e);
String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso;
logger.error(msg);
throw new CloudRuntimeException(msg);
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists");
}
}
} finally {
lock.unlock();
}
}
} finally {
lock.releaseRef();
}
}
private String getMountPoint(String storageUrl) {
String mountPoint = null;
synchronized (_storageMounts) {
mountPoint = _storageMounts.get(storageUrl);
if (mountPoint != null) {
return mountPoint;
}
URI uri;
try {
uri = new URI(storageUrl);
} catch (URISyntaxException e) {
logger.error("Invalid storage URL format ", e);
throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl);
}
mountPoint = mount(File.separator + File.separator + uri.getHost() + uri.getPath(), getMountParent(),
uri.getScheme(), uri.getQuery());
if (mountPoint == null) {
logger.error("Unable to create mount point for " + storageUrl);
return "/mnt/sec";
}
_storageMounts.put(storageUrl, mountPoint);
return mountPoint;
}
}
protected String mount(String path, String parent, String scheme, String query) {
String mountPoint = setupMountPoint(parent);
if (mountPoint == null) {
logger.warn("Unable to create a mount point");
return null;
}
Script script = null;
String result = null;
if (scheme.equals("cifs")) {
String user = System.getProperty("user.name");
Script command = new Script(true, "mount", _timeout, logger);
command.add("-t", "cifs");
command.add(path);
command.add(mountPoint);
if (user != null) {
command.add("-o", "uid=" + user + ",gid=" + user);
}
if (query != null) {
query = query.replace('&', ',');
command.add("-o", query);
}
result = command.execute();
}
if (result != null) {
logger.warn("Unable to mount " + path + " due to " + result);
File file = new File(mountPoint);
if (file.exists()) {
file.delete();
}
return null;
}
// Change permissions for the mountpoint
script = new Script(true, "chmod", _timeout, logger);
script.add("-R", "777", mountPoint);
result = script.execute();
if (result != null) {
logger.warn("Unable to set permissions for " + mountPoint + " due to " + result);
}
return mountPoint;
}
private String setupMountPoint(String parent) {
String mountPoint = null;
long mshostId = ManagementServerNode.getManagementServerId();
for (int i = 0; i < 10; i++) {
String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE));
File file = new File(mntPt);
if (!file.exists()) {
if (_storage.mkdir(mntPt)) {
mountPoint = mntPt;
break;
}
}
logger.error("Unable to create mount: " + mntPt);
}
return mountPoint;
}
private String getSystemVMIsoFileNameOnDatastore() {
String version = this.getClass().getPackage().getImplementationVersion();
String fileName = "systemvm-" + version + ".iso";
return fileName.replace(':', '-');
}
private File getSystemVMPatchIsoFile() {
// locate systemvm.iso
URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso");
File isoFile = null;
if (url != null) {
isoFile = new File(url.getPath());
}
if (isoFile == null || !isoFile.exists()) {
isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso");
}
assert (isoFile != null);
if (!isoFile.exists()) {
logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString());
}
return isoFile;
}
private String getMountParent() {
String mountParent = _configDao.getValue(Config.MountParent.key());
if (mountParent == null) {
mountParent = File.separator + "mnt";
}
String instance = _configDao.getValue(Config.InstanceName.key());
if (instance == null) {
instance = "DEFAULT";
}
if (instance != null) {
mountParent = mountParent + File.separator + instance;
}
return mountParent;
}
private void startupCleanup(String parent) {
logger.info("Cleanup mounted mount points used in previous session");
long mshostId = ManagementServerNode.getManagementServerId();
// cleanup left-over NFS mounts from previous session
String[] mounts = _storage.listFiles(parent + File.separator + String.valueOf(mshostId) + ".*");
if (mounts != null && mounts.length > 0) {
for (String mountPoint : mounts) {
logger.info("umount NFS mount from previous session: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint);
result = command.execute();
if (result != null) {
logger.warn("Unable to umount " + mountPoint + " due to " + result);
}
File file = new File(mountPoint);
if (file.exists()) {
file.delete();
}
}
}
}
private void shutdownCleanup() {
logger.info("Cleanup mounted mount points used in current session");
synchronized (_storageMounts) {
for (String mountPoint : _storageMounts.values()) {
logger.info("umount NFS mount: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint);
result = command.execute();
if (result != null) {
logger.warn("Unable to umount " + mountPoint + " due to " + result);
}
File file = new File(mountPoint);
if (file.exists()) {
file.delete();
}
}
}
}
@Override
public int getRouterExtraPublicNics() {
return _routerExtraPublicNics;
}
}