CLOUDSTACK-24: multiple ip address per vm nic changes for isolated and vpc networks changes.

This commit is contained in:
Jayapal Uradi 2013-03-01 16:40:26 +05:30 committed by Abhinandan Prateek
parent 1a4ab95d2e
commit f9d96c9169
46 changed files with 1867 additions and 69 deletions

View File

@ -87,4 +87,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity
* @param vpcId * @param vpcId
*/ */
void setVpcId(Long vpcId); void setVpcId(Long vpcId);
String getVmIp();
void setVmIp(String vmIp);
} }

View File

@ -19,9 +19,10 @@ package com.cloud.network;
import java.util.List; import java.util.List;
import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientAddressCapacityException;
@ -33,6 +34,8 @@ import com.cloud.network.Networks.TrafficType;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
/** /**
* The NetworkService interface is the "public" api to entities that make requests to the orchestration engine * The NetworkService interface is the "public" api to entities that make requests to the orchestration engine
@ -153,5 +156,13 @@ public interface NetworkService {
Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan,
String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId)
throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException;
/* Requests an IP address for the guest nic */
String allocateSecondaryGuestIP(Account account, long zoneId, Long nicId,
Long networkId, String ipaddress) throws InsufficientAddressCapacityException;
boolean releaseSecondaryIpFromNic(long ipAddressId);
/* lists the nic informaton */
List<? extends Nic> listNics(ListNicsCmd listNicsCmd);
} }

View File

@ -25,6 +25,7 @@ import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.net.Ip;
public interface RulesService { public interface RulesService {
Pair<List<? extends FirewallRule>, Integer> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId, Long projectId, boolean isRecursive, boolean listAll); Pair<List<? extends FirewallRule>, Integer> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId, Long projectId, boolean isRecursive, boolean listAll);
@ -43,7 +44,7 @@ public interface RulesService {
* @throws NetworkRuleConflictException * @throws NetworkRuleConflictException
* if conflicts in the network rules are detected. * if conflicts in the network rules are detected.
*/ */
PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException; PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, Ip vmIp, boolean openFirewall) throws NetworkRuleConflictException;
/** /**
* Revokes a port forwarding rule * Revokes a port forwarding rule
@ -66,7 +67,7 @@ public interface RulesService {
boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException;
boolean enableStaticNat(long ipAddressId, long vmId, long networkId, boolean isSystemVm) throws NetworkRuleConflictException, ResourceUnavailableException; boolean enableStaticNat(long ipAddressId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException;
PortForwardingRule getPortForwardigRule(long ruleId); PortForwardingRule getPortForwardigRule(long ruleId);

View File

@ -151,4 +151,5 @@ public interface Nic extends Identity, InternalIdentity {
String getIp6Cidr(); String getIp6Cidr();
String getIp6Address(); String getIp6Address();
boolean getSecondaryIp();
} }

View File

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.vm;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
/**
* Nic represents one nic on the VM.
*/
public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIdentity {
/**
* @return id in the CloudStack database
*/
long getId();
long getNicId();
String getIp4Address();
long getNetworkId();
long getVmId();
}

View File

@ -458,6 +458,7 @@ public class ApiConstants {
public static final String UCS_PROFILE_DN = "profiledn"; public static final String UCS_PROFILE_DN = "profiledn";
public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_DN = "bladedn";
public static final String UCS_BLADE_ID = "bladeid"; public static final String UCS_BLADE_ID = "bladeid";
public static final String VM_GUEST_IP = "vmguestip";
public enum HostDetails { public enum HostDetails {
all, capacity, events, stats, min; all, capacity, events, stats, min;

View File

@ -53,6 +53,8 @@ import org.apache.cloudstack.api.response.LoadBalancerResponse;
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.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.PrivateGatewayResponse; import org.apache.cloudstack.api.response.PrivateGatewayResponse;
@ -163,6 +165,8 @@ import com.cloud.user.User;
import com.cloud.user.UserAccount; import com.cloud.user.UserAccount;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroup;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshot;
@ -385,4 +389,7 @@ public interface ResponseGenerator {
TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor);
VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot);
NicSecondaryIpResponse createSecondaryIPToNicResponse(String ip,
Long nicId, Long networkId);
public NicResponse createNicResponse(Nic result);
} }

View File

@ -94,6 +94,9 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
description="The network of the vm the Port Forwarding rule will be created for. " + description="The network of the vm the Port Forwarding rule will be created for. " +
"Required when public Ip address is not associated with any Guest network yet (VPC case)") "Required when public Ip address is not associated with any Guest network yet (VPC case)")
private Long networkId; private Long networkId;
@Parameter(name = ApiConstants.VM_GUEST_IP, type = CommandType.STRING, required = false,
description = "VM guest nic Secondary ip address for the port forwarding rule")
private String vmSecondaryIp;
// /////////////////////////////////////////////////// // ///////////////////////////////////////////////////
// ///////////////// Accessors /////////////////////// // ///////////////// Accessors ///////////////////////
@ -104,6 +107,13 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
return ipAddressId; return ipAddressId;
} }
public Ip getVmSecondaryIp() {
if (vmSecondaryIp == null) {
return null;
}
return new Ip(vmSecondaryIp);
}
@Override @Override
public String getProtocol() { public String getProtocol() {
return protocol.trim(); return protocol.trim();
@ -300,8 +310,15 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command");
} }
Ip privateIp = getVmSecondaryIp();
if (privateIp != null) {
if ( !privateIp.isIp4()) {
throw new InvalidParameterValueException("Invalid vm ip address");
}
}
try { try {
PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, getOpenFirewall()); PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, privateIp, getOpenFirewall());
setEntityId(result.getId()); setEntityId(result.getId());
setEntityUuid(result.getUuid()); setEntityUuid(result.getUuid());
} catch (NetworkRuleConflictException ex) { } catch (NetworkRuleConflictException ex) {

View File

@ -59,6 +59,9 @@ public class EnableStaticNatCmd extends BaseCmd{
description="The network of the vm the static nat will be enabled for." + description="The network of the vm the static nat will be enabled for." +
" Required when public Ip address is not associated with any Guest network yet (VPC case)") " Required when public Ip address is not associated with any Guest network yet (VPC case)")
private Long networkId; private Long networkId;
@Parameter(name = ApiConstants.VM_GUEST_IP, type = CommandType.STRING, required = false,
description = "VM guest nic Secondary ip address for the port forwarding rule")
private String vmSecondaryIp;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
@ -72,6 +75,13 @@ public class EnableStaticNatCmd extends BaseCmd{
return virtualMachineId; return virtualMachineId;
} }
public String getVmSecondaryIp() {
if (vmSecondaryIp == null) {
return null;
}
return vmSecondaryIp;
}
public long getNetworkId() { public long getNetworkId() {
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
Long ntwkId = null; Long ntwkId = null;
@ -110,7 +120,7 @@ public class EnableStaticNatCmd extends BaseCmd{
@Override @Override
public void execute() throws ResourceUnavailableException{ public void execute() throws ResourceUnavailableException{
try { try {
boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false); boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false, getVmSecondaryIp());
if (result) { if (result) {
SuccessResponse response = new SuccessResponse(getCommandName()); SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response); this.setResponseObject(response);

View File

@ -0,0 +1,176 @@
// 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.command.user.vm;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.Nic;
@APICommand(name = "addIpToNic", description = "Assigns secondary IP to NIC", responseObject = NicSecondaryIpResponse.class)
public class AddIpToVmNicCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(AddIpToVmNicCmd.class.getName());
private static final String s_name = "addiptovmnicresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType = NicResponse.class, required = true,
description="the ID of the nic to which you want to assign private IP")
private Long nicId;
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, required = false,
description = "Secondary IP Address")
private String ipAddr;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getEntityTable() {
return "nic_secondary_ips";
}
public String getAccountName() {
return UserContext.current().getCaller().getAccountName();
}
public long getDomainId() {
return UserContext.current().getCaller().getDomainId();
}
private long getZoneId() {
Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
if (ntwk == null) {
throw new InvalidParameterValueException("Can't find zone id for specified");
}
return ntwk.getDataCenterId();
}
public Long getNetworkId() {
Nic nic = _entityMgr.findById(Nic.class, nicId);
Long networkId = nic.getNetworkId();
return networkId;
}
public Long getNicId() {
return nicId;
}
public String getIpaddress () {
if (ipAddr != null) {
return ipAddr;
} else {
return null;
}
}
@Override
public long getEntityOwnerId() {
Account caller = UserContext.current().getCaller();
return caller.getAccountId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_NET_IP_ASSIGN;
}
@Override
public String getEventDescription() {
return "associating ip to nic id: " + getNetworkId() + " in zone " + getZoneId();
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
public static String getResultObjectName() {
return "addressinfo";
}
@Override
public void execute() throws ResourceUnavailableException, ResourceAllocationException,
ConcurrentOperationException, InsufficientCapacityException {
UserContext.current().setEventDetails("Nic Id: " + getNicId() );
String ip;
String SecondaryIp = null;
if ((ip = getIpaddress()) != null) {
if (!NetUtils.isValidIp(ip)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid ip address " + ip);
}
}
try {
SecondaryIp = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress());
} catch (InsufficientAddressCapacityException e) {
throw new InvalidParameterValueException("Allocating guest ip for nic failed");
}
if (SecondaryIp != null) {
s_logger.info("Associated ip address to NIC : " + SecondaryIp);
NicSecondaryIpResponse response = new NicSecondaryIpResponse();
response = _responseGenerator.createSecondaryIPToNicResponse(ip, getNicId(), getNetworkId());
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign secondary ip to nic");
}
}
@Override
public String getSyncObjType() {
return BaseAsyncCmd.networkSyncObject;
}
@Override
public Long getSyncObjId() {
return getNetworkId();
}
@Override
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.IpAddress;
}
}

View File

@ -0,0 +1,133 @@
// 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.command.user.vm;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import com.cloud.async.AsyncJob;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
@APICommand(name = "listNics", description = "list the vm nics IP to NIC", responseObject = NicResponse.class)
public class ListNicsCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(ListNicsCmd.class.getName());
private static final String s_name = "listnics";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType = NicResponse.class, required = false,
description="the ID of the nic to to list IPs")
private Long nicId;
@Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class, required = true,
description="the ID of the vm")
private Long vmId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getEntityTable() {
return "nics";
}
public String getAccountName() {
return UserContext.current().getCaller().getAccountName();
}
public long getDomainId() {
return UserContext.current().getCaller().getDomainId();
}
public Long getNicId() {
return nicId;
}
public Long getVmId() {
return vmId;
}
@Override
public long getEntityOwnerId() {
Account caller = UserContext.current().getCaller();
return caller.getAccountId();
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
public static String getResultObjectName() {
return "addressinfo";
}
@Override
public void execute() throws ResourceUnavailableException, ResourceAllocationException,
ConcurrentOperationException, InsufficientCapacityException {
try {
List<? extends Nic> results = _networkService.listNics(this);
ListResponse<NicResponse> response = new ListResponse<NicResponse>();
List<NicResponse> resList = new ArrayList<NicResponse>(results.size());
for (Nic r : results) {
NicResponse resp = _responseGenerator.createNicResponse(r);
resp.setObjectName("nic");
resList.add(resp);
}
response.setResponses(resList);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
s_logger.warn("Failed to list secondary ip address per nic ");
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.IpAddress;
}
}

View File

@ -0,0 +1,123 @@
// 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.command.user.vm;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@APICommand(name = "removeIpFromNic", description="Assigns secondary IP to NIC.", responseObject=SuccessResponse.class)
public class RemoveIpFromVmNicCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(RemoveIpFromVmNicCmd.class.getName());
private static final String s_name = "unassignsecondaryipaddrtonicresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.ID, type=CommandType.UUID, required = true, entityType = NicSecondaryIpResponse.class,
description="the ID of the secondary ip address to nic")
private long id;
// unexposed parameter needed for events logging
@Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, expose=false)
private Long ownerId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getEntityTable() {
return "nic_secondary_ips";
}
public long getIpAddressId() {
return id;
}
public String getAccountName() {
return UserContext.current().getCaller().getAccountName();
}
public long getDomainId() {
return UserContext.current().getCaller().getDomainId();
}
@Override
public long getEntityOwnerId() {
Account caller = UserContext.current().getCaller();
return caller.getAccountId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_NET_IP_ASSIGN;
}
@Override
public String getEventDescription() {
return ("Disassociating ip address with id=" + id);
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
public static String getResultObjectName() {
return "addressinfo";
}
@Override
public void execute() throws InvalidParameterValueException {
UserContext.current().setEventDetails("Ip Id: " + getIpAddressId());
boolean result = _networkService.releaseSecondaryIpFromNic(getIpAddressId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove secondary ip address for the nic");
}
}
@Override
public String getSyncObjType() {
return BaseAsyncCmd.networkSyncObject;
}
@Override
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.IpAddress;
}
}

