diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index 74cfd1c21d6..f7eac674712 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -79,4 +79,4 @@ domr.scripts.dir=scripts/network/domr/kvm # be overridden here. # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver # openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver -#libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver \ No newline at end of file +#libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index 47df4d6523b..fce8f38c2f2 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -87,4 +87,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity * @param vpcId */ void setVpcId(Long vpcId); + String getVmIp(); + void setVmIp(String vmIp); + } diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 95bcc42b17a..ab6d7bfd882 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -19,9 +19,10 @@ package com.cloud.network; import java.util.List; 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.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.InsufficientAddressCapacityException; @@ -33,6 +34,8 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.user.Account; import com.cloud.user.User; 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 @@ -153,5 +156,13 @@ public interface NetworkService { Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) 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 listNics(ListNicsCmd listNicsCmd); } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index 921a86e865f..d47b38f9d43 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -25,6 +25,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; public interface RulesService { Pair, 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 * 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 @@ -66,7 +67,7 @@ public interface RulesService { 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); diff --git a/api/src/com/cloud/vm/Nic.java b/api/src/com/cloud/vm/Nic.java index 9d21130327a..b2f6976240c 100644 --- a/api/src/com/cloud/vm/Nic.java +++ b/api/src/com/cloud/vm/Nic.java @@ -151,4 +151,5 @@ public interface Nic extends Identity, InternalIdentity { String getIp6Cidr(); String getIp6Address(); + boolean getSecondaryIp(); } diff --git a/api/src/com/cloud/vm/NicSecondaryIp.java b/api/src/com/cloud/vm/NicSecondaryIp.java new file mode 100644 index 00000000000..655d172b33f --- /dev/null +++ b/api/src/com/cloud/vm/NicSecondaryIp.java @@ -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(); +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 4fdc91edef2..1b544fd1641 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -458,6 +458,7 @@ public class ApiConstants { public static final String UCS_PROFILE_DN = "profiledn"; public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_ID = "bladeid"; + public static final String VM_GUEST_IP = "vmguestip"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 267238af37b..a6025149846 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -53,6 +53,8 @@ import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.cloudstack.api.response.NetworkACLResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse; 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.PodResponse; import org.apache.cloudstack.api.response.PrivateGatewayResponse; @@ -163,6 +165,8 @@ import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; import com.cloud.vm.InstanceGroup; +import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; import com.cloud.vm.snapshot.VMSnapshot; @@ -385,4 +389,7 @@ public interface ResponseGenerator { TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); + NicSecondaryIpResponse createSecondaryIPToNicResponse(String ip, + Long nicId, Long networkId); + public NicResponse createNicResponse(Nic result); } diff --git a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java index 39ab812909d..40128526ce0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java @@ -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. " + "Required when public Ip address is not associated with any Guest network yet (VPC case)") 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 /////////////////////// @@ -104,6 +107,13 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P return ipAddressId; } + public Ip getVmSecondaryIp() { + if (vmSecondaryIp == null) { + return null; + } + return new Ip(vmSecondaryIp); + } + @Override public String getProtocol() { 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"); } + Ip privateIp = getVmSecondaryIp(); + if (privateIp != null) { + if ( !privateIp.isIp4()) { + throw new InvalidParameterValueException("Invalid vm ip address"); + } + } + try { - PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, getOpenFirewall()); + PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, privateIp, getOpenFirewall()); setEntityId(result.getId()); setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException ex) { diff --git a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java index ce6ea1663b9..a0ec68ef5dd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java @@ -59,6 +59,9 @@ public class EnableStaticNatCmd extends BaseCmd{ 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)") 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 /////////////////////// @@ -72,6 +75,13 @@ public class EnableStaticNatCmd extends BaseCmd{ return virtualMachineId; } + public String getVmSecondaryIp() { + if (vmSecondaryIp == null) { + return null; + } + return vmSecondaryIp; + } + public long getNetworkId() { IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); Long ntwkId = null; @@ -110,7 +120,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute() throws ResourceUnavailableException{ try { - boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false, getVmSecondaryIp()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java new file mode 100644 index 00000000000..0f992743f6d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java @@ -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; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java new file mode 100644 index 00000000000..9af044ebb70 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java @@ -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 results = _networkService.listNics(this); + ListResponse response = new ListResponse(); + List resList = new ArrayList(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; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java new file mode 100644 index 00000000000..cb5e0855f64 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java @@ -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; + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java new file mode 100644 index 00000000000..9af20b23871 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java @@ -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; + } + + +} diff --git a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java index 251b2dd09e8..cede84f931e 100644 --- a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java +++ b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java @@ -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)") 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)") private String virtualMachineName; @@ -185,6 +189,10 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR this.virtualMachineId = virtualMachineId; } + public void setVirtualMachineIp(String virtualMachineIp) { + this.virtualMachineIp = virtualMachineIp; + } + public void setVirtualMachineName(String virtualMachineName) { this.virtualMachineName = virtualMachineName; } diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java index a7d1a0d068e..a1ceaf63798 100644 --- a/api/src/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.List; + import org.apache.cloudstack.api.ApiConstants; 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") private String ip6Address; - + + @SerializedName("secondaryip") @Param(description="the Secondary ipv4 addr of nic") + private List secondaryIps; + public String getId() { return id; } @@ -167,4 +172,9 @@ public class NicResponse extends BaseResponse { return false; return true; } + + public void setSecondaryIps(List ipList) { + this.secondaryIps = ipList; + } + } diff --git a/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java b/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java new file mode 100644 index 00000000000..3464a63540e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/NicSecondaryIpResponse.java @@ -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; + } + + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java new file mode 100644 index 00000000000..106589d10cc --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java @@ -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()); + } + } +} diff --git a/client/pom.xml b/client/pom.xml index e82660b8704..cda6ab8b4e7 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -271,6 +271,10 @@ + + + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index f03e8d50adb..dd0c3f894fd 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -326,6 +326,11 @@ addNicToVirtualMachine=15 removeNicFromVirtualMachine=15 updateDefaultNicForVirtualMachine=15 +#### +addIpToNic=15 +removeIpFromNic=15 +listNics=15 + #### SSH key pair commands registerSSHKeyPair=15 createSSHKeyPair=15 diff --git a/docs/en-US/accessing-vms.xml b/docs/en-US/accessing-vms.xml index ce780cff080..67d9d774172 100644 --- a/docs/en-US/accessing-vms.xml +++ b/docs/en-US/accessing-vms.xml @@ -32,9 +32,9 @@ To access a VM directly over the network: - The VM must have some port open to incoming traffic. For example, in a basic zone, a new VM might be assigned to a security group which allows incoming traffic. This depends on what security group you picked when creating the VM. In other cases, you can open a port by setting up a port forwarding policy. See IP Forwarding and Firewalling. + The VM must have some port open to incoming traffic. For example, in a basic zone, a new VM might be assigned to a security group which allows incoming traffic. This depends on what security group you picked when creating the VM. In other cases, you can open a port by setting up a port forwarding policy. See . If a port is open but you can not access the VM using ssh, it’s possible that ssh is not already enabled on the VM. This will depend on whether ssh is enabled in the template you picked when creating the VM. Access the VM through the &PRODUCT; UI and enable ssh on the machine using the commands for the VM’s operating system. - If the network has an external firewall device, you will need to create a firewall rule to allow access. See IP Forwarding and Firewalling. + If the network has an external firewall device, you will need to create a firewall rule to allow access. See . diff --git a/docs/en-US/deployment-architecture-overview.xml b/docs/en-US/deployment-architecture-overview.xml index fba36eb85a3..e3103c52c1c 100644 --- a/docs/en-US/deployment-architecture-overview.xml +++ b/docs/en-US/deployment-architecture-overview.xml @@ -48,7 +48,8 @@ A more full-featured installation consists of a highly-available multi-node Management Server installation and up to tens of thousands of hosts using any of several advanced networking setups. For - information about deployment options, see Choosing a Deployment Architecture. + information about deployment options, see the "Choosing a Deployment Architecture" + section of the $PRODUCT; Installation Guide. diff --git a/docs/en-US/zone-add.xml b/docs/en-US/zone-add.xml index 2a85bb0b432..4f6606fce03 100644 --- a/docs/en-US/zone-add.xml +++ b/docs/en-US/zone-add.xml @@ -63,7 +63,7 @@ Basic. For AWS-style networking. Provides a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering). Advanced. For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support. - For more information about the network types, see Network Setup. + For more information about the network types, see . The rest of the steps differ depending on whether you chose Basic or Advanced. Continue with the steps that apply to you: diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 24ec2455c3f..74055ac496e 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -318,6 +318,10 @@ if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/ fi +# change cloud user's home to 4.1+ version if needed. Would do this via 'usermod', but it +# requires that cloud user not be in use, so RPM could not be installed while management is running +getent passwd cloud | grep -q /var/lib/cloud && sed -i 's/\/var\/lib\/cloud\/management/\/var\/cloudstack\/management/g' /etc/passwd + %post awsapi if [ -d "%{_datadir}/%{name}-management" ] ; then ln -s %{_datadir}/%{name}-bridge/webapps %{_datadir}/%{name}-management/webapps7080 diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java index 2b9b140607b..58c6e862d9f 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java @@ -175,7 +175,7 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { } String copyTo = String.format("%s/%s", _tftpDir, cmd.getTemplateUuid()); - String script = String.format("python /usr/bin/prepare_kickstart_kernel_initrd.py %s %s", cmd.getRepo(), copyTo); + String script = String.format("python /usr/bin/prepare_kickstart_kernel_initrd.py %s %s %s", cmd.getKernel(), cmd.getInitrd(), copyTo); if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) { return new Answer(cmd, false, "prepare kickstart at pxe server " + _ip + " failed, command:" + script); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java index ba5fb0d0b6c..8a5ac78729e 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java @@ -95,11 +95,36 @@ public class BaremetalKickStartServiceImpl extends BareMetalPxeServiceBase imple try { String tpl = profile.getTemplate().getUrl(); assert tpl != null : "How can a null template get here!!!"; - String[] tpls = tpl.split(";"); - assert tpls.length == 2 : "Template is not correctly encoded. " + tpl; + String[] tpls = tpl.split(";"); + CloudRuntimeException err = new CloudRuntimeException(String.format("template url[%s] is not correctly encoded. it must be in format of ks=http_link_to_kickstartfile;kernel=nfs_path_to_pxe_kernel;initrd=nfs_path_to_pxe_initrd", tpl)); + if (tpls.length != 3) { + throw err; + } + + String ks = null; + String kernel = null; + String initrd = null; + + for (String t : tpls) { + String[] kv = t.split("="); + if (kv.length != 2) { + throw err; + } + if (kv[0].equals("ks")) { + ks = kv[1]; + } else if (kv[0].equals("kernel")) { + kernel = kv[1]; + } else if (kv[0].equals("initrd")) { + initrd = kv[1]; + } else { + throw err; + } + } + PrepareKickstartPxeServerCommand cmd = new PrepareKickstartPxeServerCommand(); - cmd.setKsFile(tpls[0]); - cmd.setRepo(tpls[1]); + cmd.setKsFile(ks); + cmd.setInitrd(initrd); + cmd.setKernel(kernel); cmd.setMac(nic.getMacAddress()); cmd.setTemplateUuid(template.getUuid()); Answer aws = _agentMgr.send(pxeVo.getHostId(), cmd); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java index 89515475062..25dfeb70d30 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java @@ -22,10 +22,11 @@ import com.cloud.agent.api.Command; public class PrepareKickstartPxeServerCommand extends Command { private String ksFile; - private String repo; private String templateUuid; private String mac; - private String ksDevice; + private String ksDevice; + private String kernel; + private String initrd; @Override public boolean executeInSequence() { @@ -39,15 +40,23 @@ public class PrepareKickstartPxeServerCommand extends Command { public void setKsFile(String ksFile) { this.ksFile = ksFile; } - - public String getRepo() { - return repo; - } - - public void setRepo(String repo) { - this.repo = repo; - } - + + public String getKernel() { + return kernel; + } + + public void setKernel(String kernel) { + this.kernel = kernel; + } + + public String getInitrd() { + return initrd; + } + + public void setInitrd(String initrd) { + this.initrd = initrd; + } + public String getTemplateUuid() { return templateUuid; } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 805de408996..5a96c360616 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -41,6 +41,8 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; import java.util.Properties; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -276,7 +278,11 @@ ServerResource { private String _mountPoint = "/mnt"; StorageLayer _storage; private KVMStoragePoolManager _storagePoolMgr; - private VifDriver _vifDriver; + + private VifDriver _defaultVifDriver; + private Map _trafficTypeVifDrivers; + protected static final String DEFAULT_OVS_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.OvsVifDriver"; + protected static final String DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver"; private static final class KeyValueInterpreter extends OutputInterpreter { private final Map map = new HashMap(); @@ -775,24 +781,66 @@ ServerResource { params.put("libvirt.host.bridges", bridges); params.put("libvirt.host.pifs", _pifs); - // Load the vif driver - String vifDriverName = (String) params.get("libvirt.vif.driver"); - if (vifDriverName == null) { - if (_bridgeType == BridgeType.OPENVSWITCH) { - s_logger.info("No libvirt.vif.driver specififed. Defaults to OvsVifDriver."); - vifDriverName = "com.cloud.hypervisor.kvm.resource.OvsVifDriver"; - } else { - s_logger.info("No libvirt.vif.driver specififed. Defaults to BridgeVifDriver."); - vifDriverName = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver"; - } - } - params.put("libvirt.computing.resource", this); + configureVifDrivers(params); + + return true; + } + + protected void configureVifDrivers(Map params) + throws ConfigurationException { + final String LIBVIRT_VIF_DRIVER = "libvirt.vif.driver"; + + _trafficTypeVifDrivers = new HashMap(); + + // Load the default vif driver + String defaultVifDriverName = (String) params.get(LIBVIRT_VIF_DRIVER); + if (defaultVifDriverName == null) { + if (_bridgeType == BridgeType.OPENVSWITCH) { + s_logger.info("No libvirt.vif.driver specified. Defaults to OvsVifDriver."); + defaultVifDriverName = DEFAULT_OVS_VIF_DRIVER_CLASS_NAME; + } else { + s_logger.info("No libvirt.vif.driver specified. Defaults to BridgeVifDriver."); + defaultVifDriverName = DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME; + } + } + _defaultVifDriver = getVifDriverClass(defaultVifDriverName, params); + + // Load any per-traffic-type vif drivers + for (Map.Entry entry : params.entrySet()) + { + String k = entry.getKey(); + String vifDriverPrefix = LIBVIRT_VIF_DRIVER + "."; + + if(k.startsWith(vifDriverPrefix)){ + // Get trafficType + String trafficTypeSuffix = k.substring(vifDriverPrefix.length()); + + // Does this suffix match a real traffic type? + TrafficType trafficType = TrafficType.getTrafficType(trafficTypeSuffix); + if(!trafficType.equals(TrafficType.None)){ + // Get vif driver class name + String vifDriverClassName = (String) entry.getValue(); + // if value is null, ignore + if(vifDriverClassName != null){ + // add traffic type to vif driver mapping to Map + _trafficTypeVifDrivers.put(trafficType, + getVifDriverClass(vifDriverClassName, params)); + } + } + } + } + } + + protected VifDriver getVifDriverClass(String vifDriverClassName, Map params) + throws ConfigurationException { + VifDriver vifDriver; + try { - Class clazz = Class.forName(vifDriverName); - _vifDriver = (VifDriver) clazz.newInstance(); - _vifDriver.configure(params); + Class clazz = Class.forName(vifDriverClassName); + vifDriver = (VifDriver) clazz.newInstance(); + vifDriver.configure(params); } catch (ClassNotFoundException e) { throw new ConfigurationException("Unable to find class for libvirt.vif.driver " + e); } catch (InstantiationException e) { @@ -800,8 +848,28 @@ ServerResource { } catch (Exception e) { throw new ConfigurationException("Failed to initialize libvirt.vif.driver " + e); } + return vifDriver; + } - return true; + protected VifDriver getVifDriver(TrafficType trafficType){ + VifDriver vifDriver = _trafficTypeVifDrivers.get(trafficType); + + if(vifDriver == null){ + vifDriver = _defaultVifDriver; + } + + return vifDriver; + } + + protected List getAllVifDrivers(){ + Set vifDrivers = new HashSet(); + + vifDrivers.add(_defaultVifDriver); + vifDrivers.addAll(_trafficTypeVifDrivers.values()); + + ArrayList vifDriverList = new ArrayList(vifDrivers); + + return vifDriverList; } private void getPifs() { @@ -1443,7 +1511,7 @@ ServerResource { } Domain vm = getDomain(conn, vmName); - vm.attachDevice(_vifDriver.plug(nicTO, "Other PV (32-bit)").toString()); + vm.attachDevice(getVifDriver(nicTO.getType()).plug(nicTO, "Other PV (32-bit)").toString()); } private PlugNicAnswer execute(PlugNicCommand cmd) { @@ -1462,7 +1530,7 @@ ServerResource { } nicnum++; } - vm.attachDevice(_vifDriver.plug(nic, "Other PV (32-bit)").toString()); + vm.attachDevice(getVifDriver(nic.getType()).plug(nic, "Other PV (32-bit)").toString()); return new PlugNicAnswer(cmd, true, "success"); } catch (Exception e) { String msg = " Plug Nic failed due to " + e.toString(); @@ -2560,7 +2628,11 @@ ServerResource { } else { destroy_network_rules_for_vm(conn, vmName); for (InterfaceDef iface : ifaces) { - _vifDriver.unplug(iface); + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for(VifDriver vifDriver : getAllVifDrivers()){ + vifDriver.unplug(iface); + } } cleanupVM(conn, vmName, getVnetId(VirtualMachineName.getVnet(vmName))); @@ -2580,7 +2652,7 @@ ServerResource { try { Connect conn = LibvirtConnection.getConnection(); for (NicTO nic : nics) { - _vifDriver.plug(nic, null); + getVifDriver(nic.getType()).plug(nic, null); } /* setup disks, e.g for iso */ @@ -2794,7 +2866,11 @@ ServerResource { } } for (InterfaceDef iface: ifaces) { - _vifDriver.unplug(iface); + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for(VifDriver vifDriver : getAllVifDrivers()){ + vifDriver.unplug(iface); + } } } @@ -3231,7 +3307,7 @@ ServerResource { private void createVif(LibvirtVMDef vm, NicTO nic) throws InternalErrorException, LibvirtException { vm.getDevices().addDevice( - _vifDriver.plug(nic, vm.getGuestOSType()).toString()); + getVifDriver(nic.getType()).plug(nic, vm.getGuestOSType()).toString()); } protected CheckSshAnswer execute(CheckSshCommand cmd) { diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java new file mode 100644 index 00000000000..7d47e6e81de --- /dev/null +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.cloud.hypervisor.kvm.resource; + +import com.cloud.network.Networks.TrafficType; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource.BridgeType; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.HashMap; +import java.util.Map; +import javax.naming.ConfigurationException; + + +import static org.mockito.Mockito.*; + +public class LibvirtVifDriverTest { + private LibvirtComputingResource res; + + private Map assertions; + + final String LIBVIRT_VIF_DRIVER = "libvirt.vif.driver"; + final String FAKE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.FakeVifDriver"; + final String NONEXISTENT_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.NonExistentVifDriver"; + + private VifDriver fakeVifDriver, bridgeVifDriver, ovsVifDriver; + + @Before + public void setUp() { + // Use a spy because we only want to override getVifDriverClass + LibvirtComputingResource resReal = new LibvirtComputingResource(); + res = spy(resReal); + + try{ + bridgeVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME).newInstance(); + ovsVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME).newInstance(); + + // Instantiating bridge vif driver again as the fake vif driver + // is good enough, as this is a separate instance + fakeVifDriver = + (VifDriver) Class.forName(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME).newInstance(); + + doReturn(bridgeVifDriver).when(res) + .getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME), anyMap()); + doReturn(ovsVifDriver).when(res) + .getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME), anyMap()); + doReturn(fakeVifDriver).when(res) + .getVifDriverClass(eq(FAKE_VIF_DRIVER_CLASS_NAME), anyMap()); + + } catch (final ConfigurationException ex){ + fail("Unexpected ConfigurationException while configuring VIF drivers: " + ex.getMessage()); + } catch (final Exception ex){ + fail("Unexpected Exception while configuring VIF drivers"); + } + + assertions = new HashMap(); + } + + + // Helper function + // Configure LibvirtComputingResource using params + private void configure (Map params) + throws ConfigurationException{ + res.configureVifDrivers(params); + } + + // Helper function + private void checkAssertions(){ + // Check the defined assertions + for (Map.Entry assertion : assertions.entrySet()){ + assertEquals(res.getVifDriver(assertion.getKey()), + assertion.getValue()); + } + } + + // Helper when all answers should be the same + private void checkAllSame(VifDriver vifDriver) + throws ConfigurationException { + + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, vifDriver); + } + + checkAssertions(); + } + + @Test + public void testDefaults() + throws ConfigurationException { + // If no special vif driver settings, all traffic types should + // map to the default vif driver for the bridge type + Map params = new HashMap(); + + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(bridgeVifDriver); + + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(ovsVifDriver); + } + + @Test + public void testDefaultsWhenExplicitlySet() + throws ConfigurationException { + + Map params = new HashMap(); + + // Switch res' bridge type for test purposes + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(bridgeVifDriver); + + params.clear(); + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(ovsVifDriver); + } + + @Test + public void testWhenExplicitlySetDifferentDefault() + throws ConfigurationException { + + // Tests when explicitly set vif driver to OVS when using regular bridges and vice versa + Map params = new HashMap(); + + // Switch res' bridge type for test purposes + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + checkAllSame(ovsVifDriver); + + params.clear(); + params.put(LIBVIRT_VIF_DRIVER, LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.OPENVSWITCH; + configure(params); + checkAllSame(bridgeVifDriver); + } + + @Test + public void testOverrideSomeTrafficTypes() + throws ConfigurationException { + + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "Public", FAKE_VIF_DRIVER_CLASS_NAME); + params.put(LIBVIRT_VIF_DRIVER + "." + "Guest", + LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Initially, set all traffic types to use default + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + assertions.put(TrafficType.Public, fakeVifDriver); + assertions.put(TrafficType.Guest, ovsVifDriver); + + checkAssertions(); + } + + @Test + public void testBadTrafficType() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "NonExistentTrafficType", FAKE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Set all traffic types to use default, because bad traffic type should be ignored + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + checkAssertions(); + } + + @Test + public void testEmptyTrafficType() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + ".", FAKE_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + + // Set all traffic types to use default, because bad traffic type should be ignored + for(TrafficType trafficType : TrafficType.values()){ + assertions.put(trafficType, bridgeVifDriver); + } + + checkAssertions(); + } + + @Test(expected=ConfigurationException.class) + public void testBadVifDriverClassName() + throws ConfigurationException { + Map params = new HashMap(); + params.put(LIBVIRT_VIF_DRIVER + "." + "Public", NONEXISTENT_VIF_DRIVER_CLASS_NAME); + res._bridgeType = BridgeType.NATIVE; + configure(params); + } +} diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index e2de43b1852..94ba97d96a1 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -160,10 +160,12 @@ public class VmwareServerDiscoverer extends DiscovererBase implements VmwareTrafficLabel guestTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Guest); VmwareTrafficLabel publicTrafficLabelObj = new VmwareTrafficLabel(TrafficType.Public); Map clusterDetails = _clusterDetailsDao.findDetails(clusterId); + DataCenterVO zone = _dcDao.findById(dcId); + NetworkType zoneType = zone.getNetworkType(); _readGlobalConfigParameters(); // Set default physical network end points for public and guest traffic - // Private traffic will be only on standard vSwitch for now. See below TODO. + // Private traffic will be only on standard vSwitch for now. if (useDVS) { // Parse url parameters for type of vswitch and name of vswitch specified at cluster level paramGuestVswitchType = _urlParams.get(ApiConstants.VSWITCH_TYPE_GUEST_TRAFFIC); @@ -172,13 +174,6 @@ public class VmwareServerDiscoverer extends DiscovererBase implements paramPublicVswitchName = _urlParams.get(ApiConstants.VSWITCH_NAME_PUBLIC_TRAFFIC); defaultVirtualSwitchType = getDefaultVirtualSwitchType(); } - // Get zone wide traffic labels for Guest traffic and Public traffic - guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); - publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); - - // Process traffic label information provided at zone level and cluster level - guestTrafficLabelObj = getTrafficInfo(TrafficType.Guest, guestTrafficLabel, defaultVirtualSwitchType, paramGuestVswitchType, paramGuestVswitchName, clusterId); - publicTrafficLabelObj = getTrafficInfo(TrafficType.Public, publicTrafficLabel, defaultVirtualSwitchType, paramPublicVswitchType, paramPublicVswitchName, clusterId); // Zone level vSwitch Type depends on zone level traffic labels // @@ -197,6 +192,18 @@ public class VmwareServerDiscoverer extends DiscovererBase implements // 'vmwaresvs' is for vmware standard vswitch // 'vmwaredvs' is for vmware distributed virtual switch // 'nexusdvs' is for cisco nexus distributed virtual switch + // Get zone wide traffic labels for Guest traffic and Public traffic + guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); + + // Process traffic label information provided at zone level and cluster level + guestTrafficLabelObj = getTrafficInfo(TrafficType.Guest, guestTrafficLabel, defaultVirtualSwitchType, paramGuestVswitchType, paramGuestVswitchName, clusterId); + + if (zoneType == NetworkType.Advanced) { + // Get zone wide traffic label for Public traffic + publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); + + // Process traffic label information provided at zone level and cluster level + publicTrafficLabelObj = getTrafficInfo(TrafficType.Public, publicTrafficLabel, defaultVirtualSwitchType, paramPublicVswitchType, paramPublicVswitchName, clusterId); // Configuration Check: A physical network cannot be shared by different types of virtual switches. // @@ -208,6 +215,7 @@ public class VmwareServerDiscoverer extends DiscovererBase implements // if yes - compare publicTrafficLabelObj.getVirtualSwitchType() == guestTrafficLabelObj.getVirtualSwitchType() // true - pass // false - throw exception - fail cluster add operation + List pNetworkListGuestTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Guest); List pNetworkListPublicTraffic = _netmgr.getPhysicalNtwksSupportingTrafficType(dcId, TrafficType.Public); // Public network would be on single physical network hence getting first object of the list would suffice. @@ -221,6 +229,15 @@ public class VmwareServerDiscoverer extends DiscovererBase implements throw new InvalidParameterValueException(msg); } } + } else { + // Distributed virtual switch is not supported in Basic zone for now. + // Private / Management network traffic is not yet supported over distributed virtual switch. + if (guestTrafficLabelObj.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { + String msg = "Detected that Guest traffic is over Distributed virtual switch in Basic zone. Only Standard vSwitch is supported in Basic zone."; + s_logger.error(msg); + throw new DiscoveredWithErrorException(msg); + } + } privateTrafficLabel = _netmgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.VMware); if (privateTrafficLabel != null) { @@ -228,8 +245,6 @@ public class VmwareServerDiscoverer extends DiscovererBase implements } if (nexusDVS) { - DataCenterVO zone = _dcDao.findById(dcId); - NetworkType zoneType = zone.getNetworkType(); if (zoneType != NetworkType.Basic) { publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); if (publicTrafficLabel != null) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index e44054ee1d5..9d29abf8d35 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -532,37 +532,36 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private File getSystemVMPatchIsoFile() { // locate systemvm.iso - //URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation(); - //File file = new File(url.getFile()); - //File isoFile = new File(file.getParent() + "/vms/systemvm.iso"); URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso"); File isoFile = null; if (url != null) { isoFile = new File(url.getPath()); } - if (isoFile == null || !isoFile.exists()) { - isoFile = new File("/usr/lib64/cloud/common/" + "/vms/systemvm.iso"); - if (!isoFile.exists()) { - isoFile = new File("/usr/lib/cloud/common/" + "/vms/systemvm.iso"); - } + + if(isoFile == null || !isoFile.exists()) { + isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); + } + + assert(isoFile != null); + if(!isoFile.exists()) { + s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); } return isoFile; } @Override public File getSystemVMKeyFile() { - // URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation(); - // File file = new File(url.getFile()); URL url = this.getClass().getClassLoader().getResource("scripts/vm/systemvm/id_rsa.cloud"); File keyFile = null; if ( url != null ){ keyFile = new File(url.getPath()); } if (keyFile == null || !keyFile.exists()) { - keyFile = new File("/usr/lib64/cloud/common" + "/scripts/vm/systemvm/id_rsa.cloud"); - if (!keyFile.exists()) { - keyFile = new File("/usr/lib/cloud/common" + "/scripts/vm/systemvm/id_rsa.cloud"); - } + keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud"); + } + assert(keyFile != null); + if(!keyFile.exists()) { + s_logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile.toString()); } return keyFile; } diff --git a/pom.xml b/pom.xml index b547d935637..86cec1d8336 100644 --- a/pom.xml +++ b/pom.xml @@ -382,8 +382,10 @@ tools/appliance/definitions/systemvmtemplate/definition.rb tools/appliance/definitions/systemvmtemplate/preseed.cfg tools/appliance/definitions/systemvmtemplate/zerodisk.sh + tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg + tools/marvin/Marvin.egg-info/* ui/lib/flot/jquery.colorhelpers.js ui/lib/flot/jquery.flot.crosshair.js ui/lib/flot/jquery.flot.fillbetween.js diff --git a/scripts/network/ping/prepare_kickstart_kernel_initrd.py b/scripts/network/ping/prepare_kickstart_kernel_initrd.py index b234a62de70..ff618480e69 100755 --- a/scripts/network/ping/prepare_kickstart_kernel_initrd.py +++ b/scripts/network/ping/prepare_kickstart_kernel_initrd.py @@ -21,50 +21,55 @@ import tempfile import os.path import os -iso_folder = '' -copy_to = '' +kernel = None +initrd = None +copy_to = None def cmd(cmdstr, err=True): + print cmdstr if os.system(cmdstr) != 0 and err: raise Exception("Failed to run shell command: %s" % cmdstr) def prepare(): + global kernel, initrd, copy_to try: - kernel = os.path.join(copy_to, "vmlinuz") - initrd = os.path.join(copy_to, "initrd.img") - if os.path.exists(kernel) and os.path.exists(initrd): + k = os.path.join(copy_to, "vmlinuz") + i = os.path.join(copy_to, "initrd.img") + if os.path.exists(k) and os.path.exists(i): print "Having template(%s) prepared already, skip copying" % copy_to return 0 else: if not os.path.exists(copy_to): os.makedirs(copy_to) - mnt_path = tempfile.mkdtemp() - try: - mnt = "mount %s %s" % (iso_folder, mnt_path) - cmd(mnt) - - kernel = os.path.join(mnt_path, "vmlinuz") - initrd = os.path.join(mnt_path, "initrd.img") - cp = "cp -f %s %s/" % (kernel, copy_to) - cmd(cp) - cp = "cp -f %s %s/" % (initrd, copy_to) - cmd(cp) - finally: - umnt = "umount %s" % mnt_path - cmd(umnt, False) - rm = "rm -r %s" % mnt_path - cmd(rm, False) - return 0 + + def copy_from_nfs(src, dst): + mnt_path = tempfile.mkdtemp() + try: + nfs_path = os.path.dirname(src) + filename = os.path.basename(src) + t = os.path.join(mnt_path, filename) + mnt = "mount %s %s" % (nfs_path, mnt_path) + cmd(mnt) + cp = "cp -f %s %s" % (t, dst) + cmd(cp) + finally: + umnt = "umount %s" % mnt_path + cmd(umnt, False) + rm = "rm -r %s" % mnt_path + cmd(rm, False) + + copy_from_nfs(kernel, copy_to) + copy_from_nfs(initrd, copy_to) except Exception, e: print e return 1 if __name__ == "__main__": - if len(sys.argv) < 3: - print "Usage: prepare_kickstart_kerneal_initrd.py path_to_kernel_initrd_iso path_kernel_initrd_copy_to" + if len(sys.argv) < 4: + print "Usage: prepare_kickstart_kerneal_initrd.py path_to_kernel path_to_initrd path_kernel_initrd_copy_to" sys.exit(1) - (iso_folder, copy_to) = sys.argv[1:] + (kernel, initrd, copy_to) = sys.argv[1:] sys.exit(prepare()) diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index ffee22fa1ae..95879ee0238 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -201,6 +201,7 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; @@ -209,6 +210,8 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VmStats; import com.cloud.vm.dao.ConsoleProxyDao; 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.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; @@ -319,6 +322,7 @@ public class ApiDBUtils { static HostDetailsDao _hostDetailsDao; static VMSnapshotDao _vmSnapshotDao; static ClusterDetailsDao _clusterDetailsDao; + static NicSecondaryIpDao _nicSecondaryIpDao; @Inject private ManagementServer ms; @Inject public AsyncJobManager asyncMgr; @@ -421,6 +425,7 @@ public class ApiDBUtils { @Inject private HostDetailsDao hostDetailsDao; @Inject private ClusterDetailsDao clusterDetailsDao; @Inject private VMSnapshotDao vmSnapshotDao; + @Inject private NicSecondaryIpDao nicSecondaryIpDao; @PostConstruct void init() { _ms = ms; @@ -521,6 +526,7 @@ public class ApiDBUtils { _hostDetailsDao = hostDetailsDao; _clusterDetailsDao = clusterDetailsDao; _vmSnapshotDao = vmSnapshotDao; + _nicSecondaryIpDao = nicSecondaryIpDao; // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); } @@ -1519,4 +1525,8 @@ public class ApiDBUtils { public static Map findHostDetailsById(long hostId){ return _hostDetailsDao.findDetails(hostId); } + + public static List findNicSecondaryIps(long nicId) { + return _nicSecondaryIpDao.listByNicId(nicId); + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index eafee8a2a4a..fbfc9554111 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -19,6 +19,7 @@ package com.cloud.api; import com.cloud.api.query.ViewResponseHelper; import com.cloud.api.query.vo.*; import com.cloud.api.response.ApiResponseSerializer; + import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; 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.NetworkOfferingResponse; 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.PodResponse; 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.vm.ConsoleProxyVO; import com.cloud.vm.InstanceGroup; +import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.dao.NicSecondaryIpVO; + import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; 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) { Network ntwk = ApiDBUtils.findNetworkById(ipAddr.getAssociatedWithNetworkId()); @@ -3435,4 +3444,51 @@ public class ApiResponseHelper implements ResponseGenerator { response.setTimeout(tmDetails.get("timeout")); 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 secondaryIps = ApiDBUtils.findNicSecondaryIps(result.getId()); + if (secondaryIps != null) { + List ipList = new ArrayList(); + 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; + } } diff --git a/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java index 1bb3981cd72..7072324080d 100644 --- a/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java @@ -22,22 +22,17 @@ import javax.ejb.Local; import org.apache.log4j.Logger; -import com.cloud.api.ApiDBUtils; -import com.cloud.api.ApiResponseHelper; -import com.cloud.api.query.vo.InstanceGroupJoinVO; + import com.cloud.api.query.vo.UserAccountJoinVO; -import org.apache.cloudstack.api.response.InstanceGroupResponse; import org.apache.cloudstack.api.response.UserResponse; import org.springframework.stereotype.Component; -import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.vm.InstanceGroup; @Component @@ -58,7 +53,7 @@ public class UserAccountJoinDaoImpl extends GenericDaoBase listVmNics(Long vmId, Long nicId); + } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index f527b73d481..a575183a152 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -140,8 +140,19 @@ import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; 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.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.VMInstanceDao; @@ -240,6 +251,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L UsageEventDao _usageEventDao; @Inject NetworkModel _networkModel; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; @Inject UserIpv6AddressDao _ipv6Dao; @Inject @@ -1750,6 +1763,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guru.deallocate(network, profile, vm); _nicDao.remove(nic.getId()); s_logger.debug("Removed nic id=" + nic.getId()); + //remove the secondary ip addresses corresponding to to this nic + List 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 @@ -2792,6 +2813,33 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Random _rand = new Random(System.currentTimeMillis()); + public List listVmNics(Long vmId, Long nicId) { + List 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 @DB public String acquireGuestIpAddress(Network network, String requestedIp) { @@ -2802,7 +2850,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Set availableIps = _networkModel.getAvailableIps(network, requestedIp); - if (availableIps.isEmpty()) { + if (availableIps == null || availableIps.isEmpty()) { 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"); } - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); + //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), firewallStaticNatRule.getNetworkId()); ruleVO.setState(FirewallRule.State.Revoke); - staticNatRules.add(new StaticNatRuleImpl(ruleVO, dstIp)); + staticNatRules.add(new StaticNatRuleImpl(ruleVO, ip.getVmIp())); } try { @@ -3598,4 +3646,26 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } 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 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; + } + } diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index ac1bc874f9c..05258884db9 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -109,6 +109,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.VMInstanceDao; @Component @@ -170,6 +171,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { PrivateIpDao _privateIpDao; @Inject UserIpv6AddressDao _ipv6Dao; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao;; private final HashMap _systemNetworks = new HashMap(5); @@ -1624,6 +1627,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { public Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); List ips = _nicDao.listIpAddressInNetwork(network.getId()); + List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); + ips.addAll(secondaryIps); Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); Set usedIps = new TreeSet(); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 1708224b47e..4c61aec284f 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -37,23 +37,28 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; 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.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.log4j.Logger; 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.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; 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.UsageEventDao; import com.cloud.exception.*; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDao; import com.cloud.network.IpAddress.State; import com.cloud.vm.Nic; 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.guru.NetworkGuru; 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.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.vpc.PrivateIpVO; 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.vm.*; 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.VMInstanceDao; import java.util.*; @@ -203,6 +214,16 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Inject NetworkModel _networkModel; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; + + @Inject + PortForwardingRulesDao _portForwardingDao; + @Inject + HostDao _hostDao; + @Inject + HostPodDao _hostPodDao; + int _cidrLimit; 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 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 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 @DB @@ -3025,4 +3178,21 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { public Network getNetwork(String networkUuid) { return _networksDao.findByUuid(networkUuid); } + + @Override + public List 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); + } } diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java index 61351a64050..8217e4e47b9 100644 --- a/server/src/com/cloud/network/addr/PublicIp.java +++ b/server/src/com/cloud/network/addr/PublicIp.java @@ -211,18 +211,28 @@ public class PublicIp implements PublicIpAddress { _addr.setVpcId(vpcId); } - @Override - public String getIp6Gateway() { - return _vlan.getIp6Gateway(); - } + @Override + public String getIp6Gateway() { + return _vlan.getIp6Gateway(); + } - @Override - public String getIp6Cidr() { - return _vlan.getIp6Cidr(); - } + @Override + public String getIp6Cidr() { + return _vlan.getIp6Cidr(); + } - @Override - public String getIp6Range() { - return _vlan.getIp6Range(); - } + @Override + public String getIp6Range() { + return _vlan.getIp6Range(); + } + + @Override + public String getVmIp() { + return _addr.getVmIp(); + } + + @Override + public void setVmIp(String vmIp) { + _addr.setVmIp(vmIp); + } } diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 9cdb975d208..1052639ebf2 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -62,5 +62,8 @@ public interface IPAddressDao extends GenericDao { long countFreePublicIPs(); - long countFreeIPsInNetwork(long networkId); -} + long countFreeIPsInNetwork(long networkId); + IPAddressVO findByVmIp(String vmIp); + + IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp); +} diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index e7067d98156..691e46047de 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -80,6 +80,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen AllFieldsSearch.and("sourcenetwork", AllFieldsSearch.entity().getSourceNetworkId(), Op.EQ); AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ); AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); + AllFieldsSearch.and("associatedVmIp", AllFieldsSearch.entity().getVmIp(), Op.EQ); AllFieldsSearch.done(); VlanDbIdSearchUnallocated = createSearchBuilder(); @@ -232,6 +233,12 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return findOneBy(sc); } + @Override + public IPAddressVO findByVmIp(String vmIp) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("associatedVmIp", vmIp); + return findOneBy(sc); + } @Override public int countIPs(long dcId, long vlanId, boolean onlyCountAllocated) { SearchCriteria sc = onlyCountAllocated ? AllocatedIpCount.create() : AllIpCount.create(); @@ -347,5 +354,13 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen boolean result = super.remove(id); txn.commit(); return result; - } + } + + @Override + public IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("associatedWithVmId", vmId); + sc.setParameters("associatedVmIp", vmIp); + return findOneBy(sc); + } } diff --git a/server/src/com/cloud/network/dao/IPAddressVO.java b/server/src/com/cloud/network/dao/IPAddressVO.java index 00da5eb9a39..8ce8d3382b2 100644 --- a/server/src/com/cloud/network/dao/IPAddressVO.java +++ b/server/src/com/cloud/network/dao/IPAddressVO.java @@ -112,6 +112,10 @@ public class IPAddressVO implements IpAddress { @Column(name="vpc_id") private Long vpcId; + @Column(name="dnat_vmip") + private String vmIp; + + protected IPAddressVO() { this.uuid = UUID.randomUUID().toString(); } @@ -288,8 +292,18 @@ public class IPAddressVO implements IpAddress { return vpcId; } - @Override + @Override public void setVpcId(Long vpcId) { this.vpcId = vpcId; } + + @Override + public String getVmIp() { + return vmIp; + } + + @Override + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 0e2eb63793c..b387ab5934c 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2318,8 +2318,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.StaticNat, provider)) { if (ip.isOneToOneNat()) { - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), guestNetworkId); - StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), dstIp, false); + StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), guestNetworkId, ip.getId(), ip.getVmIp(), false); staticNats.add(staticNat); } } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 614d30820b4..29ed5f36d5e 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -78,10 +78,13 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; +import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; @Component @@ -123,6 +126,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules ResourceTagDao _resourceTagDao; @Inject VpcManager _vpcMgr; + @Inject + NicSecondaryIpDao _nicSecondaryDao; @Override public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) { @@ -172,7 +177,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Override @DB @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 { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -192,6 +197,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules Network network = _networkModel.getNetwork(networkId); //associate ip address to network (if needed) boolean performedIpAssoc = false; + Nic guestNic; if (ipAddress.getAssociatedWithNetworkId() == null) { boolean assignToVpcNtwk = network.getVpcId() != null && 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 Ip dstIp = rule.getDestinationIpAddress(); - Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); + guestNic = _networkModel.getNicInNetwork(vmId, networkId); if (guestNic == null || guestNic.getIp4Address() == null) { throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress"); } else { 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 boolean validatePortRange = false; 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"); } - String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId); - + //String dstIp = _networkModel.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId); + String dstIp = ipAddress.getVmIp(); Transaction txn = Transaction.currentTxn(); txn.start(); @@ -397,14 +416,13 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Override @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 { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); UserContext.current().setEventDetails("Ip Id: " + ipId); // Verify input parameters - IPAddressVO ipAddress = _ipAddressDao.findById(ipId); if (ipAddress == null) { 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 isOneToOneNat = ipAddress.isOneToOneNat(); Long associatedWithVmId = ipAddress.getAssociatedWithVmId(); + Nic guestNic; + NicSecondaryIpVO nicSecIp = null; + String dstIp = null; + try { Network network = _networkModel.getNetwork(networkId); if (network == null) { @@ -421,11 +443,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules } // Check that vm has a nic in the network - Nic guestNic = _networkModel.getNicInNetwork(vmId, networkId); + guestNic = _networkModel.getNicInNetwork(vmId, networkId); if (guestNic == null) { throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id"); } - + dstIp = guestNic.getIp4Address(); if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { 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 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 - 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.setAssociatedWithVmId(vmId); + ipAddress.setVmIp(dstIp); if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) { // enable static nat 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"); ipAddress.setOneToOneNat(isOneToOneNat); ipAddress.setAssociatedWithVmId(associatedWithVmId); + ipAddress.setVmIp(null); _ipAddressDao.update(ipAddress.getId(), ipAddress); } } else { @@ -490,16 +536,17 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules } } finally { - if (performedIpAssoc) { - //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()); - _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); + if (performedIpAssoc) { + //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()); + _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); } } 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 { if (ipAddress.isSourceNat()) { 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"); } - 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 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) { 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 - s_logger.debug("Disassociating static nat for ip " + oldIP); - if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { + // unassign old static nat rule + s_logger.debug("Disassociating static nat for ip " + oldIP); + if (!disableStaticNat(oldIP.getId(), caller, callerUserId, true)) { 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 staticNats = new ArrayList(); for (IPAddressVO ip : ips) { // Get nic IP4 address - String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId); - StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), dstIp, false); + //String dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), networkId); + StaticNatImpl staticNat = new StaticNatImpl(ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), networkId, ip.getId(), ip.getVmIp(), false); staticNats.add(staticNat); } @@ -1209,6 +1257,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules boolean isIpSystem = ipAddress.getSystem(); ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); + ipAddress.setVmIp(null); if (isIpSystem && !releaseIpIfElastic) { ipAddress.setSystem(false); } @@ -1248,11 +1297,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw ex; } - String dstIp; - if (forRevoke) { - dstIp = _networkModel.getIpInNetworkIncludingRemoved(ip.getAssociatedWithVmId(), rule.getNetworkId()); - } else { - dstIp = _networkModel.getIpInNetwork(ip.getAssociatedWithVmId(), rule.getNetworkId()); + String dstIp = ip.getVmIp(); + if (dstIp == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("VM ip address of the specified public ip is not set "); + ex.addProxyObject(ruleVO, rule.getId(), "ruleId"); + throw ex; } return new StaticNatRuleImpl(ruleVO, dstIp); @@ -1333,12 +1382,16 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // create new static nat rule // 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; - if (forRevoke) { - dstIp = _networkModel.getIpInNetworkIncludingRemoved(sourceIp.getAssociatedWithVmId(), networkId); - } else { - dstIp = _networkModel.getIpInNetwork(sourceIp.getAssociatedWithVmId(), networkId); + + dstIp = sourceIp.getVmIp(); + if (dstIp == null) { + throw new InvalidParameterValueException("Vm ip is not set as dnat ip for this public ip"); } 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); try { - success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM); + success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM, null); } catch (NetworkRuleConflictException ex) { 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); diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java index 91f08e7a8ff..682a941856c 100644 --- a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java +++ b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java @@ -41,5 +41,7 @@ public interface PortForwardingRulesDao extends GenericDao listByNetwork(long networkId); List listByAccount(long accountId); + + List listByDestIpAddr(String ip4Address); } diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java index 5406ab624e0..1d2e991ab39 100644 --- a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java +++ b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java @@ -32,6 +32,7 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.vm.dao.NicSecondaryIpVO; @Component @Local(value=PortForwardingRulesDao.class) @@ -55,6 +56,7 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase listByDestIpAddr(String ip4Address) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + return listBy(sc); + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index e80d48c6512..95b2973a384 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2165,6 +2165,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(CreateVMSnapshotCmd.class); cmdList.add(RevertToSnapshotCmd.class); cmdList.add(DeleteVMSnapshotCmd.class); + cmdList.add(AddIpToVmNicCmd.class); + cmdList.add(RemoveIpFromVmNicCmd.class); + cmdList.add(ListNicsCmd.class); return cmdList; } diff --git a/server/src/com/cloud/vm/NicVO.java b/server/src/com/cloud/vm/NicVO.java index 8e2edda40aa..987596cff32 100644 --- a/server/src/com/cloud/vm/NicVO.java +++ b/server/src/com/cloud/vm/NicVO.java @@ -122,6 +122,9 @@ public class NicVO implements Nic { @Column(name = "uuid") String uuid = UUID.randomUUID().toString(); + @Column(name = "secondary_ip") + boolean secondaryIp; + public NicVO(String reserver, Long instanceId, long configurationId, VirtualMachine.Type vmType) { this.reserver = reserver; this.instanceId = instanceId; @@ -349,4 +352,12 @@ public class NicVO implements Nic { public void setIp6Cidr(String ip6Cidr) { this.ip6Cidr = ip6Cidr; } + + public boolean getSecondaryIp() { + return secondaryIp; + } + + public void setSecondaryIp(boolean secondaryIp) { + this.secondaryIp = secondaryIp; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ce53c4579fd..ca9c13fd1c4 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -360,6 +360,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected ProjectManager _projectMgr; @Inject protected ResourceManager _resourceMgr; + @Inject protected NetworkServiceMapDao _ntwkSrvcDao; @Inject @@ -1359,6 +1360,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " as a part of vm id=" + vmId + " 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; } diff --git a/server/src/com/cloud/vm/dao/NicDao.java b/server/src/com/cloud/vm/dao/NicDao.java index 762048b65bf..794bacc6e8b 100644 --- a/server/src/com/cloud/vm/dao/NicDao.java +++ b/server/src/com/cloud/vm/dao/NicDao.java @@ -58,4 +58,6 @@ public interface NicDao extends GenericDao { NicVO findByNetworkIdInstanceIdAndBroadcastUri(long networkId, long instanceId, String broadcastUri); NicVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, long instanceId, String ip4Address); + + List listByVmIdAndNicId(Long vmId, Long nicId); } diff --git a/server/src/com/cloud/vm/dao/NicDaoImpl.java b/server/src/com/cloud/vm/dao/NicDaoImpl.java index 5cf152f9f90..44911740e96 100644 --- a/server/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDaoImpl.java @@ -53,8 +53,10 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.EQ); AllFieldsSearch.and("isDefault", AllFieldsSearch.entity().isDefaultNic(), 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(); - + IpSearch = createSearchBuilder(String.class); IpSearch.select(null, Func.DISTINCT, IpSearch.entity().getIp4Address()); IpSearch.and("network", IpSearch.entity().getNetworkId(), Op.EQ); @@ -202,4 +204,12 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { sc.setParameters("address", ip4Address); return findOneBy(sc); } + + @Override + public List listByVmIdAndNicId(Long vmId, Long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instance", vmId); + sc.setParameters("nicid", nicId); + return listBy(sc); + } } diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java b/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java new file mode 100644 index 00000000000..da96df43e83 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java @@ -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 { + List listByVmId(long instanceId); + + List listSecondaryIpAddressInNetwork(long networkConfigId); + List 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 getSecondaryIpAddressesForVm(long vmId); + + List listByNicId(long nicId); + + List listByNicIdAndVmid(long nicId, long vmId); + + NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId); + + NicSecondaryIpVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, + Long vmId, String vmIp); + + List getSecondaryIpAddressesForNic(long nicId); +} diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java new file mode 100644 index 00000000000..3befaf70529 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java @@ -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 implements NicSecondaryIpDao { + private final SearchBuilder AllFieldsSearch; + private final GenericSearchBuilder 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 listByVmId(long instanceId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", instanceId); + return listBy(sc); + } + + @Override + public List listByNicId(long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + return listBy(sc); + } + + @Override + public List listSecondaryIpAddressInNetwork(long networkId) { + SearchCriteria sc = IpSearch.create(); + sc.setParameters("network", networkId); + return customSearch(sc, null); + } + + @Override + public List listByNetworkId(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + return listBy(sc); + } + + @Override + public List listByNicIdAndVmid(long nicId, long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + sc.setParameters("instanceId", vmId); + return listBy(sc); + } + + @Override + public List getSecondaryIpAddressesForVm(long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", vmId); + return listBy(sc); + } + + @Override + public List getSecondaryIpAddressesForNic(long nicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", nicId); + List results = search(sc, null); + List ips = new ArrayList(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 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 sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + sc.setParameters("instanceId", vmId); + sc.setParameters("address", vmIp); + return findOneBy(sc); + } +} diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java b/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java new file mode 100644 index 00000000000..770e188ad83 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java @@ -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; + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 3568da57b71..80043102648 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -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.RestartNetworkCmd; import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import com.cloud.dc.DataCenter; 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.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -824,4 +826,49 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub 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 listVmNics(Long vmId, Long nicId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List listNics(ListNicsCmd listNicsCmd) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/network/MockRulesManagerImpl.java b/server/test/com/cloud/network/MockRulesManagerImpl.java index ba3dd413cc3..e5a6894d76d 100644 --- a/server/test/com/cloud/network/MockRulesManagerImpl.java +++ b/server/test/com/cloud/network/MockRulesManagerImpl.java @@ -39,6 +39,7 @@ import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.net.Ip; import com.cloud.vm.VirtualMachine; @Local(value = {RulesManager.class, RulesService.class}) @@ -53,14 +54,6 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return null; } - @Override - public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, - Long vmId, boolean openFirewall) - throws NetworkRuleConflictException { - // TODO Auto-generated method stub - return null; - } - @Override public boolean revokePortForwardingRule(long ruleId, boolean apply) { // TODO Auto-generated method stub @@ -83,7 +76,7 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R @Override public boolean enableStaticNat(long ipAddressId, long vmId, long networkId, - boolean isSystemVm) throws NetworkRuleConflictException, + boolean isSystemVm, String ipAddr) throws NetworkRuleConflictException, ResourceUnavailableException { // TODO Auto-generated method stub return false; @@ -310,4 +303,12 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return "MockRulesManagerImpl"; } + @Override + public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, + Long vmId, Ip vmIp, boolean openFirewall) + throws NetworkRuleConflictException { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 828a555a539..63ef8744be8 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -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.ListNetworksCmd; 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.springframework.stereotype.Component; @@ -80,6 +81,7 @@ import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -1317,4 +1319,75 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub 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 listVmNics(Long vmId, Long nicId) { + // TODO Auto-generated method stub + return null; + } + + + + + + @Override + public List listNics(ListNicsCmd listNicsCmd) { + // TODO Auto-generated method stub + return null; + } } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index db83416310c..f3112a1da27 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -119,3 +119,24 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'UserV -- Re-enable foreign key checking, at the end of the upgrade path 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); diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 2fd855d75ad..6292c536a9d 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -132,6 +132,9 @@ known_categories = { 'Condition': 'AutoScale', 'Api': 'API Discovery', 'Region': 'Region', + 'addIpToNic': 'Nic', + 'removeIpFromNic': 'Nic', + 'listNics':'Nic', } diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index cce91008dba..ed9248c49a3 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -48,6 +48,26 @@ class codeGenerator: self.subclass = [] self.outputFolder = outputFolder self.apiSpecFile = apiSpecFile + lic = """\ + # 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. + + """ + self.license = dedent(lic) def addAttribute(self, attr, pro): value = pro.value @@ -81,25 +101,7 @@ class codeGenerator: self.cmd = cmd self.cmdsName.append(self.cmd.name) - license = """\ - # 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. - """ - self.code = dedent(license) + self.code = self.license self.code += "\n" self.code += '"""%s"""\n'%self.cmd.desc self.code += 'from baseCmd import *\n' @@ -186,25 +188,28 @@ class codeGenerator: initCmdsList += '"%s",'%cmdName fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w') + fp.write(self.license) for item in [header, imports, body]: fp.write(item) fp.close() '''generate __init__.py''' - initCmdsList += '"cloudstackAPIClient"]' + initCmdsList = self.license + initCmdsList + '"cloudstackAPIClient"]' fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w') fp.write(initCmdsList) fp.close() fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') - basecmd = '"""Base Command"""\n' + basecmd = self.license + basecmd += '"""Base Command"""\n' basecmd += 'class baseCmd:\n' basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') - basecmd = '"""Base class for response"""\n' + basecmd = self.license + basecmd += '"""Base class for response"""\n' basecmd += 'class baseResponse:\n' basecmd += self.space + 'pass\n' fp.write(basecmd) diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js index 0ccedc5ddb1..3356ecb866e 100755 --- a/ui/scripts/docs.js +++ b/ui/scripts/docs.js @@ -15,6 +15,25 @@ // specific language governing permissions and limitations // under the License. cloudStack.docs = { + + //IP Reservation tooltips + helpIPReservationCidr: { + desc:'Edit CIDR when you want to configure IP Reservation in isolated guest Network', + externalLink:'' + + }, + + helpIPReservationNetworkCidr:{ + desc:'The CIDR of the entire network when IP reservation is configured', + externalLink:' ' + + }, + + helpReservedIPRange:{ + desc:'The IP Range which is not used by CloudStack to allocate to Guest VMs.Can be used for Non Cloudstack purposes.', + externalLink:'' + }, + // Add account helpAccountUsername: { desc: 'Any desired login ID. Must be unique in the current domain. The same username can exist in other domains, including sub-domains.', diff --git a/ui/scripts/globalSettings.js b/ui/scripts/globalSettings.js index 0f573d8d196..912dde7d86b 100644 --- a/ui/scripts/globalSettings.js +++ b/ui/scripts/globalSettings.js @@ -134,7 +134,7 @@ title: 'Configure LDAP', fields:{ - name:{label: 'Bind Username' , validation: {required:true} }, + name:{label: 'Bind DN' , validation: {required:true} }, password: {label: 'Bind Password', validation: {required: true },isPassword:true }, hostname: {label:'Hostname' , validation:{required:true}}, queryfilter: {label:'Query Filter' , validation: {required:true}}, diff --git a/ui/scripts/system.js b/ui/scripts/system.js index d1bd9c5e10b..ac8fe3d8870 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7598,7 +7598,6 @@ if(vSwitchEnabled) { items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -7609,10 +7608,8 @@ // items.push({id: "" , description:" " }); else{ - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } @@ -7662,21 +7659,17 @@ if(vSwitchEnabled){ - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - } else{ - - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index f0cc8fd60b2..db7f5240e20 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -338,6 +338,8 @@ $detailView.find('.tagger').find('input[type=text]').val(''); + $('div.container div.panel div.detail-group .details .main-groups').find('.cidr').toolTip({ docID:'helpIPReservationCidr' , mode:'hover' , tooltip:'.tooltip-box' }); + var convertInputs = function($inputs) { // Save and turn back into labels $inputs.each(function() { @@ -489,7 +491,11 @@ return true; }); - + + $('div.container div.panel div.detail-group .details .main-groups').find('.reservediprange').toolTip({ docID:'helpReservedIPRange' , mode:'hover' , tooltip:'.tooltip-box' }); + $('div.container div.panel div.detail-group .details .main-groups').find('.networkcidr').toolTip({ docID:'helpIPReservationNetworkCidr' , mode:'hover' , tooltip:'.tooltip-box' }); + + $detailView.find('td.value span').each(function() { var name = $(this).closest('tr').data('detail-view-field'); var $value = $(this); diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index d8684fb8e28..47932664927 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -909,10 +909,8 @@ // items.push({id: " ", description: " "}); else{ + items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } @@ -923,7 +921,7 @@ }, vSwitchPublicName:{ - label:'vSwitch Public Traffic Name', + label:'Public Traffic vSwitch Name', dependsOn:'overridepublictraffic', isHidden:true @@ -961,8 +959,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); - + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -972,10 +969,9 @@ } else{ - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); @@ -986,7 +982,7 @@ }, vSwitchGuestName:{ - label:'vSwitch Guest Traffic Name', + label:'Guest Traffic vSwitch Name', dependsOn:'overrideguesttraffic', isHidden:true diff --git a/utils/src/com/cloud/utils/db/Transaction.java b/utils/src/com/cloud/utils/db/Transaction.java index c15104455c0..9113aca4b25 100755 --- a/utils/src/com/cloud/utils/db/Transaction.java +++ b/utils/src/com/cloud/utils/db/Transaction.java @@ -97,8 +97,8 @@ public class Transaction { /* FIXME: We need a better solution for this * Initialize encryption if we need it for db.properties */ - /*EncryptionSecretKeyChecker enc = new EncryptionSecretKeyChecker(); - enc.check(); */ + EncryptionSecretKeyChecker enc = new EncryptionSecretKeyChecker(); + enc.check(); } private final LinkedList _stack; diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java index bcfc64b6174..d67128f723e 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualSwitchType.java @@ -29,14 +29,12 @@ public enum VirtualSwitchType { public final static String nexusDistributedVirtualSwitch = "nexusdvs"; public static VirtualSwitchType getType(String vSwitchType) { - if (vSwitchType == null) { + if (vSwitchType == null || vSwitchType.equalsIgnoreCase(vmwareStandardVirtualSwitch)) { return VirtualSwitchType.StandardVirtualSwitch; - } else if (vSwitchType.equalsIgnoreCase(vmwareStandardVirtualSwitch)) { - return VirtualSwitchType.VMwareDistributedVirtualSwitch; } else if (vSwitchType.equalsIgnoreCase(vmwareDistributedVirtualSwitch)) { - return VirtualSwitchType.NexusDistributedVirtualSwitch; + return VirtualSwitchType.VMwareDistributedVirtualSwitch; } else if (vSwitchType.equalsIgnoreCase(nexusDistributedVirtualSwitch)) { - return VirtualSwitchType.StandardVirtualSwitch; + return VirtualSwitchType.NexusDistributedVirtualSwitch; } return VirtualSwitchType.None; }