CLOUDSTACK-9776: extra DHCP options support for Nuage VSP

Co-Authored-By: Frank Maximus <frank.maximus@nuagenetworks.net>
Co-Authored-By: Prashanth Manthena <prashanth.manthena@nuagenetworks.net>
Co-Authored-By: Raf Smeets <raf.smeets@nuagenetworks.net>

Bug: https://issues.apache.org/jira/browse/CLOUDSTACK-9776

Design-Doc: https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+extra+DHCP+option+support
This commit is contained in:
Sigert Goeminne 2017-04-18 11:31:45 +02:00 committed by Frank Maximus
parent 421f1072d5
commit 77864992fe
41 changed files with 3145 additions and 70 deletions

View File

@ -47,7 +47,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
private static List<Service> supportedServices = new ArrayList<Service>(); private static List<Service> supportedServices = new ArrayList<Service>();
public static final Service Vpn = new Service("Vpn", Capability.SupportedVpnProtocols, Capability.VpnTypes); public static final Service Vpn = new Service("Vpn", Capability.SupportedVpnProtocols, Capability.VpnTypes);
public static final Service Dhcp = new Service("Dhcp"); public static final Service Dhcp = new Service("Dhcp", Capability.ExtraDhcpOptions);
public static final Service Dns = new Service("Dns", Capability.AllowDnsSuffixModification); public static final Service Dns = new Service("Dns", Capability.AllowDnsSuffixModification);
public static final Service Gateway = new Service("Gateway"); public static final Service Gateway = new Service("Gateway");
public static final Service Firewall = new Service("Firewall", Capability.SupportedProtocols, Capability.MultipleIps, Capability.TrafficStatistics, public static final Service Firewall = new Service("Firewall", Capability.SupportedProtocols, Capability.MultipleIps, Capability.TrafficStatistics,
@ -218,6 +218,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
public static final Capability RegionLevelVpc = new Capability("RegionLevelVpc"); public static final Capability RegionLevelVpc = new Capability("RegionLevelVpc");
public static final Capability NoVlan = new Capability("NoVlan"); public static final Capability NoVlan = new Capability("NoVlan");
public static final Capability PublicAccess = new Capability("PublicAccess"); public static final Capability PublicAccess = new Capability("PublicAccess");
public static final Capability ExtraDhcpOptions = new Capability("ExtraDhcpOptions");
private final String name; private final String name;

View File

@ -16,6 +16,8 @@
// under the License. // under the License.
package com.cloud.network.element; package com.cloud.network.element;
import java.util.Map;
import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
@ -33,4 +35,6 @@ public interface DhcpServiceProvider extends NetworkElement {
throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException; throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException; boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException;
boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions);
} }

View File

@ -0,0 +1,41 @@
// 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.vm;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface NicExtraDhcpOption extends InternalIdentity, Identity {
/**
* Returns the nic id for which the DHCP option applies
* @return nic id
*/
long getNicId();
/**
* Returns the DHCP option code
* @return
*/
int getCode();
/**
* Returns the Dhcp value
* @return
*/
String getValue();
}

View File