View File

@ -0,0 +1,85 @@
// 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 java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class AddIpToVmNicResponse extends BaseResponse {
@SerializedName(ApiConstants.ID) @Param(description="the ID of the secondary private IP addr")
private Long id;
@SerializedName(ApiConstants.IP_ADDRESS) @Param(description="Secondary IP address")
private String ipAddr;
@SerializedName(ApiConstants.NIC_ID) @Param(description="the ID of the nic")
private Long nicId;
@SerializedName(ApiConstants.NETWORK_ID) @Param(description="the ID of the network")
private Long nwId;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="the ID of the vm")
private Long vmId;
public Long getId() {
return id;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Long getNicId() {
return nicId;
}
public void setNicId(Long nicId) {
this.nicId = nicId;
}
public Long getNwId() {
return nwId;
}
public void setNwId(Long nwId) {
this.nwId = nwId;
}
public Long getVmId() {
return vmId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
public Long setId(Long id) {
return id;
}
}

View File

@ -82,6 +82,10 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="virutal machine id the ip address is assigned to (not null only for static nat Ip)") @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="virutal machine id the ip address is assigned to (not null only for static nat Ip)")
private String virtualMachineId; private String virtualMachineId;
@SerializedName("vmipaddress") @Param(description="virutal machine (dnat) ip address (not null only for static nat Ip)")
private String virtualMachineIp;
@SerializedName("virtualmachinename") @Param(description="virutal machine name the ip address is assigned to (not null only for static nat Ip)") @SerializedName("virtualmachinename") @Param(description="virutal machine name the ip address is assigned to (not null only for static nat Ip)")
private String virtualMachineName; private String virtualMachineName;
@ -185,6 +189,10 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR
this.virtualMachineId = virtualMachineId; this.virtualMachineId = virtualMachineId;
} }
public void setVirtualMachineIp(String virtualMachineIp) {
this.virtualMachineIp = virtualMachineIp;
}
public void setVirtualMachineName(String virtualMachineName) { public void setVirtualMachineName(String virtualMachineName) {
this.virtualMachineName = virtualMachineName; this.virtualMachineName = virtualMachineName;
} }

View File

@ -16,6 +16,8 @@
// under the License. // under the License.
package org.apache.cloudstack.api.response; package org.apache.cloudstack.api.response;
import java.util.List;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.BaseResponse;
@ -75,7 +77,10 @@ public class NicResponse extends BaseResponse {
@SerializedName(ApiConstants.IP6_ADDRESS) @Param(description="the IPv6 address of network") @SerializedName(ApiConstants.IP6_ADDRESS) @Param(description="the IPv6 address of network")
private String ip6Address; private String ip6Address;
@SerializedName("secondaryip") @Param(description="the Secondary ipv4 addr of nic")
private List<NicSecondaryIpResponse> secondaryIps;
public String getId() { public String getId() {
return id; return id;
} }
@ -167,4 +172,9 @@ public class NicResponse extends BaseResponse {
return false; return false;
return true; return true;
} }
public void setSecondaryIps(List<NicSecondaryIpResponse> ipList) {
this.secondaryIps = ipList;
}
} }

View File

@ -0,0 +1,85 @@
// 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 java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class NicSecondaryIpResponse extends BaseResponse {
@SerializedName(ApiConstants.ID) @Param(description="the ID of the secondary private IP addr")
private Long id;
@SerializedName(ApiConstants.IP_ADDRESS) @Param(description="Secondary IP address")
private String ipAddr;
@SerializedName(ApiConstants.NIC_ID) @Param(description="the ID of the nic")
private Long nicId;
@SerializedName(ApiConstants.NETWORK_ID) @Param(description="the ID of the network")
private Long nwId;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) @Param(description="the ID of the vm")
private Long vmId;
public Long getId() {
return id;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Long getNicId() {
return nicId;
}
public void setNicId(Long nicId) {
this.nicId = nicId;
}
public Long getNwId() {
return nwId;
}
public void setNwId(Long nwId) {
this.nwId = nwId;
}
public Long getVmId() {
return vmId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
public Long setId(Long id) {
return id;
}
}

View File

@ -0,0 +1,132 @@
// 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.command.test;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd;
import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.NetworkService;
import com.cloud.user.Account;
public class AddIpToVmNicTest extends TestCase {
private AddIpToVmNicCmd addIpToVmNicCmd;
private RemoveIpFromVmNicCmd removeIpFromVmNicCmd;
private ResponseGenerator responseGenerator;
private SuccessResponse successResponseGenerator;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setUp() {
addIpToVmNicCmd = new AddIpToVmNicCmd() {
};
removeIpFromVmNicCmd = new RemoveIpFromVmNicCmd();
}
@Test
public void testCreateSuccess() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
NetworkService networkService = Mockito.mock(NetworkService.class);
AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class);
Mockito.when(
networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn("10.1.1.2");
ipTonicCmd._networkService = networkService;
responseGenerator = Mockito.mock(ResponseGenerator.class);
NicSecondaryIpResponse ipres = Mockito.mock(NicSecondaryIpResponse.class);
Mockito.when(responseGenerator.createSecondaryIPToNicResponse(Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(ipres);
ipTonicCmd._responseGenerator = responseGenerator;
ipTonicCmd.execute();
}
@Test
public void testCreateFailure() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
NetworkService networkService = Mockito.mock(NetworkService.class);
AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class);
Mockito.when(
networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(null);
ipTonicCmd._networkService = networkService;
try {
ipTonicCmd.execute();
} catch (InsufficientAddressCapacityException e) {
throw new InvalidParameterValueException("Allocating guest ip for nic failed");
}
}
@Test
public void testRemoveIpFromVmNicSuccess() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
NetworkService networkService = Mockito.mock(NetworkService.class);
RemoveIpFromVmNicCmd removeIpFromNic = Mockito.mock(RemoveIpFromVmNicCmd.class);
Mockito.when(
networkService.releaseSecondaryIpFromNic(Mockito.anyInt())).thenReturn(true);
removeIpFromNic._networkService = networkService;
successResponseGenerator = Mockito.mock(SuccessResponse.class);
removeIpFromNic.execute();
}
@Test
public void testRemoveIpFromVmNicFailure() throws InsufficientAddressCapacityException {
NetworkService networkService = Mockito.mock(NetworkService.class);
RemoveIpFromVmNicCmd removeIpFromNic = Mockito.mock(RemoveIpFromVmNicCmd.class);
Mockito.when(
networkService.releaseSecondaryIpFromNic(Mockito.anyInt())).thenReturn(false);
removeIpFromNic._networkService = networkService;
successResponseGenerator = Mockito.mock(SuccessResponse.class);
try {
removeIpFromNic.execute();
} catch (InvalidParameterValueException exception) {
Assert.assertEquals("Failed to remove secondary ip address for the nic",
exception.getLocalizedMessage());
}
}
}

