You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2019/05/23 12:47:17 UTC

[cloudstack] 01/01: Merge remote-tracking branch 'origin/4.11' into 4.12

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.12
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit d77e69a2f291a2eba655e821eaf2b163dbbff6b0
Merge: 29918e2 0929866
Author: Rohit Yadav <ro...@shapeblue.com>
AuthorDate: Thu May 23 18:16:45 2019 +0530

    Merge remote-tracking branch 'origin/4.11' into 4.12
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>

 .travis.yml                                        |  46 ++++---
 .../kvm/resource/LibvirtComputingResource.java     |   2 +-
 .../wrapper/LibvirtStartCommandWrapper.java        |  11 +-
 .../com/cloud/server/ConfigurationServerImpl.java  |  29 ++--
 .../bin/setup/{cloud-early-config => bootstrap.sh} | 114 ++++++----------
 .../debian/opt/cloud/bin/setup/cloud-early-config  | 147 ++-------------------
 .../debian/opt/cloud/bin/setup/patchsystemvm.sh    |  63 ---------
 systemvm/debian/opt/cloud/bin/setup/router.sh      |   4 +-
 systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh   |   6 +-
 .../scripts/install_systemvm_packages.sh           |   1 +
 10 files changed, 104 insertions(+), 319 deletions(-)