@ -194,6 +194,8 @@ public interface UserVmService {
* @param memory * @param memory
* @param cpuNumber * @param cpuNumber
* @param customId * @param customId
* @param dhcpOptionMap
* - Maps the dhcp option code and the dhcp value to the network uuid
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
@ -208,7 +210,7 @@ public interface UserVmService {
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId) throws InsufficientCapacityException, List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/** /**
@ -267,6 +269,8 @@ public interface UserVmService {
* @param memory * @param memory
* @param cpuNumber * @param cpuNumber
* @param customId * @param customId
* @param dhcpOptionMap
* - Maps the dhcp option code and the dhcp value to the network uuid
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
@ -281,7 +285,7 @@ public interface UserVmService {
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId) throws InsufficientCapacityException, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/** /**
@ -338,6 +342,8 @@ public interface UserVmService {
* @param memory * @param memory
* @param cpuNumber * @param cpuNumber
* @param customId * @param customId
* @param dhcpOptionMap
* - Map that maps the DhcpOption code and their value on the Network uuid
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
@ -352,7 +358,7 @@ public interface UserVmService {
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
Map<String, String> customParameters, String customId) Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;

View File

@ -88,6 +88,9 @@ public class ApiConstants {
public static final String UTILIZATION = "utilization"; public static final String UTILIZATION = "utilization";
public static final String DRIVER = "driver"; public static final String DRIVER = "driver";
public static final String ROOT_DISK_SIZE = "rootdisksize"; public static final String ROOT_DISK_SIZE = "rootdisksize";
public static final String DHCP_OPTIONS_NETWORK_LIST = "dhcpoptionsnetworklist";
public static final String DHCP_OPTIONS = "dhcpoptions";
public static final String DHCP_PREFIX = "dhcp:";
public static final String DISPLAY_NAME = "displayname"; public static final String DISPLAY_NAME = "displayname";
public static final String DISPLAY_NETWORK = "displaynetwork"; public static final String DISPLAY_NETWORK = "displaynetwork";
public static final String DISPLAY_NIC = "displaynic"; public static final String DISPLAY_NIC = "displaynic";
@ -111,6 +114,10 @@ public class ApiConstants {
public static final String END_PORT = "endport"; public static final String END_PORT = "endport";
public static final String ENTRY_TIME = "entrytime"; public static final String ENTRY_TIME = "entrytime";
public static final String EXPIRES = "expires"; public static final String EXPIRES = "expires";
public static final String EXTRA_DHCP_OPTION = "extradhcpoption";
public static final String EXTRA_DHCP_OPTION_NAME = "extradhcpoptionname";
public static final String EXTRA_DHCP_OPTION_CODE = "extradhcpoptioncode";
public static final String EXTRA_DHCP_OPTION_VALUE = "extradhcpvalue";
public static final String FENCE = "fence"; public static final String FENCE = "fence";
public static final String FETCH_LATEST = "fetchlatest"; public static final String FETCH_LATEST = "fetchlatest";
public static final String FIRSTNAME = "firstname"; public static final String FIRSTNAME = "firstname";
@ -242,6 +249,7 @@ public class ApiConstants {
public static final String SCHEDULE = "schedule"; public static final String SCHEDULE = "schedule";
public static final String SCOPE = "scope"; public static final String SCOPE = "scope";
public static final String SECRET_KEY = "usersecretkey"; public static final String SECRET_KEY = "usersecretkey";
public static final String SECONDARY_IP = "secondaryip";
public static final String SINCE = "since"; public static final String SINCE = "since";
public static final String KEY = "key"; public static final String KEY = "key";
public static final String SEARCH_BASE = "searchbase"; public static final String SEARCH_BASE = "searchbase";
@ -309,6 +317,7 @@ public class ApiConstants {
public static final String REMOVE_VLAN = "removevlan"; public static final String REMOVE_VLAN = "removevlan";
public static final String VLAN_ID = "vlanid"; public static final String VLAN_ID = "vlanid";
public static final String ISOLATED_PVLAN = "isolatedpvlan"; public static final String ISOLATED_PVLAN = "isolatedpvlan";
public static final String ISOLATION_URI = "isolationuri";
public static final String VM_AVAILABLE = "vmavailable"; public static final String VM_AVAILABLE = "vmavailable";
public static final String VM_LIMIT = "vmlimit"; public static final String VM_LIMIT = "vmlimit";
public static final String VM_TOTAL = "vmtotal"; public static final String VM_TOTAL = "vmtotal";
@ -410,6 +419,7 @@ public class ApiConstants {
public static final String CAPACITY_IOPS = "capacityiops"; public static final String CAPACITY_IOPS = "capacityiops";
public static final String NETWORK_SPEED = "networkspeed"; public static final String NETWORK_SPEED = "networkspeed";
public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange"; public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange";
public static final String BROADCAST_URI = "broadcasturi";
public static final String ISOLATION_METHOD = "isolationmethod"; public static final String ISOLATION_METHOD = "isolationmethod";
public static final String ISOLATION_METHODS = "isolationmethods"; public static final String ISOLATION_METHODS = "isolationmethods";
public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid"; public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid";
@ -536,6 +546,8 @@ public class ApiConstants {
public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename"; public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
public static final String NICIRA_NVP_GATEWAYSERVICE_UUID = "l3gatewayserviceuuid"; public static final String NICIRA_NVP_GATEWAYSERVICE_UUID = "l3gatewayserviceuuid";
public static final String NICIRA_NVP_L2_GATEWAYSERVICE_UUID = "l2gatewayserviceuuid"; public static final String NICIRA_NVP_L2_GATEWAYSERVICE_UUID = "l2gatewayserviceuuid";
public static final String NSX_LOGICAL_SWITCH = "nsxlogicalswitch";
public static final String NSX_LOGICAL_SWITCH_PORT = "nsxlogicalswitchport";
public static final String S3_ACCESS_KEY = "accesskey"; public static final String S3_ACCESS_KEY = "accesskey";
public static final String S3_SECRET_KEY = "secretkey"; public static final String S3_SECRET_KEY = "secretkey";
public static final String S3_END_POINT = "endpoint"; public static final String S3_END_POINT = "endpoint";
@ -665,6 +677,7 @@ public class ApiConstants {
public static final String SUPPORTS_PUBLIC_ACCESS = "supportspublicaccess"; public static final String SUPPORTS_PUBLIC_ACCESS = "supportspublicaccess";
public static final String REGION_LEVEL_VPC = "regionlevelvpc"; public static final String REGION_LEVEL_VPC = "regionlevelvpc";
public static final String STRECHED_L2_SUBNET = "strechedl2subnet"; public static final String STRECHED_L2_SUBNET = "strechedl2subnet";
public static final String NETWORK_NAME = "networkname";
public static final String NETWORK_SPANNED_ZONES = "zonesnetworkspans"; public static final String NETWORK_SPANNED_ZONES = "zonesnetworkspans";
public static final String METADATA = "metadata"; public static final String METADATA = "metadata";
public static final String PHYSICAL_SIZE = "physicalsize"; public static final String PHYSICAL_SIZE = "physicalsize";

View File

@ -17,7 +17,10 @@
package org.apache.cloudstack.api.command.user.vm; package org.apache.cloudstack.api.command.user.vm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -39,6 +42,7 @@ import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -65,6 +69,10 @@ public class AddNicToVMCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "Mac Address for the new network") @Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "Mac Address for the new network")
private String macaddr; private String macaddr;
@Parameter(name = ApiConstants.DHCP_OPTIONS, type = CommandType.MAP, description = "DHCP options which are passed to the nic"
+ " Example: dhcpoptions[0].dhcp:114=url&dhcpoptions[0].dhcp:66=www.test.com")
private Map dhcpOptions;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -125,6 +133,28 @@ public class AddNicToVMCmd extends BaseAsyncCmd {
return vm.getAccountId(); return vm.getAccountId();
} }
public Map<Integer, String> getDhcpOptionsMap() {
Map<Integer, String> dhcpOptionsMap = new HashMap<>();
if (dhcpOptions != null && !dhcpOptions.isEmpty()) {
Collection<Map<String, String>> paramsCollection = this.dhcpOptions.values();
for(Map<String, String> dhcpNetworkOptions : paramsCollection) {
for (String key : dhcpNetworkOptions.keySet()) {
if (key.startsWith(ApiConstants.DHCP_PREFIX)) {
int dhcpOptionValue = Integer.parseInt(key.replaceFirst(ApiConstants.DHCP_PREFIX, ""));
dhcpOptionsMap.put(dhcpOptionValue, dhcpNetworkOptions.get(key));
} else {
Dhcp.DhcpOptionCode dhcpOptionEnum = Dhcp.DhcpOptionCode.valueOfString(key);
dhcpOptionsMap.put(dhcpOptionEnum.getCode(), dhcpNetworkOptions.get(key));
}
}
}
}
return dhcpOptionsMap;
}
@Override @Override
public void execute() { public void execute() {
CallContext.current().setEventDetails("Vm Id: " + getVmId() + " Network Id: " + getNetworkId()); CallContext.current().setEventDetails("Vm Id: " + getVmId() + " Network Id: " + getNetworkId());

View File

@ -59,6 +59,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network; import com.cloud.network.Network;
import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.IpAddresses;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -187,6 +188,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
@Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin }) @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })
private String deploymentPlanner; private String deploymentPlanner;
@Parameter(name = ApiConstants.DHCP_OPTIONS_NETWORK_LIST, type = CommandType.MAP, description = "DHCP options which are passed to the VM on start up"
+ " Example: dhcpoptionsnetworklist[0].dhcp:114=url&dhcpoptionsetworklist[0].networkid=networkid&dhcpoptionsetworklist[0].dhcp:66=www.test.com")
private Map dhcpOptionsNetworkList;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -407,6 +412,37 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
return keyboard; return keyboard;
} }
public Map<String, Map<Integer, String>> getDhcpOptionsMap() {
Map<String, Map<Integer, String>> dhcpOptionsMap = new HashMap<>();
if (dhcpOptionsNetworkList != null && !dhcpOptionsNetworkList.isEmpty()) {
Collection<Map<String, String>> paramsCollection = this.dhcpOptionsNetworkList.values();
for(Map<String, String> dhcpNetworkOptions : paramsCollection) {
String networkId = dhcpNetworkOptions.get(ApiConstants.NETWORK_ID);
if(networkId == null) {
throw new IllegalArgumentException("No networkid specified when providing extra dhcp options.");
}
Map<Integer, String> dhcpOptionsForNetwork = new HashMap<>();
dhcpOptionsMap.put(networkId, dhcpOptionsForNetwork);
for (String key : dhcpNetworkOptions.keySet()) {
if (key.startsWith(ApiConstants.DHCP_PREFIX)) {
int dhcpOptionValue = Integer.parseInt(key.replaceFirst(ApiConstants.DHCP_PREFIX, ""));
dhcpOptionsForNetwork.put(dhcpOptionValue, dhcpNetworkOptions.get(key));
} else if (!key.equals(ApiConstants.NETWORK_ID)){
Dhcp.DhcpOptionCode dhcpOptionEnum = Dhcp.DhcpOptionCode.valueOfString(key);
dhcpOptionsForNetwork.put(dhcpOptionEnum.getCode(), dhcpNetworkOptions.get(key));
}
}
}
}
return dhcpOptionsMap;
}
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////// API Implementation/////////////////// /////////////// API Implementation///////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.user.vm; package org.apache.cloudstack.api.command.user.vm;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -40,6 +41,7 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " + @APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " +
@ -121,6 +123,11 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction
description = "optional boolean field, which indicates if details should be cleaned up or not (if set to true, details removed for this resource, details field ignored; if false or not set, no action)") description = "optional boolean field, which indicates if details should be cleaned up or not (if set to true, details removed for this resource, details field ignored; if false or not set, no action)")
private Boolean cleanupDetails; private Boolean cleanupDetails;
@Parameter(name = ApiConstants.DHCP_OPTIONS_NETWORK_LIST, type = CommandType.MAP, description = "DHCP options which are passed to the VM on start up"
+ " Example: dhcpoptionsnetworklist[0].dhcp:114=url&dhcpoptionsetworklist[0].networkid=networkid&dhcpoptionsetworklist[0].dhcp:66=www.test.com")
private Map dhcpOptionsNetworkList;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -182,6 +189,37 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction
return cleanupDetails == null ? false : cleanupDetails.booleanValue(); return cleanupDetails == null ? false : cleanupDetails.booleanValue();
} }
public Map<String, Map<Integer, String>> getDhcpOptionsMap() {
Map<String, Map<Integer, String>> dhcpOptionsMap = new HashMap<>();
if (dhcpOptionsNetworkList != null && !dhcpOptionsNetworkList.isEmpty()) {
Collection<Map<String, String>> paramsCollection = this.dhcpOptionsNetworkList.values();
for(Map<String, String> dhcpNetworkOptions : paramsCollection) {
String networkId = dhcpNetworkOptions.get(ApiConstants.NETWORK_ID);
if(networkId == null) {
throw new IllegalArgumentException("No networkid specified when providing extra dhcp options.");
}
Map<Integer, String> dhcpOptionsForNetwork = new HashMap<>();
dhcpOptionsMap.put(networkId, dhcpOptionsForNetwork);
for (String key : dhcpNetworkOptions.keySet()) {
if (key.startsWith(ApiConstants.DHCP_PREFIX)) {
int dhcpOptionValue = Integer.parseInt(key.replaceFirst(ApiConstants.DHCP_PREFIX, ""));
dhcpOptionsForNetwork.put(dhcpOptionValue, dhcpNetworkOptions.get(key));
} else if (!key.equals(ApiConstants.NETWORK_ID)) {
Dhcp.DhcpOptionCode dhcpOptionEnum = Dhcp.DhcpOptionCode.valueOfString(key);
dhcpOptionsForNetwork.put(dhcpOptionEnum.getCode(), dhcpNetworkOptions.get(key));
}
}
}
}
return dhcpOptionsMap;
}
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////// API Implementation/////////////////// /////////////// API Implementation///////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////

View File

@ -0,0 +1,99 @@
// 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 org.apache.cloudstack.api.response;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.serializer.Param;
@EntityReference(value = NicExtraDhcpOptionResponse.class)
public class NicExtraDhcpOptionResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the extra dhcp option")
private String id;
@SerializedName(ApiConstants.NIC_ID)
@Param(description = "the ID of the nic")
private String nicId;
@SerializedName(ApiConstants.EXTRA_DHCP_OPTION_NAME)
@Param(description = "the name of the extra DHCP option")
private String codeName;
@SerializedName(ApiConstants.EXTRA_DHCP_OPTION_CODE)
@Param(description = "the extra DHCP option code")
private int code;
@SerializedName(ApiConstants.EXTRA_DHCP_OPTION_VALUE)
@Param(description = "the extra DHCP option value")
private String value;
public NicExtraDhcpOptionResponse() {
super();
}
public NicExtraDhcpOptionResponse(String codeName, int code, String value) {
this.codeName = codeName;
this.code = code;
this.value = value;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNicId() {
return nicId;
}
public void setNicId(String nicId) {
this.nicId = nicId;
}
public String getCodeName() {
return codeName;
}
public void setCodeName(String codeName) {
this.codeName = codeName;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -29,15 +29,15 @@ import java.util.List;
@EntityReference(value = Nic.class) @EntityReference(value = Nic.class)
public class NicResponse extends BaseResponse { public class NicResponse extends BaseResponse {
@SerializedName("id") @SerializedName(ApiConstants.ID)
@Param(description = "the ID of the nic") @Param(description = "the ID of the nic")
private String id; private String id;
@SerializedName("networkid") @SerializedName(ApiConstants.NETWORK_ID)
@Param(description = "the ID of the corresponding network") @Param(description = "the ID of the corresponding network")
private String networkId; private String networkId;
@SerializedName("networkname") @SerializedName(ApiConstants.NETWORK_NAME)
@Param(description = "the name of the corresponding network") @Param(description = "the name of the corresponding network")
private String networkName; private String networkName;
@ -53,11 +53,11 @@ public class NicResponse extends BaseResponse {
@Param(description = "the ip address of the nic") @Param(description = "the ip address of the nic")
private String ipaddress; private String ipaddress;
@SerializedName("isolationuri") @SerializedName(ApiConstants.ISOLATION_URI)
@Param(description = "the isolation uri of the nic") @Param(description = "the isolation uri of the nic")
private String isolationUri; private String isolationUri;
@SerializedName("broadcasturi") @SerializedName(ApiConstants.BROADCAST_URI)
@Param(description = "the broadcast uri of the nic") @Param(description = "the broadcast uri of the nic")
private String broadcastUri; private String broadcastUri;
@ -73,7 +73,7 @@ public class NicResponse extends BaseResponse {
@Param(description = "true if nic is default, false otherwise") @Param(description = "true if nic is default, false otherwise")
private Boolean isDefault; private Boolean isDefault;
@SerializedName("macaddress") @SerializedName(ApiConstants.MAC_ADDRESS)
@Param(description = "true if nic is default, false otherwise") @Param(description = "true if nic is default, false otherwise")
private String macAddress; private String macAddress;
@ -89,10 +89,14 @@ public class NicResponse extends BaseResponse {
@Param(description = "the IPv6 address of network") @Param(description = "the IPv6 address of network")
private String ip6Address; private String ip6Address;
@SerializedName("secondaryip") @SerializedName(ApiConstants.SECONDARY_IP)
@Param(description = "the Secondary ipv4 addr of nic") @Param(description = "the Secondary ipv4 addr of nic")
private List<NicSecondaryIpResponse> secondaryIps; private List<NicSecondaryIpResponse> secondaryIps;
@SerializedName(ApiConstants.EXTRA_DHCP_OPTION)
@Param(description = "the extra dhcp options on the nic", since = "4.11.0")
private List<NicExtraDhcpOptionResponse> extraDhcpOptions;
@SerializedName(ApiConstants.DEVICE_ID) @SerializedName(ApiConstants.DEVICE_ID)
@Param(description = "device id for the network when plugged into the virtual machine", since = "4.4") @Param(description = "device id for the network when plugged into the virtual machine", since = "4.4")
private String deviceId; private String deviceId;
@ -101,11 +105,11 @@ public class NicResponse extends BaseResponse {
@Param(description = "Id of the vm to which the nic belongs") @Param(description = "Id of the vm to which the nic belongs")
private String vmId; private String vmId;
@SerializedName("nsxlogicalswitch") @SerializedName(ApiConstants.NSX_LOGICAL_SWITCH)
@Param(description = "Id of the NSX Logical Switch (if NSX based), null otherwise", since="4.6.0") @Param(description = "Id of the NSX Logical Switch (if NSX based), null otherwise", since="4.6.0")
private String nsxLogicalSwitch; private String nsxLogicalSwitch;
@SerializedName("nsxlogicalswitchport") @SerializedName(ApiConstants.NSX_LOGICAL_SWITCH_PORT)
@Param(description = "Id of the NSX Logical Switch Port (if NSX based), null otherwise", since="4.6.0") @Param(description = "Id of the NSX Logical Switch Port (if NSX based), null otherwise", since="4.6.0")
private String nsxLogicalSwitchPort; private String nsxLogicalSwitchPort;
@ -181,6 +185,10 @@ public class NicResponse extends BaseResponse {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public void setExtraDhcpOptions(List<NicExtraDhcpOptionResponse> extraDhcpOptions) {
this.extraDhcpOptions = extraDhcpOptions;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;

View File

@ -78,7 +78,7 @@ public interface VirtualMachineManager extends Manager {
*/ */
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo, void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan, List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
HypervisorType hyperType) throws InsufficientCapacityException; HypervisorType hyperType, Map<String, Map<Integer, String>> extraDhcpOptions) throws InsufficientCapacityException;
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
LinkedHashMap<? extends Network, List<? extends NicProfile>> networkProfiles, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException; LinkedHashMap<? extends Network, List<? extends NicProfile>> networkProfiles, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException;