View File

@ -326,6 +326,11 @@ addNicToVirtualMachine=15
removeNicFromVirtualMachine=15 removeNicFromVirtualMachine=15
updateDefaultNicForVirtualMachine=15 updateDefaultNicForVirtualMachine=15
####
addIpToNic=15;
removeIpFromNic=15;
listNics=15;
#### SSH key pair commands #### SSH key pair commands
registerSSHKeyPair=15 registerSSHKeyPair=15
createSSHKeyPair=15 createSSHKeyPair=15

View File

@ -201,6 +201,7 @@ import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroup;
import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.InstanceGroupVO;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
@ -209,6 +210,8 @@ import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmStats; import com.cloud.vm.VmStats;
import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
@ -319,6 +322,7 @@ public class ApiDBUtils {
static HostDetailsDao _hostDetailsDao; static HostDetailsDao _hostDetailsDao;
static VMSnapshotDao _vmSnapshotDao; static VMSnapshotDao _vmSnapshotDao;
static ClusterDetailsDao _clusterDetailsDao; static ClusterDetailsDao _clusterDetailsDao;
static NicSecondaryIpDao _nicSecondaryIpDao;
@Inject private ManagementServer ms; @Inject private ManagementServer ms;
@Inject public AsyncJobManager asyncMgr; @Inject public AsyncJobManager asyncMgr;
@ -421,6 +425,7 @@ public class ApiDBUtils {
@Inject private HostDetailsDao hostDetailsDao; @Inject private HostDetailsDao hostDetailsDao;
@Inject private ClusterDetailsDao clusterDetailsDao; @Inject private ClusterDetailsDao clusterDetailsDao;
@Inject private VMSnapshotDao vmSnapshotDao; @Inject private VMSnapshotDao vmSnapshotDao;
@Inject private NicSecondaryIpDao nicSecondaryIpDao;
@PostConstruct @PostConstruct
void init() { void init() {
_ms = ms; _ms = ms;
@ -521,6 +526,7 @@ public class ApiDBUtils {
_hostDetailsDao = hostDetailsDao; _hostDetailsDao = hostDetailsDao;
_clusterDetailsDao = clusterDetailsDao; _clusterDetailsDao = clusterDetailsDao;
_vmSnapshotDao = vmSnapshotDao; _vmSnapshotDao = vmSnapshotDao;
_nicSecondaryIpDao = nicSecondaryIpDao;
// Note: stats collector should already have been initialized by this time, otherwise a null instance is returned // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
_statsCollector = StatsCollector.getInstance(); _statsCollector = StatsCollector.getInstance();
} }
@ -1519,4 +1525,8 @@ public class ApiDBUtils {
public static Map<String, String> findHostDetailsById(long hostId){ public static Map<String, String> findHostDetailsById(long hostId){
return _hostDetailsDao.findDetails(hostId); return _hostDetailsDao.findDetails(hostId);
} }
public static List<NicSecondaryIpVO> findNicSecondaryIps(long nicId) {
return _nicSecondaryIpDao.listByNicId(nicId);
}
} }

View File

@ -19,6 +19,7 @@ package com.cloud.api;
import com.cloud.api.query.ViewResponseHelper; import com.cloud.api.query.ViewResponseHelper;
import com.cloud.api.query.vo.*; import com.cloud.api.query.vo.*;
import com.cloud.api.response.ApiResponseSerializer; import com.cloud.api.response.ApiResponseSerializer;
import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AsyncJobResponse;
import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
@ -52,6 +53,7 @@ import org.apache.cloudstack.api.response.LoadBalancerResponse;
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.NicResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.PrivateGatewayResponse; import org.apache.cloudstack.api.response.PrivateGatewayResponse;
@ -180,10 +182,14 @@ import com.cloud.utils.StringUtils;
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.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.NicSecondaryIp;
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.NicSecondaryIpVO;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.api.ApiConstants.HostDetails; import org.apache.cloudstack.api.ApiConstants.HostDetails;
@ -551,6 +557,9 @@ public class ApiResponseHelper implements ResponseGenerator {
} }
} }
} }
if (ipAddr.getVmIp() != null) {
ipResponse.setVirtualMachineIp(ipAddr.getVmIp());
}
if (ipAddr.getAssociatedWithNetworkId() != null) { if (ipAddr.getAssociatedWithNetworkId() != null) {
Network ntwk = ApiDBUtils.findNetworkById(ipAddr.getAssociatedWithNetworkId()); Network ntwk = ApiDBUtils.findNetworkById(ipAddr.getAssociatedWithNetworkId());
@ -3435,4 +3444,51 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setTimeout(tmDetails.get("timeout")); response.setTimeout(tmDetails.get("timeout"));
return response; return response;
} }
public NicSecondaryIpResponse createSecondaryIPToNicResponse(String ipAddr, Long nicId, Long networkId) {
NicSecondaryIpResponse response = new NicSecondaryIpResponse();
response.setIpAddr(ipAddr);
response.setNicId(nicId);
response.setNwId(networkId);
response.setObjectName("nicsecondaryip");
return response;
}
public NicResponse createNicResponse(Nic result) {
NicResponse response = new NicResponse();
response.setId(result.getUuid());
response.setIpaddress(result.getIp4Address());
if (result.getSecondaryIp()) {
List<NicSecondaryIpVO> secondaryIps = ApiDBUtils.findNicSecondaryIps(result.getId());
if (secondaryIps != null) {
List<NicSecondaryIpResponse> ipList = new ArrayList<NicSecondaryIpResponse>();
for (NicSecondaryIpVO ip: secondaryIps) {
NicSecondaryIpResponse ipRes = new NicSecondaryIpResponse();
ipRes.setId(ip.getId());
ipRes.setIpAddr(ip.getIp4Address());
ipList.add(ipRes);
}
response.setSecondaryIps(ipList);
}
}
response.setGateway(result.getGateway());
response.setId(result.getUuid());
response.setGateway(result.getGateway());
response.setNetmask(result.getNetmask());
response.setMacAddress(result.getMacAddress());
if (result.getBroadcastUri() != null) {
response.setBroadcastUri(result.getBroadcastUri().toString());
}
if (result.getIsolationUri() != null) {
response.setIsolationUri(result.getIsolationUri().toString());
}
if (result.getIp6Address() != null) {
response.setId(result.getIp6Address());
}
response.setIsDefault(result.isDefaultNic());
return response;
}
} }

View File

@ -49,6 +49,7 @@ import com.cloud.user.User;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -331,4 +332,15 @@ public interface NetworkManager {
int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state);
LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network);
boolean isSecondaryIpSetForNic(long nicId);
public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp)
throws InsufficientAddressCapacityException;
boolean removeVmSecondaryIps(long vmId);
List<? extends Nic> listVmNics(Long vmId, Long nicId);
} }

View File

