mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-5561 Support of multiple public vlans on VR running in HyperV
This commit is contained in:
parent
ce0dc3b306
commit
807dc09138
68
core/src/com/cloud/agent/api/GetVmConfigAnswer.java
Normal file
68
core/src/com/cloud/agent/api/GetVmConfigAnswer.java
Normal file
@ -0,0 +1,68 @@
|
||||
// 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.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GetVmConfigAnswer extends Answer {
|
||||
|
||||
String vmName;
|
||||
List<NicDetails> nics;
|
||||
|
||||
protected GetVmConfigAnswer() {
|
||||
}
|
||||
|
||||
public GetVmConfigAnswer(String vmName, List<NicDetails> nics) {
|
||||
this.vmName = vmName;
|
||||
this.nics = nics;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public List<NicDetails> getNics() {
|
||||
return nics;
|
||||
}
|
||||
|
||||
public class NicDetails {
|
||||
String macAddress;
|
||||
int vlanid;
|
||||
|
||||
public NicDetails() {
|
||||
}
|
||||
|
||||
public NicDetails(String macAddress, int vlanid) {
|
||||
this.macAddress = macAddress;
|
||||
this.vlanid = vlanid;
|
||||
}
|
||||
|
||||
public String getMacAddress() {
|
||||
return macAddress;
|
||||
}
|
||||
|
||||
public int getVlanid() {
|
||||
return vlanid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
46
core/src/com/cloud/agent/api/GetVmConfigCommand.java
Normal file
46
core/src/com/cloud/agent/api/GetVmConfigCommand.java
Normal file
@ -0,0 +1,46 @@
|
||||
// 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.agent.api;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
|
||||
public class GetVmConfigCommand extends Command {
|
||||
String vmName;
|
||||
List<NicTO> nics;
|
||||
protected GetVmConfigCommand() {
|
||||
}
|
||||
|
||||
public GetVmConfigCommand(String vmName) {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public void setNics(List<NicTO> nics){
|
||||
this.nics = nics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
36
core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java
Normal file
36
core/src/com/cloud/agent/api/ModifyVmNicConfigAnswer.java
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.agent.api;
|
||||
|
||||
public class ModifyVmNicConfigAnswer extends Answer {
|
||||
String vmName;
|
||||
protected ModifyVmNicConfigAnswer() {
|
||||
}
|
||||
|
||||
public ModifyVmNicConfigAnswer(String vmName) {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
42
core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
Normal file
42
core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
Normal file
@ -0,0 +1,42 @@
|
||||
// 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.agent.api;
|
||||
|
||||
|
||||
public class ModifyVmNicConfigCommand extends Command {
|
||||
String vmName;
|
||||
int vlan;
|
||||
String macAddress;
|
||||
protected ModifyVmNicConfigCommand() {
|
||||
}
|
||||
|
||||
public ModifyVmNicConfigCommand(String vmName, int vlan, String macAddress) {
|
||||
this.vmName = vmName;
|
||||
this.vlan = vlan;
|
||||
this.macAddress = macAddress;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@
|
||||
<value>2048</value>
|
||||
</setting>
|
||||
<setting name="private_ip_address" serializeAs="String">
|
||||
<value>10.102.192.150</value>
|
||||
<value>0.0.0.0</value>
|
||||
</setting>
|
||||
</CloudStack.Plugin.AgentShell.AgentSettings>
|
||||
</applicationSettings>
|
||||
|
||||
@ -690,6 +690,20 @@ namespace HypervResource
|
||||
public String entityType;
|
||||
}
|
||||
|
||||
public class NicDetails
|
||||
{
|
||||
[JsonProperty("macAddress")]
|
||||
public string macaddress;
|
||||
[JsonProperty("vlanid")]
|
||||
public int vlanid;
|
||||
public NicDetails() { }
|
||||
public NicDetails(String macaddress, int vlanid)
|
||||
{
|
||||
this.macaddress = macaddress;
|
||||
this.vlanid = vlanid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fully qualified named for a number of types used in CloudStack. Used to specify the intended type for JSON serialised objects.
|
||||
/// </summary>
|
||||
@ -738,6 +752,10 @@ namespace HypervResource
|
||||
public const string GetVmDiskStatsCommand = "com.cloud.agent.api.GetVmDiskStatsCommand";
|
||||
public const string GetVmStatsAnswer = "com.cloud.agent.api.GetVmStatsAnswer";
|
||||
public const string GetVmStatsCommand = "com.cloud.agent.api.GetVmStatsCommand";
|
||||
public const string GetVmConfigCommand = "com.cloud.agent.api.GetVmConfigCommand";
|
||||
public const string GetVmConfigAnswer = "com.cloud.agent.api.GetVmConfigAnswer";
|
||||
public const string ModifyVmNicConfigCommand = "com.cloud.agent.api.ModifyVmNicConfigCommand";
|
||||
public const string ModifyVmNicConfigAnswer = "com.cloud.agent.api.ModifyVmNicConfigAnswer";
|
||||
public const string GetVncPortAnswer = "com.cloud.agent.api.GetVncPortAnswer";
|
||||
public const string GetVncPortCommand = "com.cloud.agent.api.GetVncPortCommand";
|
||||
public const string HostStatsEntry = "com.cloud.agent.api.HostStatsEntry";
|
||||
|
||||
@ -982,6 +982,24 @@ namespace HypervResource
|
||||
return true;
|
||||
}
|
||||
|
||||
// POST api/HypervResource/PlugNicCommand
|
||||
[HttpPost]
|
||||
[ActionName(CloudStackTypes.PlugNicCommand)]
|
||||
public JContainer PlugNicCommand([FromBody]dynamic cmd)
|
||||
{
|
||||
using (log4net.NDC.Push(Guid.NewGuid().ToString()))
|
||||
{
|
||||
logger.Info(CloudStackTypes.PlugNicCommand + cmd.ToString());
|
||||
object ansContent = new
|
||||
{
|
||||
result = true,
|
||||
details = "instead of plug, change he network settings",
|
||||
contextMap = contextMap
|
||||
};
|
||||
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PlugNicAnswer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// POST api/HypervResource/CleanupNetworkRulesCmd
|
||||
[HttpPost]
|
||||
@ -1264,6 +1282,88 @@ namespace HypervResource
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/HypervResource/ModifyVmVnicVlanCommand
|
||||
[HttpPost]
|
||||
[ActionName(CloudStackTypes.ModifyVmNicConfigCommand)]
|
||||
public JContainer ModifyVmNicConfigCommand([FromBody]dynamic cmd)
|
||||
{
|
||||
|
||||
using (log4net.NDC.Push(Guid.NewGuid().ToString()))
|
||||
{
|
||||
logger.Info(CloudStackTypes.ModifyVmNicConfigCommand + cmd.ToString());
|
||||
bool result = false;
|
||||
String vmName = cmd.vmName;
|
||||
uint vlan = (uint)cmd.vlan;
|
||||
string macAddress = cmd.macAddress;
|
||||
wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress);
|
||||
|
||||
result = true;
|
||||
|
||||
object ansContent = new
|
||||
{
|
||||
vmName = vmName,
|
||||
result = result,
|
||||
contextMap = contextMap
|
||||
};
|
||||
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyVmNicConfigAnswer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// POST api/HypervResource/GetVmConfigCommand
|
||||
[HttpPost]
|
||||
[ActionName(CloudStackTypes.GetVmConfigCommand)]
|
||||
public JContainer GetVmConfigCommand([FromBody]dynamic cmd)
|
||||
{
|
||||
using (log4net.NDC.Push(Guid.NewGuid().ToString()))
|
||||
{
|
||||
logger.Info(CloudStackTypes.GetVmConfigCommand + cmd.ToString());
|
||||
bool result = false;
|
||||
String vmName = cmd.vmName;
|
||||
ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName);
|
||||
List<NicDetails> nicDetails = new List<NicDetails>();
|
||||
var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm);
|
||||
NicDetails nic = null;
|
||||
String[] macAddress = new String[nicSettingsViaVm.Length];
|
||||
int index = 0;
|
||||
foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
|
||||
{
|
||||
macAddress[index++] = item.Address;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm);
|
||||
int vlanid = 1;
|
||||
foreach (EthernetPortAllocationSettingData item in ethernetConnections)
|
||||
{
|
||||
EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item);
|
||||
if (vlanSettings == null)
|
||||
{
|
||||
vlanid = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlanid = vlanSettings.AccessVlanId;
|
||||
}
|
||||
nic = new NicDetails(macAddress[index++], vlanid);
|
||||
nicDetails.Add(nic);
|
||||
}
|
||||
|
||||
result = true;
|
||||
|
||||
object ansContent = new
|
||||
{
|
||||
vmName = vmName,
|
||||
nics = nicDetails,
|
||||
result = result,
|
||||
contextMap = contextMap
|
||||
};
|
||||
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmConfigAnswer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// POST api/HypervResource/GetVmStatsCommand
|
||||
[HttpPost]
|
||||
[ActionName(CloudStackTypes.GetVmStatsCommand)]
|
||||
|
||||
@ -66,5 +66,6 @@ namespace HypervResource
|
||||
void patchSystemVmIso(string vmName, string systemVmIso);
|
||||
void SetState(ComputerSystem vm, ushort requiredState);
|
||||
Dictionary<String, VmState> GetVmSync(String privateIpAddress);
|
||||
void ModifyVmVLan(string vmName, uint vlanid, string mac);
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,6 +443,7 @@ namespace HypervResource
|
||||
nicCount++;
|
||||
}
|
||||
|
||||
|
||||
// pass the boot args for the VM using KVP component.
|
||||
// We need to pass the boot args to system vm's to get them configured with cloudstack configuration.
|
||||
// Add new user data
|
||||
@ -909,6 +910,37 @@ namespace HypervResource
|
||||
return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
|
||||
}
|
||||
|
||||
|
||||
// Modify the systemvm nic's VLAN id
|
||||
public void ModifyVmVLan(string vmName, uint vlanid, String mac)
|
||||
{
|
||||
ComputerSystem vm = GetComputerSystem(vmName);
|
||||
SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
|
||||
// Obtain controller for Hyper-V virtualisation subsystem
|
||||
VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
|
||||
string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
|
||||
int index = 0;
|
||||
foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
|
||||
{
|
||||
if (normalisedMAC.ToLower().Equals(item.Address.ToLower()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
//TODO: make sure the index wont be out of range.
|
||||
|
||||
EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
|
||||
EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]);
|
||||
|
||||
//Assign configuration to new NIC
|
||||
vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
|
||||
vlanSettings.LateBoundObject["OperationMode"] = 1;
|
||||
ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
|
||||
vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
|
||||
}
|
||||
|
||||
public void AttachIso(string displayName, string iso)
|
||||
{
|
||||
logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName);
|
||||
@ -1420,6 +1452,36 @@ namespace HypervResource
|
||||
return vSwitch;
|
||||
}
|
||||
|
||||
|
||||
private static void ModifyFeatureVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
|
||||
{
|
||||
// Resource settings are changed through the management service
|
||||
System.Management.ManagementPath jobPath;
|
||||
System.Management.ManagementPath[] results;
|
||||
|
||||
var ret_val = vmMgmtSvc.ModifyFeatureSettings(
|
||||
resourceSettings,
|
||||
out jobPath,
|
||||
out results);
|
||||
|
||||
// If the Job is done asynchronously
|
||||
if (ret_val == ReturnCode.Started)
|
||||
{
|
||||
JobCompleted(jobPath);
|
||||
}
|
||||
else if (ret_val != ReturnCode.Completed)
|
||||
{
|
||||
var errMsg = string.Format(
|
||||
"Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",
|
||||
vm.ElementName,
|
||||
vm.Name,
|
||||
ReturnCode.ToString(ret_val));
|
||||
var ex = new WmiException(errMsg);
|
||||
logger.Error(errMsg, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
|
||||
{
|
||||
// Resource settings are changed through the management service
|
||||
|
||||
@ -16,15 +16,30 @@
|
||||
// under the License.
|
||||
package com.cloud.hypervisor.hyperv.guru;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.hypervisor.HypervisorGuru;
|
||||
import com.cloud.hypervisor.HypervisorGuruBase;
|
||||
import com.cloud.storage.GuestOSVO;
|
||||
import com.cloud.storage.dao.GuestOSDao;
|
||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||
import com.cloud.hypervisor.hyperv.manager.HypervManager;
|
||||
import com.cloud.network.NetworkModel;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.NicProfile;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
/**
|
||||
@ -35,6 +50,9 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
|
||||
|
||||
@Inject
|
||||
private GuestOSDao _guestOsDao;
|
||||
@Inject HypervManager _hypervMgr;
|
||||
@Inject NetworkDao _networkDao;
|
||||
@Inject NetworkModel _networkMgr;
|
||||
|
||||
@Override
|
||||
public final HypervisorType getHypervisorType() {
|
||||
@ -51,6 +69,78 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
|
||||
@Override
|
||||
public final VirtualMachineTO implement(VirtualMachineProfile vm) {
|
||||
VirtualMachineTO to = toVirtualMachineTO(vm);
|
||||
List<NicProfile> nicProfiles = vm.getNics();
|
||||
|
||||
if(vm.getVirtualMachine().getType() == VirtualMachine.Type.DomainRouter) {
|
||||
|
||||
NicProfile publicNicProfile = null;
|
||||
for(NicProfile nicProfile : nicProfiles) {
|
||||
if(nicProfile.getTrafficType() == TrafficType.Public) {
|
||||
publicNicProfile = nicProfile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(publicNicProfile != null) {
|
||||
NicTO[] nics = to.getNics();
|
||||
|
||||
// reserve extra NICs
|
||||
NicTO[] expandedNics = new NicTO[nics.length + _hypervMgr.getRouterExtraPublicNics()];
|
||||
int i = 0;
|
||||
int deviceId = -1;
|
||||
for(i = 0; i < nics.length; i++) {
|
||||
expandedNics[i] = nics[i];
|
||||
if(nics[i].getDeviceId() > deviceId)
|
||||
deviceId = nics[i].getDeviceId();
|
||||
}
|
||||
deviceId++;
|
||||
|
||||
long networkId = publicNicProfile.getNetworkId();
|
||||
NetworkVO network = _networkDao.findById(networkId);
|
||||
|
||||
for(; i < nics.length + _hypervMgr.getRouterExtraPublicNics(); i++) {
|
||||
NicTO nicTo = new NicTO();
|
||||
nicTo.setDeviceId(deviceId++);
|
||||
nicTo.setBroadcastType(publicNicProfile.getBroadcastType());
|
||||
nicTo.setType(publicNicProfile.getTrafficType());
|
||||
nicTo.setIp("0.0.0.0");
|
||||
nicTo.setNetmask("255.255.255.255");
|
||||
nicTo.setName(publicNicProfile.getName());
|
||||
|
||||
try {
|
||||
String mac = _networkMgr.getNextAvailableMacAddressInNetwork(networkId);
|
||||
nicTo.setMac(mac);
|
||||
} catch (InsufficientAddressCapacityException e) {
|
||||
throw new CloudRuntimeException("unable to allocate mac address on network: " + networkId);
|
||||
}
|
||||
nicTo.setDns1(publicNicProfile.getDns1());
|
||||
nicTo.setDns2(publicNicProfile.getDns2());
|
||||
if (publicNicProfile.getGateway() != null) {
|
||||
nicTo.setGateway(publicNicProfile.getGateway());
|
||||
} else {
|
||||
nicTo.setGateway(network.getGateway());
|
||||
}
|
||||
nicTo.setDefaultNic(false);
|
||||
nicTo.setBroadcastUri(publicNicProfile.getBroadCastUri());
|
||||
nicTo.setIsolationuri(publicNicProfile.getIsolationUri());
|
||||
|
||||
Integer networkRate = _networkMgr.getNetworkRate(network.getId(), null);
|
||||
nicTo.setNetworkRateMbps(networkRate);
|
||||
|
||||
expandedNics[i] = nicTo;
|
||||
}
|
||||
to.setNics(expandedNics);
|
||||
}
|
||||
|
||||
StringBuffer sbMacSequence = new StringBuffer();
|
||||
for(NicTO nicTo : sortNicsByDeviceId(to.getNics())) {
|
||||
sbMacSequence.append(nicTo.getMac()).append("|");
|
||||
}
|
||||
sbMacSequence.deleteCharAt(sbMacSequence.length() - 1);
|
||||
String bootArgs = to.getBootArgs();
|
||||
to.setBootArgs(bootArgs + " nic_macs=" + sbMacSequence.toString());
|
||||
|
||||
}
|
||||
|
||||
// Determine the VM's OS description
|
||||
GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId());
|
||||
@ -59,6 +149,29 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
|
||||
return to;
|
||||
}
|
||||
|
||||
private NicTO[] sortNicsByDeviceId(NicTO[] nics) {
|
||||
|
||||
List<NicTO> listForSort = new ArrayList<NicTO>();
|
||||
for (NicTO nic : nics) {
|
||||
listForSort.add(nic);
|
||||
}
|
||||
Collections.sort(listForSort, new Comparator<NicTO>() {
|
||||
|
||||
@Override
|
||||
public int compare(NicTO arg0, NicTO arg1) {
|
||||
if (arg0.getDeviceId() < arg1.getDeviceId()) {
|
||||
return -1;
|
||||
} else if (arg0.getDeviceId() == arg1.getDeviceId()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
return listForSort.toArray(new NicTO[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean trackVmHostChange() {
|
||||
return false;
|
||||
|
||||
@ -21,4 +21,5 @@ import com.cloud.utils.component.Manager;
|
||||
|
||||
public interface HypervManager extends Manager {
|
||||
public String prepareSecondaryStorageStore(long zoneId);
|
||||
int getRouterExtraPublicNics();
|
||||
}
|
||||
|
||||
@ -45,6 +45,8 @@ import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GlobalLock;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.script.Script;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
@Local(value = {HypervManager.class})
|
||||
public class HypervManagerImpl implements HypervManager {
|
||||
@ -60,10 +62,11 @@ public class HypervManagerImpl implements HypervManager {
|
||||
Map<String, String> _storageMounts = new HashMap<String, String>();
|
||||
StorageLayer _storage;
|
||||
|
||||
@Inject
|
||||
ConfigurationDao _configDao;
|
||||
@Inject
|
||||
DataStoreManager _dataStoreMgr;
|
||||
@Inject ConfigurationDao _configDao;
|
||||
@Inject DataStoreManager _dataStoreMgr;
|
||||
@Inject VMInstanceDao _vminstanceDao;
|
||||
@Inject NicDao _nicDao;
|
||||
int _routerExtraPublicNics = 2;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
@ -77,7 +80,7 @@ public class HypervManagerImpl implements HypervManager {
|
||||
_storage = new JavaStorageLayer();
|
||||
_storage.configure("StorageLayer", params);
|
||||
}
|
||||
|
||||
_routerExtraPublicNics = NumbersUtil.parseInt(_configDao.getValue(Config.RouterExtraPublicNics.key()), 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -373,4 +376,9 @@ public class HypervManagerImpl implements HypervManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRouterExtraPublicNics() {
|
||||
return _routerExtraPublicNics;
|
||||
}
|
||||
}
|
||||
@ -71,7 +71,12 @@ import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.GetDomRVersionAnswer;
|
||||
import com.cloud.agent.api.GetDomRVersionCmd;
|
||||
import com.cloud.agent.api.GetVmConfigAnswer;
|
||||
import com.cloud.agent.api.GetVmConfigAnswer.NicDetails;
|
||||
import com.cloud.agent.api.GetVmConfigCommand;
|
||||
import com.cloud.agent.api.HostVmStateReportEntry;
|
||||
import com.cloud.agent.api.ModifyVmNicConfigAnswer;
|
||||
import com.cloud.agent.api.ModifyVmNicConfigCommand;
|
||||
import com.cloud.agent.api.NetworkUsageAnswer;
|
||||
import com.cloud.agent.api.NetworkUsageCommand;
|
||||
import com.cloud.agent.api.PingCommand;
|
||||
@ -117,11 +122,13 @@ import com.cloud.agent.api.to.PortForwardingRuleTO;
|
||||
import com.cloud.agent.api.to.StaticNatRuleTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.dc.DataCenter.NetworkType;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.host.Host.Type;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.hypervisor.hyperv.manager.HypervManager;
|
||||
import com.cloud.network.HAProxyConfigurator;
|
||||
import com.cloud.network.LoadBalancerConfigurator;
|
||||
import com.cloud.network.Networks.BroadcastDomainType;
|
||||
import com.cloud.network.Networks.RouterPrivateIpStrategy;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
import com.cloud.resource.ServerResource;
|
||||
@ -133,6 +140,8 @@ import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.utils.ssh.SshHelper;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineName;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of dummy resource to be returned from discoverer.
|
||||
**/
|
||||
@ -706,65 +715,6 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// find mac address of a specified ethx device
|
||||
// ip address show ethx | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2
|
||||
// returns
|
||||
// eth0:xx.xx.xx.xx
|
||||
|
||||
//
|
||||
// list IP with eth devices
|
||||
// ifconfig ethx |grep -B1 "inet addr" | awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }'
|
||||
// | awk -F: '{ print $1 ": " $3 }'
|
||||
//
|
||||
// returns
|
||||
// eth0:xx.xx.xx.xx
|
||||
//
|
||||
//
|
||||
|
||||
private int findRouterEthDeviceIndex(String domrName, String routerIp, String mac) throws Exception {
|
||||
|
||||
s_logger.info("findRouterEthDeviceIndex. mac: " + mac);
|
||||
|
||||
// TODO : this is a temporary very inefficient solution, will refactor it later
|
||||
Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "ls /proc/sys/net/ipv4/conf");
|
||||
|
||||
// when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
|
||||
// we use a waiting loop here as a workaround to synchronize activities in systems
|
||||
long startTick = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - startTick < 15000) {
|
||||
if (result.first()) {
|
||||
String[] tokens = result.second().split("\\s+");
|
||||
for (String token : tokens) {
|
||||
if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
|
||||
String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
|
||||
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Run domr script " + cmd);
|
||||
Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
||||
// TODO need to find the dev index inside router based on IP address
|
||||
cmd);
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
|
||||
|
||||
if (result2.first() && result2.second().trim().equalsIgnoreCase(mac.trim()))
|
||||
return Integer.parseInt(token.substring(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_logger.warn("can not find intereface associated with mac: " + mac + ", guest OS may still at loading state, retry...");
|
||||
|
||||
try {
|
||||
Thread.currentThread();
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected Answer execute(SetPortForwardingRulesCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource SetPortForwardingRulesCommand: " + s_gson.toJson(cmd));
|
||||
@ -1170,7 +1120,6 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource VmDataCommand: " + s_gson.toJson(cmd));
|
||||
}
|
||||
|
||||
String routerPrivateIpAddress = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
|
||||
String controlIp = getRouterSshControlIp(cmd);
|
||||
|
||||
@ -1386,6 +1335,102 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
return new Answer(cmd);
|
||||
}
|
||||
|
||||
//
|
||||
// find mac address of a specified ethx device
|
||||
// ip address show ethx | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2
|
||||
// returns
|
||||
// eth0:xx.xx.xx.xx
|
||||
|
||||
//
|
||||
// list IP with eth devices
|
||||
// ifconfig ethx |grep -B1 "inet addr" | awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }'
|
||||
// | awk -F: '{ print $1 ": " $3 }'
|
||||
//
|
||||
// returns
|
||||
// eth0:xx.xx.xx.xx
|
||||
//
|
||||
//
|
||||
|
||||
private int findRouterEthDeviceIndex(String domrName, String routerIp, String mac) throws Exception {
|
||||
|
||||
s_logger.info("findRouterEthDeviceIndex. mac: " + mac);
|
||||
|
||||
// TODO : this is a temporary very inefficient solution, will refactor it later
|
||||
Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
||||
"ls /proc/sys/net/ipv4/conf");
|
||||
|
||||
// when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
|
||||
// we use a waiting loop here as a workaround to synchronize activities in systems
|
||||
long startTick = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - startTick < 15000) {
|
||||
if (result.first()) {
|
||||
String[] tokens = result.second().split("\\s+");
|
||||
for (String token : tokens) {
|
||||
if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
|
||||
String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
|
||||
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Run domr script " + cmd);
|
||||
Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
||||
// TODO need to find the dev index inside router based on IP address
|
||||
cmd);
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
|
||||
|
||||
if (result2.first() && result2.second().trim().equalsIgnoreCase(mac.trim()))
|
||||
return Integer.parseInt(token.substring(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_logger.warn("can not find intereface associated with mac: " + mac + ", guest OS may still at loading state, retry...");
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Pair<Integer, String> findRouterFreeEthDeviceIndex(String routerIp) throws Exception {
|
||||
|
||||
s_logger.info("findRouterFreeEthDeviceIndex. mac: ");
|
||||
|
||||
// TODO : this is a temporary very inefficient solution, will refactor it later
|
||||
Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
||||
"ip address | grep DOWN| cut -f2 -d :");
|
||||
|
||||
// when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
|
||||
// we use a waiting loop here as a workaround to synchronize activities in systems
|
||||
long startTick = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - startTick < 15000) {
|
||||
if (result.first() && !result.second().isEmpty()) {
|
||||
String[] tokens = result.second().split("\\n");
|
||||
for (String token : tokens) {
|
||||
if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
|
||||
//String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
|
||||
//TODO: don't check for eth0,1,2, as they will be empty by default.
|
||||
//String cmd = String.format("ip address show %s ", token);
|
||||
String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Run domr script " + cmd);
|
||||
Pair<Boolean, String> result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
||||
// TODO need to find the dev index inside router based on IP address
|
||||
cmd);
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
|
||||
|
||||
if (result2.first() && result2.second().trim().length() > 0)
|
||||
return new Pair<Integer, String>(Integer.parseInt(token.trim().substring(3)), result2.second().trim()) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//s_logger.warn("can not find intereface associated with mac: , guest OS may still at loading state, retry...");
|
||||
|
||||
}
|
||||
|
||||
return new Pair<Integer, String>(-1, "");
|
||||
}
|
||||
|
||||
protected Answer execute(IpAssocCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource IPAssocCommand: " + s_gson.toJson(cmd));
|
||||
@ -1419,16 +1464,97 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
return new IpAssocAnswer(cmd, results);
|
||||
}
|
||||
|
||||
protected int getVmNics(String vmName, int vlanid) {
|
||||
GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName);
|
||||
URI agentUri = null;
|
||||
int nicposition = -1;
|
||||
try {
|
||||
String cmdName = GetVmConfigCommand.class.getName();
|
||||
agentUri =
|
||||
new URI("https", null, _agentIp, _port,
|
||||
"/api/HypervResource/" + cmdName, null, null);
|
||||
} catch (URISyntaxException e) {
|
||||
String errMsg = "Could not generate URI for Hyper-V agent";
|
||||
s_logger.error(errMsg, e);
|
||||
}
|
||||
String ansStr = postHttpRequest(s_gson.toJson(vmConfig), agentUri);
|
||||
Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
|
||||
s_logger.debug("executeRequest received response "
|
||||
+ s_gson.toJson(result));
|
||||
if (result.length > 0) {
|
||||
GetVmConfigAnswer ans = ((GetVmConfigAnswer)result[0]);
|
||||
List<NicDetails> nics = ans.getNics();
|
||||
for (NicDetails nic : nics) {
|
||||
if (nic.getVlanid() == vlanid) {
|
||||
nicposition = nics.indexOf(nic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nicposition;
|
||||
}
|
||||
|
||||
protected void modifyNicVlan(String vmName, int vlanId, String macAddress) {
|
||||
ModifyVmNicConfigCommand modifynic = new ModifyVmNicConfigCommand(vmName, vlanId, macAddress);
|
||||
URI agentUri = null;
|
||||
try {
|
||||
String cmdName = ModifyVmNicConfigCommand.class.getName();
|
||||
agentUri =
|
||||
new URI("https", null, _agentIp, _port,
|
||||
"/api/HypervResource/" + cmdName, null, null);
|
||||
} catch (URISyntaxException e) {
|
||||
String errMsg = "Could not generate URI for Hyper-V agent";
|
||||
s_logger.error(errMsg, e);
|
||||
}
|
||||
String ansStr = postHttpRequest(s_gson.toJson(modifynic), agentUri);
|
||||
Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
|
||||
s_logger.debug("executeRequest received response "
|
||||
+ s_gson.toJson(result));
|
||||
if (result.length > 0) {
|
||||
ModifyVmNicConfigAnswer ans = ((ModifyVmNicConfigAnswer)result[0]);
|
||||
}
|
||||
}
|
||||
|
||||
protected void assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP,
|
||||
final boolean sourceNat, final String vlanId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception {
|
||||
final boolean sourceNat, final String broadcastId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception {
|
||||
|
||||
URI broadcastUri = BroadcastDomainType.fromString(broadcastId);
|
||||
if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) {
|
||||
throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + broadcastId);
|
||||
}
|
||||
int vlanId = Integer.parseInt(BroadcastDomainType.getValue(broadcastUri));
|
||||
|
||||
int publicNicInfo = -1;
|
||||
publicNicInfo = getVmNics(vmName, vlanId);
|
||||
|
||||
boolean addVif = false;
|
||||
if (add) {
|
||||
if (add && publicNicInfo == -1) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Plug new NIC to associate" + privateIpAddress + " to " + publicIpAddress);
|
||||
}
|
||||
addVif = true;
|
||||
} else if (!add && firstIP) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Unplug NIC " + publicNicInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (addVif) {
|
||||
Pair<Integer, String> nicdevice = findRouterFreeEthDeviceIndex(privateIpAddress);
|
||||
publicNicInfo = nicdevice.first();
|
||||
if (publicNicInfo > 0) {
|
||||
modifyNicVlan(vmName, vlanId, nicdevice.second());
|
||||
// After modifying the vnic on VR, check the VR VNics config in the host and get the device position
|
||||
publicNicInfo = getVmNics(vmName, vlanId);
|
||||
// As a new nic got activated in the VR. add the entry in the NIC's table.
|
||||
networkUsage(privateIpAddress, "addVif", "eth" + publicNicInfo);
|
||||
}
|
||||
else {
|
||||
// we didn't find any eth device available in VR to configure the ip range with new VLAN
|
||||
String msg = "No Nic is available on DomR VIF to associate/disassociate IP with.";
|
||||
s_logger.error(msg);
|
||||
throw new InternalErrorException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
String args = null;
|
||||
@ -1450,8 +1576,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
args += publicIpAddress + "/" + cidrSize;
|
||||
|
||||
args += " -c ";
|
||||
args += "eth" + "2"; // currently hardcoding to eth 2 (which is default public ipd)//publicNicInfo.first();
|
||||
|
||||
args += "eth" + publicNicInfo;
|
||||
args += " -g ";
|
||||
args += vlanGateway;
|
||||
|
||||
@ -1840,7 +1966,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
|
||||
sch.connect(addr);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
s_logger.info("Could not connect to " + ipAddress + " due to " + e.toString());
|
||||
s_logger.info("Could] not connect to " + ipAddress + " due to " + e.toString());
|
||||
if (e instanceof ConnectException) {
|
||||
// if connection is refused because of VM is being started,
|
||||
// we give it more sleep time
|
||||
|
||||
@ -2125,7 +2125,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
|
||||
buf.append(" dnssearchorder=").append(domain_suffix);
|
||||
}
|
||||
|
||||
if (profile.getHypervisorType() == HypervisorType.VMware) {
|
||||
if (profile.getHypervisorType() == HypervisorType.VMware || profile.getHypervisorType() == HypervisorType.Hyperv) {
|
||||
buf.append(" extra_pubnics=" + _routerExtraPublicNics);
|
||||
}
|
||||
|
||||
|
||||
@ -254,10 +254,11 @@ remove_first_ip() {
|
||||
if [ $? -gt 0 -a $? -ne 2 ]
|
||||
then
|
||||
remove_routing $1
|
||||
sudo ip link set $ethDev down
|
||||
return 1
|
||||
fi
|
||||
remove_routing $1
|
||||
|
||||
sudo ip link set $ethDev down
|
||||
return $?
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user