View File

@ -93,9 +93,24 @@ public interface NetworkOrchestrationService {
boolean errorIfAlreadySetup, Long domainId, ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) boolean errorIfAlreadySetup, Long domainId, ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled)
throws ConcurrentOperationException; throws ConcurrentOperationException;
void allocate(VirtualMachineProfile vm, LinkedHashMap<? extends Network, List<? extends NicProfile>> networks) throws InsufficientCapacityException, void allocate(VirtualMachineProfile vm, LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, Map<String, Map<Integer, String>> extraDhcpOptions) throws InsufficientCapacityException,
ConcurrentOperationException; ConcurrentOperationException;
/**
* configures the provided dhcp options on the given nic.
* @param network of the nic
* @param nicId
* @param extraDhcpOptions
*/
void configureExtraDhcpOptions(Network network, long nicId, Map<Integer, String> extraDhcpOptions);
/**
* configures dhcp options on the given nic.
* @param network of the nic
* @param nicId
*/
void configureExtraDhcpOptions(Network network, long nicId);
void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceUnavailableException; ResourceUnavailableException;
@ -112,6 +127,8 @@ public interface NetworkOrchestrationService {
Pair<? extends NetworkGuru, ? extends Network> implementNetwork(long networkId, DeployDestination dest, ReservationContext context) Pair<? extends NetworkGuru, ? extends Network> implementNetwork(long networkId, DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
Map<Integer, String> getExtraDhcpOptions(long nicId);
/** /**
* prepares vm nic change for migration * prepares vm nic change for migration
* *
@ -158,6 +175,8 @@ public interface NetworkOrchestrationService {
boolean reallocate(VirtualMachineProfile vm, DataCenterDeployment dest) throws InsufficientCapacityException, ConcurrentOperationException; boolean reallocate(VirtualMachineProfile vm, DataCenterDeployment dest) throws InsufficientCapacityException, ConcurrentOperationException;
void saveExtraDhcpOptions(String networkUuid, Long nicId, Map<String, Map<Integer, String>> extraDhcpOptionMap);
/** /**
* @param requested * @param requested
* @param network * @param network

View File

@ -65,14 +65,14 @@ public interface OrchestrationService {
@QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags, @QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
@QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan, @QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
@QueryParam("root-disk-size") Long rootDiskSize) throws InsufficientCapacityException; @QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException;
@POST @POST
VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String isoId, VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String isoId,
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor, @QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize, @QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags, @QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
@QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan) throws InsufficientCapacityException; @QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException;
@POST @POST
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway); NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);

View File

@ -387,7 +387,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@DB @DB
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering, public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings, final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType) final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions)
throws InsufficientCapacityException { throws InsufficientCapacityException {
final VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName); final VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName);
@ -415,7 +415,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
try { try {
if (!vmProfile.getBootArgs().contains("ExternalLoadBalancerVm")) if (!vmProfile.getBootArgs().contains("ExternalLoadBalancerVm"))
_networkMgr.allocate(vmProfile, auxiliaryNetworks); _networkMgr.allocate(vmProfile, auxiliaryNetworks, extraDhcpOptions);
} catch (final ConcurrentOperationException e) { } catch (final ConcurrentOperationException e) {
throw new CloudRuntimeException("Concurrent operation while trying to allocate resources for the VM", e); throw new CloudRuntimeException("Concurrent operation while trying to allocate resources for the VM", e);
} }
@ -451,7 +451,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Override @Override
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering, public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException { final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException {
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(serviceOffering), new ArrayList<DiskOfferingInfo>(), networks, plan, hyperType); allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(serviceOffering), new ArrayList<DiskOfferingInfo>(), networks, plan, hyperType, null);
} }
private VirtualMachineGuru getVmGuru(final VirtualMachine vm) { private VirtualMachineGuru getVmGuru(final VirtualMachine vm) {

View File

@ -155,7 +155,7 @@ public class CloudOrchestrator implements OrchestrationService {
@Override @Override
public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu, public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu,
int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan,
Long rootDiskSize) throws InsufficientCapacityException { Long rootDiskSize, Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException {
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, // VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks,
// vmEntityManager); // vmEntityManager);
@ -234,14 +234,14 @@ public class CloudOrchestrator implements OrchestrationService {
} }
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), computeOffering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan, _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), computeOffering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan,
hypervisorType); hypervisorType, extraDhcpOptionMap);
return vmEntity; return vmEntity;
} }
@Override @Override
public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os, public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os,
int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan) int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan, Map<String, Map<Integer, String>> extraDhcpOptionMap)
throws InsufficientCapacityException { throws InsufficientCapacityException {
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager); // VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager);
@ -299,7 +299,7 @@ public class CloudOrchestrator implements OrchestrationService {
HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor); HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), computeOffering, rootDiskOfferingInfo, new ArrayList<DiskOfferingInfo>(), networkIpMap, plan, hypervisorType); _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), computeOffering, rootDiskOfferingInfo, new ArrayList<DiskOfferingInfo>(), networkIpMap, plan, hypervisorType, extraDhcpOptionMap);
return vmEntity; return vmEntity;
} }

View File

@ -25,6 +25,7 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -32,10 +33,12 @@ import java.util.UUID;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.vm.NicExtraDhcpOptionVO;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO; import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
@ -198,6 +201,7 @@ import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.DomainRouterVO; import com.cloud.vm.DomainRouterVO;
import com.cloud.utils.net.Dhcp;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.Nic.ReservationStrategy;
import com.cloud.vm.NicIpAlias; import com.cloud.vm.NicIpAlias;
@ -212,6 +216,7 @@ import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
import com.cloud.vm.dao.NicIpAliasDao; import com.cloud.vm.dao.NicIpAliasDao;
import com.cloud.vm.dao.NicIpAliasVO; import com.cloud.vm.dao.NicIpAliasVO;
import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpDao;
@ -269,6 +274,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
@Inject @Inject
protected NicIpAliasDao _nicIpAliasDao; protected NicIpAliasDao _nicIpAliasDao;
@Inject @Inject
protected NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
@Inject
protected IPAddressDao _publicIpAddressDao; protected IPAddressDao _publicIpAddressDao;
@Inject @Inject
protected IpAddressManager _ipAddrMgr; protected IpAddressManager _ipAddrMgr;
@ -728,7 +735,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
@Override @Override
@DB @DB
public void allocate(final VirtualMachineProfile vm, final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks) throws InsufficientCapacityException, public void allocate(final VirtualMachineProfile vm, final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final Map<String, Map<Integer, String>> extraDhcpOptions) throws InsufficientCapacityException,
ConcurrentOperationException { ConcurrentOperationException {
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() { Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
@ -800,6 +807,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
nics.add(vmNic); nics.add(vmNic);
vm.addNic(vmNic); vm.addNic(vmNic);
saveExtraDhcpOptions(config.getUuid(), vmNic.getId(), extraDhcpOptions);
} }
} }
if (nics.size() != size) { if (nics.size() != size) {
@ -814,6 +822,24 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}); });
} }
@Override
public void saveExtraDhcpOptions(final String networkUuid, final Long nicId, final Map<String, Map<Integer, String>> extraDhcpOptionMap) {
if(extraDhcpOptionMap != null) {
Map<Integer, String> extraDhcpOption = extraDhcpOptionMap.get(networkUuid);
if(extraDhcpOption != null) {
List<NicExtraDhcpOptionVO> nicExtraDhcpOptionList = new LinkedList<>();
for (Integer code : extraDhcpOption.keySet()) {
Dhcp.DhcpOptionCode.valueOfInt(code); //check if code is supported or not.
NicExtraDhcpOptionVO nicExtraDhcpOptionVO = new NicExtraDhcpOptionVO(nicId, code, extraDhcpOption.get(code));
nicExtraDhcpOptionList.add(nicExtraDhcpOptionVO);
}
_nicExtraDhcpOptionDao.saveExtraDhcpOptions(nicExtraDhcpOptionList);
}
}
}
@DB @DB
@Override @Override
public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm) public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
@ -1141,6 +1167,15 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
} }
} }
//Reset the extra DHCP option that may have been cleared per nic.
List<NicVO> nicVOs = _nicDao.listByNetworkId(network.getId());
for(NicVO nicVO : nicVOs) {
if(nicVO.getState() == Nic.State.Reserved) {
configureExtraDhcpOptions(network, nicVO.getId());
}
}
for (final NetworkElement element : networkElements) { for (final NetworkElement element : networkElements) {
if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) { if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) {
((AggregatedCommandExecutor)element).prepareAggregatedExecution(network, dest); ((AggregatedCommandExecutor)element).prepareAggregatedExecution(network, dest);
@ -1457,6 +1492,22 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
return resourceCount; return resourceCount;
} }
@Override
public void configureExtraDhcpOptions(Network network, long nicId, Map<Integer, String> extraDhcpOptions) {
if(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp)) {
if (_networkModel.getNetworkServiceCapabilities(network.getId(), Service.Dhcp).containsKey(Capability.ExtraDhcpOptions)) {
DhcpServiceProvider sp = getDhcpServiceProvider(network);
sp.setExtraDhcpOptions(network, nicId, extraDhcpOptions);
}
}
}
@Override
public void configureExtraDhcpOptions(Network network, long nicId) {
Map<Integer, String> extraDhcpOptions = getExtraDhcpOptions(nicId);
configureExtraDhcpOptions(network, nicId, extraDhcpOptions);
}
@Override @Override
public void finalizeUpdateInSequence(Network network, boolean success) { public void finalizeUpdateInSequence(Network network, boolean success) {
List<Provider> providers = getNetworkProviders(network.getId()); List<Provider> providers = getNetworkProviders(network.getId());
@ -1593,9 +1644,20 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network)); profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network));
guru.updateNicProfile(profile, network); guru.updateNicProfile(profile, network);
configureExtraDhcpOptions(network, nicId);
return profile; return profile;
} }
@Override
public Map<Integer, String> getExtraDhcpOptions(long nicId) {
List<NicExtraDhcpOptionVO> nicExtraDhcpOptionVOList = _nicExtraDhcpOptionDao.listByNicId(nicId);
return nicExtraDhcpOptionVOList
.stream()
.collect(Collectors.toMap(NicExtraDhcpOptionVO::getCode, NicExtraDhcpOptionVO::getValue));
}
@Override @Override
public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployDestination dest) { public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployDestination dest) {
if(vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) { if(vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) {
@ -2949,7 +3011,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
@Override @Override
public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException { public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
cleanupNics(vm); cleanupNics(vm);
allocate(vm, profiles); allocate(vm, profiles, null);
} }
}); });
} }

View File

@ -215,6 +215,7 @@
<bean id="networkServiceMapDaoImpl" class="com.cloud.network.dao.NetworkServiceMapDaoImpl" /> <bean id="networkServiceMapDaoImpl" class="com.cloud.network.dao.NetworkServiceMapDaoImpl" />
<bean id="nicDaoImpl" class="com.cloud.vm.dao.NicDaoImpl" /> <bean id="nicDaoImpl" class="com.cloud.vm.dao.NicDaoImpl" />
<bean id="nicDetailsDaoImpl" class="com.cloud.vm.dao.NicDetailsDaoImpl" /> <bean id="nicDetailsDaoImpl" class="com.cloud.vm.dao.NicDetailsDaoImpl" />
<bean id="nicExtraDhcpOptionDaoImpl" class="com.cloud.vm.dao.NicExtraDhcpOptionDaoImpl" />
<bean id="nicSecondaryIpDaoImpl" class="com.cloud.vm.dao.NicSecondaryIpDaoImpl" /> <bean id="nicSecondaryIpDaoImpl" class="com.cloud.vm.dao.NicSecondaryIpDaoImpl" />
<bean id="nicIpAliasDaoImpl" class="com.cloud.vm.dao.NicIpAliasDaoImpl" /> <bean id="nicIpAliasDaoImpl" class="com.cloud.vm.dao.NicIpAliasDaoImpl" />
<bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" /> <bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" />

View File

@ -0,0 +1,82 @@
// 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.vm;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.UUID;
@Entity
@Table(name = "nic_extra_dhcp_options")
public class NicExtraDhcpOptionVO implements NicExtraDhcpOption {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
String uuid = UUID.randomUUID().toString();
@Column(name = "nic_id")
private long nicId;
@Column(name="code")
private int code;
@Column(name = "value")
private String value;
public NicExtraDhcpOptionVO (){
}
public NicExtraDhcpOptionVO (long nicId, int code, String value) {
this.nicId = nicId;
this.code = code;
this.value = value;
}
@Override
public long getNicId() {
return nicId;
}
@Override
public int getCode() {
return code;
}
@Override
public String getValue() {
return value;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public long getId() {
return id;
}
}

View File

@ -0,0 +1,32 @@
// 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.vm.dao;
import java.util.List;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.NicExtraDhcpOptionVO;
public interface NicExtraDhcpOptionDao extends GenericDao<NicExtraDhcpOptionVO, Long> {
List<NicExtraDhcpOptionVO> listByNicId(long nicId);
/**
* Persists list of NicExtraDhcpOptionVO
* @param extraDhcpOptions
*/
void saveExtraDhcpOptions(List<NicExtraDhcpOptionVO> extraDhcpOptions);
}

View File

@ -0,0 +1,77 @@
// 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.vm.dao;
import org.springframework.stereotype.Component;
import java.util.List;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.NicExtraDhcpOption;
import com.cloud.vm.NicExtraDhcpOptionVO;
@Component
public class NicExtraDhcpOptionDaoImpl extends GenericDaoBase<NicExtraDhcpOptionVO, Long> implements NicExtraDhcpOptionDao {
private SearchBuilder<NicExtraDhcpOptionVO> AllFieldsSearch;
protected NicExtraDhcpOptionDaoImpl() {
super();
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("nic_id", AllFieldsSearch.entity().getNicId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("code", AllFieldsSearch.entity().getCode(), SearchCriteria.Op.IN);
AllFieldsSearch.done();
}
@DB()
@Override
public List<NicExtraDhcpOptionVO> listByNicId(long nicId) {
SearchCriteria<NicExtraDhcpOptionVO> sc = AllFieldsSearch.create();
sc.setParameters("nic_id", nicId);
return listBy(sc);
}
@DB()
@Override
public void saveExtraDhcpOptions(List<NicExtraDhcpOptionVO> extraDhcpOptions) {
if (extraDhcpOptions.isEmpty()) {
return;
}
extraDhcpOptions
.stream()
.map(NicExtraDhcpOption::getNicId)
.distinct()
.forEach(this::removeByNicId);
extraDhcpOptions.stream()
.forEach(this::persist);
}
public void removeByNicId(long nicId) {
SearchCriteria<NicExtraDhcpOptionVO> sc = AllFieldsSearch.create();
sc.setParameters("nic_id", nicId);
expunge(sc);
}
}

View File

@ -180,4 +180,9 @@ public class BaremetalDhcpElement extends AdapterBase implements DhcpServiceProv
return true; return true;
} }
@Override
public boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions) {
return false;
}
} }