@ -140,8 +140,19 @@ import com.cloud.utils.fsm.StateMachine2;
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.*; import com.cloud.vm.*;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.NicVO;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
@ -240,6 +251,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
UsageEventDao _usageEventDao; UsageEventDao _usageEventDao;
@Inject @Inject
NetworkModel _networkModel; NetworkModel _networkModel;
@Inject
NicSecondaryIpDao _nicSecondaryIpDao;
@Inject @Inject
UserIpv6AddressDao _ipv6Dao; UserIpv6AddressDao _ipv6Dao;
@Inject @Inject
@ -1750,6 +1763,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
guru.deallocate(network, profile, vm); guru.deallocate(network, profile, vm);
_nicDao.remove(nic.getId()); _nicDao.remove(nic.getId());
s_logger.debug("Removed nic id=" + nic.getId()); s_logger.debug("Removed nic id=" + nic.getId());
//remove the secondary ip addresses corresponding to to this nic
List<NicSecondaryIpVO> secondaryIps = _nicSecondaryIpDao.listByNicId(nic.getId());
if (secondaryIps != null) {
for (NicSecondaryIpVO ip : secondaryIps) {
_nicSecondaryIpDao.remove(ip.getId());
}
s_logger.debug("Removed nic " + nic.getId() + " secondary ip addreses");
}
} }
@Override @Override
@ -2792,6 +2813,33 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
Random _rand = new Random(System.currentTimeMillis()); Random _rand = new Random(System.currentTimeMillis());
public List<? extends Nic> listVmNics(Long vmId, Long nicId) {
List<NicVO> result = null;
if (nicId == null) {
result = _nicDao.listByVmId(vmId);
} else {
result = _nicDao.listByVmIdAndNicId(vmId, nicId);
}
return result;
}
public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp)
throws InsufficientAddressCapacityException {
String ipaddr = null;
Account caller = UserContext.current().getCaller();
long callerUserId = UserContext.current().getCallerUserId();
// check permissions
DataCenter zone = _configMgr.getZone(zoneId);
Network network = _networksDao.findById(networkId);
_accountMgr.checkAccess(caller, null, false, network);
//return acquireGuestIpAddress(network, requestedIp);
ipaddr = acquireGuestIpAddress(network, requestedIp);
return ipaddr;
}
@Override @Override
@DB @DB
public String acquireGuestIpAddress(Network network, String requestedIp) { public String acquireGuestIpAddress(Network network, String requestedIp) {
@ -2802,7 +2850,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
Set<Long> availableIps = _networkModel.getAvailableIps(network, requestedIp); Set<Long> availableIps = _networkModel.getAvailableIps(network, requestedIp);
if (availableIps.isEmpty()) { if (availableIps == null || availableIps.isEmpty()) {
return null; return null;
} }
@ -3032,9 +3080,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
throw new InvalidParameterValueException("Source ip address of the rule id=" + firewallStaticNatRule.getId() + " is not static nat enabled"); throw new InvalidParameterValueException("Source ip address of the rule id=" + firewallStaticNatRule.getId() + " is not static nat enabled");
} }
String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId());
ruleVO.setState(FirewallRule.State.Revoke); ruleVO.setState(FirewallRule.State.Revoke);
staticNatRules.add(new StaticNatRuleImpl(ruleVO, dstIp)); staticNatRules.add(new StaticNatRuleImpl(ruleVO, ip.getVmIp()));
} }
try { try {
@ -3598,4 +3646,26 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
} }
return rules.size(); return rules.size();
} }
@Override
public boolean isSecondaryIpSetForNic(long nicId) {
NicVO nic = _nicDao.findById(nicId);
return nic.getSecondaryIp();
}
@Override
public boolean removeVmSecondaryIps(long vmId) {
Transaction txn = Transaction.currentTxn();
txn.start();
List <NicSecondaryIpVO> ipList = _nicSecondaryIpDao.listByVmId(vmId);
if (ipList != null) {
for (NicSecondaryIpVO ip: ipList) {
_nicSecondaryIpDao.remove(ip.getId());
}
s_logger.debug("Revoving nic secondary ip entry ...");
}
txn.commit();
return true;
}
} }

View File

@ -109,6 +109,7 @@ 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.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
@Component @Component
@ -170,6 +171,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel {
PrivateIpDao _privateIpDao; PrivateIpDao _privateIpDao;
@Inject @Inject
UserIpv6AddressDao _ipv6Dao; UserIpv6AddressDao _ipv6Dao;
@Inject
NicSecondaryIpDao _nicSecondaryIpDao;;
private final HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5); private final HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5);
@ -1624,6 +1627,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel {
public Set<Long> getAvailableIps(Network network, String requestedIp) { public Set<Long> getAvailableIps(Network network, String requestedIp) {
String[] cidr = network.getCidr().split("/"); String[] cidr = network.getCidr().split("/");
List<String> ips = _nicDao.listIpAddressInNetwork(network.getId()); List<String> ips = _nicDao.listIpAddressInNetwork(network.getId());
List<String> secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId());
ips.addAll(secondaryIps);
Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]));
Set<Long> usedIps = new TreeSet<Long>(); Set<Long> usedIps = new TreeSet<Long>();

View File

@ -37,23 +37,28 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
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.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import org.bouncycastle.util.IPAddress;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter;
import com.cloud.dc.Pod;
import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO; import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.AccountVlanMapDao;
import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao; import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeployDestination;
import com.cloud.domain.Domain; import com.cloud.domain.Domain;
@ -65,6 +70,8 @@ import com.cloud.event.UsageEventUtils;
import com.cloud.event.dao.EventDao; import com.cloud.event.dao.EventDao;
import com.cloud.event.dao.UsageEventDao; import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.*; import com.cloud.exception.*;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDao;
import com.cloud.network.IpAddress.State; import com.cloud.network.IpAddress.State;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.network.Network.Capability; import com.cloud.network.Network.Capability;
@ -82,7 +89,9 @@ import com.cloud.network.element.VirtualRouterElement;
import com.cloud.network.element.VpcVirtualRouterElement; import com.cloud.network.element.VpcVirtualRouterElement;
import com.cloud.network.guru.NetworkGuru; import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.PortForwardingRuleVO;
import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.RulesManager;
import com.cloud.network.vpc.PrivateIpVO; import com.cloud.network.vpc.PrivateIpVO;
import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcManager;
@ -112,6 +121,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.vm.*; import com.cloud.vm.*;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import java.util.*; import java.util.*;
@ -203,6 +214,16 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
@Inject @Inject
NetworkModel _networkModel; NetworkModel _networkModel;
@Inject
NicSecondaryIpDao _nicSecondaryIpDao;
@Inject
PortForwardingRulesDao _portForwardingDao;
@Inject
HostDao _hostDao;
@Inject
HostPodDao _hostPodDao;
int _cidrLimit; int _cidrLimit;
boolean _allowSubdomainNetworkAccess; boolean _allowSubdomainNetworkAccess;
@ -449,6 +470,138 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
} }
public String allocateSecondaryGuestIP (Account ipOwner, long zoneId, Long nicId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException {
Long accountId = null;
Long domainId = null;
Long vmId = null;
String ipaddr = null;
if (networkId == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
Network network = _networksDao.findById(networkId);
if (network == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
accountId = network.getAccountId();
domainId = network.getDomainId();
// verify permissions
_accountMgr.checkAccess(ipOwner, null, true, network);
//check whether the nic belongs to user vm.
NicVO nicVO = _nicDao.findById(nicId);
if (nicVO == null) {
throw new InvalidParameterValueException("There is no nic for the " + nicId);
}
if (nicVO.getVmType() != VirtualMachine.Type.User) {
throw new InvalidParameterValueException("The nic is not belongs to user vm");
}
DataCenter dc = _dcDao.findById(network.getDataCenterId());
Long id = nicVO.getInstanceId();
DataCenter zone = _configMgr.getZone(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Invalid zone Id is given");
}
s_logger.debug("Calling the ip allocation ...");
if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) {
try {
ipaddr = _networkMgr.allocateGuestIP(ipOwner, false, zoneId, networkId, requestedIp);
} catch (InsufficientAddressCapacityException e) {
throw new InvalidParameterValueException("Allocating guest ip for nic failed");
}
} else {
throw new InvalidParameterValueException("AddIpToVMNic is not supported in this network...");
}
if (ipaddr != null) {
// we got the ip addr so up the nics table and secodary ip
Transaction txn = Transaction.currentTxn();
txn.start();
boolean nicSecondaryIpSet = nicVO.getSecondaryIp();
if (!nicSecondaryIpSet) {
nicVO.setSecondaryIp(true);
// commit when previously set ??
s_logger.debug("Setting nics table ...");
_nicDao.update(nicId, nicVO);
}
s_logger.debug("Setting nic_secondary_ip table ...");
vmId = nicVO.getInstanceId();
NicSecondaryIpVO secondaryIpVO = new NicSecondaryIpVO(nicId, ipaddr, vmId, accountId, domainId, networkId);
_nicSecondaryIpDao.persist(secondaryIpVO);
txn.commit();
}
return ipaddr;
}
@DB
public boolean releaseSecondaryIpFromNic (long ipAddressId) {
Account caller = UserContext.current().getCaller();
boolean success = false;
// Verify input parameters
NicSecondaryIpVO ipVO= _nicSecondaryIpDao.findById(ipAddressId);
if (ipVO == null) {
throw new InvalidParameterValueException("Unable to find ip address by id");
}
Network network = _networksDao.findById(ipVO.getNetworkId());
// verify permissions
_accountMgr.checkAccess(caller, null, true, network);
Long nicId = ipVO.getNicId();
s_logger.debug("ip id and nic id" + ipAddressId + "..." + nicId);
//check is this the last secondary ip for NIC
List<NicSecondaryIpVO> ipList = _nicSecondaryIpDao.listByNicId(nicId);
boolean lastIp = false;
if (ipList.size() == 1) {
// this is the last secondary ip to nic
lastIp = true;
}
//check PF or static NAT is configured on this ip address
String secondaryIp = ipVO.getIp4Address();
List<PortForwardingRuleVO> pfRuleList = _portForwardingDao.listByDestIpAddr(secondaryIp);
if (pfRuleList.size() != 0) {
s_logger.debug("VM nic IP " + secondaryIp + " is associated with the port forwarding rule");
throw new InvalidParameterValueException("Can't remove the secondary ip " + secondaryIp + " is associate with the port forwarding rule");
}
//check if the secondary ip associated with any static nat rule
IPAddressVO publicIpVO = _ipAddressDao.findByVmIp(secondaryIp);
if (publicIpVO != null) {
s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId());
throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId());
}
success = removeNicSecondaryIP(ipVO, lastIp);
return success;
}
boolean removeNicSecondaryIP(NicSecondaryIpVO ipVO, boolean lastIp) {
Transaction txn = Transaction.currentTxn();
long nicId = ipVO.getNicId();
NicVO nic = _nicDao.findById(nicId);
txn.start();
if (lastIp) {
nic.setSecondaryIp(false);
s_logger.debug("Setting nics secondary ip to false ...");
_nicDao.update(nicId, nic);
}
s_logger.debug("Revoving nic secondary ip entry ...");
_nicSecondaryIpDao.remove(ipVO.getId());
txn.commit();
return true;
}
@Override @Override
@DB @DB
@ -3025,4 +3178,21 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
public Network getNetwork(String networkUuid) { public Network getNetwork(String networkUuid) {
return _networksDao.findByUuid(networkUuid); return _networksDao.findByUuid(networkUuid);
} }
@Override
public List<? extends Nic> listNics(ListNicsCmd cmd) {
Account caller = UserContext.current().getCaller();
Long nicId = cmd.getNicId();
Long vmId = cmd.getVmId();
UserVmVO userVm = _userVmDao.findById(vmId);
if (userVm == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Virtual mahine id does not exist");
ex.addProxyObject(userVm, vmId, "vmId");
throw ex;
}
_accountMgr.checkAccess(caller, null, true, userVm);
return _networkMgr.listVmNics(vmId, nicId);
}
} }