diff --cc plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 03fa5bf,0000000..2436dc4
mode 100644,000000..100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@@ -1,3850 -1,0 +1,3850 @@@
 +// 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.io.BufferedReader;
 +import java.io.File;
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.StringReader;
 +import java.net.InetAddress;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +import java.nio.file.Paths;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Calendar;
 +import java.util.Collections;
 +import java.util.Comparator;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +import java.util.Set;
 +import java.util.UUID;
 +import java.util.concurrent.ConcurrentHashMap;
 +import java.util.regex.Matcher;
 +import java.util.regex.Pattern;
 +
 +import javax.naming.ConfigurationException;
 +import javax.xml.parsers.DocumentBuilder;
 +import javax.xml.parsers.DocumentBuilderFactory;
 +import javax.xml.parsers.ParserConfigurationException;
 +
 +import com.cloud.resource.RequestWrapper;
 +import org.apache.cloudstack.api.ApiConstants;
 +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 +import org.apache.cloudstack.storage.to.TemplateObjectTO;
 +import org.apache.cloudstack.storage.to.VolumeObjectTO;
 +import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
 +import org.apache.cloudstack.utils.linux.CPUStat;
 +import org.apache.cloudstack.utils.linux.KVMHostInfo;
 +import org.apache.cloudstack.utils.linux.MemStat;
 +import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 +import org.apache.cloudstack.utils.security.KeyStoreUtils;
 +import org.apache.commons.collections.MapUtils;
 +import org.apache.commons.io.FileUtils;
 +import org.apache.commons.lang.ArrayUtils;
 +import org.apache.commons.lang.math.NumberUtils;
 +import org.apache.log4j.Logger;
 +import org.joda.time.Duration;
 +import org.libvirt.Connect;
 +import org.libvirt.Domain;
 +import org.libvirt.DomainBlockStats;
 +import org.libvirt.DomainInfo;
 +import org.libvirt.DomainInfo.DomainState;
 +import org.libvirt.DomainInterfaceStats;
 +import org.libvirt.DomainSnapshot;
 +import org.libvirt.LibvirtException;
 +import org.libvirt.MemoryStatistic;
 +import org.libvirt.NodeInfo;
 +import org.w3c.dom.Document;
 +import org.w3c.dom.Element;
 +import org.w3c.dom.Node;
 +import org.w3c.dom.NodeList;
 +import org.xml.sax.InputSource;
 +import org.xml.sax.SAXException;
 +
 +import com.cloud.agent.api.Answer;
 +import com.cloud.agent.api.Command;
 +import com.cloud.agent.api.HostVmStateReportEntry;
 +import com.cloud.agent.api.PingCommand;
 +import com.cloud.agent.api.PingRoutingCommand;
 +import com.cloud.agent.api.PingRoutingWithNwGroupsCommand;
 +import com.cloud.agent.api.SetupGuestNetworkCommand;
 +import com.cloud.agent.api.StartupCommand;
 +import com.cloud.agent.api.StartupRoutingCommand;
 +import com.cloud.agent.api.StartupStorageCommand;
 +import com.cloud.agent.api.VmDiskStatsEntry;
 +import com.cloud.agent.api.VmNetworkStatsEntry;
 +import com.cloud.agent.api.VmStatsEntry;
 +import com.cloud.agent.api.routing.IpAssocCommand;
 +import com.cloud.agent.api.routing.IpAssocVpcCommand;
 +import com.cloud.agent.api.routing.NetworkElementCommand;
 +import com.cloud.agent.api.routing.SetSourceNatCommand;
 +import com.cloud.agent.api.to.DataStoreTO;
 +import com.cloud.agent.api.to.DataTO;
 +import com.cloud.agent.api.to.DiskTO;
 +import com.cloud.agent.api.to.IpAddressTO;
 +import com.cloud.agent.api.to.NfsTO;
 +import com.cloud.agent.api.to.NicTO;
 +import com.cloud.agent.api.to.VirtualMachineTO;
 +import com.cloud.agent.resource.virtualnetwork.VRScripts;
 +import com.cloud.agent.resource.virtualnetwork.VirtualRouterDeployer;
 +import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
 +import com.cloud.dc.Vlan;
 +import com.cloud.exception.InternalErrorException;
 +import com.cloud.host.Host.Type;
 +import com.cloud.hypervisor.Hypervisor.HypervisorType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ClockDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ConsoleDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuModeDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DevicesDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.DeviceType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.DiscardType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.DiskProtocol;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FeaturesDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FilesystemDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GraphicDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestResourceDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.GuestNetType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
 +import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper;
 +import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
 +import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
 +import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
 +import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
 +import com.cloud.hypervisor.kvm.storage.KVMStorageProcessor;
 +import com.cloud.network.Networks.BroadcastDomainType;
 +import com.cloud.network.Networks.RouterPrivateIpStrategy;
 +import com.cloud.network.Networks.TrafficType;
 +import com.cloud.resource.ServerResource;
 +import com.cloud.resource.ServerResourceBase;
 +import com.cloud.storage.JavaStorageLayer;
 +import com.cloud.storage.Storage;
 +import com.cloud.storage.Storage.StoragePoolType;
 +import com.cloud.storage.StorageLayer;
 +import com.cloud.storage.Volume;
 +import com.cloud.storage.resource.StorageSubsystemCommandHandler;
 +import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase;
 +import com.cloud.utils.ExecutionResult;
 +import com.cloud.utils.NumbersUtil;
 +import com.cloud.utils.Pair;
 +import com.cloud.utils.PropertiesUtil;
 +import com.cloud.utils.StringUtils;
 +import com.cloud.utils.Ternary;
 +import com.cloud.utils.exception.CloudRuntimeException;
 +import com.cloud.utils.net.NetUtils;
 +import com.cloud.utils.script.OutputInterpreter;
 +import com.cloud.utils.script.OutputInterpreter.AllLinesParser;
 +import com.cloud.utils.script.Script;
 +import com.cloud.utils.ssh.SshHelper;
 +import com.cloud.vm.VirtualMachine;
 +import com.cloud.vm.VirtualMachine.PowerState;
 +import com.cloud.vm.VmDetailConstants;
 +import com.google.common.base.Strings;
 +
 +/**
 + * LibvirtComputingResource execute requests on the computing/routing host using
 + * the libvirt API
 + *
 + * @config {@table || Param Name | Description | Values | Default || ||
 + *         hypervisor.type | type of local hypervisor | string | kvm || ||
 + *         hypervisor.uri | local hypervisor to connect to | URI |
 + *         qemu:///system || || domr.arch | instruction set for domr template |
 + *         string | i686 || || private.bridge.name | private bridge where the
 + *         domrs have their private interface | string | vmops0 || ||
 + *         public.bridge.name | public bridge where the domrs have their public
 + *         interface | string | br0 || || private.network.name | name of the
 + *         network where the domrs have their private interface | string |
 + *         vmops-private || || private.ipaddr.start | start of the range of
 + *         private ip addresses for domrs | ip address | 192.168.166.128 || ||
 + *         private.ipaddr.end | end of the range of private ip addresses for
 + *         domrs | ip address | start + 126 || || private.macaddr.start | start
 + *         of the range of private mac addresses for domrs | mac address |
 + *         00:16:3e:77:e2:a0 || || private.macaddr.end | end of the range of
 + *         private mac addresses for domrs | mac address | start + 126 || ||
 + *         pool | the parent of the storage pool hierarchy * }
 + **/
 +public class LibvirtComputingResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer {
 +    private static final Logger s_logger = Logger.getLogger(LibvirtComputingResource.class);
 +
 +    private String _modifyVlanPath;
 +    private String _versionstringpath;
 +    private String _patchScriptPath;
 +    private String _createvmPath;
 +    private String _manageSnapshotPath;
 +    private String _resizeVolumePath;
 +    private String _createTmplPath;
 +    private String _heartBeatPath;
 +    private String _vmActivityCheckPath;
 +    private String _securityGroupPath;
 +    private String _ovsPvlanDhcpHostPath;
 +    private String _ovsPvlanVmPath;
 +    private String _routerProxyPath;
 +    private String _ovsTunnelPath;
 +    private String _host;
 +    private String _dcId;
 +    private String _pod;
 +    private String _clusterId;
 +
 +    private long _hvVersion;
 +    private Duration _timeout;
 +    private static final int NUMMEMSTATS =2;
 +
 +    private KVMHAMonitor _monitor;
 +    public static final String SSHKEYSPATH = "/root/.ssh";
 +    public static final String SSHPRVKEYPATH = SSHKEYSPATH + File.separator + "id_rsa.cloud";
 +    public static final String SSHPUBKEYPATH = SSHKEYSPATH + File.separator + "id_rsa.pub.cloud";
 +
 +    public static final String BASH_SCRIPT_PATH = "/bin/bash";
 +
 +    private String _mountPoint = "/mnt";
 +    private StorageLayer _storage;
 +    private KVMStoragePoolManager _storagePoolMgr;
 +
 +    private VifDriver _defaultVifDriver;
 +    private Map<TrafficType, VifDriver> _trafficTypeVifDrivers;
 +
 +    protected static final String DEFAULT_OVS_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.OvsVifDriver";
 +    protected static final String DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver";
 +
 +    protected HypervisorType _hypervisorType;
 +    protected String _hypervisorURI;
 +    protected long _hypervisorLibvirtVersion;
 +    protected long _hypervisorQemuVersion;
 +    protected String _hypervisorPath;
 +    protected String _hostDistro;
 +    protected String _networkDirectSourceMode;
 +    protected String _networkDirectDevice;
 +    protected String _sysvmISOPath;
 +    protected String _privNwName;
 +    protected String _privBridgeName;
 +    protected String _linkLocalBridgeName;
 +    protected String _publicBridgeName;
 +    protected String _guestBridgeName;
 +    protected String _privateIp;
 +    protected String _pool;
 +    protected String _localGateway;
 +    private boolean _canBridgeFirewall;
 +    protected String _localStoragePath;
 +    protected String _localStorageUUID;
 +    protected boolean _noMemBalloon = false;
 +    protected String _guestCpuMode;
 +    protected String _guestCpuModel;
 +    protected boolean _noKvmClock;
 +    protected String _videoHw;
 +    protected int _videoRam;
 +    protected Pair<Integer,Integer> hostOsVersion;
 +    protected int _migrateSpeed;
 +    protected int _migrateDowntime;
 +    protected int _migratePauseAfter;
 +    protected boolean _diskActivityCheckEnabled;
 +    protected long _diskActivityCheckFileSizeMin = 10485760; // 10MB
 +    protected int _diskActivityCheckTimeoutSeconds = 120; // 120s
 +    protected long _diskActivityInactiveThresholdMilliseconds = 30000; // 30s
 +    protected boolean _rngEnable = false;
 +    protected RngBackendModel _rngBackendModel = RngBackendModel.RANDOM;
 +    protected String _rngPath = "/dev/random";
 +    protected int _rngRatePeriod = 1000;
 +    protected int _rngRateBytes = 2048;
 +    protected File _qemuSocketsPath;
 +    private final String _qemuGuestAgentSocketName = "org.qemu.guest_agent.0";
 +    protected WatchDogAction _watchDogAction = WatchDogAction.NONE;
 +    protected WatchDogModel _watchDogModel = WatchDogModel.I6300ESB;
 +
 +    private final Map <String, String> _pifs = new HashMap<String, String>();
 +    private final Map<String, VmStats> _vmStats = new ConcurrentHashMap<String, VmStats>();
 +
 +    protected static final HashMap<DomainState, PowerState> s_powerStatesTable;
 +    static {
 +        s_powerStatesTable = new HashMap<DomainState, PowerState>();
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_SHUTOFF, PowerState.PowerOff);
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_PAUSED, PowerState.PowerOn);
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_RUNNING, PowerState.PowerOn);
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_BLOCKED, PowerState.PowerOn);
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_NOSTATE, PowerState.PowerUnknown);
 +        s_powerStatesTable.put(DomainState.VIR_DOMAIN_SHUTDOWN, PowerState.PowerOff);
 +    }
 +
 +    private VirtualRoutingResource _virtRouterResource;
 +
 +    private String _pingTestPath;
 +
 +    private String _updateHostPasswdPath;
 +
 +    private long _dom0MinMem;
 +
 +    private long _dom0OvercommitMem;
 +
 +    protected int _cmdsTimeout;
 +    protected int _stopTimeout;
 +    protected CPUStat _cpuStat = new CPUStat();
 +    protected MemStat _memStat = new MemStat(_dom0MinMem, _dom0OvercommitMem);
 +    private final LibvirtUtilitiesHelper libvirtUtilitiesHelper = new LibvirtUtilitiesHelper();
 +
 +    @Override
 +    public ExecutionResult executeInVR(final String routerIp, final String script, final String args) {
 +        return executeInVR(routerIp, script, args, _timeout);
 +    }
 +
 +    @Override
 +    public ExecutionResult executeInVR(final String routerIp, final String script, final String args, final Duration timeout) {
 +        final Script command = new Script(_routerProxyPath, timeout, s_logger);
 +        final AllLinesParser parser = new AllLinesParser();
 +        command.add(script);
 +        command.add(routerIp);
 +        if (args != null) {
 +            command.add(args);
 +        }
 +        String details = command.execute(parser);
 +        if (details == null) {
 +            details = parser.getLines();
 +        }
 +
 +        s_logger.debug("Executing script in VR: " + script);
 +
 +        return new ExecutionResult(command.getExitValue() == 0, details);
 +    }
 +
 +    @Override
 +    public ExecutionResult createFileInVR(final String routerIp, final String path, final String filename, final String content) {
 +        final File permKey = new File("/root/.ssh/id_rsa.cloud");
 +        boolean success = true;
 +        String details = "Creating file in VR, with ip: " + routerIp + ", file: " + filename;
 +        s_logger.debug(details);
 +
 +        try {
 +            SshHelper.scpTo(routerIp, 3922, "root", permKey, null, path, content.getBytes(), filename, null);
 +        } catch (final Exception e) {
 +            s_logger.warn("Fail to create file " + path + filename + " in VR " + routerIp, e);
 +            details = e.getMessage();
 +            success = false;
 +        }
 +        return new ExecutionResult(success, details);
 +    }
 +
 +    @Override
 +    public ExecutionResult prepareCommand(final NetworkElementCommand cmd) {
 +        //Update IP used to access router
 +        cmd.setRouterAccessIp(cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP));
 +        assert cmd.getRouterAccessIp() != null;
 +
 +        if (cmd instanceof IpAssocVpcCommand) {
 +            return prepareNetworkElementCommand((IpAssocVpcCommand)cmd);
 +        } else if (cmd instanceof IpAssocCommand) {
 +            return prepareNetworkElementCommand((IpAssocCommand)cmd);
 +        } else if (cmd instanceof SetupGuestNetworkCommand) {
 +            return prepareNetworkElementCommand((SetupGuestNetworkCommand)cmd);
 +        } else if (cmd instanceof SetSourceNatCommand) {
 +            return prepareNetworkElementCommand((SetSourceNatCommand)cmd);
 +        }
 +        return new ExecutionResult(true, null);
 +    }
 +
 +    @Override
 +    public ExecutionResult cleanupCommand(final NetworkElementCommand cmd) {
 +        if (cmd instanceof IpAssocCommand && !(cmd instanceof IpAssocVpcCommand)) {
 +            return cleanupNetworkElementCommand((IpAssocCommand)cmd);
 +        }
 +        return new ExecutionResult(true, null);
 +    }
 +
 +    public LibvirtUtilitiesHelper getLibvirtUtilitiesHelper() {
 +        return libvirtUtilitiesHelper;
 +    }
 +
 +    public CPUStat getCPUStat() {
 +        return _cpuStat;
 +    }
 +
 +    public MemStat getMemStat() {
 +        return _memStat;
 +    }
 +
 +    public VirtualRoutingResource getVirtRouterResource() {
 +        return _virtRouterResource;
 +    }
 +
 +    public String getPublicBridgeName() {
 +        return _publicBridgeName;
 +    }
 +
 +    public KVMStoragePoolManager getStoragePoolMgr() {
 +        return _storagePoolMgr;
 +    }
 +
 +    public String getPrivateIp() {
 +        return _privateIp;
 +    }
 +
 +    public int getMigrateDowntime() {
 +        return _migrateDowntime;
 +    }
 +
 +    public int getMigratePauseAfter() {
 +        return _migratePauseAfter;
 +    }
 +
 +    public int getMigrateSpeed() {
 +        return _migrateSpeed;
 +    }
 +
 +    public String getPingTestPath() {
 +        return _pingTestPath;
 +    }
 +
 +    public String getUpdateHostPasswdPath() {
 +        return _updateHostPasswdPath;
 +    }
 +
 +    public Duration getTimeout() {
 +        return _timeout;
 +    }
 +
 +    public String getOvsTunnelPath() {
 +        return _ovsTunnelPath;
 +    }
 +
 +    public KVMHAMonitor getMonitor() {
 +        return _monitor;
 +    }
 +
 +    public StorageLayer getStorage() {
 +        return _storage;
 +    }
 +
 +    public String createTmplPath() {
 +        return _createTmplPath;
 +    }
 +
 +    public int getCmdsTimeout() {
 +        return _cmdsTimeout;
 +    }
 +
 +    public String manageSnapshotPath() {
 +        return _manageSnapshotPath;
 +    }
 +
 +    public String getGuestBridgeName() {
 +        return _guestBridgeName;
 +    }
 +
 +    public String getVmActivityCheckPath() {
 +        return _vmActivityCheckPath;
 +    }
 +
 +    public String getOvsPvlanDhcpHostPath() {
 +        return _ovsPvlanDhcpHostPath;
 +    }
 +
 +    public String getOvsPvlanVmPath() {
 +        return _ovsPvlanVmPath;
 +    }
 +
 +    public String getResizeVolumePath() {
 +        return _resizeVolumePath;
 +    }
 +
 +    public StorageSubsystemCommandHandler getStorageHandler() {
 +        return storageHandler;
 +    }
 +
 +    private static final class KeyValueInterpreter extends OutputInterpreter {
 +        private final Map<String, String> map = new HashMap<String, String>();
 +
 +        @Override
 +        public String interpret(final BufferedReader reader) throws IOException {
 +            String line = null;
 +            int numLines = 0;
 +            while ((line = reader.readLine()) != null) {
 +                final String[] toks = line.trim().split("=");
 +                if (toks.length < 2) {
 +                    s_logger.warn("Failed to parse Script output: " + line);
 +                } else {
 +                    map.put(toks[0].trim(), toks[1].trim());
 +                }
 +                numLines++;
 +            }
 +            if (numLines == 0) {
 +                s_logger.warn("KeyValueInterpreter: no output lines?");
 +            }
 +            return null;
 +        }
 +
 +        public Map<String, String> getKeyValues() {
 +            return map;
 +        }
 +    }
 +
 +    @Override
 +    protected String getDefaultScriptsDir() {
 +        return null;
 +    }
 +
 +    protected List<String> _cpuFeatures;
 +
 +    protected enum BridgeType {
 +        NATIVE, OPENVSWITCH
 +    }
 +
 +    protected BridgeType _bridgeType;
 +
 +    protected StorageSubsystemCommandHandler storageHandler;
 +
 +    protected boolean dpdkSupport = false;
 +    protected String dpdkOvsPath;
 +    protected static final String DPDK_NUMA = ApiConstants.EXTRA_CONFIG + "-dpdk-numa";
 +    protected static final String DPDK_HUGE_PAGES = ApiConstants.EXTRA_CONFIG + "-dpdk-hugepages";
 +    protected static final String DPDK_INTERFACE_PREFIX = ApiConstants.EXTRA_CONFIG + "-dpdk-interface-";
 +
 +    private String getEndIpFromStartIp(final String startIp, final int numIps) {
 +        final String[] tokens = startIp.split("[.]");
 +        assert tokens.length == 4;
 +        int lastbyte = Integer.parseInt(tokens[3]);
 +        lastbyte = lastbyte + numIps;
 +        tokens[3] = Integer.toString(lastbyte);
 +        final StringBuilder end = new StringBuilder(15);
 +        end.append(tokens[0]).append(".").append(tokens[1]).append(".").append(tokens[2]).append(".").append(tokens[3]);
 +        return end.toString();
 +    }
 +
 +    private Map<String, Object> getDeveloperProperties() throws ConfigurationException {
 +
 +        final File file = PropertiesUtil.findConfigFile("developer.properties");
 +        if (file == null) {
 +            throw new ConfigurationException("Unable to find developer.properties.");
 +        }
 +
 +        s_logger.info("developer.properties found at " + file.getAbsolutePath());
 +        try {
 +            final Properties properties = PropertiesUtil.loadFromFile(file);
 +
 +            final String startMac = (String)properties.get("private.macaddr.start");
 +            if (startMac == null) {
 +                throw new ConfigurationException("Developers must specify start mac for private ip range");
 +            }
 +
 +            final String startIp = (String)properties.get("private.ipaddr.start");
 +            if (startIp == null) {
 +                throw new ConfigurationException("Developers must specify start ip for private ip range");
 +            }
 +            final Map<String, Object> params = PropertiesUtil.toMap(properties);
 +
 +            String endIp = (String)properties.get("private.ipaddr.end");
 +            if (endIp == null) {
 +                endIp = getEndIpFromStartIp(startIp, 16);
 +                params.put("private.ipaddr.end", endIp);
 +            }
 +            return params;
 +        } catch (final FileNotFoundException ex) {
 +            throw new CloudRuntimeException("Cannot find the file: " + file.getAbsolutePath(), ex);
 +        } catch (final IOException ex) {
 +            throw new CloudRuntimeException("IOException in reading " + file.getAbsolutePath(), ex);
 +        }
 +    }
 +
 +    protected String getDefaultNetworkScriptsDir() {
 +        return "scripts/vm/network/vnet";
 +    }
 +
 +    protected String getDefaultStorageScriptsDir() {
 +        return "scripts/storage/qcow2";
 +    }
 +
 +    protected String getDefaultHypervisorScriptsDir() {
 +        return "scripts/vm/hypervisor";
 +    }
 +
 +    protected String getDefaultKvmScriptsDir() {
 +        return "scripts/vm/hypervisor/kvm";
 +    }
 +
 +    protected String getDefaultDomrScriptsDir() {
 +        return "scripts/network/domr";
 +    }
 +
 +    protected String getNetworkDirectSourceMode() {
 +        return _networkDirectSourceMode;
 +    }
 +
 +    protected String getNetworkDirectDevice() {
 +        return _networkDirectDevice;
 +    }
 +
 +    @Override
 +    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
 +        boolean success = super.configure(name, params);
 +        if (!success) {
 +            return false;
 +        }
 +
 +        _storage = new JavaStorageLayer();
 +        _storage.configure("StorageLayer", params);
 +
 +        String domrScriptsDir = (String)params.get("domr.scripts.dir");
 +        if (domrScriptsDir == null) {
 +            domrScriptsDir = getDefaultDomrScriptsDir();
 +        }
 +
 +        String hypervisorScriptsDir = (String)params.get("hypervisor.scripts.dir");
 +        if (hypervisorScriptsDir == null) {
 +            hypervisorScriptsDir = getDefaultHypervisorScriptsDir();
 +        }
 +
 +        String kvmScriptsDir = (String)params.get("kvm.scripts.dir");
 +        if (kvmScriptsDir == null) {
 +            kvmScriptsDir = getDefaultKvmScriptsDir();
 +        }
 +
 +        String networkScriptsDir = (String)params.get("network.scripts.dir");
 +        if (networkScriptsDir == null) {
 +            networkScriptsDir = getDefaultNetworkScriptsDir();
 +        }
 +
 +        String storageScriptsDir = (String)params.get("storage.scripts.dir");
 +        if (storageScriptsDir == null) {
 +            storageScriptsDir = getDefaultStorageScriptsDir();
 +        }
 +
 +        final String bridgeType = (String)params.get("network.bridge.type");
 +        if (bridgeType == null) {
 +            _bridgeType = BridgeType.NATIVE;
 +        } else {
 +            _bridgeType = BridgeType.valueOf(bridgeType.toUpperCase());
 +        }
 +
 +        String dpdk = (String) params.get("openvswitch.dpdk.enabled");
 +        if (_bridgeType == BridgeType.OPENVSWITCH && Boolean.parseBoolean(dpdk)) {
 +            dpdkSupport = true;
 +            dpdkOvsPath = (String) params.get("openvswitch.dpdk.ovs.path");
 +            if (dpdkOvsPath != null && !dpdkOvsPath.endsWith("/")) {
 +                dpdkOvsPath += "/";
 +            }
 +        }
 +
 +        params.put("domr.scripts.dir", domrScriptsDir);
 +
 +        _virtRouterResource = new VirtualRoutingResource(this);
 +        success = _virtRouterResource.configure(name, params);
 +
 +        if (!success) {
 +            return false;
 +        }
 +
 +        _host = (String)params.get("host");
 +        if (_host == null) {
 +            _host = "localhost";
 +        }
 +
 +        _dcId = (String)params.get("zone");
 +        if (_dcId == null) {
 +            _dcId = "default";
 +        }
 +
 +        _pod = (String)params.get("pod");
 +        if (_pod == null) {
 +            _pod = "default";
 +        }
 +
 +        _clusterId = (String)params.get("cluster");
 +
 +        _updateHostPasswdPath = Script.findScript(hypervisorScriptsDir, VRScripts.UPDATE_HOST_PASSWD);
 +        if (_updateHostPasswdPath == null) {
 +            throw new ConfigurationException("Unable to find update_host_passwd.sh");
 +        }
 +
 +        _modifyVlanPath = Script.findScript(networkScriptsDir, "modifyvlan.sh");
 +        if (_modifyVlanPath == null) {
 +            throw new ConfigurationException("Unable to find modifyvlan.sh");
 +        }
 +
 +        _versionstringpath = Script.findScript(kvmScriptsDir, "versions.sh");
 +        if (_versionstringpath == null) {
 +            throw new ConfigurationException("Unable to find versions.sh");
 +        }
 +
 +        _patchScriptPath = Script.findScript(kvmScriptsDir, "patch.sh");
 +        if (_patchScriptPath == null) {
 +            throw new ConfigurationException("Unable to find patch.sh");
 +        }
 +
 +        _heartBeatPath = Script.findScript(kvmScriptsDir, "kvmheartbeat.sh");
 +        if (_heartBeatPath == null) {
 +            throw new ConfigurationException("Unable to find kvmheartbeat.sh");
 +        }
 +
 +        _createvmPath = Script.findScript(storageScriptsDir, "createvm.sh");
 +        if (_createvmPath == null) {
 +            throw new ConfigurationException("Unable to find the createvm.sh");
 +        }
 +
 +        _manageSnapshotPath = Script.findScript(storageScriptsDir, "managesnapshot.sh");
 +        if (_manageSnapshotPath == null) {
 +            throw new ConfigurationException("Unable to find the managesnapshot.sh");
 +        }
 +
 +        _resizeVolumePath = Script.findScript(storageScriptsDir, "resizevolume.sh");
 +        if (_resizeVolumePath == null) {
 +            throw new ConfigurationException("Unable to find the resizevolume.sh");
 +        }
 +
 +        _vmActivityCheckPath = Script.findScript(kvmScriptsDir, "kvmvmactivity.sh");
 +        if (_vmActivityCheckPath == null) {
 +            throw new ConfigurationException("Unable to find kvmvmactivity.sh");
 +        }
 +
 +        _createTmplPath = Script.findScript(storageScriptsDir, "createtmplt.sh");
 +        if (_createTmplPath == null) {
 +            throw new ConfigurationException("Unable to find the createtmplt.sh");
 +        }
 +
 +        _securityGroupPath = Script.findScript(networkScriptsDir, "security_group.py");
 +        if (_securityGroupPath == null) {
 +            throw new ConfigurationException("Unable to find the security_group.py");
 +        }
 +
 +        _ovsTunnelPath = Script.findScript(networkScriptsDir, "ovstunnel.py");
 +        if (_ovsTunnelPath == null) {
 +            throw new ConfigurationException("Unable to find the ovstunnel.py");
 +        }
 +
 +        _routerProxyPath = Script.findScript("scripts/network/domr/", "router_proxy.sh");
 +        if (_routerProxyPath == null) {
 +            throw new ConfigurationException("Unable to find the router_proxy.sh");
 +        }
 +
 +        _ovsPvlanDhcpHostPath = Script.findScript(networkScriptsDir, "ovs-pvlan-dhcp-host.sh");
 +        if (_ovsPvlanDhcpHostPath == null) {
 +            throw new ConfigurationException("Unable to find the ovs-pvlan-dhcp-host.sh");
 +        }
 +
 +        _ovsPvlanVmPath = Script.findScript(networkScriptsDir, "ovs-pvlan-vm.sh");
 +        if (_ovsPvlanVmPath == null) {
 +            throw new ConfigurationException("Unable to find the ovs-pvlan-vm.sh");
 +        }
 +
 +        String value = (String)params.get("developer");
 +        final boolean isDeveloper = Boolean.parseBoolean(value);
 +
 +        if (isDeveloper) {
 +            params.putAll(getDeveloperProperties());
 +        }
 +
 +        _pool = (String)params.get("pool");
 +        if (_pool == null) {
 +            _pool = "/root";
 +        }
 +
 +        final String instance = (String)params.get("instance");
 +
 +        _hypervisorType = HypervisorType.getType((String)params.get("hypervisor.type"));
 +        if (_hypervisorType == HypervisorType.None) {
 +            _hypervisorType = HypervisorType.KVM;
 +        }
 +
 +        _hypervisorURI = (String)params.get("hypervisor.uri");
 +        if (_hypervisorURI == null) {
 +            _hypervisorURI = LibvirtConnection.getHypervisorURI(_hypervisorType.toString());
 +        }
 +
 +        _networkDirectSourceMode = (String)params.get("network.direct.source.mode");
 +        _networkDirectDevice = (String)params.get("network.direct.device");
 +
 +        String startMac = (String)params.get("private.macaddr.start");
 +        if (startMac == null) {
 +            startMac = "00:16:3e:77:e2:a0";
 +        }
 +
 +        String startIp = (String)params.get("private.ipaddr.start");
 +        if (startIp == null) {
 +            startIp = "192.168.166.128";
 +        }
 +
 +        _pingTestPath = Script.findScript(kvmScriptsDir, "pingtest.sh");
 +        if (_pingTestPath == null) {
 +            throw new ConfigurationException("Unable to find the pingtest.sh");
 +        }
 +
 +        _linkLocalBridgeName = (String)params.get("private.bridge.name");
 +        if (_linkLocalBridgeName == null) {
 +            if (isDeveloper) {
 +                _linkLocalBridgeName = "cloud-" + instance + "-0";
 +            } else {
 +                _linkLocalBridgeName = "cloud0";
 +            }
 +        }
 +
 +        _publicBridgeName = (String)params.get("public.network.device");
 +        if (_publicBridgeName == null) {
 +            _publicBridgeName = "cloudbr0";
 +        }
 +
 +        _privBridgeName = (String)params.get("private.network.device");
 +        if (_privBridgeName == null) {
 +            _privBridgeName = "cloudbr1";
 +        }
 +
 +        _guestBridgeName = (String)params.get("guest.network.device");
 +        if (_guestBridgeName == null) {
 +            _guestBridgeName = _privBridgeName;
 +        }
 +
 +        _privNwName = (String)params.get("private.network.name");
 +        if (_privNwName == null) {
 +            if (isDeveloper) {
 +                _privNwName = "cloud-" + instance + "-private";
 +            } else {
 +                _privNwName = "cloud-private";
 +            }
 +        }
 +
 +        _localStoragePath = (String)params.get("local.storage.path");
 +        if (_localStoragePath == null) {
 +            _localStoragePath = "/var/lib/libvirt/images/";
 +        }
 +
 +        /* Directory to use for Qemu sockets like for the Qemu Guest Agent */
 +        _qemuSocketsPath = new File("/var/lib/libvirt/qemu");
 +        String _qemuSocketsPathVar = (String)params.get("qemu.sockets.path");
 +        if (_qemuSocketsPathVar != null && StringUtils.isNotBlank(_qemuSocketsPathVar)) {
 +            _qemuSocketsPath = new File(_qemuSocketsPathVar);
 +        }
 +
 +        final File storagePath = new File(_localStoragePath);
 +        _localStoragePath = storagePath.getAbsolutePath();
 +
 +        _localStorageUUID = (String)params.get("local.storage.uuid");
 +        if (_localStorageUUID == null) {
 +            _localStorageUUID = UUID.randomUUID().toString();
 +        }
 +
 +        value = (String)params.get("scripts.timeout");
 +        _timeout = Duration.standardSeconds(NumbersUtil.parseInt(value, 30 * 60));
 +
 +        value = (String)params.get("stop.script.timeout");
 +        _stopTimeout = NumbersUtil.parseInt(value, 120) * 1000;
 +
 +        value = (String)params.get("cmds.timeout");
 +        _cmdsTimeout = NumbersUtil.parseInt(value, 7200) * 1000;
 +
 +        value = (String) params.get("vm.memballoon.disable");
 +        if (Boolean.parseBoolean(value)) {
 +            _noMemBalloon = true;
 +        }
 +
 +        _videoHw = (String) params.get("vm.video.hardware");
 +        value = (String) params.get("vm.video.ram");
 +        _videoRam = NumbersUtil.parseInt(value, 0);
 +
 +        value = (String)params.get("host.reserved.mem.mb");
 +        // Reserve 1GB unless admin overrides
 +        _dom0MinMem = NumbersUtil.parseInt(value, 1024) * 1024* 1024L;
 +
 +        value = (String)params.get("host.overcommit.mem.mb");
 +        // Support overcommit memory for host if host uses ZSWAP, KSM and other memory
 +        // compressing technologies
 +        _dom0OvercommitMem = NumbersUtil.parseInt(value, 0) * 1024 * 1024L;
 +
 +        value = (String) params.get("kvmclock.disable");
 +        if (Boolean.parseBoolean(value)) {
 +            _noKvmClock = true;
 +        }
 +
 +        value = (String) params.get("vm.rng.enable");
 +        if (Boolean.parseBoolean(value)) {
 +            _rngEnable = true;
 +
 +            value = (String) params.get("vm.rng.model");
 +            if (!Strings.isNullOrEmpty(value)) {
 +                _rngBackendModel = RngBackendModel.valueOf(value.toUpperCase());
 +            }
 +
 +            value = (String) params.get("vm.rng.path");
 +            if (!Strings.isNullOrEmpty(value)) {
 +                _rngPath = value;
 +            }
 +
 +            value = (String) params.get("vm.rng.rate.bytes");
 +            _rngRateBytes = NumbersUtil.parseInt(value, new Integer(_rngRateBytes));
 +
 +            value = (String) params.get("vm.rng.rate.period");
 +            _rngRatePeriod = NumbersUtil.parseInt(value, new Integer(_rngRatePeriod));
 +        }
 +
 +        value = (String) params.get("vm.watchdog.model");
 +        if (!Strings.isNullOrEmpty(value)) {
 +            _watchDogModel = WatchDogModel.valueOf(value.toUpperCase());
 +        }
 +
 +        value = (String) params.get("vm.watchdog.action");
 +        if (!Strings.isNullOrEmpty(value)) {
 +            _watchDogAction = WatchDogAction.valueOf(value.toUpperCase());
 +        }
 +
 +        LibvirtConnection.initialize(_hypervisorURI);
 +        Connect conn = null;
 +        try {
 +            conn = LibvirtConnection.getConnection();
 +
 +            if (_bridgeType == BridgeType.OPENVSWITCH) {
 +                if (conn.getLibVirVersion() < 10 * 1000 + 0) {
 +                    throw new ConfigurationException("Libvirt version 0.10.0 required for openvswitch support, but version " + conn.getLibVirVersion() + " detected");
 +                }
 +            }
 +        } catch (final LibvirtException e) {
 +            throw new CloudRuntimeException(e.getMessage());
 +        }
 +
 +        if (HypervisorType.KVM == _hypervisorType) {
 +            /* Does node support HVM guest? If not, exit */
 +            if (!IsHVMEnabled(conn)) {
 +                throw new ConfigurationException("NO HVM support on this machine, please make sure: " + "1. VT/SVM is supported by your CPU, or is enabled in BIOS. "
 +                        + "2. kvm modules are loaded (kvm, kvm_amd|kvm_intel)");
 +            }
 +        }
 +
 +        _hypervisorPath = getHypervisorPath(conn);
 +        try {
 +            _hvVersion = conn.getVersion();
 +            _hvVersion = _hvVersion % 1000000 / 1000;
 +            _hypervisorLibvirtVersion = conn.getLibVirVersion();
 +            _hypervisorQemuVersion = conn.getVersion();
 +        } catch (final LibvirtException e) {
 +            s_logger.trace("Ignoring libvirt error.", e);
 +        }
 +
 +        _guestCpuMode = (String)params.get("guest.cpu.mode");
 +        if (_guestCpuMode != null) {
 +            _guestCpuModel = (String)params.get("guest.cpu.model");
 +
 +            if (_hypervisorLibvirtVersion < 9 * 1000 + 10) {
 +                s_logger.warn("Libvirt version 0.9.10 required for guest cpu mode, but version " + prettyVersion(_hypervisorLibvirtVersion) +
 +                        " detected, so it will be disabled");
 +                _guestCpuMode = "";
 +                _guestCpuModel = "";
 +            }
 +            params.put("guest.cpu.mode", _guestCpuMode);
 +            params.put("guest.cpu.model", _guestCpuModel);
 +        }
 +
 +        final String cpuFeatures = (String)params.get("guest.cpu.features");
 +        if (cpuFeatures != null) {
 +            _cpuFeatures = new ArrayList<String>();
 +            for (final String feature: cpuFeatures.split(" ")) {
 +                if (!feature.isEmpty()) {
 +                    _cpuFeatures.add(feature);
 +                }
 +            }
 +        }
 +
 +        final String[] info = NetUtils.getNetworkParams(_privateNic);
 +
 +        _monitor = new KVMHAMonitor(null, info[0], _heartBeatPath);
 +        final Thread ha = new Thread(_monitor);
 +        ha.start();
 +
 +        _storagePoolMgr = new KVMStoragePoolManager(_storage, _monitor);
 +
 +        _sysvmISOPath = (String)params.get("systemvm.iso.path");
 +        if (_sysvmISOPath == null) {
 +            final String[] isoPaths = {"/usr/share/cloudstack-common/vms/systemvm.iso"};
 +            for (final String isoPath : isoPaths) {
 +                if (_storage.exists(isoPath)) {
 +                    _sysvmISOPath = isoPath;
 +                    break;
 +                }
 +            }
 +            if (_sysvmISOPath == null) {
 +                s_logger.debug("Can't find system vm ISO");
 +            }
 +        }
 +
 +        final Map<String, String> bridges = new HashMap<String, String>();
 +
 +        params.put("libvirt.host.bridges", bridges);
 +        params.put("libvirt.host.pifs", _pifs);
 +
 +        params.put("libvirt.computing.resource", this);
 +        params.put("libvirtVersion", _hypervisorLibvirtVersion);
 +
 +
 +        configureVifDrivers(params);
 +
 +        /*
 +        switch (_bridgeType) {
 +        case OPENVSWITCH:
 +            getOvsPifs();
 +            break;
 +        case NATIVE:
 +        default:
 +            getPifs();
 +            break;
 +        }
 +        */
 +
 +        if (_pifs.get("private") == null) {
 +            s_logger.error("Failed to get private nic name");
 +            throw new ConfigurationException("Failed to get private nic name");
 +        }
 +
 +        if (_pifs.get("public") == null) {
 +            s_logger.error("Failed to get public nic name");
 +            throw new ConfigurationException("Failed to get public nic name");
 +        }
 +        s_logger.debug("Found pif: " + _pifs.get("private") + " on " + _privBridgeName + ", pif: " + _pifs.get("public") + " on " + _publicBridgeName);
 +
 +        _canBridgeFirewall = canBridgeFirewall(_pifs.get("public"));
 +
 +        _localGateway = Script.runSimpleBashScript("ip route show default 0.0.0.0/0|head -1|awk '{print $3}'");
 +        if (_localGateway == null) {
 +            s_logger.warn("No default IPv4 gateway found");
 +        }
 +
 +        _mountPoint = (String)params.get("mount.path");
 +        if (_mountPoint == null) {
 +            _mountPoint = "/mnt";
 +        }
 +
 +        value = (String) params.get("vm.migrate.downtime");
 +        _migrateDowntime = NumbersUtil.parseInt(value, -1);
 +
 +        value = (String) params.get("vm.migrate.pauseafter");
 +        _migratePauseAfter = NumbersUtil.parseInt(value, -1);
 +
 +        value = (String)params.get("vm.migrate.speed");
 +        _migrateSpeed = NumbersUtil.parseInt(value, -1);
 +        if (_migrateSpeed == -1) {
 +            //get guest network device speed
 +            _migrateSpeed = 0;
 +            final String speed = Script.runSimpleBashScript("ethtool " + _pifs.get("public") + " |grep Speed | cut -d \\  -f 2");
 +            if (speed != null) {
 +                final String[] tokens = speed.split("M");
 +                if (tokens.length == 2) {
 +                    try {
 +                        _migrateSpeed = Integer.parseInt(tokens[0]);
 +                    } catch (final NumberFormatException e) {
 +                        s_logger.trace("Ignoring migrateSpeed extraction error.", e);
 +                    }
 +                    s_logger.debug("device " + _pifs.get("public") + " has speed: " + String.valueOf(_migrateSpeed));
 +                }
 +            }
 +            params.put("vm.migrate.speed", String.valueOf(_migrateSpeed));
 +        }
 +
 +        bridges.put("linklocal", _linkLocalBridgeName);
 +        bridges.put("public", _publicBridgeName);
 +        bridges.put("private", _privBridgeName);
 +        bridges.put("guest", _guestBridgeName);
 +
 +        getVifDriver(TrafficType.Control).createControlNetwork(_linkLocalBridgeName);
 +
 +        configureDiskActivityChecks(params);
 +
 +        final KVMStorageProcessor storageProcessor = new KVMStorageProcessor(_storagePoolMgr, this);
 +        storageProcessor.configure(name, params);
 +        storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
 +
 +        return true;
 +    }
 +
 +    protected void configureDiskActivityChecks(final Map<String, Object> params) {
 +        _diskActivityCheckEnabled = Boolean.parseBoolean((String)params.get("vm.diskactivity.checkenabled"));
 +        if (_diskActivityCheckEnabled) {
 +            final int timeout = NumbersUtil.parseInt((String)params.get("vm.diskactivity.checktimeout_s"), 0);
 +            if (timeout > 0) {
 +                _diskActivityCheckTimeoutSeconds = timeout;
 +            }
 +            final long inactiveTime = NumbersUtil.parseLong((String)params.get("vm.diskactivity.inactivetime_ms"), 0L);
 +            if (inactiveTime > 0) {
 +                _diskActivityInactiveThresholdMilliseconds = inactiveTime;
 +            }
 +        }
 +    }
 +
 +    protected void configureVifDrivers(final Map<String, Object> params) throws ConfigurationException {
 +        final String LIBVIRT_VIF_DRIVER = "libvirt.vif.driver";
 +
 +        _trafficTypeVifDrivers = new HashMap<TrafficType, VifDriver>();
 +
 +        // Load the default vif driver
 +        String defaultVifDriverName = (String)params.get(LIBVIRT_VIF_DRIVER);
 +        if (defaultVifDriverName == null) {
 +            if (_bridgeType == BridgeType.OPENVSWITCH) {
 +                s_logger.info("No libvirt.vif.driver specified. Defaults to OvsVifDriver.");
 +                defaultVifDriverName = DEFAULT_OVS_VIF_DRIVER_CLASS_NAME;
 +            } else {
 +                s_logger.info("No libvirt.vif.driver specified. Defaults to BridgeVifDriver.");
 +                defaultVifDriverName = DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME;
 +            }
 +        }
 +        _defaultVifDriver = getVifDriverClass(defaultVifDriverName, params);
 +
 +        // Load any per-traffic-type vif drivers
 +        for (final Map.Entry<String, Object> entry : params.entrySet()) {
 +            final String k = entry.getKey();
 +            final String vifDriverPrefix = LIBVIRT_VIF_DRIVER + ".";
 +
 +            if (k.startsWith(vifDriverPrefix)) {
 +                // Get trafficType
 +                final String trafficTypeSuffix = k.substring(vifDriverPrefix.length());
 +
 +                // Does this suffix match a real traffic type?
 +                final TrafficType trafficType = TrafficType.getTrafficType(trafficTypeSuffix);
 +                if (!trafficType.equals(TrafficType.None)) {
 +                    // Get vif driver class name
 +                    final String vifDriverClassName = (String)entry.getValue();
 +                    // if value is null, ignore
 +                    if (vifDriverClassName != null) {
 +                        // add traffic type to vif driver mapping to Map
 +                        _trafficTypeVifDrivers.put(trafficType, getVifDriverClass(vifDriverClassName, params));
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    protected VifDriver getVifDriverClass(final String vifDriverClassName, final Map<String, Object> params) throws ConfigurationException {
 +        VifDriver vifDriver;
 +
 +        try {
 +            final Class<?> clazz = Class.forName(vifDriverClassName);
 +            vifDriver = (VifDriver)clazz.newInstance();
 +            vifDriver.configure(params);
 +        } catch (final ClassNotFoundException e) {
 +            throw new ConfigurationException("Unable to find class for libvirt.vif.driver " + e);
 +        } catch (final InstantiationException e) {
 +            throw new ConfigurationException("Unable to instantiate class for libvirt.vif.driver " + e);
 +        } catch (final IllegalAccessException e) {
 +            throw new ConfigurationException("Unable to instantiate class for libvirt.vif.driver " + e);
 +        }
 +        return vifDriver;
 +    }
 +
 +    public VifDriver getVifDriver(final TrafficType trafficType) {
 +        VifDriver vifDriver = _trafficTypeVifDrivers.get(trafficType);
 +
 +        if (vifDriver == null) {
 +            vifDriver = _defaultVifDriver;
 +        }
 +
 +        return vifDriver;
 +    }
 +
 +    public VifDriver getVifDriver(final TrafficType trafficType, final String bridgeName) {
 +        VifDriver vifDriver = null;
 +
 +        for (VifDriver driver : getAllVifDrivers()) {
 +            if (driver.isExistingBridge(bridgeName)) {
 +                vifDriver = driver;
 +                break;
 +            }
 +        }
 +
 +        if (vifDriver == null) {
 +            vifDriver = getVifDriver(trafficType);
 +        }
 +
 +        return vifDriver;
 +    }
 +
 +    public List<VifDriver> getAllVifDrivers() {
 +        final Set<VifDriver> vifDrivers = new HashSet<VifDriver>();
 +
 +        vifDrivers.add(_defaultVifDriver);
 +        vifDrivers.addAll(_trafficTypeVifDrivers.values());
 +
 +        final ArrayList<VifDriver> vifDriverList = new ArrayList<VifDriver>(vifDrivers);
 +
 +        return vifDriverList;
 +    }
 +
 +    private void getPifs() {
 +        final File dir = new File("/sys/devices/virtual/net");
 +        final File[] netdevs = dir.listFiles();
 +        final List<String> bridges = new ArrayList<String>();
 +        for (int i = 0; i < netdevs.length; i++) {
 +            final File isbridge = new File(netdevs[i].getAbsolutePath() + "/bridge");
 +            final String netdevName = netdevs[i].getName();
 +            s_logger.debug("looking in file " + netdevs[i].getAbsolutePath() + "/bridge");
 +            if (isbridge.exists()) {
 +                s_logger.debug("Found bridge " + netdevName);
 +                bridges.add(netdevName);
 +            }
 +        }
 +
 +        for (final String bridge : bridges) {
 +            s_logger.debug("looking for pif for bridge " + bridge);
 +            final String pif = getPif(bridge);
 +            if (isPublicBridge(bridge)) {
 +                _pifs.put("public", pif);
 +            }
 +            if (isGuestBridge(bridge)) {
 +                _pifs.put("private", pif);
 +            }
 +            _pifs.put(bridge, pif);
 +        }
 +
 +        // guest(private) creates bridges on a pif, if private bridge not found try pif direct
 +        // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label
 +        if (_pifs.get("private") == null) {
 +            s_logger.debug("guest(private) traffic label '" + _guestBridgeName + "' not found as bridge, looking for physical interface");
 +            final File dev = new File("/sys/class/net/" + _guestBridgeName);
 +            if (dev.exists()) {
 +                s_logger.debug("guest(private) traffic label '" + _guestBridgeName + "' found as a physical device");
 +                _pifs.put("private", _guestBridgeName);
 +            }
 +        }
 +
 +        // public creates bridges on a pif, if private bridge not found try pif direct
 +        // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label
 +        if (_pifs.get("public") == null) {
 +            s_logger.debug("public traffic label '" + _publicBridgeName+ "' not found as bridge, looking for physical interface");
 +            final File dev = new File("/sys/class/net/" + _publicBridgeName);
 +            if (dev.exists()) {
 +                s_logger.debug("public traffic label '" + _publicBridgeName + "' found as a physical device");
 +                _pifs.put("public", _publicBridgeName);
 +            }
 +        }
 +
 +        s_logger.debug("done looking for pifs, no more bridges");
 +    }
 +
 +    boolean isGuestBridge(String bridge) {
 +        return _guestBridgeName != null && bridge.equals(_guestBridgeName);
 +    }
 +
 +    private void getOvsPifs() {
 +        final String cmdout = Script.runSimpleBashScript("ovs-vsctl list-br | sed '{:q;N;s/\\n/%/g;t q}'");
 +        s_logger.debug("cmdout was " + cmdout);
 +        final List<String> bridges = Arrays.asList(cmdout.split("%"));
 +        for (final String bridge : bridges) {
 +            s_logger.debug("looking for pif for bridge " + bridge);
 +            // String pif = getOvsPif(bridge);
 +            // Not really interested in the pif name at this point for ovs
 +            // bridges
 +            final String pif = bridge;
 +            if (isPublicBridge(bridge)) {
 +                _pifs.put("public", pif);
 +            }
 +            if (isGuestBridge(bridge)) {
 +                _pifs.put("private", pif);
 +            }
 +            _pifs.put(bridge, pif);
 +        }
 +        s_logger.debug("done looking for pifs, no more bridges");
 +    }
 +
 +    public boolean isPublicBridge(String bridge) {
 +        return _publicBridgeName != null && bridge.equals(_publicBridgeName);
 +    }
 +
 +    private String getPif(final String bridge) {
 +        String pif = matchPifFileInDirectory(bridge);
 +        final File vlanfile = new File("/proc/net/vlan/" + pif);
 +
 +        if (vlanfile.isFile()) {
 +            pif = Script.runSimpleBashScript("grep ^Device\\: /proc/net/vlan/" + pif + " | awk {'print $2'}");
 +        }
 +
 +        return pif;
 +    }
 +
 +    private String matchPifFileInDirectory(final String bridgeName) {
 +        final File brif = new File("/sys/devices/virtual/net/" + bridgeName + "/brif");
 +
 +        if (!brif.isDirectory()) {
 +            final File pif = new File("/sys/class/net/" + bridgeName);
 +            if (pif.isDirectory()) {
 +                // if bridgeName already refers to a pif, return it as-is
 +                return bridgeName;
 +            }
 +            s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", does " + brif.getAbsolutePath() + "exist?");
 +            return "";
 +        }
 +
 +        final File[] interfaces = brif.listFiles();
 +
 +        for (int i = 0; i < interfaces.length; i++) {
 +            final String fname = interfaces[i].getName();
 +            s_logger.debug("matchPifFileInDirectory: file name '" + fname + "'");
 +            if (isInterface(fname)) {
 +                return fname;
 +            }
 +        }
 +
 +        s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", did not find an eth*, bond*, team*, vlan*, em*, p*p*, ens*, eno*, enp*, or enx* in " + brif.getAbsolutePath());
 +        return "";
 +    }
 +
 +    static String [] ifNamePatterns = {
 +            "^eth",
 +            "^bond",
 +            "^vlan",
 +            "^vx",
 +            "^em",
 +            "^ens",
 +            "^eno",
 +            "^enp",
 +            "^team",
 +            "^enx",
 +            "^dummy",
 +            "^lo",
 +            "^p\\d+p\\d+"
 +    };
 +
 +    /**
 +     * @param fname
 +     * @return
 +     */
 +    protected static boolean isInterface(final String fname) {
 +        StringBuffer commonPattern = new StringBuffer();
 +        for (final String ifNamePattern : ifNamePatterns) {
 +            commonPattern.append("|(").append(ifNamePattern).append(".*)");
 +        }
 +        if(fname.matches(commonPattern.toString())) {
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    public boolean checkNetwork(final TrafficType trafficType, final String networkName) {
 +        if (networkName == null) {
 +            return true;
 +        }
 +
 +        if (getVifDriver(trafficType, networkName) instanceof OvsVifDriver) {
 +            return checkOvsNetwork(networkName);
 +        } else {
 +            return checkBridgeNetwork(networkName);
 +        }
 +    }
 +
 +    private boolean checkBridgeNetwork(final String networkName) {
 +        if (networkName == null) {
 +            return true;
 +        }
 +
 +        final String name = matchPifFileInDirectory(networkName);
 +
 +        if (name == null || name.isEmpty()) {
 +            return false;
 +        } else {
 +            return true;
 +        }
 +    }
 +
 +    private boolean checkOvsNetwork(final String networkName) {
 +        s_logger.debug("Checking if network " + networkName + " exists as openvswitch bridge");
 +        if (networkName == null) {
 +            return true;
 +        }
 +
 +        final Script command = new Script("/bin/sh", _timeout);
 +        command.add("-c");
 +        command.add("ovs-vsctl br-exists " + networkName);
 +        return "0".equals(command.execute(null));
 +    }
 +
 +    public boolean passCmdLine(final String vmName, final String cmdLine) throws InternalErrorException {
-         final Script command = new Script(_patchScriptPath, 30 * 1000, s_logger);
++        final Script command = new Script(_patchScriptPath, 300 * 1000, s_logger);
 +        String result;
 +        command.add("-n", vmName);
 +        command.add("-c", cmdLine);
 +        result = command.execute();
 +        if (result != null) {
 +            s_logger.error("Passing cmdline failed:" + result);
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    boolean isDirectAttachedNetwork(final String type) {
 +        if ("untagged".equalsIgnoreCase(type)) {
 +            return true;
 +        } else {
 +            try {
 +                Long.valueOf(type);
 +            } catch (final NumberFormatException e) {
 +                return true;
 +            }
 +            return false;
 +        }
 +    }
 +
 +    public String startVM(final Connect conn, final String vmName, final String domainXML) throws LibvirtException, InternalErrorException {
 +        try {
 +            /*
 +                We create a transient domain here. When this method gets
 +                called we receive a full XML specification of the guest,
 +                so no need to define it persistent.
 +
 +                This also makes sure we never have any old "garbage" defined
 +                in libvirt which might haunt us.
 +             */
 +
 +            // check for existing inactive vm definition and remove it
 +            // this can sometimes happen during crashes, etc
 +            Domain dm = null;
 +            try {
 +                dm = conn.domainLookupByName(vmName);
 +                if (dm != null && dm.isPersistent() == 1) {
 +                    // this is safe because it doesn't stop running VMs
 +                    dm.undefine();
 +                }
 +            } catch (final LibvirtException e) {
 +                // this is what we want, no domain found
 +            } finally {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            }
 +
 +            conn.domainCreateXML(domainXML, 0);
 +        } catch (final LibvirtException e) {
 +            throw e;
 +        }
 +        return null;
 +    }
 +
 +    @Override
 +    public boolean stop() {
 +        try {
 +            final Connect conn = LibvirtConnection.getConnection();
 +            conn.close();
 +        } catch (final LibvirtException e) {
 +            s_logger.trace("Ignoring libvirt error.", e);
 +        }
 +
 +        return true;
 +    }
 +
 +    /**
 +     * This finds a command wrapper to handle the command and executes it.
 +     * If no wrapper is found an {@see UnsupportedAnswer} is sent back.
 +     * Any other exceptions are to be caught and wrapped in an generic {@see Answer}, marked as failed.
 +     *
 +     * @param cmd the instance of a {@see Command} to execute.
 +     * @return the for the {@see Command} appropriate {@see Answer} or {@see UnsupportedAnswer}
 +     */
 +    @Override
 +    public Answer executeRequest(final Command cmd) {
 +
 +        final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
 +        try {
 +            return wrapper.execute(cmd, this);
 +        } catch (final RequestWrapper.CommandNotSupported cmde) {
 +            return Answer.createUnsupportedCommandAnswer(cmd);
 +        }
 +    }
 +
 +    public synchronized boolean destroyTunnelNetwork(final String bridge) {
 +        findOrCreateTunnelNetwork(bridge);
 +
 +        final Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
 +        cmd.add("destroy_ovs_bridge");
 +        cmd.add("--bridge", bridge);
 +
 +        final String result = cmd.execute();
 +
 +        if (result != null) {
 +            s_logger.debug("OVS Bridge could not be destroyed due to error ==> " + result);
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public synchronized boolean findOrCreateTunnelNetwork(final String nwName) {
 +        try {
 +            if (checkNetwork(TrafficType.Guest, nwName)) {
 +                return true;
 +            }
 +            // if not found, create a new one
 +            final Map<String, String> otherConfig = new HashMap<String, String>();
 +            otherConfig.put("ovs-host-setup", "");
 +            Script.runSimpleBashScript("ovs-vsctl -- --may-exist add-br "
 +                    + nwName + " -- set bridge " + nwName
 +                    + " other_config:ovs-host-setup='-1'");
 +            s_logger.debug("### KVM network for tunnels created:" + nwName);
 +        } catch (final Exception e) {
 +            s_logger.warn("createTunnelNetwork failed", e);
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public synchronized boolean configureTunnelNetwork(final long networkId,
 +                                                       final long hostId, final String nwName) {
 +        try {
 +            final boolean findResult = findOrCreateTunnelNetwork(nwName);
 +            if (!findResult) {
 +                s_logger.warn("LibvirtComputingResource.findOrCreateTunnelNetwork() failed! Cannot proceed creating the tunnel.");
 +                return false;
 +            }
 +            final String configuredHosts = Script
 +                    .runSimpleBashScript("ovs-vsctl get bridge " + nwName
 +                            + " other_config:ovs-host-setup");
 +            boolean configured = false;
 +            if (configuredHosts != null) {
 +                final String hostIdsStr[] = configuredHosts.split(",");
 +                for (final String hostIdStr : hostIdsStr) {
 +                    if (hostIdStr.equals(((Long)hostId).toString())) {
 +                        configured = true;
 +                        break;
 +                    }
 +                }
 +            }
 +            if (!configured) {
 +                final Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
 +                cmd.add("setup_ovs_bridge");
 +                cmd.add("--key", nwName);
 +                cmd.add("--cs_host_id", ((Long)hostId).toString());
 +                cmd.add("--bridge", nwName);
 +                final String result = cmd.execute();
 +                if (result != null) {
 +                    throw new CloudRuntimeException(
 +                            "Unable to pre-configure OVS bridge " + nwName
 +                                    + " for network ID:" + networkId);
 +                }
 +            }
 +        } catch (final Exception e) {
 +            s_logger.warn("createandConfigureTunnelNetwork failed", e);
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    protected Storage.StorageResourceType getStorageResourceType() {
 +        return Storage.StorageResourceType.STORAGE_POOL;
 +    }
 +
 +    // this is much like PrimaryStorageDownloadCommand, but keeping it separate
 +    public KVMPhysicalDisk templateToPrimaryDownload(final String templateUrl, final KVMStoragePool primaryPool, final String volUuid) {
 +        final int index = templateUrl.lastIndexOf("/");
 +        final String mountpoint = templateUrl.substring(0, index);
 +        String templateName = null;
 +        if (index < templateUrl.length() - 1) {
 +            templateName = templateUrl.substring(index + 1);
 +        }
 +
 +        KVMPhysicalDisk templateVol = null;
 +        KVMStoragePool secondaryPool = null;
 +        try {
 +            secondaryPool = _storagePoolMgr.getStoragePoolByURI(mountpoint);
 +            /* Get template vol */
 +            if (templateName == null) {
 +                secondaryPool.refresh();
 +                final List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
 +                if (disks == null || disks.isEmpty()) {
 +                    s_logger.error("Failed to get volumes from pool: " + secondaryPool.getUuid());
 +                    return null;
 +                }
 +                for (final KVMPhysicalDisk disk : disks) {
 +                    if (disk.getName().endsWith("qcow2")) {
 +                        templateVol = disk;
 +                        break;
 +                    }
 +                }
 +                if (templateVol == null) {
 +                    s_logger.error("Failed to get template from pool: " + secondaryPool.getUuid());
 +                    return null;
 +                }
 +            } else {
 +                templateVol = secondaryPool.getPhysicalDisk(templateName);
 +            }
 +
 +            /* Copy volume to primary storage */
 +
 +            final KVMPhysicalDisk primaryVol = _storagePoolMgr.copyPhysicalDisk(templateVol, volUuid, primaryPool, 0);
 +            return primaryVol;
 +        } catch (final CloudRuntimeException e) {
 +            s_logger.error("Failed to download template to primary storage", e);
 +            return null;
 +        } finally {
 +            if (secondaryPool != null) {
 +                _storagePoolMgr.deleteStoragePool(secondaryPool.getType(), secondaryPool.getUuid());
 +            }
 +        }
 +    }
 +
 +    public String getResizeScriptType(final KVMStoragePool pool, final KVMPhysicalDisk vol) {
 +        final StoragePoolType poolType = pool.getType();
 +        final PhysicalDiskFormat volFormat = vol.getFormat();
 +
 +        if (pool.getType() == StoragePoolType.CLVM && volFormat == PhysicalDiskFormat.RAW) {
 +            return "CLVM";
 +        } else if ((poolType == StoragePoolType.NetworkFilesystem
 +                || poolType == StoragePoolType.SharedMountPoint
 +                || poolType == StoragePoolType.Filesystem
 +                || poolType == StoragePoolType.Gluster)
 +                && volFormat == PhysicalDiskFormat.QCOW2 ) {
 +            return "QCOW2";
 +        }
 +        throw new CloudRuntimeException("Cannot determine resize type from pool type " + pool.getType());
 +    }
 +
 +    private String getBroadcastUriFromBridge(final String brName) {
 +        final String pif = matchPifFileInDirectory(brName);
 +        final Pattern pattern = Pattern.compile("(\\D+)(\\d+)(\\D*)(\\d*)(\\D*)(\\d*)");
 +        final Matcher matcher = pattern.matcher(pif);
 +        s_logger.debug("getting broadcast uri for pif " + pif + " and bridge " + brName);
 +        if(matcher.find()) {
 +            if (brName.startsWith("brvx")){
 +                return BroadcastDomainType.Vxlan.toUri(matcher.group(2)).toString();
 +            }
 +            else{
 +                if (!matcher.group(6).isEmpty()) {
 +                    return BroadcastDomainType.Vlan.toUri(matcher.group(6)).toString();
 +                } else if (!matcher.group(4).isEmpty()) {
 +                    return BroadcastDomainType.Vlan.toUri(matcher.group(4)).toString();
 +                } else {
 +                    //untagged or not matching (eth|bond|team)#.#
 +                    s_logger.debug("failed to get vNet id from bridge " + brName
 +                            + "attached to physical interface" + pif + ", perhaps untagged interface");
 +                    return "";
 +                }
 +            }
 +        } else {
 +            s_logger.debug("failed to get vNet id from bridge " + brName + "attached to physical interface" + pif);
 +            return "";
 +        }
 +    }
 +
 +    private void VifHotPlug(final Connect conn, final String vmName, final String broadcastUri, final String macAddr) throws InternalErrorException, LibvirtException {
 +        final NicTO nicTO = new NicTO();
 +        nicTO.setMac(macAddr);
 +        nicTO.setType(TrafficType.Public);
 +        if (broadcastUri == null) {
 +            nicTO.setBroadcastType(BroadcastDomainType.Native);
 +        } else {
 +            final URI uri = BroadcastDomainType.fromString(broadcastUri);
 +            nicTO.setBroadcastType(BroadcastDomainType.getSchemeValue(uri));
 +            nicTO.setBroadcastUri(uri);
 +        }
 +
 +        final Domain vm = getDomain(conn, vmName);
 +        vm.attachDevice(getVifDriver(nicTO.getType()).plug(nicTO, "Other PV", "", null).toString());
 +    }
 +
 +
 +    private void vifHotUnPlug (final Connect conn, final String vmName, final String macAddr) throws InternalErrorException, LibvirtException {
 +
 +        Domain vm = null;
 +        vm = getDomain(conn, vmName);
 +        final List<InterfaceDef> pluggedNics = getInterfaces(conn, vmName);
 +        for (final InterfaceDef pluggedNic : pluggedNics) {
 +            if (pluggedNic.getMacAddress().equalsIgnoreCase(macAddr)) {
 +                vm.detachDevice(pluggedNic.toString());
 +                // We don't know which "traffic type" is associated with
 +                // each interface at this point, so inform all vif drivers
 +                for (final VifDriver vifDriver : getAllVifDrivers()) {
 +                    vifDriver.unplug(pluggedNic);
 +                }
 +            }
 +        }
 +    }
 +
 +    private ExecutionResult prepareNetworkElementCommand(final SetupGuestNetworkCommand cmd) {
 +        Connect conn;
 +        final NicTO nic = cmd.getNic();
 +        final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
 +
 +        try {
 +            conn = LibvirtConnection.getConnectionByVmName(routerName);
 +            final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
 +            InterfaceDef routerNic = null;
 +
 +            for (final InterfaceDef pluggedNic : pluggedNics) {
 +                if (pluggedNic.getMacAddress().equalsIgnoreCase(nic.getMac())) {
 +                    routerNic = pluggedNic;
 +                    break;
 +                }
 +            }
 +
 +            if (routerNic == null) {
 +                return new ExecutionResult(false, "Can not find nic with mac " + nic.getMac() + " for VM " + routerName);
 +            }
 +
 +            return new ExecutionResult(true, null);
 +        } catch (final LibvirtException e) {
 +            final String msg = "Creating guest network failed due to " + e.toString();
 +            s_logger.warn(msg, e);
 +            return new ExecutionResult(false, msg);
 +        }
 +    }
 +
 +    protected ExecutionResult prepareNetworkElementCommand(final SetSourceNatCommand cmd) {
 +        Connect conn;
 +        final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
 +        cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
 +        final IpAddressTO pubIP = cmd.getIpAddress();
 +
 +        try {
 +            conn = LibvirtConnection.getConnectionByVmName(routerName);
 +            Integer devNum = 0;
 +            final String pubVlan = pubIP.getBroadcastUri();
 +            final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
 +
 +            for (final InterfaceDef pluggedNic : pluggedNics) {
 +                final String pluggedVlanBr = pluggedNic.getBrName();
 +                final String pluggedVlanId = getBroadcastUriFromBridge(pluggedVlanBr);
 +                if (pubVlan.equalsIgnoreCase(Vlan.UNTAGGED) && pluggedVlanBr.equalsIgnoreCase(_publicBridgeName)) {
 +                    break;
 +                } else if (pluggedVlanBr.equalsIgnoreCase(_linkLocalBridgeName)) {
 +                    /*skip over, no physical bridge device exists*/
 +                } else if (pluggedVlanId == null) {
 +                    /*this should only be true in the case of link local bridge*/
 +                    return new ExecutionResult(false, "unable to find the vlan id for bridge " + pluggedVlanBr + " when attempting to set up" + pubVlan +
 +                            " on router " + routerName);
 +                } else if (pluggedVlanId.equals(pubVlan)) {
 +                    break;
 +                }
 +                devNum++;
 +            }
 +
 +            pubIP.setNicDevId(devNum);
 +
 +            return new ExecutionResult(true, "success");
 +        } catch (final LibvirtException e) {
 +            final String msg = "Ip SNAT failure due to " + e.toString();
 +            s_logger.error(msg, e);
 +            return new ExecutionResult(false, msg);
 +        }
 +    }
 +
 +    protected ExecutionResult prepareNetworkElementCommand(final IpAssocVpcCommand cmd) {
 +        Connect conn;
 +        final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
 +
 +        try {
 +            conn = getLibvirtUtilitiesHelper().getConnectionByVmName(routerName);
 +            final IpAddressTO[] ips = cmd.getIpAddresses();
 +            Integer devNum = 0;
 +            final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
 +            final Map<String, Integer> macAddressToNicNum = new HashMap<>(pluggedNics.size());
 +
 +            for (final InterfaceDef pluggedNic : pluggedNics) {
 +                final String pluggedVlan = pluggedNic.getBrName();
 +                macAddressToNicNum.put(pluggedNic.getMacAddress(), devNum);
 +                devNum++;
 +            }
 +
 +            for (final IpAddressTO ip : ips) {
 +                ip.setNicDevId(macAddressToNicNum.get(ip.getVifMacAddress()));
 +            }
 +
 +            return new ExecutionResult(true, null);
 +        } catch (final LibvirtException e) {
 +            s_logger.error("Ip Assoc failure on applying one ip due to exception:  ", e);
 +            return new ExecutionResult(false, e.getMessage());
 +        }
 +    }
 +
 +    public ExecutionResult prepareNetworkElementCommand(final IpAssocCommand cmd) {
 +        final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
 +        final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
 +        Connect conn;
 +        try {
 +            conn = LibvirtConnection.getConnectionByVmName(routerName);
 +            final List<InterfaceDef> nics = getInterfaces(conn, routerName);
 +            final Map<String, Integer> broadcastUriAllocatedToVM = new HashMap<String, Integer>();
 +            Integer nicPos = 0;
 +            for (final InterfaceDef nic : nics) {
 +                if (nic.getBrName().equalsIgnoreCase(_linkLocalBridgeName)) {
 +                    broadcastUriAllocatedToVM.put("LinkLocal", nicPos);
 +                } else {
 +                    if (nic.getBrName().equalsIgnoreCase(_publicBridgeName) || nic.getBrName().equalsIgnoreCase(_privBridgeName) ||
 +                            nic.getBrName().equalsIgnoreCase(_guestBridgeName)) {
 +                        broadcastUriAllocatedToVM.put(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString(), nicPos);
 +                    } else {
 +                        final String broadcastUri = getBroadcastUriFromBridge(nic.getBrName());
 +                        broadcastUriAllocatedToVM.put(broadcastUri, nicPos);
 +                    }
 +                }
 +                nicPos++;
 +            }
 +            final IpAddressTO[] ips = cmd.getIpAddresses();
 +            int nicNum = 0;
 +            for (final IpAddressTO ip : ips) {
 +                boolean newNic = false;
 +                if (!broadcastUriAllocatedToVM.containsKey(ip.getBroadcastUri())) {
 +                    /* plug a vif into router */
 +                    VifHotPlug(conn, routerName, ip.getBroadcastUri(), ip.getVifMacAddress());
 +                    broadcastUriAllocatedToVM.put(ip.getBroadcastUri(), nicPos++);
 +                    newNic = true;
 +                }
 +                nicNum = broadcastUriAllocatedToVM.get(ip.getBroadcastUri());
 +                networkUsage(routerIp, "addVif", "eth" + nicNum);
 +
 +                ip.setNicDevId(nicNum);
 +                ip.setNewNic(newNic);
 +            }
 +            return new ExecutionResult(true, null);
 +        } catch (final LibvirtException e) {
 +            s_logger.error("ipassoccmd failed", e);
 +            return new ExecutionResult(false, e.getMessage());
 +        } catch (final InternalErrorException e) {
 +            s_logger.error("ipassoccmd failed", e);
 +            return new ExecutionResult(false, e.getMessage());
 +        }
 +    }
 +
 +    protected ExecutionResult cleanupNetworkElementCommand(final IpAssocCommand cmd) {
 +
 +        final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
 +        final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
 +        final String lastIp = cmd.getAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP);
 +        Connect conn;
 +
 +
 +        try{
 +            conn = LibvirtConnection.getConnectionByVmName(routerName);
 +            final List<InterfaceDef> nics = getInterfaces(conn, routerName);
 +            final Map<String, Integer> broadcastUriAllocatedToVM = new HashMap<String, Integer>();
 +
 +            Integer nicPos = 0;
 +            for (final InterfaceDef nic : nics) {
 +                if (nic.getBrName().equalsIgnoreCase(_linkLocalBridgeName)) {
 +                    broadcastUriAllocatedToVM.put("LinkLocal", nicPos);
 +                } else {
 +                    if (nic.getBrName().equalsIgnoreCase(_publicBridgeName) || nic.getBrName().equalsIgnoreCase(_privBridgeName) ||
 +                            nic.getBrName().equalsIgnoreCase(_guestBridgeName)) {
 +                        broadcastUriAllocatedToVM.put(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString(), nicPos);
 +                    } else {
 +                        final String broadcastUri = getBroadcastUriFromBridge(nic.getBrName());
 +                        broadcastUriAllocatedToVM.put(broadcastUri, nicPos);
 +                    }
 +                }
 +                nicPos++;
 +            }
 +
 +            final IpAddressTO[] ips = cmd.getIpAddresses();
 +            int nicNum = 0;
 +            for (final IpAddressTO ip : ips) {
 +
 +                if (!broadcastUriAllocatedToVM.containsKey(ip.getBroadcastUri())) {
 +                    /* plug a vif into router */
 +                    VifHotPlug(conn, routerName, ip.getBroadcastUri(), ip.getVifMacAddress());
 +                    broadcastUriAllocatedToVM.put(ip.getBroadcastUri(), nicPos++);
 +                }
 +                nicNum = broadcastUriAllocatedToVM.get(ip.getBroadcastUri());
 +
 +                if (org.apache.commons.lang.StringUtils.equalsIgnoreCase(lastIp, "true") && !ip.isAdd()) {
 +                    // in isolated network eth2 is the default public interface. We don't want to delete it.
 +                    if (nicNum != 2) {
 +                        vifHotUnPlug(conn, routerName, ip.getVifMacAddress());
 +                        networkUsage(routerIp, "deleteVif", "eth" + nicNum);
 +                    }
 +                }
 +            }
 +
 +        } catch (final LibvirtException e) {
 +            s_logger.error("ipassoccmd failed", e);
 +            return new ExecutionResult(false, e.getMessage());
 +        } catch (final InternalErrorException e) {
 +            s_logger.error("ipassoccmd failed", e);
 +            return new ExecutionResult(false, e.getMessage());
 +        }
 +
 +        return new ExecutionResult(true, null);
 +    }
 +
 +    protected PowerState convertToPowerState(final DomainState ps) {
 +        final PowerState state = s_powerStatesTable.get(ps);
 +        return state == null ? PowerState.PowerUnknown : state;
 +    }
 +
 +    public PowerState getVmState(final Connect conn, final String vmName) {
 +        int retry = 3;
 +        Domain vms = null;
 +        while (retry-- > 0) {
 +            try {
 +                vms = conn.domainLookupByName(vmName);
 +                final PowerState s = convertToPowerState(vms.getInfo().state);
 +                return s;
 +            } catch (final LibvirtException e) {
 +                s_logger.warn("Can't get vm state " + vmName + e.getMessage() + "retry:" + retry);
 +            } finally {
 +                try {
 +                    if (vms != null) {
 +                        vms.free();
 +                    }
 +                } catch (final LibvirtException l) {
 +                    s_logger.trace("Ignoring libvirt error.", l);
 +                }
 +            }
 +        }
 +        return PowerState.PowerOff;
 +    }
 +
 +    public String networkUsage(final String privateIpAddress, final String option, final String vif) {
 +        final Script getUsage = new Script(_routerProxyPath, s_logger);
 +        getUsage.add("netusage.sh");
 +        getUsage.add(privateIpAddress);
 +        if (option.equals("get")) {
 +            getUsage.add("-g");
 +        } else if (option.equals("create")) {
 +            getUsage.add("-c");
 +        } else if (option.equals("reset")) {
 +            getUsage.add("-r");
 +        } else if (option.equals("addVif")) {
 +            getUsage.add("-a", vif);
 +        } else if (option.equals("deleteVif")) {
 +            getUsage.add("-d", vif);
 +        }
 +
 +        final OutputInterpreter.OneLineParser usageParser = new OutputInterpreter.OneLineParser();
 +        final String result = getUsage.execute(usageParser);
 +        if (result != null) {
 +            s_logger.debug("Failed to execute networkUsage:" + result);
 +            return null;
 +        }
 +        return usageParser.getLine();
 +    }
 +
 +    public long[] getNetworkStats(final String privateIP) {
 +        final String result = networkUsage(privateIP, "get", null);
 +        final long[] stats = new long[2];
 +        if (result != null) {
 +            final String[] splitResult = result.split(":");
 +            int i = 0;
 +            while (i < splitResult.length - 1) {
 +                stats[0] += Long.parseLong(splitResult[i++]);
 +                stats[1] += Long.parseLong(splitResult[i++]);
 +            }
 +        }
 +        return stats;
 +    }
 +
 +    public String configureVPCNetworkUsage(final String privateIpAddress, final String publicIp, final String option, final String vpcCIDR) {
 +        final Script getUsage = new Script(_routerProxyPath, s_logger);
 +        getUsage.add("vpc_netusage.sh");
 +        getUsage.add(privateIpAddress);
 +        getUsage.add("-l", publicIp);
 +
 +        if (option.equals("get")) {
 +            getUsage.add("-g");
 +        } else if (option.equals("create")) {
 +            getUsage.add("-c");
 +            getUsage.add("-v", vpcCIDR);
 +        } else if (option.equals("reset")) {
 +            getUsage.add("-r");
 +        } else if (option.equals("vpn")) {
 +            getUsage.add("-n");
 +        } else if (option.equals("remove")) {
 +            getUsage.add("-d");
 +        }
 +
 +        final OutputInterpreter.OneLineParser usageParser = new OutputInterpreter.OneLineParser();
 +        final String result = getUsage.execute(usageParser);
 +        if (result != null) {
 +            s_logger.debug("Failed to execute VPCNetworkUsage:" + result);
 +            return null;
 +        }
 +        return usageParser.getLine();
 +    }
 +
 +    public long[] getVPCNetworkStats(final String privateIP, final String publicIp, final String option) {
 +        final String result = configureVPCNetworkUsage(privateIP, publicIp, option, null);
 +        final long[] stats = new long[2];
 +        if (result != null) {
 +            final String[] splitResult = result.split(":");
 +            int i = 0;
 +            while (i < splitResult.length - 1) {
 +                stats[0] += Long.parseLong(splitResult[i++]);
 +                stats[1] += Long.parseLong(splitResult[i++]);
 +            }
 +        }
 +        return stats;
 +    }
 +
 +    public void handleVmStartFailure(final Connect conn, final String vmName, final LibvirtVMDef vm) {
 +        if (vm != null && vm.getDevices() != null) {
 +            cleanupVMNetworks(conn, vm.getDevices().getInterfaces());
 +        }
 +    }
 +
 +    protected String getUuid(String uuid) {
 +        if (uuid == null) {
 +            uuid = UUID.randomUUID().toString();
 +        } else {
 +            try {
 +                final UUID uuid2 = UUID.fromString(uuid);
 +                final String uuid3 = uuid2.toString();
 +                if (!uuid3.equals(uuid)) {
 +                    uuid = UUID.randomUUID().toString();
 +                }
 +            } catch (final IllegalArgumentException e) {
 +                uuid = UUID.randomUUID().toString();
 +            }
 +        }
 +        return uuid;
 +    }
 +
 +    /**
 +     * Set quota and period tags on 'ctd' when CPU limit use is set
 +     */
 +    protected void setQuotaAndPeriod(VirtualMachineTO vmTO, CpuTuneDef ctd) {
 +        if (vmTO.getLimitCpuUse() && vmTO.getCpuQuotaPercentage() != null) {
 +            Double cpuQuotaPercentage = vmTO.getCpuQuotaPercentage();
 +            int period = CpuTuneDef.DEFAULT_PERIOD;
 +            int quota = (int) (period * cpuQuotaPercentage);
 +            if (quota < CpuTuneDef.MIN_QUOTA) {
 +                s_logger.info("Calculated quota (" + quota + ") below the minimum (" + CpuTuneDef.MIN_QUOTA + ") for VM domain " + vmTO.getUuid() + ", setting it to minimum " +
 +                        "and calculating period instead of using the default");
 +                quota = CpuTuneDef.MIN_QUOTA;
 +                period = (int) ((double) quota / cpuQuotaPercentage);
 +                if (period > CpuTuneDef.MAX_PERIOD) {
 +                    s_logger.info("Calculated period (" + period + ") exceeds the maximum (" + CpuTuneDef.MAX_PERIOD +
 +                            "), setting it to the maximum");
 +                    period = CpuTuneDef.MAX_PERIOD;
 +                }
 +            }
 +            ctd.setQuota(quota);
 +            ctd.setPeriod(period);
 +            s_logger.info("Setting quota=" + quota + ", period=" + period + " to VM domain " + vmTO.getUuid());
 +        }
 +    }
 +
 +    protected void enlightenWindowsVm(VirtualMachineTO vmTO, FeaturesDef features) {
 +        if (vmTO.getOs().contains("Windows PV")) {
 +            // If OS is Windows PV, then enable the features. Features supported on Windows 2008 and later
 +            LibvirtVMDef.HyperVEnlightenmentFeatureDef hyv = new LibvirtVMDef.HyperVEnlightenmentFeatureDef();
 +            hyv.setFeature("relaxed", true);
 +            hyv.setFeature("vapic", true);
 +            hyv.setFeature("spinlocks", true);
 +            hyv.setRetries(8096);
 +            features.addHyperVFeature(hyv);
 +            s_logger.info("Enabling KVM Enlightment Features to VM domain " + vmTO.getUuid());
 +        }
 +    }
 +
 +    public LibvirtVMDef createVMFromSpec(final VirtualMachineTO vmTO) {
 +        final LibvirtVMDef vm = new LibvirtVMDef();
 +        vm.setDomainName(vmTO.getName());
 +        String uuid = vmTO.getUuid();
 +        uuid = getUuid(uuid);
 +        vm.setDomUUID(uuid);
 +        vm.setDomDescription(vmTO.getOs());
 +        vm.setPlatformEmulator(vmTO.getPlatformEmulator());
 +
 +        Map<String, String> extraConfig = vmTO.getExtraConfig();
 +        if (dpdkSupport && (!extraConfig.containsKey(DPDK_NUMA) || !extraConfig.containsKey(DPDK_HUGE_PAGES))) {
 +            s_logger.info("DPDK is enabled but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment");
 +        }
 +
 +        final GuestDef guest = new GuestDef();
 +
 +        if (HypervisorType.LXC == _hypervisorType && VirtualMachine.Type.User == vmTO.getType()) {
 +            // LXC domain is only valid for user VMs. Use KVM for system VMs.
 +            guest.setGuestType(GuestDef.GuestType.LXC);
 +            vm.setHvsType(HypervisorType.LXC.toString().toLowerCase());
 +        } else {
 +            guest.setGuestType(GuestDef.GuestType.KVM);
 +            vm.setHvsType(HypervisorType.KVM.toString().toLowerCase());
 +            vm.setLibvirtVersion(_hypervisorLibvirtVersion);
 +            vm.setQemuVersion(_hypervisorQemuVersion);
 +        }
 +        guest.setGuestArch(vmTO.getArch());
 +        guest.setMachineType("pc");
 +        guest.setUuid(uuid);
 +        guest.setBootOrder(GuestDef.BootOrder.CDROM);
 +        guest.setBootOrder(GuestDef.BootOrder.HARDISK);
 +
 +        vm.addComp(guest);
 +
 +        final GuestResourceDef grd = new GuestResourceDef();
 +
 +        if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) {
 +            grd.setMemBalloning(true);
 +            grd.setCurrentMem(vmTO.getMinRam() / 1024);
 +            grd.setMemorySize(vmTO.getMaxRam() / 1024);
 +        } else {
 +            grd.setMemorySize(vmTO.getMaxRam() / 1024);
 +        }
 +        final int vcpus = vmTO.getCpus();
 +        grd.setVcpuNum(vcpus);
 +        vm.addComp(grd);
 +
 +        if (!extraConfig.containsKey(DPDK_NUMA)) {
 +            final CpuModeDef cmd = new CpuModeDef();
 +            cmd.setMode(_guestCpuMode);
 +            cmd.setModel(_guestCpuModel);
 +            if (vmTO.getType() == VirtualMachine.Type.User) {
 +                cmd.setFeatures(_cpuFeatures);
 +            }
 +            // multi cores per socket, for larger core configs
 +            if (vcpus % 6 == 0) {
 +                final int sockets = vcpus / 6;
 +                cmd.setTopology(6, sockets);
 +            } else if (vcpus % 4 == 0) {
 +                final int sockets = vcpus / 4;
 +                cmd.setTopology(4, sockets);
 +            }
 +            vm.addComp(cmd);
 +        }
 +
 +        if (_hypervisorLibvirtVersion >= 9000) {
 +            final CpuTuneDef ctd = new CpuTuneDef();
 +            /**
 +             A 4.0.X/4.1.X management server doesn't send the correct JSON
 +             command for getMinSpeed, it only sends a 'speed' field.
 +
 +             So if getMinSpeed() returns null we fall back to getSpeed().
 +
 +             This way a >4.1 agent can work communicate a <=4.1 management server
 +
 +             This change is due to the overcommit feature in 4.2
 +             */
 +            if (vmTO.getMinSpeed() != null) {
 +                ctd.setShares(vmTO.getCpus() * vmTO.getMinSpeed());
 +            } else {
 +                ctd.setShares(vmTO.getCpus() * vmTO.getSpeed());
 +            }
 +
 +            setQuotaAndPeriod(vmTO, ctd);
 +
 +            vm.addComp(ctd);
 +        }
 +
 +        final FeaturesDef features = new FeaturesDef();
 +        features.addFeatures("pae");
 +        features.addFeatures("apic");
 +        features.addFeatures("acpi");
 +
 +        //KVM hyperv enlightenment features based on OS Type
 +        enlightenWindowsVm(vmTO, features);
 +
 +        vm.addComp(features);
 +
 +        final TermPolicy term = new TermPolicy();
 +        term.setCrashPolicy("destroy");
 +        term.setPowerOffPolicy("destroy");
 +        term.setRebootPolicy("restart");
 +        vm.addComp(term);
 +
 +        final ClockDef clock = new ClockDef();
 +        if (vmTO.getOs().startsWith("Windows")) {
 +            clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME);
 +            clock.setTimer("hypervclock", null, null);
 +        } else if (vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs())) {
 +            if (_hypervisorLibvirtVersion >= 9 * 1000 + 10) {
 +                clock.setTimer("kvmclock", null, null, _noKvmClock);
 +            }
 +        }
 +
 +        vm.addComp(clock);
 +
 +        final DevicesDef devices = new DevicesDef();
 +        devices.setEmulatorPath(_hypervisorPath);
 +        devices.setGuestType(guest.getGuestType());
 +
 +        final SerialDef serial = new SerialDef("pty", null, (short)0);
 +        devices.addDevice(serial);
 +
 +        if (_rngEnable) {
 +            final RngDef rngDevice = new RngDef(_rngPath, _rngBackendModel, _rngRateBytes, _rngRatePeriod);
 +            devices.addDevice(rngDevice);
 +        }
 +
 +        /* Add a VirtIO channel for the Qemu Guest Agent tools */
 +        File virtIoChannel = Paths.get(_qemuSocketsPath.getPath(), vmTO.getName() + "." + _qemuGuestAgentSocketName).toFile();
 +        devices.addDevice(new ChannelDef(_qemuGuestAgentSocketName, ChannelDef.ChannelType.UNIX, virtIoChannel));
 +
 +        devices.addDevice(new WatchDogDef(_watchDogAction, _watchDogModel));
 +
 +        final VideoDef videoCard = new VideoDef(_videoHw, _videoRam);
 +        devices.addDevice(videoCard);
 +
 +        final ConsoleDef console = new ConsoleDef("pty", null, null, (short)0);
 +        devices.addDevice(console);
 +
 +        //add the VNC port passwd here, get the passwd from the vmInstance.
 +        final String passwd = vmTO.getVncPassword();
 +        final GraphicDef grap = new GraphicDef("vnc", (short)0, true, vmTO.getVncAddr(), passwd, null);
 +        devices.addDevice(grap);
 +
 +        final InputDef input = new InputDef("tablet", "usb");
 +        devices.addDevice(input);
 +
 +
 +        DiskDef.DiskBus busT = getDiskModelFromVMDetail(vmTO);
 +
 +        if (busT == null) {
 +            busT = getGuestDiskModel(vmTO.getPlatformEmulator());
 +        }
 +
 +        // If we're using virtio scsi, then we need to add a virtual scsi controller
 +        if (busT == DiskDef.DiskBus.SCSI) {
 +            final SCSIDef sd = new SCSIDef((short)0, 0, 0, 9, 0, vcpus);
 +            devices.addDevice(sd);
 +        }
 +
 +        vm.addComp(devices);
 +
 +        addExtraConfigComponent(extraConfig, vm);
 +
 +        return vm;
 +    }
 +
 +    /**
 +     * Add extra configurations (if any) as a String component to the domain XML
 +     */
 +    protected void addExtraConfigComponent(Map<String, String> extraConfig, LibvirtVMDef vm) {
 +        if (MapUtils.isNotEmpty(extraConfig)) {
 +            StringBuilder extraConfigBuilder = new StringBuilder();
 +            for (String key : extraConfig.keySet()) {
 +                if (!key.startsWith(DPDK_INTERFACE_PREFIX)) {
 +                    extraConfigBuilder.append(extraConfig.get(key));
 +                }
 +            }
 +            String comp = extraConfigBuilder.toString();
 +            if (org.apache.commons.lang.StringUtils.isNotBlank(comp)) {
 +                vm.addComp(comp);
 +            }
 +        }
 +    }
 +
 +    public void createVifs(final VirtualMachineTO vmSpec, final LibvirtVMDef vm) throws InternalErrorException, LibvirtException {
 +        final NicTO[] nics = vmSpec.getNics();
 +        final Map <String, String> params = vmSpec.getDetails();
 +        String nicAdapter = "";
 +        if (params != null && params.get("nicAdapter") != null && !params.get("nicAdapter").isEmpty()) {
 +            nicAdapter = params.get("nicAdapter");
 +        }
 +        Map<String, String> extraConfig = vmSpec.getExtraConfig();
 +        for (int i = 0; i < nics.length; i++) {
 +            for (final NicTO nic : vmSpec.getNics()) {
 +                if (nic.getDeviceId() == i) {
 +                    createVif(vm, nic, nicAdapter, extraConfig);
 +                }
 +            }
 +        }
 +    }
 +
 +    public String getVolumePath(final Connect conn, final DiskTO volume) throws LibvirtException, URISyntaxException {
 +        final DataTO data = volume.getData();
 +        final DataStoreTO store = data.getDataStore();
 +
 +        if (volume.getType() == Volume.Type.ISO && data.getPath() != null && (store instanceof NfsTO ||
 +                store instanceof PrimaryDataStoreTO && data instanceof TemplateObjectTO && !((TemplateObjectTO) data).isDirectDownload())) {
 +            final String isoPath = store.getUrl().split("\\?")[0] + File.separator + data.getPath();
 +            final int index = isoPath.lastIndexOf("/");
 +            final String path = isoPath.substring(0, index);
 +            final String name = isoPath.substring(index + 1);
 +            final KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(path);
 +            final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
 +            return isoVol.getPath();
 +        } else {
 +            return data.getPath();
 +        }
 +    }
 +
 +    public void createVbd(final Connect conn, final VirtualMachineTO vmSpec, final String vmName, final LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException {
 +        final List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
 +        Collections.sort(disks, new Comparator<DiskTO>() {
 +            @Override
 +            public int compare(final DiskTO arg0, final DiskTO arg1) {
 +                return arg0.getDiskSeq() > arg1.getDiskSeq() ? 1 : -1;
 +            }
 +        });
 +
 +        for (final DiskTO volume : disks) {
 +            KVMPhysicalDisk physicalDisk = null;
 +            KVMStoragePool pool = null;
 +            final DataTO data = volume.getData();
 +            if (volume.getType() == Volume.Type.ISO && data.getPath() != null) {
 +                DataStoreTO dataStore = data.getDataStore();
 +                String dataStoreUrl = null;
 +                if (dataStore instanceof NfsTO) {
 +                    NfsTO nfsStore = (NfsTO)data.getDataStore();
 +                    dataStoreUrl = nfsStore.getUrl();
 +                } else if (dataStore instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO) dataStore).getPoolType().equals(StoragePoolType.NetworkFilesystem)) {
 +                    //In order to support directly downloaded ISOs
 +                    String psHost = ((PrimaryDataStoreTO) dataStore).getHost();
 +                    String psPath = ((PrimaryDataStoreTO) dataStore).getPath();
 +                    dataStoreUrl = "nfs://" + psHost + File.separator + psPath;
 +                }
 +                final String volPath = dataStoreUrl + File.separator + data.getPath();
 +                final int index = volPath.lastIndexOf("/");
 +                final String volDir = volPath.substring(0, index);
 +                final String volName = volPath.substring(index + 1);
 +                final KVMStoragePool secondaryStorage = _storagePoolMgr.getStoragePoolByURI(volDir);
 +                physicalDisk = secondaryStorage.getPhysicalDisk(volName);
 +            } else if (volume.getType() != Volume.Type.ISO) {
 +                final PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
 +                physicalDisk = _storagePoolMgr.getPhysicalDisk(store.getPoolType(), store.getUuid(), data.getPath());
 +                pool = physicalDisk.getPool();
 +            }
 +
 +            String volPath = null;
 +            if (physicalDisk != null) {
 +                volPath = physicalDisk.getPath();
 +            }
 +
 +            // check for disk activity, if detected we should exit because vm is running elsewhere
 +            if (_diskActivityCheckEnabled && physicalDisk != null && physicalDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
 +                s_logger.debug("Checking physical disk file at path " + volPath + " for disk activity to ensure vm is not running elsewhere");
 +                try {
 +                    HypervisorUtils.checkVolumeFileForActivity(volPath, _diskActivityCheckTimeoutSeconds, _diskActivityInactiveThresholdMilliseconds, _diskActivityCheckFileSizeMin);
 +                } catch (final IOException ex) {
 +                    throw new CloudRuntimeException("Unable to check physical disk file for activity", ex);
 +                }
 +                s_logger.debug("Disk activity check cleared");
 +            }
 +
 +            // if params contains a rootDiskController key, use its value (this is what other HVs are doing)
 +            DiskDef.DiskBus diskBusType = getDiskModelFromVMDetail(vmSpec);
 +
 +            if (diskBusType == null) {
 +                diskBusType = getGuestDiskModel(vmSpec.getPlatformEmulator());
 +            }
 +
 +            // I'm not sure why previously certain DATADISKs were hard-coded VIRTIO and others not, however this
 +            // maintains existing functionality with the exception that SCSI will override VIRTIO.
 +            DiskDef.DiskBus diskBusTypeData = (diskBusType == DiskDef.DiskBus.SCSI) ? diskBusType : DiskDef.DiskBus.VIRTIO;
 +
 +            final DiskDef disk = new DiskDef();
 +            int devId = volume.getDiskSeq().intValue();
 +            if (volume.getType() == Volume.Type.ISO) {
 +                if (volPath == null) {
 +                    /* Add iso as placeholder */
 +                    disk.defISODisk(null, devId);
 +                } else {
 +                    disk.defISODisk(volPath, devId);
 +                }
 +            } else {
 +                if (diskBusType == DiskDef.DiskBus.SCSI ) {
 +                    disk.setQemuDriver(true);
 +                    disk.setDiscard(DiscardType.UNMAP);
 +                }
 +
 +                if (pool.getType() == StoragePoolType.RBD) {
 +                    /*
 +                            For RBD pools we use the secret mechanism in libvirt.
 +                            We store the secret under the UUID of the pool, that's why
 +                            we pass the pool's UUID as the authSecret
 +                     */
 +                    disk.defNetworkBasedDisk(physicalDisk.getPath().replace("rbd:", ""), pool.getSourceHost(), pool.getSourcePort(), pool.getAuthUserName(),
 +                            pool.getUuid(), devId, diskBusType, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
 +                } else if (pool.getType() == StoragePoolType.Gluster) {
 +                    final String mountpoint = pool.getLocalPath();
 +                    final String path = physicalDisk.getPath();
 +                    final String glusterVolume = pool.getSourceDir().replace("/", "");
 +                    disk.defNetworkBasedDisk(glusterVolume + path.replace(mountpoint, ""), pool.getSourceHost(), pool.getSourcePort(), null,
 +                            null, devId, diskBusType, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
 +                } else if (pool.getType() == StoragePoolType.CLVM || physicalDisk.getFormat() == PhysicalDiskFormat.RAW) {
 +                    disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusType);
 +                } else {
 +                    if (volume.getType() == Volume.Type.DATADISK) {
 +                        disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusTypeData, DiskDef.DiskFmtType.QCOW2);
 +                    } else {
 +                        disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.DiskFmtType.QCOW2);
 +                    }
 +
 +                }
 +
 +            }
 +
 +            if (data instanceof VolumeObjectTO) {
 +                final VolumeObjectTO volumeObjectTO = (VolumeObjectTO)data;
 +                disk.setSerial(diskUuidToSerial(volumeObjectTO.getUuid()));
 +                setBurstProperties(volumeObjectTO, disk);
 +
 +                if (volumeObjectTO.getCacheMode() != null) {
 +                    disk.setCacheMode(DiskDef.DiskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString().toUpperCase()));
 +                }
 +            }
 +            if (vm.getDevices() == null) {
 +                s_logger.error("There is no devices for" + vm);
 +                throw new RuntimeException("There is no devices for" + vm);
 +            }
 +            vm.getDevices().addDevice(disk);
 +        }
 +
 +        if (vmSpec.getType() != VirtualMachine.Type.User) {
 +            if (_sysvmISOPath != null) {
 +                final DiskDef iso = new DiskDef();
 +                iso.defISODisk(_sysvmISOPath);
 +                vm.getDevices().addDevice(iso);
 +            }
 +        }
 +
 +        // For LXC, find and add the root filesystem, rbd data disks
 +        if (HypervisorType.LXC.toString().toLowerCase().equals(vm.getHvsType())) {
 +            for (final DiskTO volume : disks) {
 +                final DataTO data = volume.getData();
 +                final PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
 +                if (volume.getType() == Volume.Type.ROOT) {
 +                    final KVMPhysicalDisk physicalDisk = _storagePoolMgr.getPhysicalDisk(store.getPoolType(), store.getUuid(), data.getPath());
 +                    final FilesystemDef rootFs = new FilesystemDef(physicalDisk.getPath(), "/");
 +                    vm.getDevices().addDevice(rootFs);
 +                } else if (volume.getType() == Volume.Type.DATADISK) {
 +                    final KVMPhysicalDisk physicalDisk = _storagePoolMgr.getPhysicalDisk(store.getPoolType(), store.getUuid(), data.getPath());
 +                    final KVMStoragePool pool = physicalDisk.getPool();
 +                    if(StoragePoolType.RBD.equals(pool.getType())) {
 +                        final int devId = volume.getDiskSeq().intValue();
 +                        final String device = mapRbdDevice(physicalDisk);
 +                        if (device != null) {
 +                            s_logger.debug("RBD device on host is: " + device);
 +                            final DiskDef diskdef = new DiskDef();
 +                            diskdef.defBlockBasedDisk(device, devId, DiskDef.DiskBus.VIRTIO);
 +                            diskdef.setQemuDriver(false);
 +                            vm.getDevices().addDevice(diskdef);
 +                        } else {
 +                            throw new InternalErrorException("Error while mapping RBD device on host");
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +    }
 +
 +    private void setBurstProperties(final VolumeObjectTO volumeObjectTO, final DiskDef disk ) {
 +        if (volumeObjectTO.getBytesReadRate() != null && volumeObjectTO.getBytesReadRate() > 0) {
 +            disk.setBytesReadRate(volumeObjectTO.getBytesReadRate());
 +        }
 +        if (volumeObjectTO.getBytesReadRateMax() != null && volumeObjectTO.getBytesReadRateMax() > 0) {
 +            disk.setBytesReadRateMax(volumeObjectTO.getBytesReadRateMax());
 +        }
 +        if (volumeObjectTO.getBytesReadRateMaxLength() != null && volumeObjectTO.getBytesReadRateMaxLength() > 0) {
 +            disk.setBytesReadRateMaxLength(volumeObjectTO.getBytesReadRateMaxLength());
 +        }
 +        if (volumeObjectTO.getBytesWriteRate() != null && volumeObjectTO.getBytesWriteRate() > 0) {
 +            disk.setBytesWriteRate(volumeObjectTO.getBytesWriteRate());
 +        }
 +        if (volumeObjectTO.getBytesWriteRateMax() != null && volumeObjectTO.getBytesWriteRateMax() > 0) {
 +            disk.setBytesWriteRateMax(volumeObjectTO.getBytesWriteRateMax());
 +        }
 +        if (volumeObjectTO.getBytesWriteRateMaxLength() != null && volumeObjectTO.getBytesWriteRateMaxLength() > 0) {
 +            disk.setBytesWriteRateMaxLength(volumeObjectTO.getBytesWriteRateMaxLength());
 +        }
 +        if (volumeObjectTO.getIopsReadRate() != null && volumeObjectTO.getIopsReadRate() > 0) {
 +            disk.setIopsReadRate(volumeObjectTO.getIopsReadRate());
 +        }
 +        if (volumeObjectTO.getIopsReadRateMax() != null && volumeObjectTO.getIopsReadRateMax() > 0) {
 +            disk.setIopsReadRateMax(volumeObjectTO.getIopsReadRateMax());
 +        }
 +        if (volumeObjectTO.getIopsReadRateMaxLength() != null && volumeObjectTO.getIopsReadRateMaxLength() > 0) {
 +            disk.setIopsReadRateMaxLength(volumeObjectTO.getIopsReadRateMaxLength());
 +        }
 +        if (volumeObjectTO.getIopsWriteRate() != null && volumeObjectTO.getIopsWriteRate() > 0) {
 +            disk.setIopsWriteRate(volumeObjectTO.getIopsWriteRate());
 +        }
 +        if (volumeObjectTO.getIopsWriteRateMax() != null && volumeObjectTO.getIopsWriteRateMax() > 0) {
 +            disk.setIopsWriteRateMax(volumeObjectTO.getIopsWriteRateMax());
 +        }
 +        if (volumeObjectTO.getIopsWriteRateMaxLength() != null && volumeObjectTO.getIopsWriteRateMaxLength() > 0) {
 +            disk.setIopsWriteRateMaxLength(volumeObjectTO.getIopsWriteRateMaxLength());
 +        }
 +    }
 +
 +    private void createVif(final LibvirtVMDef vm, final NicTO nic, final String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException {
 +
 +        if (nic.getType().equals(TrafficType.Guest) && nic.getBroadcastType().equals(BroadcastDomainType.Vsp)) {
 +            String vrIp = nic.getBroadcastUri().getPath().substring(1);
 +            vm.getMetaData().getMetadataNode(LibvirtVMDef.NuageExtensionDef.class).addNuageExtension(nic.getMac(), vrIp);
 +
 +            if (s_logger.isDebugEnabled()) {
 +                s_logger.debug("NIC with MAC " + nic.getMac() + " and BroadcastDomainType " + nic.getBroadcastType() + " in network(" + nic.getGateway() + "/" + nic.getNetmask()
 +                        + ") is " + nic.getType() + " traffic type. So, vsp-vr-ip " + vrIp + " is set in the metadata");
 +            }
 +        }
 +        if (vm.getDevices() == null) {
 +            s_logger.error("LibvirtVMDef object get devices with null result");
 +            throw new InternalErrorException("LibvirtVMDef object get devices with null result");
 +        }
 +        vm.getDevices().addDevice(getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig));
 +    }
 +
 +    public boolean cleanupDisk(Map<String, String> volumeToDisconnect) {
 +        return _storagePoolMgr.disconnectPhysicalDisk(volumeToDisconnect);
 +    }
 +
 +    public boolean cleanupDisk(final DiskDef disk) {
 +        final String path = disk.getDiskPath();
 +
 +        if (path == null) {
 +            s_logger.debug("Unable to clean up disk with null path (perhaps empty cdrom drive):" + disk);
 +            return false;
 +        }
 +
 +        if (path.endsWith("systemvm.iso")) {
 +            // don't need to clean up system vm ISO as it's stored in local
 +            return true;
 +        }
 +
 +        return _storagePoolMgr.disconnectPhysicalDiskByPath(path);
 +    }
 +
 +    protected KVMStoragePoolManager getPoolManager() {
 +        return _storagePoolMgr;
 +    }
 +
 +    public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, final Integer diskSeq) throws LibvirtException, URISyntaxException,
 +            InternalErrorException {
 +        final DiskDef iso = new DiskDef();
 +        if (isoPath != null && isAttach) {
 +            final int index = isoPath.lastIndexOf("/");
 +            final String path = isoPath.substring(0, index);
 +            final String name = isoPath.substring(index + 1);
 +            final KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(path);
 +            final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
 +            isoPath = isoVol.getPath();
 +
 +            iso.defISODisk(isoPath, diskSeq);
 +        } else {
 +            iso.defISODisk(null, diskSeq);
 +        }
 +
 +        final String result = attachOrDetachDevice(conn, true, vmName, iso.toString());
 +        if (result == null && !isAttach) {
 +            final List<DiskDef> disks = getDisks(conn, vmName);
 +            for (final DiskDef disk : disks) {
 +                if (disk.getDeviceType() == DiskDef.DeviceType.CDROM
 +                        && (diskSeq == null || disk.getDiskLabel() == iso.getDiskLabel())) {
 +                    cleanupDisk(disk);
 +                }
 +            }
 +
 +        }
 +        return result;
 +    }
 +
 +    public synchronized String attachOrDetachDisk(final Connect conn,
 +                                                  final boolean attach, final String vmName, final KVMPhysicalDisk attachingDisk,
 +                                                  final int devId, final Long bytesReadRate, final Long bytesReadRateMax, final Long bytesReadRateMaxLength, final Long bytesWriteRate, final Long bytesWriteRateMax, final Long bytesWriteRateMaxLength, final Long iopsReadRate, final Long iopsReadRateMax, final Long iopsReadRateMaxLength, final Long iopsWriteRate, final Long iopsWriteRateMax, final Long iopsWriteRateMaxLength, final String cacheMode) throws LibvirtException, InternalErrorEx [...]
 +        List<DiskDef> disks = null;
 +        Domain dm = null;
 +        DiskDef diskdef = null;
 +        final KVMStoragePool attachingPool = attachingDisk.getPool();
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
 +            final String domXml = dm.getXMLDesc(0);
 +            parser.parseDomainXML(domXml);
 +            disks = parser.getDisks();
 +
 +            if (!attach) {
 +                for (final DiskDef disk : disks) {
 +                    final String file = disk.getDiskPath();
 +                    if (file != null && file.equalsIgnoreCase(attachingDisk.getPath())) {
 +                        diskdef = disk;
 +                        break;
 +                    }
 +                }
 +                if (diskdef == null) {
 +                    throw new InternalErrorException("disk: " + attachingDisk.getPath() + " is not attached before");
 +                }
 +            } else {
 +                DiskDef.DiskBus busT = DiskDef.DiskBus.VIRTIO;
 +                for (final DiskDef disk : disks) {
 +                    if (disk.getDeviceType() == DeviceType.DISK) {
 +                        if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
 +                            busT = DiskDef.DiskBus.SCSI;
 +                        }
 +                        break;
 +                    }
 +                }
 +
 +                diskdef = new DiskDef();
 +                if (busT == DiskDef.DiskBus.SCSI) {
 +                    diskdef.setQemuDriver(true);
 +                    diskdef.setDiscard(DiscardType.UNMAP);
 +                }
 +                if (attachingPool.getType() == StoragePoolType.RBD) {
 +                    diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), attachingPool.getAuthUserName(),
 +                            attachingPool.getUuid(), devId, busT, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
 +                } else if (attachingPool.getType() == StoragePoolType.Gluster) {
 +                    diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), null,
 +                            null, devId, busT, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
 +                } else if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
 +                    diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, busT, DiskDef.DiskFmtType.QCOW2);
 +                } else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
 +                    diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, busT);
 +                }
 +                if (bytesReadRate != null && bytesReadRate > 0) {
 +                    diskdef.setBytesReadRate(bytesReadRate);
 +                }
 +                if (bytesReadRateMax != null && bytesReadRateMax > 0) {
 +                    diskdef.setBytesReadRateMax(bytesReadRateMax);
 +                }
 +                if (bytesReadRateMaxLength != null && bytesReadRateMaxLength > 0) {
 +                    diskdef.setBytesReadRateMaxLength(bytesReadRateMaxLength);
 +                }
 +                if (bytesWriteRate != null && bytesWriteRate > 0) {
 +                    diskdef.setBytesWriteRate(bytesWriteRate);
 +                }
 +                if (bytesWriteRateMax != null && bytesWriteRateMax > 0) {
 +                    diskdef.setBytesWriteRateMax(bytesWriteRateMax);
 +                }
 +                if (bytesWriteRateMaxLength != null && bytesWriteRateMaxLength > 0) {
 +                    diskdef.setBytesWriteRateMaxLength(bytesWriteRateMaxLength);
 +                }
 +                if (iopsReadRate != null && iopsReadRate > 0) {
 +                    diskdef.setIopsReadRate(iopsReadRate);
 +                }
 +                if (iopsReadRateMax != null && iopsReadRateMax > 0) {
 +                    diskdef.setIopsReadRateMax(iopsReadRateMax);
 +                }
 +                if (iopsReadRateMaxLength != null && iopsReadRateMaxLength > 0) {
 +                    diskdef.setIopsReadRateMaxLength(iopsReadRateMaxLength);
 +                }
 +                if (iopsWriteRate != null && iopsWriteRate > 0) {
 +                    diskdef.setIopsWriteRate(iopsWriteRate);
 +                }
 +                if (iopsWriteRateMax != null && iopsWriteRateMax > 0) {
 +                    diskdef.setIopsWriteRateMax(iopsWriteRateMax);
 +                }
 +
 +                if (cacheMode != null) {
 +                    diskdef.setCacheMode(DiskDef.DiskCacheMode.valueOf(cacheMode.toUpperCase()));
 +                }
 +            }
 +
 +            final String xml = diskdef.toString();
 +            return attachOrDetachDevice(conn, attach, vmName, xml);
 +        } finally {
 +            if (dm != null) {
 +                dm.free();
 +            }
 +        }
 +    }
 +
 +    protected synchronized String attachOrDetachDevice(final Connect conn, final boolean attach, final String vmName, final String xml) throws LibvirtException, InternalErrorException {
 +        Domain dm = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            if (attach) {
 +                s_logger.debug("Attaching device: " + xml);
 +                dm.attachDevice(xml);
 +            } else {
 +                s_logger.debug("Detaching device: " + xml);
 +                dm.detachDevice(xml);
 +            }
 +        } catch (final LibvirtException e) {
 +            if (attach) {
 +                s_logger.warn("Failed to attach device to " + vmName + ": " + e.getMessage());
 +            } else {
 +                s_logger.warn("Failed to detach device from " + vmName + ": " + e.getMessage());
 +            }
 +            throw e;
 +        } finally {
 +            if (dm != null) {
 +                try {
 +                    dm.free();
 +                } catch (final LibvirtException l) {
 +                    s_logger.trace("Ignoring libvirt error.", l);
 +                }
 +            }
 +        }
 +
 +        return null;
 +    }
 +
 +    @Override
 +    public PingCommand getCurrentStatus(final long id) {
 +
 +        if (!_canBridgeFirewall) {
 +            return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, this.getHostVmStateReport());
 +        } else {
 +            final HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(id);
 +            return new PingRoutingWithNwGroupsCommand(getType(), id, this.getHostVmStateReport(), nwGrpStates);
 +        }
 +    }
 +
 +    @Override
 +    public Type getType() {
 +        return Type.Routing;
 +    }
 +
 +    private Map<String, String> getVersionStrings() {
 +        final Script command = new Script(_versionstringpath, _timeout, s_logger);
 +        final KeyValueInterpreter kvi = new KeyValueInterpreter();
 +        final String result = command.execute(kvi);
 +        if (result == null) {
 +            return kvi.getKeyValues();
 +        } else {
 +            return new HashMap<String, String>(1);
 +        }
 +    }
 +
 +    @Override
 +    public StartupCommand[] initialize() {
 +
 +        final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem);
 +
 +        final String capabilities = String.join(",", info.getCapabilities());
 +
 +        final StartupRoutingCommand cmd =
 +                new StartupRoutingCommand(info.getCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, _hypervisorType,
 +                        RouterPrivateIpStrategy.HostLocal);
 +        cmd.setCpuSockets(info.getCpuSockets());
 +        fillNetworkInformation(cmd);
 +        _privateIp = cmd.getPrivateIpAddress();
 +        cmd.getHostDetails().putAll(getVersionStrings());
 +        cmd.getHostDetails().put(KeyStoreUtils.SECURED, String.valueOf(isHostSecured()).toLowerCase());
 +        cmd.setPool(_pool);
 +        cmd.setCluster(_clusterId);
 +        cmd.setGatewayIpAddress(_localGateway);
 +        cmd.setIqn(getIqn());
 +
 +        if (cmd.getHostDetails().containsKey("Host.OS")) {
 +            _hostDistro = cmd.getHostDetails().get("Host.OS");
 +        }
 +
 +        StartupStorageCommand sscmd = null;
 +        try {
 +
 +            final KVMStoragePool localStoragePool = _storagePoolMgr.createStoragePool(_localStorageUUID, "localhost", -1, _localStoragePath, "", StoragePoolType.Filesystem);
 +            final com.cloud.agent.api.StoragePoolInfo pi =
 +                    new com.cloud.agent.api.StoragePoolInfo(localStoragePool.getUuid(), cmd.getPrivateIpAddress(), _localStoragePath, _localStoragePath,
 +                            StoragePoolType.Filesystem, localStoragePool.getCapacity(), localStoragePool.getAvailable());
 +
 +            sscmd = new StartupStorageCommand();
 +            sscmd.setPoolInfo(pi);
 +            sscmd.setGuid(pi.getUuid());
 +            sscmd.setDataCenter(_dcId);
 +            sscmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
 +        } catch (final CloudRuntimeException e) {
 +            s_logger.debug("Unable to initialize local storage pool: " + e);
 +        }
 +
 +        if (sscmd != null) {
 +            return new StartupCommand[] {cmd, sscmd};
 +        } else {
 +            return new StartupCommand[] {cmd};
 +        }
 +    }
 +
 +    public String diskUuidToSerial(String uuid) {
 +        String uuidWithoutHyphen = uuid.replace("-","");
 +        return uuidWithoutHyphen.substring(0, Math.min(uuidWithoutHyphen.length(), 20));
 +    }
 +
 +    private String getIqn() {
 +        try {
 +            final String textToFind = "InitiatorName=";
 +
 +            final Script iScsiAdmCmd = new Script(true, "grep", 0, s_logger);
 +
 +            iScsiAdmCmd.add(textToFind);
 +            iScsiAdmCmd.add("/etc/iscsi/initiatorname.iscsi");
 +
 +            final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
 +
 +            final String result = iScsiAdmCmd.execute(parser);
 +
 +            if (result != null) {
 +                return null;
 +            }
 +
 +            final String textFound = parser.getLine().trim();
 +
 +            return textFound.substring(textToFind.length());
 +        }
 +        catch (final Exception ex) {
 +            return null;
 +        }
 +    }
 +
 +    protected List<String> getAllVmNames(final Connect conn) {
 +        final ArrayList<String> la = new ArrayList<String>();
 +        try {
 +            final String names[] = conn.listDefinedDomains();
 +            for (int i = 0; i < names.length; i++) {
 +                la.add(names[i]);
 +            }
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("Failed to list Defined domains", e);
 +        }
 +
 +        int[] ids = null;
 +        try {
 +            ids = conn.listDomains();
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("Failed to list domains", e);
 +            return la;
 +        }
 +
 +        Domain dm = null;
 +        for (int i = 0; i < ids.length; i++) {
 +            try {
 +                dm = conn.domainLookupByID(ids[i]);
 +                la.add(dm.getName());
 +            } catch (final LibvirtException e) {
 +                s_logger.warn("Unable to get vms", e);
 +            } finally {
 +                try {
 +                    if (dm != null) {
 +                        dm.free();
 +                    }
 +                } catch (final LibvirtException e) {
 +                    s_logger.trace("Ignoring libvirt error.", e);
 +                }
 +            }
 +        }
 +
 +        return la;
 +    }
 +
 +    private HashMap<String, HostVmStateReportEntry> getHostVmStateReport() {
 +        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
 +        Connect conn = null;
 +
 +        if (_hypervisorType == HypervisorType.LXC) {
 +            try {
 +                conn = LibvirtConnection.getConnectionByType(HypervisorType.LXC.toString());
 +                vmStates.putAll(getHostVmStateReport(conn));
 +                conn = LibvirtConnection.getConnectionByType(HypervisorType.KVM.toString());
 +                vmStates.putAll(getHostVmStateReport(conn));
 +            } catch (final LibvirtException e) {
 +                s_logger.debug("Failed to get connection: " + e.getMessage());
 +            }
 +        }
 +
 +        if (_hypervisorType == HypervisorType.KVM) {
 +            try {
 +                conn = LibvirtConnection.getConnectionByType(HypervisorType.KVM.toString());
 +                vmStates.putAll(getHostVmStateReport(conn));
 +            } catch (final LibvirtException e) {
 +                s_logger.debug("Failed to get connection: " + e.getMessage());
 +            }
 +        }
 +
 +        return vmStates;
 +    }
 +
 +    private HashMap<String, HostVmStateReportEntry> getHostVmStateReport(final Connect conn) {
 +        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
 +
 +        String[] vms = null;
 +        int[] ids = null;
 +
 +        try {
 +            ids = conn.listDomains();
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("Unable to listDomains", e);
 +            return null;
 +        }
 +        try {
 +            vms = conn.listDefinedDomains();
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("Unable to listDomains", e);
 +            return null;
 +        }
 +
 +        Domain dm = null;
 +        for (int i = 0; i < ids.length; i++) {
 +            try {
 +                dm = conn.domainLookupByID(ids[i]);
 +
 +                final DomainState ps = dm.getInfo().state;
 +
 +                final PowerState state = convertToPowerState(ps);
 +
 +                s_logger.trace("VM " + dm.getName() + ": powerstate = " + ps + "; vm state=" + state.toString());
 +                final String vmName = dm.getName();
 +
 +                // TODO : for XS/KVM (host-based resource), we require to remove
 +                // VM completely from host, for some reason, KVM seems to still keep
 +                // Stopped VM around, to work-around that, reporting only powered-on VM
 +                //
 +                if (state == PowerState.PowerOn) {
 +                    vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName()));
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.warn("Unable to get vms", e);
 +            } finally {
 +                try {
 +                    if (dm != null) {
 +                        dm.free();
 +                    }
 +                } catch (final LibvirtException e) {
 +                    s_logger.trace("Ignoring libvirt error.", e);
 +                }
 +            }
 +        }
 +
 +        for (int i = 0; i < vms.length; i++) {
 +            try {
 +
 +                dm = conn.domainLookupByName(vms[i]);
 +
 +                final DomainState ps = dm.getInfo().state;
 +                final PowerState state = convertToPowerState(ps);
 +                final String vmName = dm.getName();
 +                s_logger.trace("VM " + vmName + ": powerstate = " + ps + "; vm state=" + state.toString());
 +
 +                // TODO : for XS/KVM (host-based resource), we require to remove
 +                // VM completely from host, for some reason, KVM seems to still keep
 +                // Stopped VM around, to work-around that, reporting only powered-on VM
 +                //
 +                if (state == PowerState.PowerOn) {
 +                    vmStates.put(vmName, new HostVmStateReportEntry(state, conn.getHostName()));
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.warn("Unable to get vms", e);
 +            } finally {
 +                try {
 +                    if (dm != null) {
 +                        dm.free();
 +                    }
 +                } catch (final LibvirtException e) {
 +                    s_logger.trace("Ignoring libvirt error.", e);
 +                }
 +            }
 +        }
 +
 +        return vmStates;
 +    }
 +
 +    public String rebootVM(final Connect conn, final String vmName) {
 +        Domain dm = null;
 +        String msg = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            // Get XML Dump including the secure information such as VNC password
 +            // By passing 1, or VIR_DOMAIN_XML_SECURE flag
 +            // https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainXMLFlags
 +            String vmDef = dm.getXMLDesc(1);
 +            final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
 +            parser.parseDomainXML(vmDef);
 +            for (final InterfaceDef nic : parser.getInterfaces()) {
 +                if (nic.getNetType() == GuestNetType.BRIDGE && nic.getBrName().startsWith("cloudVirBr")) {
 +                    try {
 +                        final int vnetId = Integer.parseInt(nic.getBrName().replaceFirst("cloudVirBr", ""));
 +                        final String pifName = getPif(_guestBridgeName);
 +                        final String newBrName = "br" + pifName + "-" + vnetId;
 +                        vmDef = vmDef.replaceAll("'" + nic.getBrName() + "'", "'" + newBrName + "'");
 +                        s_logger.debug("VM bridge name is changed from " + nic.getBrName() + " to " + newBrName);
 +                    } catch (final NumberFormatException e) {
 +                        continue;
 +                    }
 +                }
 +            }
 +            s_logger.debug(vmDef);
 +            msg = stopVM(conn, vmName, false);
 +            msg = startVM(conn, vmName, vmDef);
 +            return null;
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("Failed to create vm", e);
 +            msg = e.getMessage();
 +        } catch (final InternalErrorException e) {
 +            s_logger.warn("Failed to create vm", e);
 +            msg = e.getMessage();
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.trace("Ignoring libvirt error.", e);
 +            }
 +        }
 +
 +        return msg;
 +    }
 +
 +    public String stopVM(final Connect conn, final String vmName, final boolean forceStop) {
 +        DomainState state = null;
 +        Domain dm = null;
 +
 +        // delete the metadata of vm snapshots before stopping
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            cleanVMSnapshotMetadata(dm);
 +        } catch (LibvirtException e) {
 +            s_logger.debug("Failed to get vm :" + e.getMessage());
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (LibvirtException l) {
 +                s_logger.trace("Ignoring libvirt error.", l);
 +            }
 +        }
 +
 +        s_logger.debug("Try to stop the vm at first");
 +        if (forceStop) {
 +            return stopVMInternal(conn, vmName, true);
 +        }
 +        String ret = stopVMInternal(conn, vmName, false);
 +        if (ret == Script.ERR_TIMEOUT) {
 +            ret = stopVMInternal(conn, vmName, true);
 +        } else if (ret != null) {
 +            /*
 +             * There is a race condition between libvirt and qemu: libvirt
 +             * listens on qemu's monitor fd. If qemu is shutdown, while libvirt
 +             * is reading on the fd, then libvirt will report an error.
 +             */
 +            /* Retry 3 times, to make sure we can get the vm's status */
 +            for (int i = 0; i < 3; i++) {
 +                try {
 +                    dm = conn.domainLookupByName(vmName);
 +                    state = dm.getInfo().state;
 +                    break;
 +                } catch (final LibvirtException e) {
 +                    s_logger.debug("Failed to get vm status:" + e.getMessage());
 +                } finally {
 +                    try {
 +                        if (dm != null) {
 +                            dm.free();
 +                        }
 +                    } catch (final LibvirtException l) {
 +                        s_logger.trace("Ignoring libvirt error.", l);
 +                    }
 +                }
 +            }
 +
 +            if (state == null) {
 +                s_logger.debug("Can't get vm's status, assume it's dead already");
 +                return null;
 +            }
 +
 +            if (state != DomainState.VIR_DOMAIN_SHUTOFF) {
 +                s_logger.debug("Try to destroy the vm");
 +                ret = stopVMInternal(conn, vmName, true);
 +                if (ret != null) {
 +                    return ret;
 +                }
 +            }
 +        }
 +
 +        return null;
 +    }
 +
 +    protected String stopVMInternal(final Connect conn, final String vmName, final boolean force) {
 +        Domain dm = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            final int persist = dm.isPersistent();
 +            if (force) {
 +                if (dm.isActive() == 1) {
 +                    dm.destroy();
 +                    if (persist == 1) {
 +                        dm.undefine();
 +                    }
 +                }
 +            } else {
 +                if (dm.isActive() == 0) {
 +                    return null;
 +                }
 +                dm.shutdown();
 +                int retry = _stopTimeout / 2000;
 +                /* Wait for the domain gets into shutoff state. When it does
 +                   the dm object will no longer work, so we need to catch it. */
 +                try {
 +                    while (dm.isActive() == 1 && retry >= 0) {
 +                        Thread.sleep(2000);
 +                        retry--;
 +                    }
 +                } catch (final LibvirtException e) {
 +                    final String error = e.toString();
 +                    if (error.contains("Domain not found")) {
 +                        s_logger.debug("successfully shut down vm " + vmName);
 +                    } else {
 +                        s_logger.debug("Error in waiting for vm shutdown:" + error);
 +                    }
 +                }
 +                if (retry < 0) {
 +                    s_logger.warn("Timed out waiting for domain " + vmName + " to shutdown gracefully");
 +                    return Script.ERR_TIMEOUT;
 +                } else {
 +                    if (persist == 1) {
 +                        dm.undefine();
 +                    }
 +                }
 +            }
 +        } catch (final LibvirtException e) {
 +            if (e.getMessage().contains("Domain not found")) {
 +                s_logger.debug("VM " + vmName + " doesn't exist, no need to stop it");
 +                return null;
 +            }
 +            s_logger.debug("Failed to stop VM :" + vmName + " :", e);
 +            return e.getMessage();
 +        } catch (final InterruptedException ie) {
 +            s_logger.debug("Interrupted sleep");
 +            return ie.getMessage();
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.trace("Ignoring libvirt error.", e);
 +            }
 +        }
 +
 +        return null;
 +    }
 +
 +    public Integer getVncPort(final Connect conn, final String vmName) throws LibvirtException {
 +        final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
 +        Domain dm = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            final String xmlDesc = dm.getXMLDesc(0);
 +            parser.parseDomainXML(xmlDesc);
 +            return parser.getVncPort();
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (final LibvirtException l) {
 +                s_logger.trace("Ignoring libvirt error.", l);
 +            }
 +        }
 +    }
 +
 +    private boolean IsHVMEnabled(final Connect conn) {
 +        final LibvirtCapXMLParser parser = new LibvirtCapXMLParser();
 +        try {
 +            parser.parseCapabilitiesXML(conn.getCapabilities());
 +            final ArrayList<String> osTypes = parser.getGuestOsType();
 +            for (final String o : osTypes) {
 +                if (o.equalsIgnoreCase("hvm")) {
 +                    return true;
 +                }
 +            }
 +        } catch (final LibvirtException e) {
 +            s_logger.trace("Ignoring libvirt error.", e);
 +        }
 +        return false;
 +    }
 +
 +    private String getHypervisorPath(final Connect conn) {
 +        final LibvirtCapXMLParser parser = new LibvirtCapXMLParser();
 +        try {
 +            parser.parseCapabilitiesXML(conn.getCapabilities());
 +        } catch (final LibvirtException e) {
 +            s_logger.debug(e.getMessage());
 +        }
 +        return parser.getEmulator();
 +    }
 +
 +    boolean isGuestPVEnabled(final String guestOSName) {
 +        DiskDef.DiskBus db = getGuestDiskModel(guestOSName);
 +        return db != DiskDef.DiskBus.IDE;
 +    }
 +
 +    public boolean isCentosHost() {
 +        if (_hvVersion <= 9) {
 +            return true;
 +        } else {
 +            return false;
 +        }
 +    }
 +
 +    public DiskDef.DiskBus getDiskModelFromVMDetail(final VirtualMachineTO vmTO) {
 +        Map<String, String> details = vmTO.getDetails();
 +        if (details == null) {
 +            return null;
 +        }
 +
 +        final String rootDiskController = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER);
 +        if (StringUtils.isNotBlank(rootDiskController)) {
 +            s_logger.debug("Passed custom disk bus " + rootDiskController);
 +            for (final DiskDef.DiskBus bus : DiskDef.DiskBus.values()) {
 +                if (bus.toString().equalsIgnoreCase(rootDiskController)) {
 +                    s_logger.debug("Found matching enum for disk bus " + rootDiskController);
 +                    return bus;
 +                }
 +            }
 +        }
 +        return null;
 +    }
 +
 +    private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator) {
 +        if (platformEmulator == null) {
 +            return DiskDef.DiskBus.IDE;
 +        } else if (platformEmulator.startsWith("Other PV Virtio-SCSI")) {
 +            return DiskDef.DiskBus.SCSI;
 +        } else if (platformEmulator.startsWith("Ubuntu") || platformEmulator.startsWith("Fedora 13") || platformEmulator.startsWith("Fedora 12") || platformEmulator.startsWith("Fedora 11") ||
 +                platformEmulator.startsWith("Fedora 10") || platformEmulator.startsWith("Fedora 9") || platformEmulator.startsWith("CentOS 5.3") || platformEmulator.startsWith("CentOS 5.4") ||
 +                platformEmulator.startsWith("CentOS 5.5") || platformEmulator.startsWith("CentOS") || platformEmulator.startsWith("Fedora") ||
 +                platformEmulator.startsWith("Red Hat Enterprise Linux 5.3") || platformEmulator.startsWith("Red Hat Enterprise Linux 5.4") ||
 +                platformEmulator.startsWith("Red Hat Enterprise Linux 5.5") || platformEmulator.startsWith("Red Hat Enterprise Linux 6") || platformEmulator.startsWith("Debian GNU/Linux") ||
 +                platformEmulator.startsWith("FreeBSD 10") || platformEmulator.startsWith("Oracle") || platformEmulator.startsWith("Other PV")) {
 +            return DiskDef.DiskBus.VIRTIO;
 +        } else {
 +            return DiskDef.DiskBus.IDE;
 +        }
 +
 +    }
 +    private void cleanupVMNetworks(final Connect conn, final List<InterfaceDef> nics) {
 +        if (nics != null) {
 +            for (final InterfaceDef nic : nics) {
 +                for (final VifDriver vifDriver : getAllVifDrivers()) {
 +                    vifDriver.unplug(nic);
 +                }
 +            }
 +        }
 +    }
 +
 +    public Domain getDomain(final Connect conn, final String vmName) throws LibvirtException {
 +        return conn.domainLookupByName(vmName);
 +    }
 +
 +    public List<InterfaceDef> getInterfaces(final Connect conn, final String vmName) {
 +        final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
 +        Domain dm = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            parser.parseDomainXML(dm.getXMLDesc(0));
 +            return parser.getInterfaces();
 +
 +        } catch (final LibvirtException e) {
 +            s_logger.debug("Failed to get dom xml: " + e.toString());
 +            return new ArrayList<InterfaceDef>();
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.trace("Ignoring libvirt error.", e);
 +            }
 +        }
 +    }
 +
 +    public List<DiskDef> getDisks(final Connect conn, final String vmName) {
 +        final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
 +        Domain dm = null;
 +        try {
 +            dm = conn.domainLookupByName(vmName);
 +            parser.parseDomainXML(dm.getXMLDesc(0));
 +            return parser.getDisks();
 +
 +        } catch (final LibvirtException e) {
 +            s_logger.debug("Failed to get dom xml: " + e.toString());
 +            return new ArrayList<DiskDef>();
 +        } finally {
 +            try {
 +                if (dm != null) {
 +                    dm.free();
 +                }
 +            } catch (final LibvirtException e) {
 +                s_logger.trace("Ignoring libvirt error.", e);
 +            }
 +        }
 +    }
 +
 +    private String executeBashScript(final String script) {
 +        final Script command = new Script("/bin/bash", _timeout, s_logger);
 +        command.add("-c");
 +        command.add(script);
 +        return command.execute();
 +    }
 +
 +    public List<VmNetworkStatsEntry> getVmNetworkStat(Connect conn, String vmName) throws LibvirtException {
 +        Domain dm = null;
 +        try {
 +            dm = getDomain(conn, vmName);
 +
 +            List<VmNetworkStatsEntry> stats = new ArrayList<VmNetworkStatsEntry>();
 +
 +            List<InterfaceDef> nics = getInterfaces(conn, vmName);
 +
 +            for (InterfaceDef nic : nics) {
 +                DomainInterfaceStats nicStats = dm.interfaceStats(nic.getDevName());
 +                String macAddress = nic.getMacAddress();
 +                VmNetworkStatsEntry stat = new VmNetworkStatsEntry(vmName, macAddress, nicStats.tx_bytes, nicStats.rx_bytes);
 +                stats.add(stat);
 +            }
 +
 +            return stats;
 +        } finally {
 +            if (dm != null) {
 +                dm.free();
 +            }
 +        }
 +    }
 +
 +    public List<VmDiskStatsEntry> getVmDiskStat(final Connect conn, final String vmName) throws LibvirtException {
 +        Domain dm = null;
 +        try {
 +            dm = getDomain(conn, vmName);
 +
 +            final List<VmDiskStatsEntry> stats = new ArrayList<VmDiskStatsEntry>();
 +
 +            final List<DiskDef> disks = getDisks(conn, vmName);
 +
 +            for (final DiskDef disk : disks) {
 +                if (disk.getDeviceType() != DeviceType.DISK) {
 +                    break;
 +                }
 +                final DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
 +                final String path = disk.getDiskPath(); // for example, path = /mnt/pool_uuid/disk_path/
 +                String diskPath = null;
 +                if (path != null) {
 +                    final String[] token = path.split("/");
 +                    if (token.length > 3) {
 +                        diskPath = token[3];
 +                        final VmDiskStatsEntry stat = new VmDiskStatsEntry(vmName, diskPath, blockStats.wr_req, blockStats.rd_req, blockStats.wr_bytes, blockStats.rd_bytes);
 +                        stats.add(stat);
 +                    }
 +                }
 +            }
 +
 +            return stats;
 +        } finally {
 +            if (dm != null) {
 +                dm.free();
 +            }
 +        }
 +    }
 +
 +    private class VmStats {
 +        long _usedTime;
 +        long _tx;
 +        long _rx;
 +        long _ioRead;
 +        long _ioWrote;
 +        long _bytesRead;
 +        long _bytesWrote;
 +        Calendar _timestamp;
 +    }
 +
 +    public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws LibvirtException {
 +        Domain dm = null;
 +        try {
 +            dm = getDomain(conn, vmName);
 +            if (dm == null) {
 +                return null;
 +            }
 +            DomainInfo info = dm.getInfo();
 +            final VmStatsEntry stats = new VmStatsEntry();
 +
 +            stats.setNumCPUs(info.nrVirtCpu);
 +            stats.setEntityType("vm");
 +
 +            stats.setMemoryKBs(info.maxMem);
 +            stats.setTargetMemoryKBs(info.memory);
 +            stats.setIntFreeMemoryKBs(getMemoryFreeInKBs(dm));
 +
 +            /* get cpu utilization */
 +            VmStats oldStats = null;
 +
 +            final Calendar now = Calendar.getInstance();
 +
 +            oldStats = _vmStats.get(vmName);
 +
 +            long elapsedTime = 0;
 +            if (oldStats != null) {
 +                elapsedTime = now.getTimeInMillis() - oldStats._timestamp.getTimeInMillis();
 +                double utilization = (info.cpuTime - oldStats._usedTime) / ((double)elapsedTime * 1000000);
 +
 +                final NodeInfo node = conn.nodeInfo();
 +                utilization = utilization / node.cpus;
 +                if (utilization > 0) {
 +                    stats.setCPUUtilization(utilization * 100);
 +                }
 +            }
 +
 +            /* get network stats */
 +
 +            final List<InterfaceDef> vifs = getInterfaces(conn, vmName);
 +            long rx = 0;
 +            long tx = 0;
 +            for (final InterfaceDef vif : vifs) {
 +                final DomainInterfaceStats ifStats = dm.interfaceStats(vif.getDevName());
 +                rx += ifStats.rx_bytes;
 +                tx += ifStats.tx_bytes;
 +            }
 +
 +            if (oldStats != null) {
 +                final double deltarx = rx - oldStats._rx;
 +                if (deltarx > 0) {
 +                    stats.setNetworkReadKBs(deltarx / 1024);
 +                }
 +                final double deltatx = tx - oldStats._tx;
 +                if (deltatx > 0) {
 +                    stats.setNetworkWriteKBs(deltatx / 1024);
 +                }
 +            }
 +
 +            /* get disk stats */
 +            final List<DiskDef> disks = getDisks(conn, vmName);
 +            long io_rd = 0;
 +            long io_wr = 0;
 +            long bytes_rd = 0;
 +            long bytes_wr = 0;
 +            for (final DiskDef disk : disks) {
 +                if (disk.getDeviceType() == DeviceType.CDROM || disk.getDeviceType() == DeviceType.FLOPPY) {
 +                    continue;
 +                }
 +                final DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
 +                io_rd += blockStats.rd_req;
 +                io_wr += blockStats.wr_req;
 +                bytes_rd += blockStats.rd_bytes;
 +                bytes_wr += blockStats.wr_bytes;
 +            }
 +
 +            if (oldStats != null) {
 +                final long deltaiord = io_rd - oldStats._ioRead;
 +                if (deltaiord > 0) {
 +                    stats.setDiskReadIOs(deltaiord);
 +                }
 +                final long deltaiowr = io_wr - oldStats._ioWrote;
 +                if (deltaiowr > 0) {
 +                    stats.setDiskWriteIOs(deltaiowr);
 +                }
 +                final double deltabytesrd = bytes_rd - oldStats._bytesRead;
 +                if (deltabytesrd > 0) {
 +                    stats.setDiskReadKBs(deltabytesrd / 1024);
 +                }
 +                final double deltabyteswr = bytes_wr - oldStats._bytesWrote;
 +                if (deltabyteswr > 0) {
 +                    stats.setDiskWriteKBs(deltabyteswr / 1024);
 +                }
 +            }
 +
 +            /* save to Hashmap */
 +            final VmStats newStat = new VmStats();
 +            newStat._usedTime = info.cpuTime;
 +            newStat._rx = rx;
 +            newStat._tx = tx;
 +            newStat._ioRead = io_rd;
 +            newStat._ioWrote = io_wr;
 +            newStat._bytesRead = bytes_rd;
 +            newStat._bytesWrote = bytes_wr;
 +            newStat._timestamp = now;
 +            _vmStats.put(vmName, newStat);
 +            return stats;
 +        } finally {
 +            if (dm != null) {
 +                dm.free();
 +            }
 +        }
 +    }
 +
 +    /**
 +     * This method retrieves the memory statistics from the domain given as parameters.
 +     * If no memory statistic is found, it will return {@link NumberUtils#LONG_ZERO} as the value of free memory in the domain.
 +     * If it can retrieve the domain memory statistics, it will return the free memory statistic; that means, it returns the value at the first position of the array returned by {@link Domain#memoryStats(int)}.
 +     *
 +     * @return the amount of free memory in KBs
 +     */
 +    protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException {
 +        MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS);
 +        if (ArrayUtils.isEmpty(mems)) {
 +            return NumberUtils.LONG_ZERO;
 +        }
 +        return mems[0].getValue();
 +    }
 +
 +    private boolean canBridgeFirewall(final String prvNic) {
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("can_bridge_firewall");
 +        cmd.add("--privnic", prvNic);
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean destroyNetworkRulesForVM(final Connect conn, final String vmName) {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +        String vif = null;
 +        final List<InterfaceDef> intfs = getInterfaces(conn, vmName);
 +        if (intfs.size() > 0) {
 +            final InterfaceDef intf = intfs.get(0);
 +            vif = intf.getDevName();
 +        }
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("destroy_network_rules_for_vm");
 +        cmd.add("--vmname", vmName);
 +        if (vif != null) {
 +            cmd.add("--vif", vif);
 +        }
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean defaultNetworkRules(final Connect conn, final String vmName, final NicTO nic, final Long vmId, final String secIpStr) {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +
 +        final List<InterfaceDef> intfs = getInterfaces(conn, vmName);
 +        if (intfs.size() == 0 || intfs.size() < nic.getDeviceId()) {
 +            return false;
 +        }
 +
 +        final InterfaceDef intf = intfs.get(nic.getDeviceId());
 +        final String brname = intf.getBrName();
 +        final String vif = intf.getDevName();
 +
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("default_network_rules");
 +        cmd.add("--vmname", vmName);
 +        cmd.add("--vmid", vmId.toString());
 +        if (nic.getIp() != null) {
 +            cmd.add("--vmip", nic.getIp());
 +        }
 +        if (nic.getIp6Address() != null) {
 +            cmd.add("--vmip6", nic.getIp6Address());
 +        }
 +        cmd.add("--vmmac", nic.getMac());
 +        cmd.add("--vif", vif);
 +        cmd.add("--brname", brname);
 +        cmd.add("--nicsecips", secIpStr);
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    protected boolean post_default_network_rules(final Connect conn, final String vmName, final NicTO nic, final Long vmId, final InetAddress dhcpServerIp, final String hostIp, final String hostMacAddr) {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +
 +        final List<InterfaceDef> intfs = getInterfaces(conn, vmName);
 +        if (intfs.size() < nic.getDeviceId()) {
 +            return false;
 +        }
 +
 +        final InterfaceDef intf = intfs.get(nic.getDeviceId());
 +        final String brname = intf.getBrName();
 +        final String vif = intf.getDevName();
 +
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("post_default_network_rules");
 +        cmd.add("--vmname", vmName);
 +        cmd.add("--vmid", vmId.toString());
 +        cmd.add("--vmip", nic.getIp());
 +        cmd.add("--vmmac", nic.getMac());
 +        cmd.add("--vif", vif);
 +        cmd.add("--brname", brname);
 +        if (dhcpServerIp != null) {
 +            cmd.add("--dhcpSvr", dhcpServerIp.getHostAddress());
 +        }
 +
 +        cmd.add("--hostIp", hostIp);
 +        cmd.add("--hostMacAddr", hostMacAddr);
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean configureDefaultNetworkRulesForSystemVm(final Connect conn, final String vmName) {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("default_network_rules_systemvm");
 +        cmd.add("--vmname", vmName);
 +        cmd.add("--localbrname", _linkLocalBridgeName);
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean addNetworkRules(final String vmName, final String vmId, final String guestIP, final String guestIP6, final String sig, final String seq, final String mac, final String rules, final String vif, final String brname,
 +                                   final String secIps) {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +
 +        final String newRules = rules.replace(" ", ";");
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("add_network_rules");
 +        cmd.add("--vmname", vmName);
 +        cmd.add("--vmid", vmId);
 +        cmd.add("--vmip", guestIP);
 +        if (StringUtils.isNotBlank(guestIP6)) {
 +            cmd.add("--vmip6", guestIP6);
 +        }
 +        cmd.add("--sig", sig);
 +        cmd.add("--seq", seq);
 +        cmd.add("--vmmac", mac);
 +        cmd.add("--vif", vif);
 +        cmd.add("--brname", brname);
 +        cmd.add("--nicsecips", secIps);
 +        if (newRules != null && !newRules.isEmpty()) {
 +            cmd.add("--rules", newRules);
 +        }
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean configureNetworkRulesVMSecondaryIP(final Connect conn, final String vmName, final String secIp, final String action) {
 +
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("network_rules_vmSecondaryIp");
 +        cmd.add("--vmname", vmName);
 +        cmd.add("--nicsecips", secIp);
 +        cmd.add("--action", action);
 +
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public boolean cleanupRules() {
 +        if (!_canBridgeFirewall) {
 +            return false;
 +        }
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("cleanup_rules");
 +        final String result = cmd.execute();
 +        if (result != null) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    public String getRuleLogsForVms() {
 +        final Script cmd = new Script(_securityGroupPath, _timeout, s_logger);
 +        cmd.add("get_rule_logs_for_vms");
 +        final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
 +        final String result = cmd.execute(parser);
 +        if (result == null) {
 +            return parser.getLine();
 +        }
 +        return null;
 +    }
 +
 +    private HashMap<String, Pair<Long, Long>> syncNetworkGroups(final long id) {
 +        final HashMap<String, Pair<Long, Long>> states = new HashMap<String, Pair<Long, Long>>();
 +
 +        final String result = getRuleLogsForVms();
 +        s_logger.trace("syncNetworkGroups: id=" + id + " got: " + result);
 +        final String[] rulelogs = result != null ? result.split(";") : new String[0];
 +        for (final String rulesforvm : rulelogs) {
 +            final String[] log = rulesforvm.split(",");
 +            if (log.length != 6) {
 +                continue;
 +            }
 +            try {
 +                states.put(log[0], new Pair<Long, Long>(Long.parseLong(log[1]), Long.parseLong(log[5])));
 +            } catch (final NumberFormatException nfe) {
 +                states.put(log[0], new Pair<Long, Long>(-1L, -1L));
 +            }
 +        }
 +        return states;
 +    }
 +
 +    /* online snapshot supported by enhanced qemu-kvm */
 +    private boolean isSnapshotSupported() {
 +        final String result = executeBashScript("qemu-img --help|grep convert");
 +        if (result != null) {
 +            return false;
 +        } else {
 +            return true;
 +        }
 +    }
 +
 +    public Pair<Double, Double> getNicStats(final String nicName) {
 +        return new Pair<Double, Double>(readDouble(nicName, "rx_bytes"), readDouble(nicName, "tx_bytes"));
 +    }
 +
 +    static double readDouble(final String nicName, final String fileName) {
 +        final String path = "/sys/class/net/" + nicName + "/statistics/" + fileName;
 +        try {
 +            return Double.parseDouble(FileUtils.readFileToString(new File(path)));
 +        } catch (final IOException ioe) {
 +            s_logger.warn("Failed to read the " + fileName + " for " + nicName + " from " + path, ioe);
 +            return 0.0;
 +        }
 +    }
 +
 +    private String prettyVersion(final long version) {
 +        final long major = version / 1000000;
 +        final long minor = version % 1000000 / 1000;
 +        final long release = version % 1000000 % 1000;
 +        return major + "." + minor + "." + release;
 +    }
 +
 +    @Override
 +    public void setName(final String name) {
 +        // TODO Auto-generated method stub
 +    }
 +
 +    @Override
 +    public void setConfigParams(final Map<String, Object> params) {
 +        // TODO Auto-generated method stub
 +    }
 +
 +    @Override
 +    public Map<String, Object> getConfigParams() {
 +        // TODO Auto-generated method stub
 +        return null;
 +    }
 +
 +    @Override
 +    public int getRunLevel() {
 +        // TODO Auto-generated method stub
 +        return 0;
 +    }
 +
 +    @Override
 +    public void setRunLevel(final int level) {
 +        // TODO Auto-generated method stub
 +    }
 +
 +    public HypervisorType getHypervisorType(){
 +        return _hypervisorType;
 +    }
 +
 +    public String mapRbdDevice(final KVMPhysicalDisk disk){
 +        final KVMStoragePool pool = disk.getPool();
 +        //Check if rbd image is already mapped
 +        final String[] splitPoolImage = disk.getPath().split("/");
 +        String device = Script.runSimpleBashScript("rbd showmapped | grep \""+splitPoolImage[0]+"[ ]*"+splitPoolImage[1]+"\" | grep -o \"[^ ]*[ ]*$\"");
 +        if(device == null) {
 +            //If not mapped, map and return mapped device
 +            Script.runSimpleBashScript("rbd map " + disk.getPath() + " --id " + pool.getAuthUserName());
 +            device = Script.runSimpleBashScript("rbd showmapped | grep \""+splitPoolImage[0]+"[ ]*"+splitPoolImage[1]+"\" | grep -o \"[^ ]*[ ]*$\"");
 +        }
 +        return device;
 +    }
 +
 +    public List<Ternary<String, Boolean, String>> cleanVMSnapshotMetadata(Domain dm) throws LibvirtException {
 +        s_logger.debug("Cleaning the metadata of vm snapshots of vm " + dm.getName());
 +        List<Ternary<String, Boolean, String>> vmsnapshots = new ArrayList<Ternary<String, Boolean, String>>();
 +        if (dm.snapshotNum() == 0) {
 +            return vmsnapshots;
 +        }
 +        String currentSnapshotName = null;
 +        try {
 +            DomainSnapshot snapshotCurrent = dm.snapshotCurrent();
 +            String snapshotXML = snapshotCurrent.getXMLDesc();
 +            snapshotCurrent.free();
 +            DocumentBuilder builder;
 +            try {
 +                builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 +
 +                InputSource is = new InputSource();
 +                is.setCharacterStream(new StringReader(snapshotXML));
 +                Document doc = builder.parse(is);
 +                Element rootElement = doc.getDocumentElement();
 +
 +                currentSnapshotName = getTagValue("name", rootElement);
 +            } catch (ParserConfigurationException e) {
 +                s_logger.debug(e.toString());
 +            } catch (SAXException e) {
 +                s_logger.debug(e.toString());
 +            } catch (IOException e) {
 +                s_logger.debug(e.toString());
 +            }
 +        } catch (LibvirtException e) {
 +            s_logger.debug("Fail to get the current vm snapshot for vm: " + dm.getName() + ", continue");
 +        }
 +        int flags = 2; // VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY = 2
 +        String[] snapshotNames = dm.snapshotListNames();
 +        Arrays.sort(snapshotNames);
 +        for (String snapshotName: snapshotNames) {
 +            DomainSnapshot snapshot = dm.snapshotLookupByName(snapshotName);
 +            Boolean isCurrent = (currentSnapshotName != null && currentSnapshotName.equals(snapshotName)) ? true: false;
 +            vmsnapshots.add(new Ternary<String, Boolean, String>(snapshotName, isCurrent, snapshot.getXMLDesc()));
 +        }
 +        for (String snapshotName: snapshotNames) {
 +            DomainSnapshot snapshot = dm.snapshotLookupByName(snapshotName);
 +            snapshot.delete(flags); // clean metadata of vm snapshot
 +        }
 +        return vmsnapshots;
 +    }
 +
 +    private static String getTagValue(String tag, Element eElement) {
 +        NodeList nlList = eElement.getElementsByTagName(tag).item(0).getChildNodes();
 +        Node nValue = nlList.item(0);
 +
 +        return nValue.getNodeValue();
 +    }
 +
 +    public void restoreVMSnapshotMetadata(Domain dm, String vmName, List<Ternary<String, Boolean, String>> vmsnapshots) {
 +        s_logger.debug("Restoring the metadata of vm snapshots of vm " + vmName);
 +        for (Ternary<String, Boolean, String> vmsnapshot: vmsnapshots) {
 +            String snapshotName = vmsnapshot.first();
 +            Boolean isCurrent = vmsnapshot.second();
 +            String snapshotXML = vmsnapshot.third();
 +            s_logger.debug("Restoring vm snapshot " + snapshotName + " on " + vmName + " with XML:\n " + snapshotXML);
 +            try {
 +                int flags = 1; // VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE = 1
 +                if (isCurrent) {
 +                    flags += 2; // VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT = 2
 +                }
 +                dm.snapshotCreateXML(snapshotXML, flags);
 +            } catch (LibvirtException e) {
 +                s_logger.debug("Failed to restore vm snapshot " + snapshotName + ", continue");
 +                continue;
 +            }
 +        }
 +    }
 +
 +    public String getHostDistro() {
 +        return _hostDistro;
 +    }
 +
 +    public boolean isHostSecured() {
 +        // Test for host certificates
 +        final File confFile = PropertiesUtil.findConfigFile(KeyStoreUtils.AGENT_PROPSFILE);
 +        if (confFile == null || !confFile.exists() || !Paths.get(confFile.getParent(), KeyStoreUtils.CERT_FILENAME).toFile().exists()) {
 +            return false;
 +        }
 +
 +        // Test for libvirt TLS configuration
 +        try {
 +            new Connect(String.format("qemu+tls://%s/system", _privateIp));
 +        } catch (final LibvirtException ignored) {
 +            return false;
 +        }
 +        return true;
 +    }
 +}
diff --cc plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java
index da9f1f3,0000000..f3839f0
mode 100644,000000..100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java
@@@ -1,157 -1,0 +1,162 @@@
 +//
 +// 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.wrapper;
 +
 +import java.net.URISyntaxException;
 +import java.util.List;
 +
 +import org.apache.log4j.Logger;
 +import org.libvirt.Connect;
 +import org.libvirt.DomainInfo.DomainState;
 +import org.libvirt.LibvirtException;
 +
 +import com.cloud.agent.api.Answer;
 +import com.cloud.agent.api.StartAnswer;
 +import com.cloud.agent.api.StartCommand;
 +import com.cloud.agent.api.to.NicTO;
 +import com.cloud.agent.api.to.VirtualMachineTO;
 +import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
 +import com.cloud.exception.InternalErrorException;
 +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
 +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
 +import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
 +import com.cloud.network.Networks.IsolationType;
 +import com.cloud.network.Networks.TrafficType;
 +import com.cloud.resource.CommandWrapper;
 +import com.cloud.resource.ResourceWrapper;
 +import com.cloud.vm.VirtualMachine;
 +
 +@ResourceWrapper(handles =  StartCommand.class)
 +public final class LibvirtStartCommandWrapper extends CommandWrapper<StartCommand, Answer, LibvirtComputingResource> {
 +
 +    private static final Logger s_logger = Logger.getLogger(LibvirtStartCommandWrapper.class);
 +
 +    @Override
 +    public Answer execute(final StartCommand command, final LibvirtComputingResource libvirtComputingResource) {
 +        final VirtualMachineTO vmSpec = command.getVirtualMachine();
 +        vmSpec.setVncAddr(command.getHostIp());
 +        final String vmName = vmSpec.getName();
 +        LibvirtVMDef vm = null;
 +
 +        DomainState  state = DomainState.VIR_DOMAIN_SHUTOFF;
 +        final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
 +        final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
 +        Connect conn = null;
 +        try {
 +
 +            vm = libvirtComputingResource.createVMFromSpec(vmSpec);
 +            conn = libvirtUtilitiesHelper.getConnectionByType(vm.getHvsType());
 +
 +            final NicTO[] nics = vmSpec.getNics();
 +
 +            for (final NicTO nic : nics) {
 +                if (vmSpec.getType() != VirtualMachine.Type.User) {
 +                    nic.setPxeDisable(true);
 +                    nic.setDpdkDisabled(true);
 +                }
 +            }
 +
 +            libvirtComputingResource.createVbd(conn, vmSpec, vmName, vm);
 +
 +            if (!storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)) {
 +                return new StartAnswer(command, "Failed to connect physical disks to host");
 +            }
 +
 +            libvirtComputingResource.createVifs(vmSpec, vm);
 +
 +            s_logger.debug("starting " + vmName + ": " + vm.toString());
 +            libvirtComputingResource.startVM(conn, vmName, vm.toString());
 +
 +            for (final NicTO nic : nics) {
 +                if (nic.isSecurityGroupEnabled() || nic.getIsolationUri() != null && nic.getIsolationUri().getScheme().equalsIgnoreCase(IsolationType.Ec2.toString())) {
 +                    if (vmSpec.getType() != VirtualMachine.Type.User) {
 +                        libvirtComputingResource.configureDefaultNetworkRulesForSystemVm(conn, vmName);
 +                        break;
 +                    } else {
 +                        final List<String> nicSecIps = nic.getNicSecIps();
 +                        String secIpsStr;
 +                        final StringBuilder sb = new StringBuilder();
 +                        if (nicSecIps != null) {
 +                            for (final String ip : nicSecIps) {
 +                                sb.append(ip).append(";");
 +                            }
 +                            secIpsStr = sb.toString();
 +                        } else {
 +                            secIpsStr = "0;";
 +                        }
 +                        libvirtComputingResource.defaultNetworkRules(conn, vmName, nic, vmSpec.getId(), secIpsStr);
 +                    }
 +                }
 +            }
 +
 +            // pass cmdline info to system vms
 +            if (vmSpec.getType() != VirtualMachine.Type.User) {
 +                String controlIp = null;
 +                for (final NicTO nic : nics) {
 +                    if (nic.getType() == TrafficType.Control) {
 +                        controlIp = nic.getIp();
 +                        break;
 +                    }
 +                }
 +                // try to patch and SSH into the systemvm for up to 5 minutes
 +                for (int count = 0; count < 10; count++) {
 +                    // wait and try passCmdLine for 30 seconds at most for CLOUDSTACK-2823
-                     libvirtComputingResource.passCmdLine(vmName, vmSpec.getBootArgs());
-                     // check router is up?
-                     final VirtualRoutingResource virtRouterResource = libvirtComputingResource.getVirtRouterResource();
++                    if (libvirtComputingResource.passCmdLine(vmName, vmSpec.getBootArgs())) {
++                        break;
++                    }
++                }
++
++                final VirtualRoutingResource virtRouterResource = libvirtComputingResource.getVirtRouterResource();
++                // check if the router is up?
++                for (int count = 0; count < 60; count++) {
 +                    final boolean result = virtRouterResource.connect(controlIp, 1, 5000);
 +                    if (result) {
 +                        break;
 +                    }
 +                }
 +            }
 +
 +            state = DomainState.VIR_DOMAIN_RUNNING;
 +            return new StartAnswer(command);
 +        } catch (final LibvirtException e) {
 +            s_logger.warn("LibvirtException ", e);
 +            if (conn != null) {
 +                libvirtComputingResource.handleVmStartFailure(conn, vmName, vm);
 +            }
 +            return new StartAnswer(command, e.getMessage());
 +        } catch (final InternalErrorException e) {
 +            s_logger.warn("InternalErrorException ", e);
 +            if (conn != null) {
 +                libvirtComputingResource.handleVmStartFailure(conn, vmName, vm);
 +            }
 +            return new StartAnswer(command, e.getMessage());
 +        } catch (final URISyntaxException e) {
 +            s_logger.warn("URISyntaxException ", e);
 +            if (conn != null) {
 +                libvirtComputingResource.handleVmStartFailure(conn, vmName, vm);
 +            }
 +            return new StartAnswer(command, e.getMessage());
 +        } finally {
 +            if (state != DomainState.VIR_DOMAIN_RUNNING) {
 +                storagePoolMgr.disconnectPhysicalDisksViaVmSpec(vmSpec);
 +            }
 +        }
 +    }
 +}
diff --cc server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
index 68c1233,0000000..c4bcb4e
mode 100644,000000..100644
--- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
@@@ -1,1382 -1,0 +1,1375 @@@
 +// 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.server;
 +
- import java.io.DataInputStream;
- import java.io.EOFException;
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileNotFoundException;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
++import java.nio.file.Files;
 +import java.security.NoSuchAlgorithmException;
 +import java.sql.PreparedStatement;
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +import java.util.Set;
 +import java.util.UUID;
 +
 +import javax.crypto.KeyGenerator;
 +import javax.crypto.SecretKey;
 +import javax.inject.Inject;
 +import javax.naming.ConfigurationException;
 +
 +import org.apache.cloudstack.config.ApiServiceConfiguration;
 +import org.apache.cloudstack.framework.config.ConfigDepot;
 +import org.apache.cloudstack.framework.config.ConfigDepotAdmin;
 +import org.apache.cloudstack.framework.config.ConfigKey;
 +import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 +import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
 +import org.apache.commons.codec.binary.Base64;
 +import org.apache.commons.lang.StringUtils;
 +import org.apache.log4j.Logger;
 +
 +import com.cloud.configuration.Config;
 +import com.cloud.configuration.ConfigurationManager;
 +import com.cloud.configuration.Resource;
 +import com.cloud.configuration.Resource.ResourceOwnerType;
 +import com.cloud.configuration.Resource.ResourceType;
 +import com.cloud.configuration.ResourceCountVO;
 +import com.cloud.configuration.dao.ResourceCountDao;
 +import com.cloud.dc.DataCenter.NetworkType;
 +import com.cloud.dc.DataCenterVO;
 +import com.cloud.dc.HostPodVO;
 +import com.cloud.dc.VlanVO;
 +import com.cloud.dc.dao.DataCenterDao;
 +import com.cloud.dc.dao.HostPodDao;
 +import com.cloud.dc.dao.VlanDao;
 +import com.cloud.domain.DomainVO;
 +import com.cloud.domain.dao.DomainDao;
 +import com.cloud.exception.InternalErrorException;
 +import com.cloud.exception.InvalidParameterValueException;
 +import com.cloud.network.Network;
 +import com.cloud.network.Network.GuestType;
 +import com.cloud.network.Network.Provider;
 +import com.cloud.network.Network.Service;
 +import com.cloud.network.Network.State;
 +import com.cloud.network.Networks.BroadcastDomainType;
 +import com.cloud.network.Networks.Mode;
 +import com.cloud.network.Networks.TrafficType;
 +import com.cloud.network.dao.NetworkDao;
 +import com.cloud.network.dao.NetworkVO;
 +import com.cloud.network.guru.ControlNetworkGuru;
 +import com.cloud.network.guru.DirectPodBasedNetworkGuru;
 +import com.cloud.network.guru.PodBasedNetworkGuru;
 +import com.cloud.network.guru.PublicNetworkGuru;
 +import com.cloud.network.guru.StorageNetworkGuru;
 +import com.cloud.offering.NetworkOffering;
 +import com.cloud.offering.NetworkOffering.Availability;
 +import com.cloud.offerings.NetworkOfferingServiceMapVO;
 +import com.cloud.offerings.NetworkOfferingVO;
 +import com.cloud.offerings.dao.NetworkOfferingDao;
 +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 +import com.cloud.service.ServiceOfferingVO;
 +import com.cloud.service.dao.ServiceOfferingDao;
 +import com.cloud.storage.DiskOfferingVO;
 +import com.cloud.storage.Storage.ProvisioningType;
 +import com.cloud.storage.dao.DiskOfferingDao;
 +import com.cloud.test.IPRangeConfig;
 +import com.cloud.user.Account;
 +import com.cloud.user.AccountVO;
 +import com.cloud.user.User;
 +import com.cloud.user.dao.AccountDao;
 +import com.cloud.utils.PasswordGenerator;
 +import com.cloud.utils.PropertiesUtil;
 +import com.cloud.utils.component.ComponentLifecycle;
 +import com.cloud.utils.component.ManagerBase;
 +import com.cloud.utils.crypt.DBEncryptionUtil;
 +import com.cloud.utils.db.DB;
 +import com.cloud.utils.db.Transaction;
 +import com.cloud.utils.db.TransactionCallbackNoReturn;
 +import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 +import com.cloud.utils.db.TransactionLegacy;
 +import com.cloud.utils.db.TransactionStatus;
 +import com.cloud.utils.exception.CloudRuntimeException;
 +import com.cloud.utils.net.NetUtils;
 +import com.cloud.utils.script.Script;
 +
 +public class ConfigurationServerImpl extends ManagerBase implements ConfigurationServer {
 +    public static final Logger s_logger = Logger.getLogger(ConfigurationServerImpl.class);
 +
 +    @Inject
 +    private ConfigurationDao _configDao;
 +    @Inject
 +    private DataCenterDao _zoneDao;
 +    @Inject
 +    private HostPodDao _podDao;
 +    @Inject
 +    private DiskOfferingDao _diskOfferingDao;
 +    @Inject
 +    private ServiceOfferingDao _serviceOfferingDao;
 +    @Inject
 +    private NetworkOfferingDao _networkOfferingDao;
 +    @Inject
 +    private DataCenterDao _dataCenterDao;
 +    @Inject
 +    private NetworkDao _networkDao;
 +    @Inject
 +    private VlanDao _vlanDao;
 +    @Inject
 +    private DomainDao _domainDao;
 +    @Inject
 +    private AccountDao _accountDao;
 +    @Inject
 +    private ResourceCountDao _resourceCountDao;
 +    @Inject
 +    private NetworkOfferingServiceMapDao _ntwkOfferingServiceMapDao;
 +    @Inject
 +    protected ConfigDepotAdmin _configDepotAdmin;
 +    @Inject
 +    protected ConfigDepot _configDepot;
 +    @Inject
 +    protected ConfigurationManager _configMgr;
 +    @Inject
 +    protected ManagementService _mgrService;
 +
 +
 +    public ConfigurationServerImpl() {
 +        setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP);
 +    }
 +
 +    @Override
 +    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
 +        try {
 +            persistDefaultValues();
 +            _configDepotAdmin.populateConfigurations();
 +        } catch (InternalErrorException e) {
 +            throw new RuntimeException("Unhandled configuration exception", e);
 +        }
 +        return true;
 +    }
 +
 +    @Override
 +    public void persistDefaultValues() throws InternalErrorException {
 +
 +        // Create system user and admin user
 +        saveUser();
 +
 +        // Get init
 +        String init = _configDao.getValue("init");
 +
 +        if (init == null || init.equals("false")) {
 +            s_logger.debug("ConfigurationServer is saving default values to the database.");
 +
 +            // Save default Configuration Table values
 +            List<String> categories = Config.getCategories();
 +            for (String category : categories) {
 +                // If this is not a premium environment, don't insert premium configuration values
 +                if (!_configDao.isPremium() && category.equals("Premium")) {
 +                    continue;
 +                }
 +
 +                List<Config> configs = Config.getConfigs(category);
 +                for (Config c : configs) {
 +                    String name = c.key();
 +
 +                    // if the config value already present in the db, don't insert it again
 +                    if (_configDao.findByName(name) != null) {
 +                        continue;
 +                    }
 +
 +                    String instance = "DEFAULT";
 +                    String component = c.getComponent();
 +                    String value = c.getDefaultValue();
 +                    String description = c.getDescription();
 +                    ConfigurationVO configVO = new ConfigurationVO(category, instance, component, name, value, description);
 +                    configVO.setDefaultValue(value);
 +                    _configDao.persist(configVO);
 +                }
 +            }
 +
 +            _configDao.update(Config.UseSecondaryStorageVm.key(), Config.UseSecondaryStorageVm.getCategory(), "true");
 +            s_logger.debug("ConfigurationServer made secondary storage vm required.");
 +
 +            _configDao.update(Config.SecStorageEncryptCopy.key(), Config.SecStorageEncryptCopy.getCategory(), "false");
 +            s_logger.debug("ConfigurationServer made secondary storage copy encrypt set to false.");
 +
 +            _configDao.update("secstorage.secure.copy.cert", "realhostip");
 +            s_logger.debug("ConfigurationServer made secondary storage copy use realhostip.");
 +
 +            _configDao.update("user.password.encoders.exclude", "MD5,LDAP,PLAINTEXT");
 +            s_logger.debug("Configuration server excluded insecure encoders");
 +
 +            _configDao.update("user.authenticators.exclude", "PLAINTEXT");
 +            s_logger.debug("Configuration server excluded plaintext authenticator");
 +
 +            // Save default service offerings
 +            createServiceOffering(User.UID_SYSTEM, "Small Instance", 1, 512, 500, "Small Instance", ProvisioningType.THIN, false, false, null);
 +            createServiceOffering(User.UID_SYSTEM, "Medium Instance", 1, 1024, 1000, "Medium Instance", ProvisioningType.THIN, false, false, null);
 +            // Save default disk offerings
 +            createdefaultDiskOffering(null, "Small", "Small Disk, 5 GB", ProvisioningType.THIN, 5, null, false, false);
 +            createdefaultDiskOffering(null, "Medium", "Medium Disk, 20 GB", ProvisioningType.THIN, 20, null, false, false);
 +            createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false);
 +            createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false);
 +            createdefaultDiskOffering(null, "Custom", "Custom Disk", ProvisioningType.THIN, 0, null, true, false);
 +
 +            // Save the mount parent to the configuration table
 +            String mountParent = getMountParent();
 +            if (mountParent != null) {
 +                _configDao.update(Config.MountParent.key(), Config.MountParent.getCategory(), mountParent);
 +                s_logger.debug("ConfigurationServer saved \"" + mountParent + "\" as mount.parent.");
 +            } else {
 +                s_logger.debug("ConfigurationServer could not detect mount.parent.");
 +            }
 +
 +            String hostIpAdr = NetUtils.getDefaultHostIp();
 +            boolean needUpdateHostIp = true;
 +            if (hostIpAdr != null) {
 +                Boolean devel = Boolean.valueOf(_configDao.getValue("developer"));
 +                if (devel) {
 +                    String value = _configDao.getValue(ApiServiceConfiguration.ManagementServerAddresses.key());
 +                    if (value != null && !value.equals("localhost")) {
 +                        needUpdateHostIp = false;
 +                    }
 +                }
 +
 +                if (needUpdateHostIp) {
 +                    _configDepot.createOrUpdateConfigObject(ApiServiceConfiguration.class.getSimpleName(), ApiServiceConfiguration.ManagementServerAddresses, hostIpAdr);
 +                    s_logger.debug("ConfigurationServer saved \"" + hostIpAdr + "\" as host.");
 +                }
 +            }
 +
 +            // generate a single sign-on key
 +            updateSSOKey();
 +
 +            // Create default network offerings
 +            createDefaultNetworkOfferings();
 +
 +            // Create default networks
 +            createDefaultNetworks();
 +
 +            // Create userIpAddress ranges
 +
 +            // Update existing vlans with networkId
 +            List<VlanVO> vlans = _vlanDao.listAll();
 +            if (vlans != null && !vlans.isEmpty()) {
 +                for (final VlanVO vlan : vlans) {
 +                    if (vlan.getNetworkId().longValue() == 0) {
 +                        updateVlanWithNetworkId(vlan);
 +                    }
 +
 +                    // Create vlan user_ip_address range
 +                    String ipPange = vlan.getIpRange();
 +                    String[] range = ipPange.split("-");
 +                    final String startIp = range[0];
 +                    final String endIp = range[1];
 +
 +                    Transaction.execute(new TransactionCallbackNoReturn() {
 +                        @Override
 +                        public void doInTransactionWithoutResult(TransactionStatus status) {
 +                            IPRangeConfig config = new IPRangeConfig();
 +                            long startIPLong = NetUtils.ip2Long(startIp);
 +                            long endIPLong = NetUtils.ip2Long(endIp);
 +                            config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, vlan.getDataCenterId(), vlan.getId(), vlan.getNetworkId(),
 +                                    vlan.getPhysicalNetworkId(), false);
 +                        }
 +                    });
 +
 +                }
 +            }
 +        }
 +        // Update resource count if needed
 +        updateResourceCount();
 +
 +        // store the public and private keys in the database
 +        updateKeyPairs();
 +
 +        // generate a PSK to communicate with SSVM
 +        updateSecondaryStorageVMSharedKey();
 +
 +        // generate a random password for system vm
 +        updateSystemvmPassword();
 +
 +        // generate a random password used to authenticate zone-to-zone copy
 +        generateSecStorageVmCopyPassword();
 +
 +        // Update the cloud identifier
 +        updateCloudIdentifier();
 +
 +        _configDepotAdmin.populateConfigurations();
 +        // setup XenServer default PV driver version
 +        initiateXenServerPVDriverVersion();
 +
 +        // We should not update seed data UUID column here since this will be invoked in upgrade case as well.
 +        //updateUuids();
 +        // Set init to true
 +        _configDao.update("init", "Hidden", "true");
 +
 +        // invalidate cache in DAO as we have changed DB status
 +        _configDao.invalidateCache();
 +    }
 +
 +    private void templateDetailsInitIfNotExist(long id, String name, String value) {
 +        TransactionLegacy txn = TransactionLegacy.currentTxn();
 +        PreparedStatement stmt = null;
 +        PreparedStatement stmtInsert = null;
 +        boolean insert = false;
 +        try {
 +            txn.start();
 +            stmt = txn.prepareAutoCloseStatement("SELECT id FROM vm_template_details WHERE template_id=? and name=?");
 +            stmt.setLong(1, id);
 +            stmt.setString(2, name);
 +            ResultSet rs = stmt.executeQuery();
 +            if (rs == null || !rs.next()) {
 +                insert = true;
 +            }
 +            stmt.close();
 +
 +            if (insert) {
 +                stmtInsert = txn.prepareAutoCloseStatement("INSERT INTO vm_template_details(template_id, name, value) VALUES(?, ?, ?)");
 +                stmtInsert.setLong(1, id);
 +                stmtInsert.setString(2, name);
 +                stmtInsert.setString(3, value);
 +                if (stmtInsert.executeUpdate() < 1) {
 +                    throw new CloudRuntimeException("Unable to init template " + id + " datails: " + name);
 +                }
 +            }
 +            txn.commit();
 +        } catch (Exception e) {
 +            s_logger.warn("Unable to init template " + id + " datails: " + name, e);
 +            throw new CloudRuntimeException("Unable to init template " + id + " datails: " + name);
 +        }
 +    }
 +
 +    private void initiateXenServerPVDriverVersion() {
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(TransactionStatus status) {
 +                TransactionLegacy txn = TransactionLegacy.currentTxn();
 +                String pvdriverversion = Config.XenServerPVdriverVersion.getDefaultValue();
 +                PreparedStatement pstmt = null;
 +                ResultSet rs1 = null;
 +                ResultSet rs2 = null;
 +                try {
 +                    String oldValue = _configDao.getValue(Config.XenServerPVdriverVersion.key());
 +                    if (oldValue == null) {
 +                        String sql = "select resource from host where hypervisor_type='XenServer' and removed is null and status not in ('Error', 'Removed') group by resource";
 +                        pstmt = txn.prepareAutoCloseStatement(sql);
 +                        rs1 = pstmt.executeQuery();
 +                        while (rs1.next()) {
 +                            String resouce = rs1.getString(1); //resource column
 +                            if (resouce == null)
 +                                continue;
 +                            if (resouce.equalsIgnoreCase("com.cloud.hypervisor.xenserver.resource.XenServer56Resource")
 +                                    || resouce.equalsIgnoreCase("com.cloud.hypervisor.xenserver.resource.XenServer56FP1Resource")
 +                                    || resouce.equalsIgnoreCase("com.cloud.hypervisor.xenserver.resource.XenServer56SP2Resource")
 +                                    || resouce.equalsIgnoreCase("com.cloud.hypervisor.xenserver.resource.XenServer600Resource")
 +                                    || resouce.equalsIgnoreCase("com.cloud.hypervisor.xenserver.resource.XenServer602Resource")) {
 +                                pvdriverversion = "xenserver56";
 +                                break;
 +                            }
 +                        }
 +                        _configDao.getValueAndInitIfNotExist(Config.XenServerPVdriverVersion.key(), Config.XenServerPVdriverVersion.getCategory(), pvdriverversion,
 +                                Config.XenServerPVdriverVersion.getDescription());
 +                        sql = "select id from vm_template where hypervisor_type='XenServer'  and format!='ISO' and removed is null";
 +                        pstmt = txn.prepareAutoCloseStatement(sql);
 +                        rs2 = pstmt.executeQuery();
 +                        List<Long> tmpl_ids = new ArrayList<Long>();
 +                        while (rs2.next()) {
 +                            tmpl_ids.add(rs2.getLong(1));
 +                        }
 +                        for (Long tmpl_id : tmpl_ids) {
 +                            templateDetailsInitIfNotExist(tmpl_id, "hypervisortoolsversion", pvdriverversion);
 +                        }
 +                    }
 +                } catch (Exception e) {
 +                    s_logger.debug("initiateXenServerPVDriverVersion failed due to " + e.toString());
 +                    // ignore
 +                }
 +            }
 +        });
 +    }
 +
 +    private String getMountParent() {
 +        return getEnvironmentProperty("mount.parent");
 +    }
 +
 +    private String getEnvironmentProperty(String name) {
 +        try {
 +            final File propsFile = PropertiesUtil.findConfigFile("environment.properties");
 +
 +            if (propsFile == null) {
 +                return null;
 +            } else {
 +                final Properties props = new Properties();
 +                try(final FileInputStream finputstream = new FileInputStream(propsFile);) {
 +                    props.load(finputstream);
 +                }catch (IOException e) {
 +                    s_logger.error("getEnvironmentProperty:Exception:" + e.getMessage());
 +                }
 +                return props.getProperty("mount.parent");
 +            }
 +        } catch (Exception e) {
 +            return null;
 +        }
 +    }
 +
 +    @DB
 +    public void saveUser() {
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(TransactionStatus status) {
 +                TransactionLegacy txn = TransactionLegacy.currentTxn();
 +                // insert system account
 +                String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (1, UUID(), 'system', '1', '1', '1', 1)";
 +
 +                try {
 +                    PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
 +                    stmt.executeUpdate();
 +                } catch (SQLException ex) {
 +                    s_logger.debug("Looks like system account already exists");
 +                }
 +                // insert system user
 +                insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created, user.default)"
 +                        + " VALUES (1, UUID(), 'system', RAND(), 1, 'system', 'cloud', now(), 1)";
 +
 +                try {
 +                    PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
 +                    stmt.executeUpdate();
 +                } catch (SQLException ex) {
 +                    s_logger.debug("Looks like system user already exists");
 +                }
 +
 +                // insert admin user, but leave the account disabled until we set a
 +                // password with the user authenticator
 +                long id = 2;
 +                String username = "admin";
 +                String firstname = "admin";
 +                String lastname = "cloud";
 +
 +                // create an account for the admin user first
 +                insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (" + id + ", UUID(), '" + username
 +                        + "', '1', '1', '1', 1)";
 +                try {
 +                    PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
 +                    stmt.executeUpdate();
 +                } catch (SQLException ex) {
 +                    s_logger.debug("Looks like admin account already exists");
 +                }
 +
 +                // now insert the user
 +                insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created, state, user.default) " + "VALUES (" + id
 +                        + ", UUID(), '" + username + "', RAND(), 2, '" + firstname + "','" + lastname + "',now(), 'disabled', 1)";
 +
 +                try {
 +                    PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
 +                    stmt.executeUpdate();
 +                } catch (SQLException ex) {
 +                    s_logger.debug("Looks like admin user already exists");
 +                }
 +
 +                try {
 +                    String tableName = "security_group";
 +                    try {
 +                        String checkSql = "SELECT * from network_group";
 +                        PreparedStatement stmt = txn.prepareAutoCloseStatement(checkSql);
 +                        stmt.executeQuery();
 +                        tableName = "network_group";
 +                    } catch (Exception ex) {
 +                        // Ignore in case of exception, table must not exist
 +                    }
 +
 +                    insertSql = "SELECT * FROM " + tableName + " where account_id=2 and name='default'";
 +                    PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
 +                    ResultSet rs = stmt.executeQuery();
 +                    if (!rs.next()) {
 +                        // save default security group
 +                        if (tableName.equals("security_group")) {
 +                            insertSql = "INSERT INTO " + tableName + " (uuid, name, description, account_id, domain_id) "
 +                                    + "VALUES (UUID(), 'default', 'Default Security Group', 2, 1)";
 +                        } else {
 +                            insertSql = "INSERT INTO " + tableName + " (name, description, account_id, domain_id, account_name) "
 +                                    + "VALUES ('default', 'Default Security Group', 2, 1, 'admin')";
 +                        }
 +
 +                        try {
 +                            stmt = txn.prepareAutoCloseStatement(insertSql);
 +                            stmt.executeUpdate();
 +                        } catch (SQLException ex) {
 +                            s_logger.warn("Failed to create default security group for default admin account due to ", ex);
 +                        }
 +                    }
 +                    rs.close();
 +                } catch (Exception ex) {
 +                    s_logger.warn("Failed to create default security group for default admin account due to ", ex);
 +                }
 +            }
 +        });
 +    }
 +
 +    protected void updateCloudIdentifier() {
 +        // Creates and saves a UUID as the cloud identifier
 +        String currentCloudIdentifier = _configDao.getValue("cloud.identifier");
 +        if (currentCloudIdentifier == null || currentCloudIdentifier.isEmpty()) {
 +            String uuid = UUID.randomUUID().toString();
 +            _configDao.update(Config.CloudIdentifier.key(), Config.CloudIdentifier.getCategory(), uuid);
 +        }
 +    }
 +
 +    @DB
 +    protected void updateSystemvmPassword() {
 +        String userid = System.getProperty("user.name");
 +        if (!userid.startsWith("cloud")) {
 +            return;
 +        }
 +
 +        if (!Boolean.valueOf(_configDao.getValue("system.vm.random.password"))) {
 +            return;
 +        }
 +
 +        String already = _configDao.getValue("system.vm.password");
 +        if (already == null) {
 +            TransactionLegacy txn = TransactionLegacy.currentTxn();
 +            try {
 +                String rpassword = _mgrService.generateRandomPassword();
 +                String wSql = "INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) "
 +                + "VALUES ('Secure','DEFAULT', 'management-server','system.vm.password', ?,'randmon password generated each management server starts for system vm')";
 +                PreparedStatement stmt = txn.prepareAutoCloseStatement(wSql);
 +                stmt.setString(1, DBEncryptionUtil.encrypt(rpassword));
 +                stmt.executeUpdate();
 +                s_logger.info("Updated systemvm password in database");
 +            } catch (SQLException e) {
 +                s_logger.error("Cannot retrieve systemvm password", e);
 +            }
 +        }
 +
 +    }
 +
 +    @Override
 +    @DB
 +    public void updateKeyPairs() {
 +        // Grab the SSH key pair and insert it into the database, if it is not present
 +
 +        String username = System.getProperty("user.name");
 +        Boolean devel = Boolean.valueOf(_configDao.getValue("developer"));
 +        if (!username.equalsIgnoreCase("cloud") && !devel) {
 +            s_logger.warn("Systemvm keypairs could not be set. Management server should be run as cloud user, or in development mode.");
 +            return;
 +        }
 +        String already = _configDao.getValue("ssh.privatekey");
 +        String homeDir = System.getProperty("user.home");
 +        if (homeDir == null) {
 +            throw new CloudRuntimeException("Cannot get home directory for account: " + username);
 +        }
 +
 +        if (s_logger.isInfoEnabled()) {
 +            s_logger.info("Processing updateKeyPairs");
 +        }
 +
 +        if (homeDir != null && homeDir.startsWith("~")) {
 +            s_logger.error("No home directory was detected for the user '" + username + "'. Please check the profile of this user.");
 +            throw new CloudRuntimeException("No home directory was detected for the user '" + username + "'. Please check the profile of this user.");
 +        }
 +
 +        // Using non-default file names (id_rsa.cloud and id_rsa.cloud.pub) in developer mode. This is to prevent SSH keys overwritten for user running management server
 +        File privkeyfile = null;
 +        File pubkeyfile = null;
 +        if (devel) {
 +            privkeyfile = new File(homeDir + "/.ssh/id_rsa.cloud");
 +            pubkeyfile = new File(homeDir + "/.ssh/id_rsa.cloud.pub");
 +        } else {
 +            privkeyfile = new File(homeDir + "/.ssh/id_rsa");
 +            pubkeyfile = new File(homeDir + "/.ssh/id_rsa.pub");
 +        }
 +
 +        if (already == null || already.isEmpty()) {
 +            if (s_logger.isInfoEnabled()) {
 +                s_logger.info("Systemvm keypairs not found in database. Need to store them in the database");
 +            }
 +            // FIXME: take a global database lock here for safety.
 +            boolean onWindows = isOnWindows();
 +            if(!onWindows) {
-                 Script.runSimpleBashScript("if [ -f " + privkeyfile + " ]; then rm -f " + privkeyfile + "; fi; ssh-keygen -t rsa -N '' -f " + privkeyfile + " -q");
++                Script.runSimpleBashScript("if [ -f " + privkeyfile + " ]; then rm -f " + privkeyfile + "; fi; ssh-keygen -t rsa -m PEM -N '' -f " + privkeyfile + " -q 2>/dev/null || ssh-keygen -t rsa -N '' -f " + privkeyfile + " -q");
 +            }
 +
-             byte[] arr1 = new byte[4094]; // configuration table column value size
-             try (DataInputStream dis = new DataInputStream(new FileInputStream(privkeyfile))) {
-                 dis.readFully(arr1);
-             } catch (EOFException e) {
-                 s_logger.info("[ignored] eof reached");
-             } catch (Exception e) {
++            final String privateKey;
++            final String publicKey;
++            try {
++                privateKey = new String(Files.readAllBytes(privkeyfile.toPath()));
++            } catch (IOException e) {
 +                s_logger.error("Cannot read the private key file", e);
 +                throw new CloudRuntimeException("Cannot read the private key file");
 +            }
-             String privateKey = new String(arr1).trim();
-             byte[] arr2 = new byte[4094]; // configuration table column value size
-             try (DataInputStream dis = new DataInputStream(new FileInputStream(pubkeyfile))) {
-                 dis.readFully(arr2);
-             } catch (EOFException e) {
-                 s_logger.info("[ignored] eof reached");
-             } catch (Exception e) {
-                 s_logger.warn("Cannot read the public key file", e);
++            try {
++                publicKey = new String(Files.readAllBytes(pubkeyfile.toPath()));
++            } catch (IOException e) {
++                s_logger.error("Cannot read the public key file", e);
 +                throw new CloudRuntimeException("Cannot read the public key file");
 +            }
-             String publicKey = new String(arr2).trim();
 +
 +            final String insertSql1 =
 +                    "INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) " +
 +                            "VALUES ('Hidden','DEFAULT', 'management-server','ssh.privatekey', '" + DBEncryptionUtil.encrypt(privateKey) +
 +                            "','Private key for the entire CloudStack')";
 +            final String insertSql2 =
 +                    "INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) " +
 +                            "VALUES ('Hidden','DEFAULT', 'management-server','ssh.publickey', '" + DBEncryptionUtil.encrypt(publicKey) +
 +                            "','Public key for the entire CloudStack')";
 +
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(TransactionStatus status) {
 +
 +                    TransactionLegacy txn = TransactionLegacy.currentTxn();
 +                    try {
 +                        PreparedStatement stmt1 = txn.prepareAutoCloseStatement(insertSql1);
 +                        stmt1.executeUpdate();
 +                        if (s_logger.isDebugEnabled()) {
 +                            s_logger.debug("Private key inserted into database");
 +                        }
 +                    } catch (SQLException ex) {
 +                        s_logger.error("SQL of the private key failed", ex);
 +                        throw new CloudRuntimeException("SQL of the private key failed");
 +                    }
 +
 +                    try {
 +                        PreparedStatement stmt2 = txn.prepareAutoCloseStatement(insertSql2);
 +                        stmt2.executeUpdate();
 +                        if (s_logger.isDebugEnabled()) {
 +                            s_logger.debug("Public key inserted into database");
 +                        }
 +                    } catch (SQLException ex) {
 +                        s_logger.error("SQL of the public key failed", ex);
 +                        throw new CloudRuntimeException("SQL of the public key failed");
 +                    }
 +                }
 +            });
 +
 +        } else {
 +            s_logger.info("Keypairs already in database, updating local copy");
 +            updateKeyPairsOnDisk(homeDir);
 +        }
 +        s_logger.info("Going to update systemvm iso with generated keypairs if needed");
 +        try {
 +            injectSshKeysIntoSystemVmIsoPatch(pubkeyfile.getAbsolutePath(), privkeyfile.getAbsolutePath());
 +        } catch (CloudRuntimeException e) {
 +            if (!devel) {
 +                throw new CloudRuntimeException(e.getMessage());
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public List<ConfigurationVO> getConfigListByScope(String scope, Long resourceId) {
 +
 +        // Getting the list of parameters defined at the scope
 +        Set<ConfigKey<?>> configList = _configDepot.getConfigListByScope(scope);
 +        List<ConfigurationVO> configVOList = new ArrayList<ConfigurationVO>();
 +        for (ConfigKey<?> param : configList) {
 +            ConfigurationVO configVo = _configDao.findByName(param.toString());
 +            configVo.setValue(_configDepot.get(param.toString()).valueIn(resourceId).toString());
 +            configVOList.add(configVo);
 +        }
 +        return configVOList;
 +    }
 +
 +    private void writeKeyToDisk(String key, String keyPath) {
 +        File keyfile = new File(keyPath);
 +        if (!keyfile.exists()) {
 +            try {
 +                keyfile.createNewFile();
 +            } catch (IOException e) {
 +                s_logger.warn("Failed to create file: " + e.toString());
 +                throw new CloudRuntimeException("Failed to update keypairs on disk: cannot create  key file " + keyPath);
 +            }
 +        }
 +
 +        if (keyfile.exists()) {
 +            try (FileOutputStream kStream = new FileOutputStream(keyfile);){
 +                if (kStream != null) {
 +                    kStream.write(key.getBytes());
 +                }
 +            } catch (FileNotFoundException e) {
 +                s_logger.warn("Failed to write  key to " + keyfile.getAbsolutePath(), e);
 +                throw new CloudRuntimeException("Failed to update keypairs on disk: cannot find  key file " + keyPath);
 +            } catch (IOException e) {
 +                s_logger.warn("Failed to write  key to " + keyfile.getAbsolutePath(), e);
 +                throw new CloudRuntimeException("Failed to update keypairs on disk: cannot write to  key file " + keyPath);
 +            }
 +        }
 +
 +    }
 +
 +    private void updateKeyPairsOnDisk(String homeDir) {
 +        File keyDir = new File(homeDir + "/.ssh");
 +        Boolean devel = Boolean.valueOf(_configDao.getValue("developer"));
 +        if (!keyDir.isDirectory()) {
 +            s_logger.warn("Failed to create " + homeDir + "/.ssh for storing the SSH keypars");
 +            keyDir.mkdirs();
 +        }
 +        String pubKey = _configDao.getValue("ssh.publickey");
 +        String prvKey = _configDao.getValue("ssh.privatekey");
 +
 +        // Using non-default file names (id_rsa.cloud and id_rsa.cloud.pub) in developer mode. This is to prevent SSH keys overwritten for user running management server
 +        if (devel) {
 +            writeKeyToDisk(prvKey, homeDir + "/.ssh/id_rsa.cloud");
 +            writeKeyToDisk(pubKey, homeDir + "/.ssh/id_rsa.cloud.pub");
 +        } else {
 +            writeKeyToDisk(prvKey, homeDir + "/.ssh/id_rsa");
 +            writeKeyToDisk(pubKey, homeDir + "/.ssh/id_rsa.pub");
 +        }
 +    }
 +
 +    protected void injectSshKeysIntoSystemVmIsoPatch(String publicKeyPath, String privKeyPath) {
 +        s_logger.info("Trying to inject public and private keys into systemvm iso");
 +        String injectScript = getInjectScript();
 +        String scriptPath = Script.findScript("", injectScript);
 +        String systemVmIsoPath = Script.findScript("", "vms/systemvm.iso");
 +        if (scriptPath == null) {
 +            throw new CloudRuntimeException("Unable to find key inject script " + injectScript);
 +        }
 +        if (systemVmIsoPath == null) {
 +            throw new CloudRuntimeException("Unable to find systemvm iso vms/systemvm.iso");
 +        }
 +        Script command = null;
 +        if(isOnWindows()) {
 +            command = new Script("python", s_logger);
 +        } else {
 +            command = new Script("/bin/bash", s_logger);
 +        }
 +        if (isOnWindows()) {
 +            scriptPath = scriptPath.replaceAll("\\\\" ,"/" );
 +            systemVmIsoPath = systemVmIsoPath.replaceAll("\\\\" ,"/" );
 +            publicKeyPath = publicKeyPath.replaceAll("\\\\" ,"/" );
 +            privKeyPath = privKeyPath.replaceAll("\\\\" ,"/" );
 +        }
 +        command.add(scriptPath);
 +        command.add(publicKeyPath);
 +        command.add(privKeyPath);
 +        command.add(systemVmIsoPath);
 +
 +        final String result = command.execute();
 +        s_logger.info("Injected public and private keys into systemvm iso with result : " + result);
 +        if (result != null) {
 +            s_logger.warn("Failed to inject generated public key into systemvm iso " + result);
 +            throw new CloudRuntimeException("Failed to inject generated public key into systemvm iso " + result);
 +        }
 +    }
 +
 +    protected String getInjectScript() {
 +        String injectScript = null;
 +        boolean onWindows = isOnWindows();
 +        if(onWindows) {
 +            injectScript = "scripts/vm/systemvm/injectkeys.py";
 +        } else {
 +            injectScript = "scripts/vm/systemvm/injectkeys.sh";
 +        }
 +        return injectScript;
 +    }
 +
 +    protected boolean isOnWindows() {
 +        String os = System.getProperty("os.name", "generic").toLowerCase();
 +        boolean onWindows = (os != null && os.startsWith("windows"));
 +        return onWindows;
 +    }
 +
 +    @DB
 +    protected void generateSecStorageVmCopyPassword() {
 +        String already = _configDao.getValue("secstorage.copy.password");
 +
 +        if (already == null) {
 +
 +            s_logger.info("Need to store secondary storage vm copy password in the database");
 +            String password = PasswordGenerator.generateRandomPassword(12);
 +
 +            final String insertSql1 =
 +                    "INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) " +
 +                            "VALUES ('Hidden','DEFAULT', 'management-server','secstorage.copy.password', '" + DBEncryptionUtil.encrypt(password) +
 +                            "','Password used to authenticate zone-to-zone template copy requests')";
 +            Transaction.execute(new TransactionCallbackNoReturn() {
 +                @Override
 +                public void doInTransactionWithoutResult(TransactionStatus status) {
 +
 +                    TransactionLegacy txn = TransactionLegacy.currentTxn();
 +                    try {
 +                        PreparedStatement stmt1 = txn.prepareAutoCloseStatement(insertSql1);
 +                        stmt1.executeUpdate();
 +                        s_logger.debug("secondary storage vm copy password inserted into database");
 +                    } catch (SQLException ex) {
 +                        s_logger.warn("Failed to insert secondary storage vm copy password", ex);
 +                    }
 +                }
 +            });
 +        }
 +    }
 +
 +    private void updateSSOKey() {
 +        try {
 +            _configDao.update(Config.SSOKey.key(), Config.SSOKey.getCategory(), getPrivateKey());
 +        } catch (NoSuchAlgorithmException ex) {
 +            s_logger.error("error generating sso key", ex);
 +        }
 +    }
 +
 +    /**
 +     * preshared key to be used by management server to communicate with SSVM during volume/template upload
 +     */
 +    private void updateSecondaryStorageVMSharedKey() {
 +        try {
 +            ConfigurationVO configInDB = _configDao.findByName(Config.SSVMPSK.key());
 +            if(configInDB == null) {
 +                ConfigurationVO configVO = new ConfigurationVO(Config.SSVMPSK.getCategory(), "DEFAULT", Config.SSVMPSK.getComponent(), Config.SSVMPSK.key(), getPrivateKey(),
 +                        Config.SSVMPSK.getDescription());
 +                s_logger.info("generating a new SSVM PSK. This goes to SSVM on Start");
 +                _configDao.persist(configVO);
 +            } else if (StringUtils.isEmpty(configInDB.getValue())) {
 +                s_logger.info("updating the SSVM PSK with new value. This goes to SSVM on Start");
 +                _configDao.update(Config.SSVMPSK.key(), Config.SSVMPSK.getCategory(), getPrivateKey());
 +            }
 +        } catch (NoSuchAlgorithmException ex) {
 +            s_logger.error("error generating ssvm psk", ex);
 +        }
 +    }
 +
 +    private String getPrivateKey() throws NoSuchAlgorithmException {
 +        String encodedKey = null;
 +        // Algorithm for generating Key is SHA1, should this be configurable?
 +        KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1");
 +        SecretKey key = generator.generateKey();
 +        encodedKey = Base64.encodeBase64URLSafeString(key.getEncoded());
 +        return encodedKey;
 +
 +    }
 +
 +
 +    @DB
 +    protected HostPodVO createPod(long userId, String podName, final long zoneId, String gateway, String cidr, final String startIp, String endIp)
 +            throws InternalErrorException {
 +        String[] cidrPair = cidr.split("\\/");
 +        String cidrAddress = cidrPair[0];
 +        int cidrSize = Integer.parseInt(cidrPair[1]);
 +
 +        if (startIp != null) {
 +            if (endIp == null) {
 +                endIp = NetUtils.getIpRangeEndIpFromCidr(cidrAddress, cidrSize);
 +            }
 +        }
 +
 +        // Create the new pod in the database
 +        String ipRange;
 +        if (startIp != null) {
 +            ipRange = startIp + "-";
 +            if (endIp != null) {
 +                ipRange += endIp;
 +            }
 +        } else {
 +            ipRange = "";
 +        }
 +
 +        final HostPodVO pod = new HostPodVO(podName, zoneId, gateway, cidrAddress, cidrSize, ipRange);
 +        try {
 +            final String endIpFinal = endIp;
 +            Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InternalErrorException>() {
 +                @Override
 +                public void doInTransactionWithoutResult(TransactionStatus status) throws InternalErrorException {
 +                    if (_podDao.persist(pod) == null) {
 +                        throw new InternalErrorException("Failed to create new pod. Please contact Cloud Support.");
 +                    }
 +
 +                    if (startIp != null) {
 +                        _zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal, false, null);
 +                    }
 +
 +                    String ipNums = _configDao.getValue("linkLocalIp.nums");
 +                    int nums = Integer.parseInt(ipNums);
 +                    if (nums > 16 || nums <= 0) {
 +                        throw new InvalidParameterValueException("The linkLocalIp.nums: " + nums + "is wrong, should be 1~16");
 +                    }
 +                    /* local link ip address starts from 169.254.0.2 - 169.254.(nums) */
 +                    String[] linkLocalIpRanges = NetUtils.getLinkLocalIPRange(nums);
 +                    if (linkLocalIpRanges == null) {
 +                        throw new InvalidParameterValueException("The linkLocalIp.nums: " + nums + "may be wrong, should be 1~16");
 +                    } else {
 +                        _zoneDao.addLinkLocalIpAddress(zoneId, pod.getId(), linkLocalIpRanges[0], linkLocalIpRanges[1]);
 +                    }
 +                }
 +            });
 +        } catch (Exception e) {
 +            s_logger.error("Unable to create new pod due to " + e.getMessage(), e);
 +            throw new InternalErrorException("Failed to create new pod. Please contact Cloud Support.");
 +        }
 +
 +        return pod;
 +    }
 +
 +    private DiskOfferingVO createdefaultDiskOffering(Long domainId, String name, String description, ProvisioningType provisioningType,
 +            int numGibibytes, String tags, boolean isCustomized, boolean isSystemUse) {
 +        long diskSize = numGibibytes;
 +        diskSize = diskSize * 1024 * 1024 * 1024;
 +        tags = cleanupTags(tags);
 +
 +        DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, provisioningType, diskSize, tags, isCustomized, null, null, null);
 +        newDiskOffering.setUniqueName("Cloud.Com-" + name);
 +        // leaving the above reference to cloud.com in as it is an identifyer and has no real world relevance
 +        newDiskOffering.setSystemUse(isSystemUse);
 +        newDiskOffering = _diskOfferingDao.persistDeafultDiskOffering(newDiskOffering);
 +        return newDiskOffering;
 +    }
 +
 +    private ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText,
 +            ProvisioningType provisioningType, boolean localStorageRequired, boolean offerHA, String tags) {
 +        tags = cleanupTags(tags);
 +        ServiceOfferingVO offering =
 +                new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, offerHA, displayText, provisioningType, localStorageRequired, false, tags, false, null, false);
 +        offering.setUniqueName("Cloud.Com-" + name);
 +        // leaving the above reference to cloud.com in as it is an identifyer and has no real world relevance
 +        offering = _serviceOfferingDao.persistSystemServiceOffering(offering);
 +        return offering;
 +    }
 +
 +    private String cleanupTags(String tags) {
 +        if (tags != null) {
 +            String[] tokens = tags.split(",");
 +            StringBuilder t = new StringBuilder();
 +            for (int i = 0; i < tokens.length; i++) {
 +                t.append(tokens[i].trim()).append(",");
 +            }
 +            t.delete(t.length() - 1, t.length());
 +            tags = t.toString();
 +        }
 +
 +        return tags;
 +    }
 +
 +    @DB
 +    protected void createDefaultNetworkOfferings() {
 +
 +        NetworkOfferingVO publicNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemPublicNetwork, TrafficType.Public, true);
 +        publicNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(publicNetworkOffering);
 +        NetworkOfferingVO managementNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemManagementNetwork, TrafficType.Management, false);
 +        managementNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(managementNetworkOffering);
 +        NetworkOfferingVO controlNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemControlNetwork, TrafficType.Control, false);
 +        controlNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(controlNetworkOffering);
 +        NetworkOfferingVO storageNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemStorageNetwork, TrafficType.Storage, true);
 +        storageNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(storageNetworkOffering);
 +        NetworkOfferingVO privateGatewayNetworkOffering = new NetworkOfferingVO(NetworkOffering.SystemPrivateGatewayNetworkOffering, GuestType.Isolated);
 +        privateGatewayNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(privateGatewayNetworkOffering);
 +
 +        //populate providers
 +        final Map<Network.Service, Network.Provider> defaultSharedNetworkOfferingProviders = new HashMap<Network.Service, Network.Provider>();
 +        defaultSharedNetworkOfferingProviders.put(Service.Dhcp, Provider.VirtualRouter);
 +        defaultSharedNetworkOfferingProviders.put(Service.Dns, Provider.VirtualRouter);
 +        defaultSharedNetworkOfferingProviders.put(Service.UserData, Provider.VirtualRouter);
 +
 +        final Map<Network.Service, Network.Provider> defaultIsolatedNetworkOfferingProviders = defaultSharedNetworkOfferingProviders;
 +
 +        final Map<Network.Service, Network.Provider> defaultSharedSGNetworkOfferingProviders = new HashMap<Network.Service, Network.Provider>();
 +        defaultSharedSGNetworkOfferingProviders.put(Service.Dhcp, Provider.VirtualRouter);
 +        defaultSharedSGNetworkOfferingProviders.put(Service.Dns, Provider.VirtualRouter);
 +        defaultSharedSGNetworkOfferingProviders.put(Service.UserData, Provider.VirtualRouter);
 +        defaultSharedSGNetworkOfferingProviders.put(Service.SecurityGroup, Provider.SecurityGroupProvider);
 +
 +        final Map<Network.Service, Network.Provider> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap<Network.Service, Network.Provider>();
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dhcp, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dns, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.UserData, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Firewall, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Gateway, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Lb, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.SourceNat, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.StaticNat, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.PortForwarding, Provider.VirtualRouter);
 +        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Vpn, Provider.VirtualRouter);
 +
 +        final Map<Network.Service, Network.Provider> netscalerServiceProviders = new HashMap<Network.Service, Network.Provider>();
 +        netscalerServiceProviders.put(Service.Dhcp, Provider.VirtualRouter);
 +        netscalerServiceProviders.put(Service.Dns, Provider.VirtualRouter);
 +        netscalerServiceProviders.put(Service.UserData, Provider.VirtualRouter);
 +        netscalerServiceProviders.put(Service.SecurityGroup, Provider.SecurityGroupProvider);
 +        netscalerServiceProviders.put(Service.StaticNat, Provider.Netscaler);
 +        netscalerServiceProviders.put(Service.Lb, Provider.Netscaler);
 +
 +        // The only one diff between 1 and 2 network offerings is that the first one has SG enabled. In Basic zone only
 +        // first network offering has to be enabled, in Advance zone - the second one
 +        Transaction.execute(new TransactionCallbackNoReturn() {
 +            @Override
 +            public void doInTransactionWithoutResult(TransactionStatus status) {
 +                // Offering #1
 +                NetworkOfferingVO defaultSharedSGNetworkOffering =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks",
 +                                TrafficType.Guest, false, true, null, null, true, Availability.Optional, null, Network.GuestType.Shared, true, true, false, false, false, false);
 +
 +                defaultSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled);
 +                defaultSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedSGNetworkOffering);
 +
 +                for (Service service : defaultSharedSGNetworkOfferingProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultSharedSGNetworkOffering.getId(), service, defaultSharedSGNetworkOfferingProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #2
 +                NetworkOfferingVO defaultSharedNetworkOffering =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, false, true, null, null, true,
 +                                Availability.Optional, null, Network.GuestType.Shared, true, true, false, false, false, false);
 +
 +                defaultSharedNetworkOffering.setState(NetworkOffering.State.Enabled);
 +                defaultSharedNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedNetworkOffering);
 +
 +                for (Service service : defaultSharedNetworkOfferingProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultSharedNetworkOffering.getId(), service, defaultSharedNetworkOfferingProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #3
 +                NetworkOfferingVO defaultIsolatedSourceNatEnabledNetworkOffering =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService,
 +                                "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Required, null,
 +                                Network.GuestType.Isolated, true, false, false, false, true, false);
 +
 +                defaultIsolatedSourceNatEnabledNetworkOffering.setState(NetworkOffering.State.Enabled);
 +                defaultIsolatedSourceNatEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedSourceNatEnabledNetworkOffering);
 +
 +                for (Service service : defaultIsolatedSourceNatEnabledNetworkOfferingProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultIsolatedSourceNatEnabledNetworkOffering.getId(), service,
 +                                    defaultIsolatedSourceNatEnabledNetworkOfferingProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #4
 +                NetworkOfferingVO defaultIsolatedEnabledNetworkOffering =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest,
 +                                false, true, null, null, true, Availability.Optional, null, Network.GuestType.Isolated, true, true, false, false, false, false);
 +
 +                defaultIsolatedEnabledNetworkOffering.setState(NetworkOffering.State.Enabled);
 +                defaultIsolatedEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedEnabledNetworkOffering);
 +
 +                for (Service service : defaultIsolatedNetworkOfferingProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultIsolatedEnabledNetworkOffering.getId(), service, defaultIsolatedNetworkOfferingProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #5
 +                NetworkOfferingVO defaultNetscalerNetworkOffering =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultSharedEIPandELBNetworkOffering,
 +                                "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, false, true, null, null, true,
 +                                Availability.Optional, null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true, true, false, false, false, false, false);
 +
 +                defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled);
 +                defaultNetscalerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetscalerNetworkOffering);
 +
 +                for (Service service : netscalerServiceProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultNetscalerNetworkOffering.getId(), service, netscalerServiceProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #6
 +                NetworkOfferingVO defaultNetworkOfferingForVpcNetworks =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks,
 +                                "Offering for Isolated Vpc networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Optional,
 +                                null, Network.GuestType.Isolated, false, false, false, false, true, true);
 +
 +                defaultNetworkOfferingForVpcNetworks.setState(NetworkOffering.State.Enabled);
 +                defaultNetworkOfferingForVpcNetworks = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworks);
 +
 +                Map<Network.Service, Network.Provider> defaultVpcNetworkOfferingProviders = new HashMap<Network.Service, Network.Provider>();
 +                defaultVpcNetworkOfferingProviders.put(Service.Dhcp, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.Dns, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.UserData, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.NetworkACL, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.Gateway, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.Lb, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.SourceNat, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.StaticNat, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.PortForwarding, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProviders.put(Service.Vpn, Provider.VPCVirtualRouter);
 +
 +                for (Map.Entry<Service,Provider> entry : defaultVpcNetworkOfferingProviders.entrySet()) {
 +                     NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultNetworkOfferingForVpcNetworks.getId(), entry.getKey(), entry.getValue());
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                // Offering #7
 +                NetworkOfferingVO defaultNetworkOfferingForVpcNetworksNoLB =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB,
 +                                "Offering for Isolated Vpc networks with Source Nat service enabled and LB service Disabled", TrafficType.Guest, false, false, null, null, true,
 +                                Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false, true);
 +
 +                defaultNetworkOfferingForVpcNetworksNoLB.setState(NetworkOffering.State.Enabled);
 +                defaultNetworkOfferingForVpcNetworksNoLB = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworksNoLB);
 +
 +                Map<Network.Service, Network.Provider> defaultVpcNetworkOfferingProvidersNoLB = new HashMap<Network.Service, Network.Provider>();
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.Dhcp, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.Dns, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.UserData, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.NetworkACL, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.Gateway, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.SourceNat, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.StaticNat, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.PortForwarding, Provider.VPCVirtualRouter);
 +                defaultVpcNetworkOfferingProvidersNoLB.put(Service.Vpn, Provider.VPCVirtualRouter);
 +
 +                for (Map.Entry<Service,Provider> entry : defaultVpcNetworkOfferingProvidersNoLB.entrySet()) {
 +                    NetworkOfferingServiceMapVO offService =
 +                            new NetworkOfferingServiceMapVO(defaultNetworkOfferingForVpcNetworksNoLB.getId(), entry.getKey(), entry.getValue());
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                //offering #8 - network offering with internal lb service
 +                NetworkOfferingVO internalLbOff =
 +                        new NetworkOfferingVO(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB,
 +                                "Offering for Isolated Vpc networks with Internal LB support", TrafficType.Guest, false, false, null, null, true, Availability.Optional, null,
 +                                Network.GuestType.Isolated, false, false, false, true, false, true);
 +
 +                internalLbOff.setState(NetworkOffering.State.Enabled);
 +                internalLbOff = _networkOfferingDao.persistDefaultNetworkOffering(internalLbOff);
 +
 +                Map<Network.Service, Network.Provider> internalLbOffProviders = new HashMap<Network.Service, Network.Provider>();
 +                internalLbOffProviders.put(Service.Dhcp, Provider.VPCVirtualRouter);
 +                internalLbOffProviders.put(Service.Dns, Provider.VPCVirtualRouter);
 +                internalLbOffProviders.put(Service.UserData, Provider.VPCVirtualRouter);
 +                internalLbOffProviders.put(Service.NetworkACL, Provider.VPCVirtualRouter);
 +                internalLbOffProviders.put(Service.Gateway, Provider.VPCVirtualRouter);
 +                internalLbOffProviders.put(Service.Lb, Provider.InternalLbVm);
 +                internalLbOffProviders.put(Service.SourceNat, Provider.VPCVirtualRouter);
 +
 +                for (Service service : internalLbOffProviders.keySet()) {
 +                    NetworkOfferingServiceMapVO offService = new NetworkOfferingServiceMapVO(internalLbOff.getId(), service, internalLbOffProviders.get(service));
 +                    _ntwkOfferingServiceMapDao.persist(offService);
 +                    s_logger.trace("Added service for the network offering: " + offService);
 +                }
 +
 +                _networkOfferingDao.persistDefaultL2NetworkOfferings();
 +            }
 +        });
 +    }
 +
 +    private void createDefaultNetworks() {
 +        List<DataCenterVO> zones = _dataCenterDao.listAll();
 +        long id = 1;
 +
 +        HashMap<TrafficType, String> guruNames = new HashMap<TrafficType, String>();
 +        guruNames.put(TrafficType.Public, PublicNetworkGuru.class.getSimpleName());
 +        guruNames.put(TrafficType.Management, PodBasedNetworkGuru.class.getSimpleName());
 +        guruNames.put(TrafficType.Control, ControlNetworkGuru.class.getSimpleName());
 +        guruNames.put(TrafficType.Storage, StorageNetworkGuru.class.getSimpleName());
 +        guruNames.put(TrafficType.Guest, DirectPodBasedNetworkGuru.class.getSimpleName());
 +
 +        for (DataCenterVO zone : zones) {
 +            long zoneId = zone.getId();
 +            long accountId = 1L;
 +            Long domainId = zone.getDomainId();
 +
 +            if (domainId == null) {
 +                domainId = 1L;
 +            }
 +            // Create default networks - system only
 +            List<NetworkOfferingVO> ntwkOff = _networkOfferingDao.listSystemNetworkOfferings();
 +
 +            for (NetworkOfferingVO offering : ntwkOff) {
 +                if (offering.isSystemOnly()) {
 +                    long related = id;
 +                    long networkOfferingId = offering.getId();
 +                    Mode mode = Mode.Static;
 +                    String networkDomain = null;
 +
 +                    BroadcastDomainType broadcastDomainType = null;
 +                    TrafficType trafficType = offering.getTrafficType();
 +
 +                    boolean specifyIpRanges = false;
 +
 +                    if (trafficType == TrafficType.Management) {
 +                        broadcastDomainType = BroadcastDomainType.Native;
 +                    } else if (trafficType == TrafficType.Storage) {
 +                        broadcastDomainType = BroadcastDomainType.Native;
 +                        specifyIpRanges = true;
 +                    } else if (trafficType == TrafficType.Control) {
 +                        broadcastDomainType = BroadcastDomainType.LinkLocal;
 +                    } else if (offering.getTrafficType() == TrafficType.Public) {
 +                        if ((zone.getNetworkType() == NetworkType.Advanced && !zone.isSecurityGroupEnabled()) || zone.getNetworkType() == NetworkType.Basic) {
 +                            specifyIpRanges = true;
 +                            broadcastDomainType = BroadcastDomainType.Vlan;
 +                        } else {
 +                            continue;
 +                        }
 +                    }
 +
 +                    if (broadcastDomainType != null) {
 +                        NetworkVO network =
 +                                new NetworkVO(id, trafficType, mode, broadcastDomainType, networkOfferingId, domainId, accountId, related, null, null, networkDomain,
 +                                        Network.GuestType.Shared, zoneId, null, null, specifyIpRanges, null, offering.isRedundantRouter());
 +                        network.setGuruName(guruNames.get(network.getTrafficType()));
 +                        network.setDns1(zone.getDns1());
 +                        network.setDns2(zone.getDns2());
 +                        network.setState(State.Implemented);
 +                        _networkDao.persist(network, false, getServicesAndProvidersForNetwork(networkOfferingId));
 +                        id++;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    private void updateVlanWithNetworkId(VlanVO vlan) {
 +        long zoneId = vlan.getDataCenterId();
 +        long networkId = 0L;
 +        DataCenterVO zone = _zoneDao.findById(zoneId);
 +
 +        if (zone.getNetworkType() == NetworkType.Advanced) {
 +            networkId = getSystemNetworkIdByZoneAndTrafficType(zoneId, TrafficType.Public);
 +        } else {
 +            networkId = getSystemNetworkIdByZoneAndTrafficType(zoneId, TrafficType.Guest);
 +        }
 +
 +        vlan.setNetworkId(networkId);
 +        _vlanDao.update(vlan.getId(), vlan);
 +    }
 +
 +    private long getSystemNetworkIdByZoneAndTrafficType(long zoneId, TrafficType trafficType) {
 +        // find system public network offering
 +        Long networkOfferingId = null;
 +        List<NetworkOfferingVO> offerings = _networkOfferingDao.listSystemNetworkOfferings();
 +        for (NetworkOfferingVO offering : offerings) {
 +            if (offering.getTrafficType() == trafficType) {
 +                networkOfferingId = offering.getId();
 +                break;
 +            }
 +        }
 +
 +        if (networkOfferingId == null) {
 +            throw new InvalidParameterValueException("Unable to find system network offering with traffic type " + trafficType);
 +        }
 +
 +        List<NetworkVO> networks = _networkDao.listBy(Account.ACCOUNT_ID_SYSTEM, networkOfferingId, zoneId);
 +        if (networks == null || networks.isEmpty()) {
 +            throw new InvalidParameterValueException("Unable to find network with traffic type " + trafficType + " in zone " + zoneId);
 +        }
 +        return networks.get(0).getId();
 +    }
 +
 +    @DB
 +    public void updateResourceCount() {
 +        ResourceType[] resourceTypes = Resource.ResourceType.values();
 +        List<AccountVO> accounts = _accountDao.listAll();
 +        List<DomainVO> domains = _domainDao.listAll();
 +        List<ResourceCountVO> domainResourceCount = _resourceCountDao.listResourceCountByOwnerType(ResourceOwnerType.Domain);
 +        List<ResourceCountVO> accountResourceCount = _resourceCountDao.listResourceCountByOwnerType(ResourceOwnerType.Account);
 +
 +        final List<ResourceType> accountSupportedResourceTypes = new ArrayList<ResourceType>();
 +        final List<ResourceType> domainSupportedResourceTypes = new ArrayList<ResourceType>();
 +
 +        for (ResourceType resourceType : resourceTypes) {
 +            if (resourceType.supportsOwner(ResourceOwnerType.Account)) {
 +                accountSupportedResourceTypes.add(resourceType);
 +            }
 +            if (resourceType.supportsOwner(ResourceOwnerType.Domain)) {
 +                domainSupportedResourceTypes.add(resourceType);
 +            }
 +        }
 +
 +        final int accountExpectedCount = accountSupportedResourceTypes.size();
 +        final int domainExpectedCount = domainSupportedResourceTypes.size();
 +
 +        if ((domainResourceCount.size() < domainExpectedCount * domains.size())) {
 +            s_logger.debug("resource_count table has records missing for some domains...going to insert them");
 +            for (final DomainVO domain : domains) {
 +                // Lock domain
 +                Transaction.execute(new TransactionCallbackNoReturn() {
 +                    @Override
 +                    public void doInTransactionWithoutResult(TransactionStatus status) {
 +                        _domainDao.lockRow(domain.getId(), true);
 +                        List<ResourceCountVO> domainCounts = _resourceCountDao.listByOwnerId(domain.getId(), ResourceOwnerType.Domain);
 +                        List<String> domainCountStr = new ArrayList<String>();
 +                        for (ResourceCountVO domainCount : domainCounts) {
 +                            domainCountStr.add(domainCount.getType().toString());
 +                        }
 +
 +                        if (domainCountStr.size() < domainExpectedCount) {
 +                            for (ResourceType resourceType : domainSupportedResourceTypes) {
 +                                if (!domainCountStr.contains(resourceType.toString())) {
 +                                    ResourceCountVO resourceCountVO = new ResourceCountVO(resourceType, 0, domain.getId(), ResourceOwnerType.Domain);
 +                                    s_logger.debug("Inserting resource count of type " + resourceType + " for domain id=" + domain.getId());
 +                                    _resourceCountDao.persist(resourceCountVO);
 +                                }
 +                            }
 +                        }
 +                    }
 +                });
 +
 +            }
 +        }
 +
 +        if ((accountResourceCount.size() < accountExpectedCount * accounts.size())) {
 +            s_logger.debug("resource_count table has records missing for some accounts...going to insert them");
 +            for (final AccountVO account : accounts) {
 +                // lock account
 +                Transaction.execute(new TransactionCallbackNoReturn() {
 +                    @Override
 +                    public void doInTransactionWithoutResult(TransactionStatus status) {
 +                        _accountDao.lockRow(account.getId(), true);
 +                        List<ResourceCountVO> accountCounts = _resourceCountDao.listByOwnerId(account.getId(), ResourceOwnerType.Account);
 +                        List<String> accountCountStr = new ArrayList<String>();
 +                        for (ResourceCountVO accountCount : accountCounts) {
 +                            accountCountStr.add(accountCount.getType().toString());
 +                        }
 +
 +                        if (accountCountStr.size() < accountExpectedCount) {
 +                            for (ResourceType resourceType : accountSupportedResourceTypes) {
 +                                if (!accountCountStr.contains(resourceType.toString())) {
 +                                    ResourceCountVO resourceCountVO = new ResourceCountVO(resourceType, 0, account.getId(), ResourceOwnerType.Account);
 +                                    s_logger.debug("Inserting resource count of type " + resourceType + " for account id=" + account.getId());
 +                                    _resourceCountDao.persist(resourceCountVO);
 +                                }
 +                            }
 +                        }
 +                    }
 +                });
 +            }
 +        }
 +    }
 +
 +    public Map<String, String> getServicesAndProvidersForNetwork(long networkOfferingId) {
 +        Map<String, String> svcProviders = new HashMap<String, String>();
 +        List<NetworkOfferingServiceMapVO> servicesMap = _ntwkOfferingServiceMapDao.listByNetworkOfferingId(networkOfferingId);
 +
 +        for (NetworkOfferingServiceMapVO serviceMap : servicesMap) {
 +            if (svcProviders.containsKey(serviceMap.getService())) {
 +                continue;
 +            }
 +            svcProviders.put(serviceMap.getService(), serviceMap.getProvider());
 +        }
 +
 +        return svcProviders;
 +    }
 +
 +}