View File

@ -374,4 +374,9 @@ public class ContrailElementImpl extends AdapterBase
throws ResourceUnavailableException { throws ResourceUnavailableException {
return false; return false;
} }
@Override
public boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions) {
return false;
}
} }

View File

@ -0,0 +1,86 @@
//
// 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.element;
import net.nuage.vsp.acs.client.api.model.VspNetwork;
import org.apache.commons.lang.builder.HashCodeBuilder;
import java.util.Map;
import java.util.Objects;
import com.cloud.agent.api.Command;
public class ExtraDhcpOptionsVspCommand extends Command {
private final VspNetwork network;
private final String nicUuid;
private final Map<Integer, String> dhcpOptions;
public ExtraDhcpOptionsVspCommand (VspNetwork network, String nicUuid, Map<Integer, String> dhcpOptions) {
super();
this.network = network;
this.nicUuid = nicUuid;
this.dhcpOptions = dhcpOptions;
}
public VspNetwork getNetwork() {
return network;
}
public String getNicUuid() {
return nicUuid;
}
public Map<Integer, String> getDhcpOptions() {
return dhcpOptions;
}
@Override
public boolean executeInSequence() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ExtraDhcpOptionsVspCommand)) {
return false;
}
ExtraDhcpOptionsVspCommand that = (ExtraDhcpOptionsVspCommand) o;
return super.equals(that)
&& Objects.equals(network, that.network)
&& Objects.equals(nicUuid, that.nicUuid)
&& Objects.equals(dhcpOptions, that.dhcpOptions);
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.appendSuper(super.hashCode())
.append(nicUuid)
.append(network)
.append(dhcpOptions)
.toHashCode();
}
}