View File

@ -211,18 +211,28 @@ public class PublicIp implements PublicIpAddress {
_addr.setVpcId(vpcId); _addr.setVpcId(vpcId);
} }
@Override @Override
public String getIp6Gateway() { public String getIp6Gateway() {
return _vlan.getIp6Gateway(); return _vlan.getIp6Gateway();
} }
@Override @Override
public String getIp6Cidr() { public String getIp6Cidr() {
return _vlan.getIp6Cidr(); return _vlan.getIp6Cidr();
} }
@Override @Override
public String getIp6Range() { public String getIp6Range() {
return _vlan.getIp6Range(); return _vlan.getIp6Range();
} }
@Override
public String getVmIp() {
return _addr.getVmIp();
}
@Override
public void setVmIp(String vmIp) {
_addr.setVmIp(vmIp);
}
} }

View File

@ -62,5 +62,8 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> {
long countFreePublicIPs(); long countFreePublicIPs();
long countFreeIPsInNetwork(long networkId); long countFreeIPsInNetwork(long networkId);
} IPAddressVO findByVmIp(String vmIp);
IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp);
}

View File

@ -80,6 +80,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
AllFieldsSearch.and("sourcenetwork", AllFieldsSearch.entity().getSourceNetworkId(), Op.EQ); AllFieldsSearch.and("sourcenetwork", AllFieldsSearch.entity().getSourceNetworkId(), Op.EQ);
AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ); AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ);
AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ);
AllFieldsSearch.and("associatedVmIp", AllFieldsSearch.entity().getVmIp(), Op.EQ);
AllFieldsSearch.done(); AllFieldsSearch.done();
VlanDbIdSearchUnallocated = createSearchBuilder(); VlanDbIdSearchUnallocated = createSearchBuilder();
@ -232,6 +233,12 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
return findOneBy(sc); return findOneBy(sc);
} }
@Override
public IPAddressVO findByVmIp(String vmIp) {
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("associatedVmIp", vmIp);
return findOneBy(sc);
}
@Override @Override
public int countIPs(long dcId, long vlanId, boolean onlyCountAllocated) { public int countIPs(long dcId, long vlanId, boolean onlyCountAllocated) {
SearchCriteria<Integer> sc = onlyCountAllocated ? AllocatedIpCount.create() : AllIpCount.create(); SearchCriteria<Integer> sc = onlyCountAllocated ? AllocatedIpCount.create() : AllIpCount.create();
@ -347,5 +354,13 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
boolean result = super.remove(id); boolean result = super.remove(id);
txn.commit(); txn.commit();
return result; return result;
} }
@Override
public IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp) {
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("associatedWithVmId", vmId);
sc.setParameters("associatedVmIp", vmIp);
return findOneBy(sc);
}
} }

View File

@ -112,6 +112,10 @@ public class IPAddressVO implements IpAddress {
@Column(name="vpc_id") @Column(name="vpc_id")
private Long vpcId; private Long vpcId;
@Column(name="dnat_vmip")
private String vmIp;
protected IPAddressVO() { protected IPAddressVO() {
this.uuid = UUID.randomUUID().toString(); this.uuid = UUID.randomUUID().toString();
} }
@ -288,8 +292,18 @@ public class IPAddressVO implements IpAddress {
return vpcId; return vpcId;
} }
@Override @Override
public void setVpcId(Long vpcId) { public void setVpcId(Long vpcId) {
this.vpcId = vpcId; this.vpcId = vpcId;
} }
@Override
public String getVmIp() {
return vmIp;
}
@Override
public void setVmIp(String vmIp) {
this.vmIp = vmIp;
}
} }

View File

@ -623,7 +623,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
Set<Long> mappedInstanceIds = new HashSet<Long>(); Set<Long> mappedInstanceIds = new HashSet<Long>();
for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { for (LoadBalancerVMMapVO mappedInstance : mappedInstances) {
mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId())); mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId()));
} }
List<UserVm> vmsToAdd = new ArrayList<UserVm>(); List<UserVm> vmsToAdd = new ArrayList<UserVm>();

View File

@ -2318,8 +2318,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.StaticNat, provider)) { if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.StaticNat, provider)) {
if (ip.isOneToOneNat()) { if (ip.isOneToOneNat()) {
String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), guestNetworkId); StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), ip.getVmIp(), false);
StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), dstIp, false);
staticNats.add(staticNat); staticNats.add(staticNat);
} }
} }

View File

@ -78,10 +78,13 @@ import com.cloud.utils.db.Transaction;
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.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
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.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
@Component @Component
@ -123,6 +126,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
ResourceTagDao _resourceTagDao; ResourceTagDao _resourceTagDao;
@Inject @Inject
VpcManager _vpcMgr; VpcManager _vpcMgr;
@Inject
NicSecondaryIpDao _nicSecondaryDao;
@Override @Override
public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) { public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) {
@ -172,7 +177,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
@Override @Override
@DB @DB
@ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true) @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true)
public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, Ip vmIp, boolean openFirewall)
throws NetworkRuleConflictException { throws NetworkRuleConflictException {
UserContext ctx = UserContext.current(); UserContext ctx = UserContext.current();
Account caller = ctx.getCaller(); Account caller = ctx.getCaller();
@ -192,6 +197,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
Network network = _networkModel.getNetwork(networkId); Network network = _networkModel.getNetwork(networkId);
//associate ip address to network (if needed) //associate ip address to network (if needed)
boolean performedIpAssoc = false; boolean performedIpAssoc = false;
Nic guestNic;
if (ipAddress.getAssociatedWithNetworkId() == null) { if (ipAddress.getAssociatedWithNetworkId() == null) {
boolean assignToVpcNtwk = network.getVpcId() != null boolean assignToVpcNtwk = network.getVpcId() != null
&& ipAddress.getVpcId() != null && ipAddress.getVpcId().longValue() == network.getVpcId(); && ipAddress.getVpcId() != null && ipAddress.getVpcId().longValue() == network.getVpcId();
@ -244,13 +250,26 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
// Verify that vm has nic in the network // Verify that vm has nic in the network
Ip dstIp = rule.getDestinationIpAddress(); Ip dstIp = rule.getDestinationIpAddress();
Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); guestNic = _networkModel.getNicInNetwork(vmId, networkId);
if (guestNic == null || guestNic.getIp4Address() == null) { if (guestNic == null || guestNic.getIp4Address() == null) {
throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress"); throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress");
} else { } else {
dstIp = new Ip(guestNic.getIp4Address()); dstIp = new Ip(guestNic.getIp4Address());
} }
if (vmIp != null) {
//vm ip is passed so it can be primary or secondary ip addreess.
if (!dstIp.equals(vmIp)) {
//the vm ip is secondary ip to the nic.
// is vmIp is secondary ip or not
NicSecondaryIp secondaryIp = _nicSecondaryDao.findByIp4AddressAndNicId(vmIp.toString(), guestNic.getId());
if (secondaryIp == null) {
throw new InvalidParameterValueException("IP Address is not in the VM nic's network ");
}
dstIp = vmIp;
}
}
//if start port and end port are passed in, and they are not equal to each other, perform the validation //if start port and end port are passed in, and they are not equal to each other, perform the validation
boolean validatePortRange = false; boolean validatePortRange = false;
if (rule.getSourcePortStart().intValue() != rule.getSourcePortEnd().intValue() if (rule.getSourcePortStart().intValue() != rule.getSourcePortEnd().intValue()
@ -350,8 +369,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
throw new InvalidParameterValueException("Can't create ip forwarding rules for the network where elasticIP service is enabled"); throw new InvalidParameterValueException("Can't create ip forwarding rules for the network where elasticIP service is enabled");
} }
String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId); //String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId);
String dstIp = ipAddress.getVmIp();
Transaction txn = Transaction.currentTxn(); Transaction txn = Transaction.currentTxn();
txn.start(); txn.start();
@ -397,14 +416,13 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ENABLE_STATIC_NAT, eventDescription = "enabling static nat") @ActionEvent(eventType = EventTypes.EVENT_ENABLE_STATIC_NAT, eventDescription = "enabling static nat")
public boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm) public boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp)
throws NetworkRuleConflictException, ResourceUnavailableException { throws NetworkRuleConflictException, ResourceUnavailableException {
UserContext ctx = UserContext.current(); UserContext ctx = UserContext.current();
Account caller = ctx.getCaller(); Account caller = ctx.getCaller();
UserContext.current().setEventDetails("Ip Id: " + ipId); UserContext.current().setEventDetails("Ip Id: " + ipId);
// Verify input parameters // Verify input parameters
IPAddressVO ipAddress = _ipAddressDao.findById(ipId); IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
if (ipAddress == null) { if (ipAddress == null) {
throw new InvalidParameterValueException("Unable to find ip address by id " + ipId); throw new InvalidParameterValueException("Unable to find ip address by id " + ipId);
@ -414,6 +432,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
boolean performedIpAssoc = false; boolean performedIpAssoc = false;
boolean isOneToOneNat = ipAddress.isOneToOneNat(); boolean isOneToOneNat = ipAddress.isOneToOneNat();
Long associatedWithVmId = ipAddress.getAssociatedWithVmId(); Long associatedWithVmId = ipAddress.getAssociatedWithVmId();
Nic guestNic;
NicSecondaryIpVO nicSecIp = null;
String dstIp = null;
try { try {
Network network = _networkModel.getNetwork(networkId); Network network = _networkModel.getNetwork(networkId);
if (network == null) { if (network == null) {
@ -421,11 +443,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
} }
// Check that vm has a nic in the network // Check that vm has a nic in the network
Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); guestNic = _networkModel.getNicInNetwork(vmId, networkId);
if (guestNic == null) { if (guestNic == null) {
throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id"); throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id");
} }
dstIp = guestNic.getIp4Address();
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) {
throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not " + throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not " +
@ -466,13 +488,36 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
// Check permissions // Check permissions
checkIpAndUserVm(ipAddress, vm, caller); checkIpAndUserVm(ipAddress, vm, caller);
//is static nat is for vm secondary ip
//dstIp = guestNic.getIp4Address();
if (vmGuestIp != null) {
//dstIp = guestNic.getIp4Address();
if (!dstIp.equals(vmGuestIp)) {
//check whether the secondary ip set to the vm or not
boolean secondaryIpSet = _networkMgr.isSecondaryIpSetForNic(guestNic.getId());
if (!secondaryIpSet) {
throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm");
}
//check the ip belongs to the vm or not
nicSecIp = _nicSecondaryDao.findByIp4AddressAndNicId(vmGuestIp, guestNic.getId());
if (nicSecIp == null) {
throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm");
}
dstIp = nicSecIp.getIp4Address();
// Set public ip column with the vm ip
}
}
// Verify ip address parameter // Verify ip address parameter
isIpReadyForStaticNat(vmId, ipAddress, caller, ctx.getCallerUserId()); // checking vm id is not sufficient, check for the vm ip
isIpReadyForStaticNat(vmId, ipAddress, dstIp, caller, ctx.getCallerUserId());
} }
ipAddress.setOneToOneNat(true); ipAddress.setOneToOneNat(true);
ipAddress.setAssociatedWithVmId(vmId); ipAddress.setAssociatedWithVmId(vmId);
ipAddress.setVmIp(dstIp);
if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) { if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) {
// enable static nat on the backend // enable static nat on the backend
s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend"); s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend");
@ -483,6 +528,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend");
ipAddress.setOneToOneNat(isOneToOneNat); ipAddress.setOneToOneNat(isOneToOneNat);
ipAddress.setAssociatedWithVmId(associatedWithVmId); ipAddress.setAssociatedWithVmId(associatedWithVmId);
ipAddress.setVmIp(null);
_ipAddressDao.update(ipAddress.getId(), ipAddress); _ipAddressDao.update(ipAddress.getId(), ipAddress);
} }
} else { } else {
@ -490,16 +536,17 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
} }
} finally { } finally {
if (performedIpAssoc) { if (performedIpAssoc) {
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network //if the rule is the last one for the ip address assigned to VPC, unassign it from the network
IpAddress ip = _ipAddressDao.findById(ipAddress.getId()); IpAddress ip = _ipAddressDao.findById(ipAddress.getId());
_vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId);
} }
} }
return false; return false;
} }
protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, Account caller, long callerUserId) protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress,
String vmIp, Account caller, long callerUserId)
throws NetworkRuleConflictException, ResourceUnavailableException { throws NetworkRuleConflictException, ResourceUnavailableException {
if (ipAddress.isSourceNat()) { if (ipAddress.isSourceNat()) {
throw new InvalidParameterValueException("Can't enable static, ip address " + ipAddress + " is a sourceNat ip address"); throw new InvalidParameterValueException("Can't enable static, ip address " + ipAddress + " is a sourceNat ip address");
@ -519,7 +566,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId + " as it's already assigned to antoher vm"); throw new NetworkRuleConflictException("Failed to enable static for the ip address " + ipAddress + " and vm id=" + vmId + " as it's already assigned to antoher vm");
} }
IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vmId); //check wether the vm ip is alreday associated with any public ip address
IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmIdAndVmIp(vmId, vmIp);
if (oldIP != null) { if (oldIP != null) {
// If elasticIP functionality is supported in the network, we always have to disable static nat on the old // If elasticIP functionality is supported in the network, we always have to disable static nat on the old
@ -538,9 +586,9 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
if (!reassignStaticNat) { if (!reassignStaticNat) {
throw new InvalidParameterValueException("Failed to enable static nat for the ip address id=" + ipAddress.getId() + " as vm id=" + vmId + " is already associated with ip id=" + oldIP.getId()); throw new InvalidParameterValueException("Failed to enable static nat for the ip address id=" + ipAddress.getId() + " as vm id=" + vmId + " is already associated with ip id=" + oldIP.getId());
} }
// unassign old static nat rule // unassign old static nat rule
s_logger.debug("Disassociating static nat for ip " + oldIP); s_logger.debug("Disassociating static nat for ip " + oldIP);
if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) {
throw new CloudRuntimeException("Failed to disable old static nat rule for vm id=" + vmId + " and ip " + oldIP); throw new CloudRuntimeException("Failed to disable old static nat rule for vm id=" + vmId + " and ip " + oldIP);
} }
} }
@ -890,8 +938,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
List<StaticNat> staticNats = new ArrayList<StaticNat>(); List<StaticNat> staticNats = new ArrayList<StaticNat>();
for (IPAddressVO ip : ips) { for (IPAddressVO ip : ips) {
// Get nic IP4 address // Get nic IP4 address
String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId); //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId);
StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), dstIp, false); StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), ip.getVmIp(), false);
staticNats.add(staticNat); staticNats.add(staticNat);
} }
@ -1209,6 +1257,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
boolean isIpSystem = ipAddress.getSystem(); boolean isIpSystem = ipAddress.getSystem();
ipAddress.setOneToOneNat(false); ipAddress.setOneToOneNat(false);
ipAddress.setAssociatedWithVmId(null); ipAddress.setAssociatedWithVmId(null);
ipAddress.setVmIp(null);
if (isIpSystem && !releaseIpIfElastic) { if (isIpSystem && !releaseIpIfElastic) {
ipAddress.setSystem(false); ipAddress.setSystem(false);
} }
@ -1248,11 +1297,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
throw ex; throw ex;
} }
String dstIp; String dstIp = ip.getVmIp();
if (forRevoke) { if (dstIp == null) {
dstIp = _networkModel.getIpInNetworkIncludingRemoved(ip.getAssociatedWithVmId(), rule.getNetworkId()); InvalidParameterValueException ex = new InvalidParameterValueException("VM ip address of the specified public ip is not set ");
} else { ex.addProxyObject(ruleVO, rule.getId(), "ruleId");
dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), rule.getNetworkId()); throw ex;
} }
return new StaticNatRuleImpl(ruleVO, dstIp); return new StaticNatRuleImpl(ruleVO, dstIp);
@ -1333,12 +1382,16 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
// create new static nat rule // create new static nat rule
// Get nic IP4 address // Get nic IP4 address
Nic guestNic = _networkModel.getNicInNetwork(vm.getId(), networkId);
if (guestNic == null) {
throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id");
}
String dstIp; String dstIp;
if (forRevoke) {
dstIp = _networkModel.getIpInNetworkIncludingRemoved(sourceIp.getAssociatedWithVmId(), networkId); dstIp = sourceIp.getVmIp();
} else { if (dstIp == null) {
dstIp = _networkModel.getIpInNetwork(sourceIp.getAssociatedWithVmId(), networkId); throw new InvalidParameterValueException("Vm ip is not set as dnat ip for this public ip");
} }
StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(),
@ -1373,7 +1426,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm); boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm);
try { try {
success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM); success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM, null);
} catch (NetworkRuleConflictException ex) { } catch (NetworkRuleConflictException ex) {
s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " +
vm + " in guest network " + guestNetwork + " due to exception ", ex); vm + " in guest network " + guestNetwork + " due to exception ", ex);