View File

@ -59,6 +59,7 @@ import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupVspCommand; import com.cloud.agent.api.StartupVspCommand;
import com.cloud.agent.api.element.ApplyAclRuleVspCommand; import com.cloud.agent.api.element.ApplyAclRuleVspCommand;
import com.cloud.agent.api.element.ApplyStaticNatVspCommand; import com.cloud.agent.api.element.ApplyStaticNatVspCommand;
import com.cloud.agent.api.element.ExtraDhcpOptionsVspCommand;
import com.cloud.agent.api.element.ImplementVspCommand; import com.cloud.agent.api.element.ImplementVspCommand;
import com.cloud.agent.api.element.ShutDownVpcVspCommand; import com.cloud.agent.api.element.ShutDownVpcVspCommand;
import com.cloud.agent.api.element.ShutDownVspCommand; import com.cloud.agent.api.element.ShutDownVspCommand;
@ -252,7 +253,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
Capability.MultipleIps, "true" Capability.MultipleIps, "true"
)) ))
.put(Service.Dhcp, ImmutableMap.of( .put(Service.Dhcp, ImmutableMap.of(
Capability.DhcpAccrossMultipleSubnets, "true" Capability.DhcpAccrossMultipleSubnets, "true",
Capability.ExtraDhcpOptions, "true"
)) ))
.put(Service.NetworkACL, ImmutableMap.of( .put(Service.NetworkACL, ImmutableMap.of(
Capability.SupportedProtocols, "tcp,udp,icmp" Capability.SupportedProtocols, "tcp,udp,icmp"
@ -515,6 +517,23 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
return true; return true;
} }
@Override
public boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions) {
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(network.getPhysicalNetworkId());
NicVO nic = _nicDao.findById(nicId);
ExtraDhcpOptionsVspCommand extraDhcpOptionsVspCommand = new ExtraDhcpOptionsVspCommand(vspNetwork, nic.getUuid(), dhcpOptions);
Answer answer = _agentMgr.easySend(nuageVspHost.getId(), extraDhcpOptionsVspCommand);
if (answer == null || !answer.getResult()) {
s_logger.error("[setExtraDhcpOptions] setting extra DHCP options for nic " + nic.getUuid() + " failed.");
return false;
}
return true;
}
@Override @Override
public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException { public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException {

View File

@ -19,6 +19,7 @@
package com.cloud.network.guru; package com.cloud.network.guru;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -42,6 +43,7 @@ import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.resourcedetail.VpcDetailVO; import org.apache.cloudstack.resourcedetail.VpcDetailVO;
import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
@ -131,6 +133,8 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
NetworkDetailsDao _networkDetailsDao; NetworkDetailsDao _networkDetailsDao;
@Inject @Inject
VpcDetailsDao _vpcDetailsDao; VpcDetailsDao _vpcDetailsDao;
@Inject
NetworkOrchestrationService _networkOrchestrationService;
public NuageVspGuestNetworkGuru() { public NuageVspGuestNetworkGuru() {
super(); super();
@ -225,7 +229,9 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr)); implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp); implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp);
if (!implement(network.getVpcId(), physicalNetworkId, vspNetwork, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering))) { boolean implementSucceeded = implement(network.getVpcId(), physicalNetworkId, vspNetwork, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering));
if (!implementSucceeded) {
return null; return null;
} }
@ -383,6 +389,8 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
// Determine if dhcp options of the other nics in the network need to be updated // Determine if dhcp options of the other nics in the network need to be updated
if (vm.getType() == VirtualMachine.Type.DomainRouter && network.getState() != State.Implementing) { if (vm.getType() == VirtualMachine.Type.DomainRouter && network.getState() != State.Implementing) {
updateDhcpOptionsForExistingVms(network, nuageVspHost, vspNetwork, networkHasDns, networkHasDnsCache); updateDhcpOptionsForExistingVms(network, nuageVspHost, vspNetwork, networkHasDns, networkHasDnsCache);
//update the extra DHCP options
} }
nic.setBroadcastUri(network.getBroadcastUri()); nic.setBroadcastUri(network.getBroadcastUri());
@ -427,6 +435,10 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
} }
} }
private void updateExtraDhcpOptionsForExistingVm(Network network, Nic nic) {
_networkOrchestrationService.configureExtraDhcpOptions(network, nic.getId());
}
private void updateDhcpOptionsForExistingVms(Network network, HostVO nuageVspHost, VspNetwork vspNetwork, boolean networkHasDns, Map<Long, Boolean> networkHasDnsCache) private void updateDhcpOptionsForExistingVms(Network network, HostVO nuageVspHost, VspNetwork vspNetwork, boolean networkHasDns, Map<Long, Boolean> networkHasDnsCache)
throws InsufficientVirtualNetworkCapacityException { throws InsufficientVirtualNetworkCapacityException {
// Update dhcp options if a VR is added when we are not initiating the network // Update dhcp options if a VR is added when we are not initiating the network
@ -437,12 +449,14 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
List<NicVO> userNics = _nicDao.listByNetworkId(network.getId()); List<NicVO> userNics = _nicDao.listByNetworkId(network.getId());
LinkedListMultimap<Long, VspDhcpVMOption> dhcpOptionsPerDomain = LinkedListMultimap.create(); LinkedListMultimap<Long, VspDhcpVMOption> dhcpOptionsPerDomain = LinkedListMultimap.create();
for (NicVO userNic : userNics) { for (Iterator<NicVO> iterator = userNics.iterator(); iterator.hasNext(); ) {
if (userNic.getVmType() == VirtualMachine.Type.DomainRouter) { NicVO userNic = iterator.next();
if (userNic.getVmType() == VirtualMachine.Type.DomainRouter || userNic.getState() != Nic.State.Reserved) {
iterator.remove();
continue; continue;
} }
VMInstanceVO userVm = _vmInstanceDao.findById(userNic.getInstanceId()); VMInstanceVO userVm = _vmInstanceDao.findById(userNic.getInstanceId());
boolean defaultHasDns = getDefaultHasDns(networkHasDnsCache, userNic); boolean defaultHasDns = getDefaultHasDns(networkHasDnsCache, userNic);
VspDhcpVMOption dhcpOption = _nuageVspEntityBuilder.buildVmDhcpOption(userNic, defaultHasDns, networkHasDns); VspDhcpVMOption dhcpOption = _nuageVspEntityBuilder.buildVmDhcpOption(userNic, defaultHasDns, networkHasDns);
dhcpOptionsPerDomain.put(userVm.getDomainId(), dhcpOption); dhcpOptionsPerDomain.put(userVm.getDomainId(), dhcpOption);
@ -463,6 +477,10 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru {
throw new InsufficientVirtualNetworkCapacityException("Failed to reserve VM in Nuage VSP.", Network.class, network.getId()); throw new InsufficientVirtualNetworkCapacityException("Failed to reserve VM in Nuage VSP.", Network.class, network.getId());
} }
} }
for (NicVO userNic : userNics) {
updateExtraDhcpOptionsForExistingVm(network, userNic);
}
} }
private void checkMultipleSubnetsCombinedWithUseData(Network network) { private void checkMultipleSubnetsCombinedWithUseData(Network network) {

View File

@ -301,10 +301,10 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
if (StringUtils.isNotBlank(cmd.getApiVersion())){ if (StringUtils.isNotBlank(cmd.getApiVersion())){
if (!clientLoader.getNuageVspManagerClient().isSupportedApiVersion(cmd.getApiVersion())){ apiVersion = cmd.getApiVersion();
if (!clientLoader.getNuageVspManagerClient().isSupportedApiVersion(apiVersion)){
throw new CloudRuntimeException("Unsupported API version : " + cmd.getApiVersion()); throw new CloudRuntimeException("Unsupported API version : " + cmd.getApiVersion());
} }
apiVersion = cmd.getApiVersion();
} else { } else {
List<NuageVspApiVersion> supportedVsdVersions = clientLoader.getNuageVspManagerClient().getSupportedVersionList(); List<NuageVspApiVersion> supportedVsdVersions = clientLoader.getNuageVspManagerClient().getSupportedVersionList();
supportedVsdVersions.retainAll(Arrays.asList(NuageVspApiVersion.SUPPORTED_VERSIONS)); supportedVsdVersions.retainAll(Arrays.asList(NuageVspApiVersion.SUPPORTED_VERSIONS));

View File

@ -248,7 +248,7 @@ public class NuageVspResource extends ManagerBase implements ServerResource, Vsp
return wrapper.execute(cmd, this); return wrapper.execute(cmd, this);
} catch (final Exception e) { } catch (final Exception e) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Received unsupported command " + cmd.toString()); s_logger.debug("Received unsupported command " + cmd.toString(), e);
} }
return Answer.createUnsupportedCommandAnswer(cmd); return Answer.createUnsupportedCommandAnswer(cmd);
} }