View File

@ -41,5 +41,7 @@ public interface PortForwardingRulesDao extends GenericDao<PortForwardingRuleVO,
List<PortForwardingRuleVO> listByNetwork(long networkId); List<PortForwardingRuleVO> listByNetwork(long networkId);
List<PortForwardingRuleVO> listByAccount(long accountId); List<PortForwardingRuleVO> listByAccount(long accountId);
List<PortForwardingRuleVO> listByDestIpAddr(String ip4Address);
} }

View File

@ -32,6 +32,7 @@ import com.cloud.utils.db.GenericDaoBase;
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.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.vm.dao.NicSecondaryIpVO;
@Component @Component
@Local(value=PortForwardingRulesDao.class) @Local(value=PortForwardingRulesDao.class)
@ -55,6 +56,7 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRul
AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ); AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
AllFieldsSearch.and("vmId", AllFieldsSearch.entity().getVirtualMachineId(), Op.EQ); AllFieldsSearch.and("vmId", AllFieldsSearch.entity().getVirtualMachineId(), Op.EQ);
AllFieldsSearch.and("purpose", AllFieldsSearch.entity().getPurpose(), Op.EQ); AllFieldsSearch.and("purpose", AllFieldsSearch.entity().getPurpose(), Op.EQ);
AllFieldsSearch.and("dstIp", AllFieldsSearch.entity().getDestinationIpAddress(), Op.EQ);
AllFieldsSearch.done(); AllFieldsSearch.done();
ApplicationSearch = createSearchBuilder(); ApplicationSearch = createSearchBuilder();
@ -149,5 +151,11 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRul
return listBy(sc); return listBy(sc);
} }
@Override
public List<PortForwardingRuleVO> listByDestIpAddr(String ip4Address) {
SearchCriteria<PortForwardingRuleVO> sc = AllFieldsSearch.create();
sc.setParameters("address", ip4Address);
return listBy(sc);
}
} }

View File

@ -2165,6 +2165,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(CreateVMSnapshotCmd.class); cmdList.add(CreateVMSnapshotCmd.class);
cmdList.add(RevertToSnapshotCmd.class); cmdList.add(RevertToSnapshotCmd.class);
cmdList.add(DeleteVMSnapshotCmd.class); cmdList.add(DeleteVMSnapshotCmd.class);
cmdList.add(AddIpToVmNicCmd.class);
cmdList.add(RemoveIpFromVmNicCmd.class);
cmdList.add(ListNicsCmd.class);
return cmdList; return cmdList;
} }

View File

@ -122,6 +122,9 @@ public class NicVO implements Nic {
@Column(name = "uuid") @Column(name = "uuid")
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
@Column(name = "secondary_ip")
boolean secondaryIp;
public NicVO(String reserver, Long instanceId, long configurationId, VirtualMachine.Type vmType) { public NicVO(String reserver, Long instanceId, long configurationId, VirtualMachine.Type vmType) {
this.reserver = reserver; this.reserver = reserver;
this.instanceId = instanceId; this.instanceId = instanceId;
@ -349,4 +352,12 @@ public class NicVO implements Nic {
public void setIp6Cidr(String ip6Cidr) { public void setIp6Cidr(String ip6Cidr) {
this.ip6Cidr = ip6Cidr; this.ip6Cidr = ip6Cidr;
} }
public boolean getSecondaryIp() {
return secondaryIp;
}
public void setSecondaryIp(boolean secondaryIp) {
this.secondaryIp = secondaryIp;
}
} }

View File

@ -360,6 +360,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
protected ProjectManager _projectMgr; protected ProjectManager _projectMgr;
@Inject @Inject
protected ResourceManager _resourceMgr; protected ResourceManager _resourceMgr;
@Inject @Inject
protected NetworkServiceMapDao _ntwkSrvcDao; protected NetworkServiceMapDao _ntwkSrvcDao;
@Inject @Inject
@ -1359,6 +1360,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
+ " as a part of vm id=" + vmId + " as a part of vm id=" + vmId
+ " expunge because resource is unavailable", e); + " expunge because resource is unavailable", e);
} }
//remove vm secondary ip addresses
if (_networkMgr.removeVmSecondaryIps(vmId)) {
s_logger.debug("Removed vm " + vmId + " secondary ip address of the VM Nics as a part of expunge process");
} else {
success = false;
s_logger.warn("Fail to remove secondary ip address of vm " + vmId + " Nics as a part of expunge process");
}
return success; return success;
} }

View File

@ -58,4 +58,6 @@ public interface NicDao extends GenericDao<NicVO, Long> {
NicVO findByNetworkIdInstanceIdAndBroadcastUri(long networkId, long instanceId, String broadcastUri); NicVO findByNetworkIdInstanceIdAndBroadcastUri(long networkId, long instanceId, String broadcastUri);
NicVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, long instanceId, String ip4Address); NicVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, long instanceId, String ip4Address);
List<NicVO> listByVmIdAndNicId(Long vmId, Long nicId);
} }

View File

@ -53,8 +53,10 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ); AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ);
AllFieldsSearch.and("isDefault", AllFieldsSearch.entity().isDefaultNic(), Op.EQ); AllFieldsSearch.and("isDefault", AllFieldsSearch.entity().isDefaultNic(), Op.EQ);
AllFieldsSearch.and("broadcastUri", AllFieldsSearch.entity().getBroadcastUri(), Op.EQ); AllFieldsSearch.and("broadcastUri", AllFieldsSearch.entity().getBroadcastUri(), Op.EQ);
AllFieldsSearch.and("secondaryip", AllFieldsSearch.entity().getSecondaryIp(), Op.EQ);
AllFieldsSearch.and("nicid", AllFieldsSearch.entity().getId(), Op.EQ);
AllFieldsSearch.done(); AllFieldsSearch.done();
IpSearch = createSearchBuilder(String.class); IpSearch = createSearchBuilder(String.class);
IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address()); IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address());
IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ); IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ);
@ -202,4 +204,12 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
sc.setParameters("address", ip4Address); sc.setParameters("address", ip4Address);
return findOneBy(sc); return findOneBy(sc);
} }
@Override
public List<NicVO> listByVmIdAndNicId(Long vmId, Long nicId) {
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
sc.setParameters("instance", vmId);
sc.setParameters("nicid", nicId);
return listBy(sc);
}
} }

View File

@ -0,0 +1,53 @@
// 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;
public interface NicSecondaryIpDao extends GenericDao<NicSecondaryIpVO, Long> {
List<NicSecondaryIpVO> listByVmId(long instanceId);
List<String> listSecondaryIpAddressInNetwork(long networkConfigId);
List<NicSecondaryIpVO> listByNetworkId(long networkId);
NicSecondaryIpVO findByInstanceIdAndNetworkId(long networkId, long instanceId);
// void removeNicsForInstance(long instanceId);
// void removeSecondaryIpForNic(long nicId);
NicSecondaryIpVO findByIp4AddressAndNetworkId(String ip4Address, long networkId);
/**
* @param networkId
* @param instanceId
* @return
*/
List<NicSecondaryIpVO> getSecondaryIpAddressesForVm(long vmId);
List<NicSecondaryIpVO> listByNicId(long nicId);
List<NicSecondaryIpVO> listByNicIdAndVmid(long nicId, long vmId);
NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId);
NicSecondaryIpVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId,
Long vmId, String vmIp);
List<String> getSecondaryIpAddressesForNic(long nicId);
}