View 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.network.vsp.resource.wrapper;
import net.nuage.vsp.acs.client.exception.NuageVspException;
import javax.naming.ConfigurationException;
import com.cloud.agent.api.element.ExtraDhcpOptionsVspCommand;
import com.cloud.network.resource.NuageVspResource;
import com.cloud.resource.ResourceWrapper;
@ResourceWrapper(handles=ExtraDhcpOptionsVspCommand.class)
public class NuageVspExtraDhcpOptionsCommandWrapper extends NuageVspCommandWrapper<ExtraDhcpOptionsVspCommand> {
@Override
public boolean executeNuageVspCommand(ExtraDhcpOptionsVspCommand command, NuageVspResource nuageVspResource) throws ConfigurationException, NuageVspException {
nuageVspResource.getNuageVspElementClient().setDhcpOptionsNic(command.getNetwork(), command.getNicUuid(), command.getDhcpOptions());
return true;
}
@Override
public StringBuilder fillDetail(StringBuilder stringBuilder, ExtraDhcpOptionsVspCommand command) {
return stringBuilder;
}
}

View File

@ -162,18 +162,21 @@ import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils; import com.cloud.utils.StringUtils;
import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.EntityManager;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip; import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroup;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicExtraDhcpOptionVO;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.NicVO; import com.cloud.vm.NicVO;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshot;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
@ -233,6 +236,7 @@ import org.apache.cloudstack.api.response.NetworkACLItemResponse;
import org.apache.cloudstack.api.response.NetworkACLResponse; import org.apache.cloudstack.api.response.NetworkACLResponse;
import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse;
import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.NicExtraDhcpOptionResponse;
import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.OvsProviderResponse; import org.apache.cloudstack.api.response.OvsProviderResponse;
@ -317,6 +321,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.stream.Collectors;
public class ApiResponseHelper implements ResponseGenerator { public class ApiResponseHelper implements ResponseGenerator {
@ -349,6 +354,8 @@ public class ApiResponseHelper implements ResponseGenerator {
private ClusterDetailsDao _clusterDetailsDao; private ClusterDetailsDao _clusterDetailsDao;
@Inject @Inject
private ResourceTagDao _resourceTagDao; private ResourceTagDao _resourceTagDao;
@Inject
private NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
@Override @Override
public UserResponse createUserResponse(User user) { public UserResponse createUserResponse(User user) {
@ -3583,6 +3590,7 @@ public class ApiResponseHelper implements ResponseGenerator {
NetworkVO network = _entityMgr.findById(NetworkVO.class, result.getNetworkId()); NetworkVO network = _entityMgr.findById(NetworkVO.class, result.getNetworkId());
VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, result.getInstanceId()); VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, result.getInstanceId());
UserVmJoinVO userVm = _entityMgr.findById(UserVmJoinVO.class, result.getInstanceId()); UserVmJoinVO userVm = _entityMgr.findById(UserVmJoinVO.class, result.getInstanceId());
List<NicExtraDhcpOptionVO> nicExtraDhcpOptionVOs = _nicExtraDhcpOptionDao.listByNicId(result.getId());
response.setId(result.getUuid()); response.setId(result.getUuid());
response.setNetworkid(network.getUuid()); response.setNetworkid(network.getUuid());
@ -3601,6 +3609,13 @@ public class ApiResponseHelper implements ResponseGenerator {
} }
response.setIpaddress(result.getIPv4Address()); response.setIpaddress(result.getIPv4Address());
List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = nicExtraDhcpOptionVOs
.stream()
.map(vo -> new NicExtraDhcpOptionResponse(Dhcp.DhcpOptionCode.valueOfInt(vo.getCode()).getName(), vo.getCode(), vo.getValue()))
.collect(Collectors.toList());
response.setExtraDhcpOptions(nicExtraDhcpOptionResponses);
if (result.getSecondaryIp()) { if (result.getSecondaryIp()) {
List<NicSecondaryIpVO> secondaryIps = ApiDBUtils.findNicSecondaryIps(result.getId()); List<NicSecondaryIpVO> secondaryIps = ApiDBUtils.findNicSecondaryIps(result.getId());
if (secondaryIps != null) { if (secondaryIps != null) {

View File

@ -24,12 +24,14 @@ import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.ApiConstants.VMDetails;
import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.response.NicExtraDhcpOptionResponse;
import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse;
@ -49,9 +51,11 @@ import com.cloud.user.dao.UserDao;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.net.Dhcp;
import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VmStats; import com.cloud.vm.VmStats;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.UserVmDetailsDao;
@ -67,6 +71,8 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
private UserVmDetailsDao _userVmDetailsDao; private UserVmDetailsDao _userVmDetailsDao;
@Inject @Inject
private UserDao _userDao; private UserDao _userDao;
@Inject
private NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
private final SearchBuilder<UserVmJoinVO> VmDetailSearch; private final SearchBuilder<UserVmJoinVO> VmDetailSearch;
private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch; private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch;
@ -267,6 +273,13 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
nicResponse.setSecondaryIps(ipList); nicResponse.setSecondaryIps(ipList);
} }
nicResponse.setObjectName("nic"); nicResponse.setObjectName("nic");
List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id)
.stream()
.map(vo -> new NicExtraDhcpOptionResponse(Dhcp.DhcpOptionCode.valueOfInt(vo.getCode()).getName(), vo.getCode(), vo.getValue()))
.collect(Collectors.toList());
nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses);
userVmResponse.addNic(nicResponse); userVmResponse.addNic(nicResponse);
} }
} }
@ -368,6 +381,11 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
} }
nicResponse.setObjectName("nic"); nicResponse.setObjectName("nic");
List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id)
.stream()
.map(vo -> new NicExtraDhcpOptionResponse(Dhcp.DhcpOptionCode.valueOfInt(vo.getCode()).getName(), vo.getCode(), vo.getValue()))
.collect(Collectors.toList());
nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses);
userVmData.addNic(nicResponse); userVmData.addNic(nicResponse);
} }

View File

@ -1325,18 +1325,18 @@ public class AutoScaleManagerImpl<Type> extends ManagerBase implements AutoScale
vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" + vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
getCurrentTimeStampString(), getCurrentTimeStampString(),
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null,
null, true, null, null, null, null); null, true, null, null, null, null, null);
} else { } else {
if (zone.isSecurityGroupEnabled()) { if (zone.isSecurityGroupEnabled()) {
vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, null, null, vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, null, null,
owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(),
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null,
null, null, true, null, null, null, null); null, null, true, null, null, null, null, null);
} else { } else {
vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" + vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(),
null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null); null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null, null);
} }
} }

View File

@ -930,6 +930,11 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
return removeDhcpSupportForSubnet(network, Service.Dhcp); return removeDhcpSupportForSubnet(network, Service.Dhcp);
} }
@Override
public boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions) {
return false;
}
@Override @Override
public boolean removeDnsSupportForSubnet(Network network) throws ResourceUnavailableException { public boolean removeDnsSupportForSubnet(Network network) throws ResourceUnavailableException {
// Ignore if virtual router is already dhcp provider // Ignore if virtual router is already dhcp provider

View File

@ -106,7 +106,7 @@ public interface UserVmManager extends UserVmService {
boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic); boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic);
UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData,
Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList) throws ResourceUnavailableException, InsufficientCapacityException; Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap) throws ResourceUnavailableException, InsufficientCapacityException;
//the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can //the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can
//find a common place for all the scaling and upgrading code of both user and systemvms. //find a common place for all the scaling and upgrading code of both user and systemvms.

View File

@ -32,10 +32,15 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.affinity.AffinityGroupService;
@ -89,9 +94,6 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
@ -296,6 +298,7 @@ import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.InstanceGroupVMMapDao;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.UserVmDetailsDao;
@ -496,6 +499,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
protected IpAddressManager _ipAddrMgr; protected IpAddressManager _ipAddrMgr;
@Inject @Inject
private SnapshotApiService _snapshotService; private SnapshotApiService _snapshotService;
@Inject
NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
protected ScheduledExecutorService _executor = null; protected ScheduledExecutorService _executor = null;
protected ScheduledExecutorService _vmIpFetchExecutor = null; protected ScheduledExecutorService _vmIpFetchExecutor = null;
@ -1161,10 +1166,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
if (!(network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Domain) if (!(network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Domain)
&& !(network.getAclType() == ACLType.Account && network.getAccountId() == vmInstance.getAccountId())) { && !(network.getAclType() == ACLType.Account && network.getAccountId() == vmInstance.getAccountId())) {
throw new InvalidParameterValueException("only shared network or isolated network with the same account_id can be added to vmId: " + vmId); throw new InvalidParameterValueException("only shared network or isolated network with the same account_id can be added to vmId: " + vmId);
} }
} }
List<NicVO> allNics = _nicDao.listByVmId(vmInstance.getId()); List<NicVO> allNics = _nicDao.listByVmId(vmInstance.getId());
@ -1220,6 +1225,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
try { try {
guestNic = _itMgr.addVmToNetwork(vmInstance, network, profile); guestNic = _itMgr.addVmToNetwork(vmInstance, network, profile);
saveExtraDhcpOptions(guestNic.getId(), cmd.getDhcpOptionsMap());
_networkMgr.configureExtraDhcpOptions(network, guestNic.getId(), cmd.getDhcpOptionsMap());
cleanUp = false; cleanUp = false;
} catch (ResourceUnavailableException e) { } catch (ResourceUnavailableException e) {
throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + ": " + e); throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + ": " + e);
@ -1245,6 +1252,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return _vmDao.findById(vmInstance.getId()); return _vmDao.findById(vmInstance.getId());
} }
private void saveExtraDhcpOptions(long nicId, Map<Integer, String> dhcpOptions) {
List<NicExtraDhcpOptionVO> nicExtraDhcpOptionVOList = dhcpOptions
.entrySet()
.stream()
.map(entry -> new NicExtraDhcpOptionVO(nicId, entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
_nicExtraDhcpOptionDao.saveExtraDhcpOptions(nicExtraDhcpOptionVOList);
}
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_NIC_DELETE, eventDescription = "Removing Nic", async = true) @ActionEvent(eventType = EventTypes.EVENT_NIC_DELETE, eventDescription = "Removing Nic", async = true)
public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException { public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
@ -2417,7 +2435,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable, return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable,
cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList); cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList, cmd.getDhcpOptionsMap());
} }
private void saveUsageEvent(UserVmVO vm) { private void saveUsageEvent(UserVmVO vm) {
@ -2467,7 +2485,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override @Override
public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData,
Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList) Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap)
throws ResourceUnavailableException, InsufficientCapacityException { throws ResourceUnavailableException, InsufficientCapacityException {
UserVmVO vm = _vmDao.findById(id); UserVmVO vm = _vmDao.findById(id);
if (vm == null) { if (vm == null) {
@ -2567,7 +2585,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
} }
List<? extends Nic> nics = _nicDao.listByVmId(vm.getId());
if (hostName != null) { if (hostName != null) {
// Check is hostName is RFC compliant // Check is hostName is RFC compliant
checkNameForRFCCompliance(hostName); checkNameForRFCCompliance(hostName);
@ -2578,14 +2596,27 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
// Verify that vm's hostName is unique // Verify that vm's hostName is unique
List<NetworkVO> vmNtwks = new ArrayList<NetworkVO>();
List<? extends Nic> nics = _nicDao.listByVmId(vm.getId()); List<NetworkVO> vmNtwks = new ArrayList<NetworkVO>(nics.size());
for (Nic nic : nics) { for (Nic nic : nics) {
vmNtwks.add(_networkDao.findById(nic.getNetworkId())); vmNtwks.add(_networkDao.findById(nic.getNetworkId()));
} }
checkIfHostNameUniqueInNtwkDomain(hostName, vmNtwks); checkIfHostNameUniqueInNtwkDomain(hostName, vmNtwks);
} }
List<NetworkVO> networks = nics.stream()
.map(nic -> _networkDao.findById(nic.getNetworkId()))
.collect(Collectors.toList());
verifyExtraDhcpOptionsNetwork(extraDhcpOptionsMap, networks);
for (Nic nic : nics) {
_networkMgr.saveExtraDhcpOptions(networks.stream()
.filter(network -> network.getId() == nic.getNetworkId())
.findFirst()
.get()
.getUuid(), nic.getId(), extraDhcpOptionsMap);
}
_vmDao.updateVM(id, displayName, ha, osTypeId, userData, isDisplayVmEnabled, isDynamicallyScalable, customId, hostName, instanceName); _vmDao.updateVM(id, displayName, ha, osTypeId, userData, isDisplayVmEnabled, isDynamicallyScalable, customId, hostName, instanceName);
if (updateUserdata) { if (updateUserdata) {
@ -2911,7 +2942,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
Map<String, String> customParametes, String customId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException, ResourceAllocationException { StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
@ -2959,7 +2990,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId); userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap);
} }
@ -2968,7 +2999,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId) throws InsufficientCapacityException, ConcurrentOperationException, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
@ -3070,7 +3101,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId); userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap);
} }
@Override @Override
@ -3078,7 +3109,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
Map<String, String> customParametrs, String customId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException, ResourceAllocationException { StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
@ -3171,9 +3202,28 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
networkList.add(network); networkList.add(network);
} }
} }
verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList);
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData,
sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId); sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap);
}
private void verifyExtraDhcpOptionsNetwork(Map<String, Map<Integer, String>> dhcpOptionsMap, List<NetworkVO> networkList) throws InvalidParameterValueException {
if (dhcpOptionsMap != null) {
for (String networkUuid : dhcpOptionsMap.keySet()) {
boolean networkFound = false;
for (NetworkVO network : networkList) {
if (network.getUuid().equals(networkUuid)) {
networkFound = true;
break;
}
}
if (!networkFound) {
throw new InvalidParameterValueException("VM does not has a nic in the Network (" + networkUuid + ") that is specified in the extra dhcp options.");
}
}
}
} }
public void checkNameForRFCCompliance(String name) { public void checkNameForRFCCompliance(String name) {
@ -3187,7 +3237,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner, protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner,
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId) throws InsufficientCapacityException, ResourceUnavailableException, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap) throws InsufficientCapacityException, ResourceUnavailableException,
ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException {
_accountMgr.checkAccess(caller, null, true, owner); _accountMgr.checkAccess(caller, null, true, owner);
@ -3520,7 +3570,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, accountId, userId, offering, UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, accountId, userId, offering,
isIso, sshPublicKey, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters); isIso, sshPublicKey, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap);
// Assign instance to the group // Assign instance to the group
try { try {
@ -3580,7 +3630,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private UserVmVO commitUserVm(final DataCenter zone, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner, private UserVmVO commitUserVm(final DataCenter zone, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner,
final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap<String, NicProfile> networkNicMap, final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap<String, NicProfile> networkNicMap,
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters) throws InsufficientCapacityException { final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException {
return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() { return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() {
@Override @Override
public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException { public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException {
@ -3686,10 +3736,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (isIso) { if (isIso) {
_orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName, _orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName,
hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags,
networkNicMap, plan); networkNicMap, plan, extraDhcpOptionMap);
} else { } else {
_orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(), _orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(),
offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize); offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize, extraDhcpOptionMap);
} }
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
@ -4634,7 +4684,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long templateId = cmd.getTemplateId(); Long templateId = cmd.getTemplateId();
if(!serviceOffering.isDynamic()) { if (!serviceOffering.isDynamic()) {
for(String detail: cmd.getDetails().keySet()) { for(String detail: cmd.getDetails().keySet()) {
if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) {
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
@ -4685,13 +4735,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} else { } else {
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(), size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
cmd.getDetails(), cmd.getCustomId()); cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap());
} }
} else { } else {
if (zone.isSecurityGroupEnabled()) { if (zone.isSecurityGroupEnabled()) {
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), getSecurityGroupIdList(cmd), owner, name, vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), getSecurityGroupIdList(cmd), owner, name,
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId()); cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap());
} else { } else {
if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) { if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) {
@ -4699,7 +4749,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, vm = createAdvancedVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), owner, name, displayName, diskOfferingId, size, group,
cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
cmd.getCustomId()); cmd.getCustomId(), cmd.getDhcpOptionsMap());
} }
} }
return vm; return vm;
@ -5546,7 +5596,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
VirtualMachine vmi = _itMgr.findById(vm.getId()); VirtualMachine vmi = _itMgr.findById(vm.getId());
VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi); VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi);
_networkMgr.allocate(vmProfile, networks); _networkMgr.allocate(vmProfile, networks, null);
_securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList); _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList);
@ -5668,7 +5718,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (applicableNetworks.isEmpty()) { if (applicableNetworks.isEmpty()) {
throw new InvalidParameterValueException("No network is specified, please specify one when you move the vm. For now, please add a network to VM on NICs tab."); throw new InvalidParameterValueException("No network is specified, please specify one when you move the vm. For now, please add a network to VM on NICs tab.");
} else { } else {
_networkMgr.allocate(vmProfile, networks); _networkMgr.allocate(vmProfile, networks, null);
} }
_securityGroupMgr.addInstanceToGroups(vm.getId(), _securityGroupMgr.addInstanceToGroups(vm.getId(),
@ -5796,7 +5846,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
VirtualMachine vmi = _itMgr.findById(vm.getId()); VirtualMachine vmi = _itMgr.findById(vm.getId());
VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi); VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vmi);
_networkMgr.allocate(vmProfile, networks); _networkMgr.allocate(vmProfile, networks, null);
s_logger.debug("AssignVM: Advance virtual, adding networks no " + networks.size() + " to " + vm.getInstanceName()); s_logger.debug("AssignVM: Advance virtual, adding networks no " + networks.size() + " to " + vm.getInstanceName());
} // END IF NON SEC GRP ENABLED } // END IF NON SEC GRP ENABLED
} // END IF ADVANCED } // END IF ADVANCED

View File

@ -523,11 +523,20 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
* @see com.cloud.network.NetworkManager#allocate(com.cloud.vm.VirtualMachineProfile, java.util.List) * @see com.cloud.network.NetworkManager#allocate(com.cloud.vm.VirtualMachineProfile, java.util.List)
*/ */
@Override @Override
public void allocate(VirtualMachineProfile vm, LinkedHashMap<? extends Network, List<? extends NicProfile>> networks) public void allocate(VirtualMachineProfile vm, LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final Map<String, Map<Integer, String>> extraDhcpOptions)
throws InsufficientCapacityException, ConcurrentOperationException { throws InsufficientCapacityException, ConcurrentOperationException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void configureExtraDhcpOptions(Network network, long nicId, Map<Integer, String> extraDhcpOptions) {
}
@Override public void configureExtraDhcpOptions(Network network, long nicId) {
}
/* (non-Javadoc) /* (non-Javadoc)
* @see com.cloud.network.NetworkManager#prepare(com.cloud.vm.VirtualMachineProfile, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) * @see com.cloud.network.NetworkManager#prepare(com.cloud.vm.VirtualMachineProfile, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext)
*/ */
@ -589,6 +598,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
return null; return null;
} }
@Override
public Map<Integer, String> getExtraDhcpOptions(long nicId) {
return null;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see com.cloud.network.NetworkManager#shutdownNetwork(long, com.cloud.vm.ReservationContext, boolean) * @see com.cloud.network.NetworkManager#shutdownNetwork(long, com.cloud.vm.ReservationContext, boolean)
*/ */
@ -653,6 +667,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
return false; return false;
} }
@Override
public void saveExtraDhcpOptions(String networkUuid, Long nicId, Map<String, Map<Integer, String>> extraDhcpOptionMap) {
}
/* (non-Javadoc) /* (non-Javadoc)
* @see com.cloud.network.NetworkManager#allocateNic(com.cloud.vm.NicProfile, com.cloud.network.Network, java.lang.Boolean, int, com.cloud.vm.VirtualMachineProfile) * @see com.cloud.network.NetworkManager#allocateNic(com.cloud.vm.NicProfile, com.cloud.network.Network, java.lang.Boolean, int, com.cloud.vm.VirtualMachineProfile)
*/ */