View File

@ -0,0 +1,138 @@
// 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.ArrayList;
import java.util.List;
import javax.ejb.Local;
import org.springframework.stereotype.Component;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
@Component
@Local(value=NicSecondaryIpDao.class)
public class NicSecondaryIpDaoImpl extends GenericDaoBase<NicSecondaryIpVO, Long> implements NicSecondaryIpDao {
private final SearchBuilder<NicSecondaryIpVO> AllFieldsSearch;
private final GenericSearchBuilder<NicSecondaryIpVO, String> IpSearch;
protected NicSecondaryIpDaoImpl() {
super();
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("instanceId", AllFieldsSearch.entity().getVmId(), Op.EQ);
AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ);
AllFieldsSearch.and("nicId", AllFieldsSearch.entity().getNicId(), Op.EQ);
AllFieldsSearch.done();
IpSearch = createSearchBuilder(String.class);
IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address());
IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ);
IpSearch.and("address", IpSearch.entity().getIp4Address(), Op.NNULL);
IpSearch.done();
}
@Override
public List<NicSecondaryIpVO> listByVmId(long instanceId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", instanceId);
return listBy(sc);
}
@Override
public List<NicSecondaryIpVO> listByNicId(long nicId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("nicId", nicId);
return listBy(sc);
}
@Override
public List<String> listSecondaryIpAddressInNetwork(long networkId) {
SearchCriteria<String> sc = IpSearch.create();
sc.setParameters("network", networkId);
return customSearch(sc, null);
}
@Override
public List<NicSecondaryIpVO> listByNetworkId(long networkId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
return listBy(sc);
}
@Override
public List<NicSecondaryIpVO> listByNicIdAndVmid(long nicId, long vmId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("nicId", nicId);
sc.setParameters("instanceId", vmId);
return listBy(sc);
}
@Override
public List<NicSecondaryIpVO> getSecondaryIpAddressesForVm(long vmId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", vmId);
return listBy(sc);
}
@Override
public List<String> getSecondaryIpAddressesForNic(long nicId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("nicId", nicId);
List<NicSecondaryIpVO> results = search(sc, null);
List<String> ips = new ArrayList<String>(results.size());
for (NicSecondaryIpVO result : results) {
ips.add(result.getIp4Address());
}
return ips;
}
@Override
public NicSecondaryIpVO findByInstanceIdAndNetworkId(long networkId, long instanceId) {
// TODO Auto-generated method stub
return null;
}
@Override
public NicSecondaryIpVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) {
// TODO Auto-generated method stub
return null;
}
@Override
public NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("address", ip4Address);
sc.setParameters("nicId", nicId);
return findOneBy(sc);
}
@Override
public NicSecondaryIpVO findByIp4AddressAndNetworkIdAndInstanceId(
long networkId, Long vmId, String vmIp) {
SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
sc.setParameters("instanceId", vmId);
sc.setParameters("address", vmIp);
return findOneBy(sc);
}
}

View File

@ -0,0 +1,160 @@
// 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.Date;
import java.util.UUID;
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 com.cloud.utils.db.GenericDao;
import com.cloud.vm.NicSecondaryIp;
@Entity
@Table(name = "nic_secondary_ips")
public class NicSecondaryIpVO implements NicSecondaryIp {
public NicSecondaryIpVO(Long nicId, String ipaddr, Long vmId,
Long accountId, Long domainId, Long networkId) {
this.nicId = nicId;
this.vmId = vmId;
this.ip4Address = ipaddr;
this.accountId = accountId;
this.domainId = domainId;
this.networkId = networkId;
}
protected NicSecondaryIpVO() {
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
long id;
@Column(name = "nicId")
long nicId;
@Column(name="domain_id", updatable=false)
long domainId;
@Column(name="account_id", updatable=false)
private Long accountId;
@Column(name = "ip4_address")
String ip4Address;
@Column(name = "ip6_address")
String ip6Address;
@Column(name = "network_id")
long networkId;
@Column(name = GenericDao.CREATED_COLUMN)
Date created;
@Column(name = "uuid")
String uuid = UUID.randomUUID().toString();
@Column(name = "vmId")
Long vmId;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getNicId() {
return nicId;
}
public void setNicId(long nicId) {
this.nicId = nicId;
}
public long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getIp4Address() {
return ip4Address;
}
public void setIp4Address(String ip4Address) {
this.ip4Address = ip4Address;
}
public String getIp6Address() {
return ip6Address;
}
public void setIp6Address(String ip6Address) {
this.ip6Address = ip6Address;
}
public long getNetworkId() {
return networkId;
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public long getVmId() {
return vmId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter;
import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.Vlan.VlanType;
@ -64,6 +65,7 @@ import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -824,4 +826,49 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
} }
@Override
public boolean isSecondaryIpSetForNic(long nicId) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean releaseSecondaryIpFromNic(long ipAddressId) {
// TODO Auto-generated method stub
return false;
}
@Override
public String allocateSecondaryGuestIP(Account account, long zoneId,
Long nicId, Long networkId, String ipaddress) {
// TODO Auto-generated method stub
return null;
}
@Override
public String allocateGuestIP(Account ipOwner, boolean isSystem,
long zoneId, Long networkId, String requestedIp)
throws InsufficientAddressCapacityException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeVmSecondaryIps(long vmId) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<? extends Nic> listVmNics(Long vmId, Long nicId) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<? extends Nic> listNics(ListNicsCmd listNicsCmd) {
// TODO Auto-generated method stub
return null;
}
} }

View File

@ -39,6 +39,7 @@ import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager; import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.net.Ip;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@Local(value = {RulesManager.class, RulesService.class}) @Local(value = {RulesManager.class, RulesService.class})
@ -53,14 +54,6 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R
return null; return null;
} }
@Override
public PortForwardingRule createPortForwardingRule(PortForwardingRule rule,
Long vmId, boolean openFirewall)
throws NetworkRuleConflictException {
// TODO Auto-generated method stub
return null;
}
@Override @Override
public boolean revokePortForwardingRule(long ruleId, boolean apply) { public boolean revokePortForwardingRule(long ruleId, boolean apply) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@ -83,7 +76,7 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R
@Override @Override
public boolean enableStaticNat(long ipAddressId, long vmId, long networkId, public boolean enableStaticNat(long ipAddressId, long vmId, long networkId,
boolean isSystemVm) throws NetworkRuleConflictException, boolean isSystemVm, String ipAddr) throws NetworkRuleConflictException,
ResourceUnavailableException { ResourceUnavailableException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
@ -310,4 +303,12 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R
return "MockRulesManagerImpl"; return "MockRulesManagerImpl";
} }
@Override
public PortForwardingRule createPortForwardingRule(PortForwardingRule rule,
Long vmId, Ip vmIp, boolean openFirewall)
throws NetworkRuleConflictException {
// TODO Auto-generated method stub
return null;
}
} }

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementors
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -80,6 +81,7 @@ import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -1317,4 +1319,75 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
} }
@Override
public boolean isSecondaryIpSetForNic(long nicId) {
// TODO Auto-generated method stub
return false;
}
@Override
public String allocateSecondaryGuestIP(Account account, long zoneId,
Long nicId, Long networkId, String ipaddress) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean releaseSecondaryIpFromNic(long ipAddressId) {
// TODO Auto-generated method stub
return false;
}
@Override
public String allocateGuestIP(Account ipOwner, boolean isSystem,
long zoneId, Long networkId, String requestedIp)
throws InsufficientAddressCapacityException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeVmSecondaryIps(long vmId) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<? extends Nic> listVmNics(Long vmId, Long nicId) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<? extends Nic> listNics(ListNicsCmd listNicsCmd) {
// TODO Auto-generated method stub
return null;
}
} }

View File

@ -112,3 +112,24 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'UserV
-- Re-enable foreign key checking, at the end of the upgrade path -- Re-enable foreign key checking, at the end of the upgrade path
SET foreign_key_checks = 1; SET foreign_key_checks = 1;
CREATE TABLE nic_secondary_ips (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`uuid` varchar(40),
`vmId` bigint unsigned COMMENT 'vm instance id',
`nicId` bigint unsigned NOT NULL,
`ip4_address` char(40) COMMENT 'ip4 address',
`ip6_address` char(40) COMMENT 'ip6 address',
`network_id` bigint unsigned NOT NULL COMMENT 'network configuration id',
`created` datetime NOT NULL COMMENT 'date created',
`account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table',
`domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to',
PRIMARY KEY (`id`),
CONSTRAINT `fk_nic_secondary_ip__vmId` FOREIGN KEY `fk_nic_secondary_ip__vmId`(`vmId`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_nic_secondary_ip__networks_id` FOREIGN KEY `fk_nic_secondary_ip__networks_id`(`network_id`) REFERENCES `networks`(`id`),
CONSTRAINT `uc_nic_secondary_ip__uuid` UNIQUE (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic';
ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40);