View File

@ -449,3 +449,14 @@ CREATE VIEW `cloud`.`volume_view` AS
`cloud`.`account` resource_tag_account ON resource_tag_account.id = resource_tags.account_id `cloud`.`account` resource_tag_account ON resource_tag_account.id = resource_tags.account_id
left join left join
`cloud`.`domain` resource_tag_domain ON resource_tag_domain.id = resource_tags.domain_id; `cloud`.`domain` resource_tag_domain ON resource_tag_domain.id = resource_tags.domain_id;
-- Extra Dhcp Options
CREATE TABLE `cloud`.`nic_extra_dhcp_options` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`uuid` varchar(255) UNIQUE,
`nic_id` bigint unsigned NOT NULL COMMENT ' nic id where dhcp options are applied',
`code` int(32),
`value` text,
PRIMARY KEY (`id`),
CONSTRAINT `fk_nic_extra_dhcp_options_nic_id` FOREIGN KEY (`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -78,6 +78,35 @@ class needscleanup(object):
return _wrapper return _wrapper
class gherkin(object):
BLACK = "\033[0;30m"
BLUE = "\033[0;34m"
GREEN = "\033[0;32m"
CYAN = "\033[0;36m"
RED = "\033[0;31m"
BOLDBLUE = "\033[1;34m"
NORMAL = "\033[0m"
def __init__(self, method):
self.method = method
def __get__(self, obj=None, objtype=None):
@functools.wraps(self.method)
def _wrapper(*args, **kwargs):
gherkin_step = self.method.__name__.replace("_", " ").capitalize()
obj.info("=G= %s%s%s" % (self.BOLDBLUE, gherkin_step, self.NORMAL))
try:
result = self.method(obj, *args, **kwargs)
obj.info("=G= %s%s: [SUCCESS]%s" %
(self.GREEN, gherkin_step, self.NORMAL))
return result
except Exception as e:
obj.info("=G= %s%s: [FAILED]%s%s" %
(self.RED, gherkin_step, self.NORMAL, e))
raise
return _wrapper
class nuageTestCase(cloudstackTestCase): class nuageTestCase(cloudstackTestCase):
@classmethod @classmethod

File diff suppressed because it is too large Load Diff

View File

@ -1952,6 +1952,42 @@ test_data = {
"Dns": "VpcVirtualRouter" "Dns": "VpcVirtualRouter"
} }
}, },
# Services supported by the Nuage VSP plugin for VPC without userdata
"vpc_network_offering_nuage_dhcp": {
"name": 'nuage_vpc_marvin',
"displaytext": 'nuage_vpc_marvin',
"guestiptype": 'Isolated',
"supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,Dns',
"traffictype": 'GUEST',
"availability": 'Optional',
"useVpc": 'on',
"ispersistent": 'True',
"serviceProviderList": {
"Dhcp": "NuageVsp",
"StaticNat": "NuageVsp",
"SourceNat": "NuageVsp",
"NetworkACL": "NuageVsp",
"Connectivity": "NuageVsp",
"Dns": "VpcVirtualRouter",
},
"serviceCapabilityList": {
"SourceNat": {"SupportedSourceNatTypes": "perzone"}
}
},
# Services supported by the Nuage VSP plugin for VPCs
"vpc_offering_nuage_dhcp": {
"name": 'Nuage VSP VPC offering',
"displaytext": 'Nuage VSP VPC offering',
"supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,Dns',
"serviceProviderList": {
"Dhcp": "NuageVsp",
"StaticNat": "NuageVsp",
"SourceNat": "NuageVsp",
"NetworkACL": "NuageVsp",
"Connectivity": "NuageVsp",
"Dns": "VpcVirtualRouter",
}
},
"shared_nuage_network_offering": { "shared_nuage_network_offering": {
"name": 'nuage_marvin', "name": 'nuage_marvin',
"displaytext": 'nuage_marvin', "displaytext": 'nuage_marvin',
@ -2048,3 +2084,4 @@ test_data = {
} }
} }
} }

View File

@ -539,6 +539,9 @@ class VirtualMachine:
if "userdata" in services: if "userdata" in services:
cmd.userdata = base64.urlsafe_b64encode(services["userdata"]) cmd.userdata = base64.urlsafe_b64encode(services["userdata"])
if "dhcpoptionsnetworklist" in services:
cmd.dhcpoptionsnetworklist = services["dhcpoptionsnetworklist"]
cmd.details = [{}] cmd.details = [{}]
if customcpunumber: if customcpunumber:
@ -780,7 +783,7 @@ class VirtualMachine:
cmd.id = volume.id cmd.id = volume.id
return apiclient.detachVolume(cmd) return apiclient.detachVolume(cmd)
def add_nic(self, apiclient, networkId, ipaddress=None, macaddress=None): def add_nic(self, apiclient, networkId, ipaddress=None, macaddress=None, dhcpoptions=None):
"""Add a NIC to a VM""" """Add a NIC to a VM"""
cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd() cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd()
cmd.virtualmachineid = self.id cmd.virtualmachineid = self.id
@ -788,6 +791,8 @@ class VirtualMachine:
if ipaddress: if ipaddress:
cmd.ipaddress = ipaddress cmd.ipaddress = ipaddress
if dhcpoptions:
cmd.dhcpoptions = dhcpoptions
if macaddress: if macaddress:
cmd.macaddress = macaddress cmd.macaddress = macaddress

View File

@ -0,0 +1,125 @@
//
// 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.utils.net;
import java.util.Arrays;
public class Dhcp {
public enum DhcpOptionCode {
NETMASK(1, "netmask"),
TIME_OFFSET(2, "time-offset"),
ROUTER(3, "router"),
TIME_SERVER(4, "time-server"),
DNS_SERVER(6, "dns-server"),
LOG_SERVER(7, "log-server"),
LPR_SERVER(9, "lpr-server"),
HOSTNAME(12, "hostname"),
BOOT_FILE_SIZE(13, "boot-file-size"),
DOMAIN_NAME(15, "domain-name"),
SWAP_SERVER(16, "swap-server"),
ROOT_PATH(17, "root-path"),
EXTENSION_PATH(18, "extension-path"),
IP_FORWARD_ENABLE(19, "ip-forward-enable"),
NON_LOCAL_SOURCE_ROUTING(20, "non-local-source-routing"),
POLICY_FILTER(21, "policy-filter"),
MAX_DATAGRAM_REASSEMBLY(22, "max-datagram-reassembly"),
DEFAULT_TTL(23, "default-ttl"),
MTU(26, "mtu"),
ALL_SUBNETS_LOCAL(27, "all-subnets-local"),
BROADCAST(28, "broadcast"),
ROUTER_DISCOVERY(31, "router-discovery"),
ROUTER_SOLICITATION(32, "router-solicitation"),
STATIC_ROUTE(33, "static-route"),
TRAILER_ENCAPSULATION(34, "trailer-encapsulation"),
ARP_TIMEOUT(35, "arp-timeout"),
ETHERNET_ENCAP(36, "ethernet-encap"),
TCP_TTL(37, "tcp-ttl"),
TCP_KEEPALIVE(38, "tcp-keepalive"),
NIS_DOMAIN(40, "nis-domain"),
NIS_SERVER(41, "nis-server"),
NTP_SERVER(42, "ntp-server"),
VENDOR_ENCAP(43, "vendor-encap"),
NETBIOS_NS(44, "netbios-ns"),
NETBIOS_DD(45, "netbios-dd"),
NETBIOS_NODETYPE(46, "netbios-nodetype"),
NETBIOS_SCOPE(47, "netbios-scope"),
X_WINDOWS_FS(48, "x-windows-fs"),
X_WINDOWS_DM(49, "x-windows-dm"),
REQUESTED_ADDRESS(50, "requested-address"),
LEASE_TIME(51, "lease-time"),
OPTION_OVERLOAD(52, "option-overload"),
MESSAGE_TYPE(53, "message-type"),
SERVER_IDENTIFIER(54, "server-identifier"),
PARAMETER_REQUEST(55, "parameter-request"),
MESSAGE(56, "message"),
MAX_MESSAGE_SIZE(57, "max-message-size"),
T1(58, "T1"),
T2(59, "T2"),
VENDOR_CLASS(60, "vendor-class"),
CLIENT_ID(61, "client-id"),
NISPLUS_DOMAIN(64, "nis+-domain"),
NISPLUS_SERVER(65, "nis+-server"),
TFTP_SERVER(66, "tftp-server"),
BOOTFILE_NAME(67, "bootfile-name"),
MOBILE_IP_HOME(68, "mobile-ip-home"),
SMTP_SERVER(69, "smtp-server"),
POP3_SERVER(70, "pop3-server"),
NNTP_SERVER(71, "nntp-server"),
IRC_SERVER(74, "irc-server"),
USER_CLASS(77, "user-class"),
CLIENT_ARCH(93, "client-arch"),
CLIENT_INTERFACE_ID(94, "client-interface-id"),
CLIENT_MACHINE_ID(97, "client-machine-id"),
URL(114, "url"),
DOMAIN_SEARCH(119, "domain-search"),
SIP_SERVER(120, "sip-server"),
CLASSLESS_STATIC_ROUTE(121, "classless-static-route"),
VENDOR_ID_ENCAP(125, "vendor-id-encap"),
SERVER_IP_ADDRESS(255, "server-ip-address");
private int code;
private String name;
DhcpOptionCode(int code, String name){
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() { return name; }
public static DhcpOptionCode valueOfInt(int code) {
return Arrays.stream(DhcpOptionCode.values())
.filter(option -> option.getCode() == code)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Dhcp option code " + code + " not supported."));
}
public static DhcpOptionCode valueOfString(String name) {
return Arrays.stream(DhcpOptionCode.values())
.filter(option -> option.getName().equals(name))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Dhcp option " + name + " not supported."));
}
}
}