You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2015/12/06 19:38:13 UTC

[1/4] git commit: updated refs/heads/master to bbe891b

Repository: cloudstack
Updated Branches:
  refs/heads/master e37842cbd -> bbe891bfc


CLOUDSTACK-9051: update nic IP address of stopped vm


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/b79d338f
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/b79d338f
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/b79d338f

Branch: refs/heads/master
Commit: b79d338f29c2b4e7387944c3a25ed0b4d0541e82
Parents: 20dcc25
Author: Wei Zhou <w....@tech.leaseweb.com>
Authored: Wed Nov 4 13:07:39 2015 +0100
Committer: Wei Zhou <w....@tech.leaseweb.com>
Committed: Mon Nov 30 09:20:25 2015 +0100

----------------------------------------------------------------------
 api/src/com/cloud/vm/UserVmService.java         |   8 +
 .../api/command/user/vm/UpdateVmNicIpCmd.java   | 186 +++++++++++++++
 .../classes/resources/messages.properties       |   2 +
 client/tomcatconf/commands.properties.in        |   1 +
 .../com/cloud/network/IpAddressManagerImpl.java | 228 +++++++++----------
 .../com/cloud/server/ManagementServerImpl.java  |   2 +
 server/src/com/cloud/vm/UserVmManagerImpl.java  |  95 ++++++++
 tools/apidoc/gen_toc.py                         |   1 +
 ui/css/cloudstack3.css                          |   3 +
 ui/dictionary.jsp                               |   1 +
 ui/dictionary2.jsp                              |   1 +
 ui/scripts/instances.js                         | 101 +++++++-
 12 files changed, 513 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/api/src/com/cloud/vm/UserVmService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java
index c0f2de9..54206ed 100644
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -34,6 +34,7 @@ import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
 import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
 import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
@@ -129,6 +130,13 @@ public interface UserVmService {
      */
     UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd);
 
+    /**
+     * Updated the ip address on the given NIC to the virtual machine
+     * @param cmd the command object that defines the ip address and the given nic
+     * @return the vm object if successful, null otherwise
+     */
+    UserVm updateNicIpForVirtualMachine(UpdateVmNicIpCmd cmd);
+
     UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException;
 
     /**

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVmNicIpCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVmNicIpCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVmNicIpCmd.java
new file mode 100644
index 0000000..c6fbedb
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVmNicIpCmd.java
@@ -0,0 +1,186 @@
+// 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.EnumSet;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandJobType;
+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.ApiConstants.VMDetails;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.response.NicResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+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.uservm.UserVm;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.Nic;
+
+@APICommand(name = "updateVmNicIp", description = "Update the default Ip of a VM Nic", responseObject = UserVmResponse.class)
+public class UpdateVmNicIpCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(AddIpToVmNicCmd.class.getName());
+    private static final String s_name = "updatevmnicipresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// 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 CallContext.current().getCallingAccount().getAccountName();
+    }
+
+    public long getDomainId() {
+        return CallContext.current().getCallingAccount().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);
+        if (nic == null) {
+            throw new InvalidParameterValueException("Can't find network id for specified nic");
+        }
+        Long networkId = nic.getNetworkId();
+        return networkId;
+    }
+
+    public Long getNicId() {
+        return nicId;
+    }
+
+    public String getIpaddress () {
+        if (ipAddr != null) {
+            return ipAddr;
+        } else {
+            return null;
+        }
+    }
+
+    public NetworkType getNetworkType() {
+        Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
+        DataCenter dc = _entityMgr.findById(DataCenter.class, ntwk.getDataCenterId());
+        return dc.getNetworkType();
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccountId();
+    }
+
+    @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 {
+
+        CallContext.current().setEventDetails("Nic Id: " + getNicId() );
+        String ip;
+        if ((ip = getIpaddress()) != null) {
+            if (!NetUtils.isValidIp(ip)) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid ip address " + ip);
+            }
+        }
+
+        UserVm vm = _userVmService.updateNicIpForVirtualMachine(this);
+        ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
+        dc.add(VMDetails.valueOf("nics"));
+        EnumSet<VMDetails> details = EnumSet.copyOf(dc);
+        if (vm != null){
+            UserVmResponse response = _responseGenerator.createUserVmResponse(ResponseView.Restricted, "virtualmachine", details, vm).get(0);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update ip address on vm NIC. Refer to server logs for details.");
+        }
+    }
+
+    @Override
+    public String getSyncObjType() {
+        return BaseAsyncCmd.networkSyncObject;
+    }
+
+    @Override
+    public Long getSyncObjId() {
+        return getNetworkId();
+    }
+
+    @Override
+    public ApiCommandJobType getInstanceType() {
+        return ApiCommandJobType.IpAddress;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index d3cc4d0..43445f9 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -441,6 +441,7 @@ label.capacity=Capacity
 label.capacity.bytes=Capacity Bytes
 label.capacity.iops=Capacity IOPS
 label.certificate=Server certificate
+label.change.ipaddress=Change IP address for NIC
 label.change.service.offering=Change service offering
 label.change.value=Change value
 label.character=Character
@@ -1783,6 +1784,7 @@ message.apply.snapshot.policy=You have successfully updated your current snapsho
 message.attach.iso.confirm=Please confirm that you want to attach the ISO to this virtual instance.
 message.attach.volume=Please fill in the following data to attach a new volume. If you are attaching a disk volume to a Windows based virtual machine, you will need to reboot the instance to see the attached disk.
 message.basic.mode.desc=Choose this network model if you do <b>*<u>not</u>*</b> want to enable any VLAN support.  All virtual instances created under this network model will be assigned an IP directly from the network and security groups are used to provide security and segregation.
+message.change.ipaddress=Please confirm that you would like to change the IP address for this NIC on VM.
 message.change.offering.confirm=Please confirm that you wish to change the service offering of this virtual instance.
 message.change.password=Please change your password.
 message.configure.all.traffic.types=You have multiple physical networks; please configure labels for each traffic type by clicking on the Edit button.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 1c788a8..b40841b 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -402,6 +402,7 @@ updateDefaultNicForVirtualMachine=15
 ####
 addIpToNic=15
 removeIpFromNic=15
+updateVmNicIp=15
 listNics=15
 
 #### SSH key pair commands

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/server/src/com/cloud/network/IpAddressManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java
index a2f2cda..d4da5fa 100644
--- a/server/src/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/com/cloud/network/IpAddressManagerImpl.java
@@ -667,137 +667,137 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
         IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() {
             @Override
             public IPAddressVO doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
-        StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in ");
-        boolean fetchFromDedicatedRange = false;
-        List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
-        List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
-
-        SearchCriteria<IPAddressVO> sc = null;
-        if (podId != null) {
-            sc = AssignIpAddressFromPodVlanSearch.create();
-            sc.setJoinParameters("podVlanMapSB", "podId", podId);
-            errorMessage.append(" pod id=" + podId);
-        } else {
-            sc = AssignIpAddressSearch.create();
-            errorMessage.append(" zone id=" + dcId);
-        }
-
-        // If owner has dedicated Public IP ranges, fetch IP from the dedicated range
-        // Otherwise fetch IP from the system pool
-        List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
-        for (AccountVlanMapVO map : maps) {
-            if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
-                dedicatedVlanDbIds.add(map.getVlanDbId());
-        }
-        List<DomainVlanMapVO> domainMaps = _domainVlanMapDao.listDomainVlanMapsByDomain(owner.getDomainId());
-        for (DomainVlanMapVO map : domainMaps) {
-            if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
-                dedicatedVlanDbIds.add(map.getVlanDbId());
-        }
-        List<VlanVO> nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId);
-        for (VlanVO nonDedicatedVlan : nonDedicatedVlans) {
-            if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId()))
-                nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
-        }
-        if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) {
-            fetchFromDedicatedRange = true;
-            sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
-                    errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray()));
-        } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
-            sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
-                    errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
-        } else {
-            if (podId != null) {
-                InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
-                ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
-                throw ex;
-            }
-            s_logger.warn(errorMessage.toString());
-            InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
-            ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
-            throw ex;
-        }
+                StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in ");
+                boolean fetchFromDedicatedRange = false;
+                List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
+                List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
+
+                SearchCriteria<IPAddressVO> sc = null;
+                if (podId != null) {
+                    sc = AssignIpAddressFromPodVlanSearch.create();
+                    sc.setJoinParameters("podVlanMapSB", "podId", podId);
+                    errorMessage.append(" pod id=" + podId);
+                } else {
+                    sc = AssignIpAddressSearch.create();
+                    errorMessage.append(" zone id=" + dcId);
+                }
 
-        sc.setParameters("dc", dcId);
+                // If owner has dedicated Public IP ranges, fetch IP from the dedicated range
+                // Otherwise fetch IP from the system pool
+                List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
+                for (AccountVlanMapVO map : maps) {
+                    if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
+                        dedicatedVlanDbIds.add(map.getVlanDbId());
+                }
+                List<DomainVlanMapVO> domainMaps = _domainVlanMapDao.listDomainVlanMapsByDomain(owner.getDomainId());
+                for (DomainVlanMapVO map : domainMaps) {
+                    if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
+                        dedicatedVlanDbIds.add(map.getVlanDbId());
+                }
+                List<VlanVO> nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId);
+                for (VlanVO nonDedicatedVlan : nonDedicatedVlans) {
+                    if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId()))
+                        nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
+                }
+                if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) {
+                    fetchFromDedicatedRange = true;
+                    sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
+                            errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray()));
+                } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
+                    sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
+                            errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
+                } else {
+                    if (podId != null) {
+                        InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
+                        ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
+                        throw ex;
+                    }
+                    s_logger.warn(errorMessage.toString());
+                    InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
+                    ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
+                    throw ex;
+                }
 
-        DataCenter zone = _entityMgr.findById(DataCenter.class, dcId);
+                sc.setParameters("dc", dcId);
 
-        // for direct network take ip addresses only from the vlans belonging to the network
-        if (vlanUse == VlanType.DirectAttached) {
-            sc.setJoinParameters("vlan", "networkId", guestNetworkId);
-            errorMessage.append(", network id=" + guestNetworkId);
-        }
-        sc.setJoinParameters("vlan", "type", vlanUse);
+                DataCenter zone = _entityMgr.findById(DataCenter.class, dcId);
 
-        if (requestedIp != null) {
-            sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp);
-            errorMessage.append(": requested ip " + requestedIp + " is not available");
-        }
+                // for direct network take ip addresses only from the vlans belonging to the network
+                if (vlanUse == VlanType.DirectAttached) {
+                    sc.setJoinParameters("vlan", "networkId", guestNetworkId);
+                    errorMessage.append(", network id=" + guestNetworkId);
+                }
+                sc.setJoinParameters("vlan", "type", vlanUse);
 
-        Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
+                if (requestedIp != null) {
+                    sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp);
+                    errorMessage.append(": requested ip " + requestedIp + " is not available");
+                }
 
-        List<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
+                Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
 
-        // If all the dedicated IPs of the owner are in use fetch an IP from the system pool
-        if (addrs.size() == 0 && fetchFromDedicatedRange) {
-            // Verify if account is allowed to acquire IPs from the system
-            boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
-            if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
-                fetchFromDedicatedRange = false;
-                sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
-                        errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
-                addrs = _ipAddressDao.lockRows(sc, filter, true);
-            }
-        }
+                List<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
 
-        if (addrs.size() == 0) {
-            if (podId != null) {
-                InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
-                // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object.
-                ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
-                throw ex;
-            }
-            s_logger.warn(errorMessage.toString());
-            InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
-            ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
-            throw ex;
-        }
+                // If all the dedicated IPs of the owner are in use fetch an IP from the system pool
+                if (addrs.size() == 0 && fetchFromDedicatedRange) {
+                    // Verify if account is allowed to acquire IPs from the system
+                    boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
+                    if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
+                        fetchFromDedicatedRange = false;
+                        sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
+                                errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
+                        addrs = _ipAddressDao.lockRows(sc, filter, true);
+                    }
+                }
 
-        assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
+                if (addrs.size() == 0) {
+                    if (podId != null) {
+                        InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
+                        // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object.
+                        ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
+                        throw ex;
+                    }
+                    s_logger.warn(errorMessage.toString());
+                    InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
+                    ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
+                    throw ex;
+                }
 
-        if (!fetchFromDedicatedRange && VlanType.VirtualNetwork.equals(vlanUse)) {
-            // Check that the maximum number of public IPs for the given accountId will not be exceeded
-            try {
-                _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
-            } catch (ResourceAllocationException ex) {
-                s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner);
-                throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
-            }
-        }
+                assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
 
-        IPAddressVO addr = addrs.get(0);
-        addr.setSourceNat(sourceNat);
-        addr.setAllocatedTime(new Date());
-        addr.setAllocatedInDomainId(owner.getDomainId());
-        addr.setAllocatedToAccountId(owner.getId());
-        addr.setSystem(isSystem);
+                if (!fetchFromDedicatedRange && VlanType.VirtualNetwork.equals(vlanUse)) {
+                    // Check that the maximum number of public IPs for the given accountId will not be exceeded
+                    try {
+                        _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
+                    } catch (ResourceAllocationException ex) {
+                        s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner);
+                        throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
+                    }
+                }
+
+                IPAddressVO addr = addrs.get(0);
+                addr.setSourceNat(sourceNat);
+                addr.setAllocatedTime(new Date());
+                addr.setAllocatedInDomainId(owner.getDomainId());
+                addr.setAllocatedToAccountId(owner.getId());
+                addr.setSystem(isSystem);
                 if (displayIp != null) {
                     addr.setDisplay(displayIp);
                 }
 
-        if (assign) {
-            markPublicIpAsAllocated(addr);
-        } else {
-            addr.setState(IpAddress.State.Allocating);
-        }
-        addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating);
+                if (assign) {
+                    markPublicIpAsAllocated(addr);
+                } else {
+                    addr.setState(IpAddress.State.Allocating);
+                }
+                addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating);
 
-        if (vlanUse != VlanType.DirectAttached) {
-            addr.setAssociatedWithNetworkId(guestNetworkId);
-            addr.setVpcId(vpcId);
-        }
+                if (vlanUse != VlanType.DirectAttached) {
+                    addr.setAssociatedWithNetworkId(guestNetworkId);
+                    addr.setVpcId(vpcId);
+                }
 
-        _ipAddressDao.update(addr.getId(), addr);
+                _ipAddressDao.update(addr.getId(), addr);
 
                 return addr;
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index dbfcb19..0425e3d 100644
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -442,6 +442,7 @@ import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
 import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
 import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
@@ -2895,6 +2896,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(DeleteVMSnapshotCmd.class);
         cmdList.add(AddIpToVmNicCmd.class);
         cmdList.add(RemoveIpFromVmNicCmd.class);
+        cmdList.add(UpdateVmNicIpCmd.class);
         cmdList.add(ListNicsCmd.class);
         cmdList.add(ArchiveAlertsCmd.class);
         cmdList.add(DeleteAlertsCmd.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 49250fb..02c58b1 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -58,6 +58,7 @@ import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
 import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
 import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
@@ -142,6 +143,7 @@ import com.cloud.event.dao.UsageEventDao;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.CloudException;
 import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ManagementServerException;
@@ -159,6 +161,7 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.HypervisorCapabilitiesVO;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
+import com.cloud.network.IpAddressManager;
 import com.cloud.network.Network;
 import com.cloud.network.Network.IpAddresses;
 import com.cloud.network.Network.Provider;
@@ -472,6 +475,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
     DomainRouterDao _routerDao;
     @Inject
     protected VMNetworkMapDao _vmNetworkMapDao;
+    @Inject
+    protected IpAddressManager _ipAddrMgr;
 
     protected ScheduledExecutorService _executor = null;
     protected int _expungeInterval;
@@ -1409,6 +1414,96 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
     }
 
     @Override
+    public UserVm updateNicIpForVirtualMachine(UpdateVmNicIpCmd cmd) {
+        Long nicId = cmd.getNicId();
+        String ipaddr = cmd.getIpaddress();
+        Account caller = CallContext.current().getCallingAccount();
+
+        //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");
+        }
+
+        UserVm vm = _vmDao.findById(nicVO.getInstanceId());
+        if (vm == null) {
+            throw new InvalidParameterValueException("There is no vm with the nic");
+        }
+        if (vm.getState() != State.Stopped) {
+            throw new InvalidParameterValueException("The vm is not Stopped, please stop it before update Vm nic Ip");
+        }
+
+        if (!_networkModel.listNetworkOfferingServices(nicVO.getNetworkId()).isEmpty() && vm.getState() != State.Stopped) {
+            InvalidParameterValueException ex = new InvalidParameterValueException(
+                    "VM is not Stopped, unable to update the vm nic having the specified id");
+            ex.addProxyObject(vm.getUuid(), "vmId");
+            throw ex;
+        }
+
+        // verify permissions
+        _accountMgr.checkAccess(caller, null, true, vm);
+        Account ipOwner = _accountDao.findByIdIncludingRemoved(vm.getAccountId());
+
+        // verify ip address
+        s_logger.debug("Calling the ip allocation ...");
+        Network network = _networkDao.findById(nicVO.getNetworkId());
+        DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) {
+            try {
+                ipaddr = _ipAddrMgr.allocateGuestIP(network, ipaddr);
+            } catch (InsufficientAddressCapacityException e) {
+                throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, for insufficient address capacity");
+            }
+            if (ipaddr == null) {
+                throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, please choose another ip");
+            }
+        } else if (dc.getNetworkType() == NetworkType.Basic || network.getGuestType()  == Network.GuestType.Shared) {
+            //handle the basic networks here
+            //for basic zone, need to provide the podId to ensure proper ip alloation
+            Long podId = null;
+            if (dc.getNetworkType() == NetworkType.Basic) {
+                podId = vm.getPodIdToDeployIn();
+                if (podId == null) {
+                    throw new InvalidParameterValueException("vm pod id is null in Basic zone; can't decide the range for ip allocation");
+                }
+            }
+
+            try {
+                ipaddr = _ipAddrMgr.allocatePublicIpForGuestNic(network, podId, ipOwner, ipaddr);
+                if (ipaddr == null) {
+                    throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, please choose another ip");
+                }
+                final IPAddressVO ip = _ipAddressDao.findByIpAndSourceNetworkId(nicVO.getNetworkId(), nicVO.getIPv4Address());
+                if (ip != null) {
+                    Transaction.execute(new TransactionCallbackNoReturn() {
+                        @Override
+                        public void doInTransactionWithoutResult(TransactionStatus status) {
+                    _ipAddrMgr.markIpAsUnavailable(ip.getId());
+                    _ipAddressDao.unassignIpAddress(ip.getId());
+                        }
+                    });
+                }
+            } catch (InsufficientAddressCapacityException e) {
+                s_logger.error("Allocating ip to guest nic " + nicVO.getUuid() + " failed, for insufficient address capacity");
+                return null;
+            }
+        } else {
+            s_logger.error("UpdateVmNicIpCmd is not supported in this network...");
+            return null;
+        }
+
+        // update nic ipaddress
+        nicVO.setIPv4Address(ipaddr);
+        _nicDao.persist(nicVO);
+
+        return vm;
+    }
+
+    @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "Upgrading VM", async = true)
     public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,
             VirtualMachineMigrationException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/tools/apidoc/gen_toc.py
----------------------------------------------------------------------
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index cb26e2b..311e55b 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -151,6 +151,7 @@ known_categories = {
     'Detail': 'Resource metadata',
     'addIpToNic': 'Nic',
     'removeIpFromNic': 'Nic',
+    'updateVmNicIp': 'Nic',
     'listNics':'Nic',
 	'AffinityGroup': 'Affinity Group',
     'addImageStore': 'Image Store',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 22f7409..3775146 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -2308,6 +2308,7 @@ div.detail-group.actions td {
   height: 35px;
   float: right;
   padding: 0;
+  min-width: 120px;
 }
 
 .details.group-multiple div.detail-group.actions .detail-actions .action {
@@ -12908,12 +12909,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
 
 .replaceacllist .icon,
 .replaceACL .icon,
+.updateIpaddr .icon,
 .changeAffinity .icon {
   background-position: -264px -2px;
 }
 
 .replaceacllist:hover .icon,
 .replaceACL:hover .icon,
+.updateIpaddr:hover .icon,
 .changeAffinity:hover .icon {
   background-position: -263px -583px;
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/ui/dictionary.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index 977cd7a..d47da27 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -458,6 +458,7 @@ dictionary = {
 'label.cancel': '<fmt:message key="label.cancel" />',
 'label.capacity': '<fmt:message key="label.capacity" />',
 'label.certificate': '<fmt:message key="label.certificate" />',
+'label.change.ipaddress': '<fmt:message key="label.change.ipaddress" />',
 'label.change.service.offering': '<fmt:message key="label.change.service.offering" />',
 'label.change.value': '<fmt:message key="label.change.value" />',
 'label.character': '<fmt:message key="label.character" />',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/ui/dictionary2.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary2.jsp b/ui/dictionary2.jsp
index d2bb683..0237611 100644
--- a/ui/dictionary2.jsp
+++ b/ui/dictionary2.jsp
@@ -449,6 +449,7 @@ under the License.
 'message.attach.iso.confirm': '<fmt:message key="message.attach.iso.confirm" />',
 'message.attach.volume': '<fmt:message key="message.attach.volume" />',
 'message.basic.mode.desc': '<fmt:message key="message.basic.mode.desc" />',
+'message.change.ipaddress': '<fmt:message key="message.change.ipaddress" />',
 'message.change.offering.confirm': '<fmt:message key="message.change.offering.confirm" />',
 'message.change.password': '<fmt:message key="message.change.password" />',
 'message.configure.all.traffic.types': '<fmt:message key="message.configure.all.traffic.types" />',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b79d338f/ui/scripts/instances.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index 83376f0..a367f46 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -2364,6 +2364,103 @@
                                 }
                             },
 
+                            updateIpaddr: {
+                                label: 'label.change.ipaddress',
+                                messages: {
+                                    confirm: function() {
+                                        return 'message.change.ipaddress';
+                                    },
+                                    notification: function(args) {
+                                        return 'label.change.ipaddress';
+                                    }
+                                },
+                                createForm: {
+                                    title: 'label.change.ipaddress',
+                                    desc: 'message.change.ipaddress',
+                                    preFilter: function(args) {
+                                        if (args.context.nics != null && args.context.nics[0].type == 'Isolated') {
+                                            args.$form.find('.form-item[rel=ipaddress1]').css('display', 'inline-block'); //shown text
+                                            args.$form.find('.form-item[rel=ipaddress2]').hide();
+                                        } else if (args.context.nics != null && args.context.nics[0].type == 'Shared') {
+                                            args.$form.find('.form-item[rel=ipaddress2]').css('display', 'inline-block'); //shown list
+                                            args.$form.find('.form-item[rel=ipaddress1]').hide();
+                                        }
+                                    },
+                                    fields: {
+                                        ipaddress1: {
+                                            label: 'label.ip.address'
+                                        },
+                                        ipaddress2: {
+                                            label: 'label.ip.address',
+                                            select: function(args) {
+                                                if (args.context.nics != null && args.context.nics[0].type == 'Shared') {
+                                                    $.ajax({
+                                                        url: createURL('listPublicIpAddresses'),
+                                                        data: {
+                                                            allocatedonly: false,
+                                                            networkid: args.context.nics[0].networkid,
+                                                            forvirtualnetwork: false
+                                                        },
+                                                        success: function(json) {
+                                                            var ips = json.listpublicipaddressesresponse.publicipaddress;
+                                                            var items = [{
+                                                                id: -1,
+                                                                description: ''
+                                                            }];
+                                                            $(ips).each(function() {
+                                                                if (this.state == "Free") {
+                                                                    items.push({
+                                                                        id: this.ipaddress,
+                                                                        description: this.ipaddress
+                                                                    });
+                                                                }
+                                                            });
+                                                            args.response.success({
+                                                                data: items
+                                                            });
+                                                        }
+                                                    });
+                                                } else {
+                                                    args.response.success({
+                                                        data: null
+                                                    });
+                                                }
+                                            }
+                                        }
+                                    }
+                                },
+                                action: function(args) {
+                                    var dataObj = {
+                                        nicId: args.context.nics[0].id
+                                    };
+
+                                    if (args.data.ipaddress1) {
+                                        dataObj.ipaddress = args.data.ipaddress1;
+                                    } else if (args.data.ipaddress2 != -1) {
+                                        dataObj.ipaddress = args.data.ipaddress2;
+                                    }
+
+                                    $.ajax({
+                                        url: createURL('updateVmNicIp'),
+                                        data: dataObj,
+                                        success: function(json) {
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: json.updatevmnicipresponse.jobid,
+                                                    getUpdatedItem: function(json) {
+                                                        return json.queryasyncjobresultresponse.jobresult.virtualmachine;
+                                                    }
+                                                }
+                                            });
+                                        }
+                                    });
+                                },
+
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            },
+
                             // Remove NIC/Network from VM
                             remove: {
                                 label: 'label.action.delete.nic',
@@ -2463,9 +2560,9 @@
                                     args.response.success({
                                         actionFilter: function(args) {
                                             if (args.context.item.isdefault) {
-                                                return [];
+                                                return ['updateIpaddr'];
                                             } else {
-                                                return ['remove', 'makeDefault'];
+                                                return ['remove', 'makeDefault', 'updateIpaddr'];
                                             }
                                         },
                                         data: $.map(json.listvirtualmachinesresponse.virtualmachine[0].nic, function(nic, index) {


[3/4] git commit: updated refs/heads/master to bbe891b

Posted by da...@apache.org.
CLOUDSTACK-9051: reprogram network as a part of vm nic ip update


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/ccf77063
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/ccf77063
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/ccf77063

Branch: refs/heads/master
Commit: ccf770636c93ab0e8d66faeef8cbc5d5b14b8450
Parents: c01c73e
Author: Wei Zhou <w....@tech.leaseweb.com>
Authored: Mon Nov 23 00:32:09 2015 +0100
Committer: Wei Zhou <w....@tech.leaseweb.com>
Committed: Mon Nov 30 09:20:26 2015 +0100

----------------------------------------------------------------------
 server/src/com/cloud/vm/UserVmManagerImpl.java  | 53 +++++++++++++++++++-
 server/test/com/cloud/vm/UserVmManagerTest.java | 43 ++++++++++++++--
 2 files changed, 90 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ccf77063/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 27c0328..6fd10ca 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -1434,7 +1434,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
             throw new InvalidParameterValueException("There is no vm with the nic");
         }
 
-        if (!_networkModel.listNetworkOfferingServices(nicVO.getNetworkId()).isEmpty() && vm.getState() != State.Stopped) {
+        Network network = _networkDao.findById(nicVO.getNetworkId());
+        if (network == null) {
+            throw new InvalidParameterValueException("There is no network with the nic");
+        }
+        // Don't allow to update vm nic ip if network is not in Implemented/Setup/Allocated state
+        if (!(network.getState() == Network.State.Allocated || network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) {
+            throw new InvalidParameterValueException("Network is not in the right state to update vm nic ip. Correct states are: " + Network.State.Allocated + ", " + Network.State.Implemented + ", "
+                    + Network.State.Setup);
+        }
+
+        NetworkOfferingVO offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
+        if (offering == null) {
+            throw new InvalidParameterValueException("There is no network offering with the network");
+        }
+        if (!_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty() && vm.getState() != State.Stopped) {
             InvalidParameterValueException ex = new InvalidParameterValueException(
                     "VM is not Stopped, unable to update the vm nic having the specified id");
             ex.addProxyObject(vm.getUuid(), "vmId");
@@ -1447,8 +1461,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
 
         // verify ip address
         s_logger.debug("Calling the ip allocation ...");
-        Network network = _networkDao.findById(nicVO.getNetworkId());
         DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        if (dc == null) {
+            throw new InvalidParameterValueException("There is no dc with the nic");
+        }
         if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) {
             try {
                 ipaddr = _ipAddrMgr.allocateGuestIP(network, ipaddr);
@@ -1458,6 +1474,39 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
             if (ipaddr == null) {
                 throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, please choose another ip");
             }
+
+            if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) {
+                IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vm.getId());
+                if (oldIP != null) {
+                    oldIP.setVmIp(ipaddr);
+                    _ipAddressDao.persist(oldIP);
+                }
+            }
+            // implementing the network elements and resources as a part of vm nic ip update if network has services and it is in Implemented state
+            if (!_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty() && network.getState() == Network.State.Implemented) {
+                User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
+                ReservationContext context = new ReservationContextImpl(null, null, callerUser, caller);
+                DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null);
+
+                s_logger.debug("Implementing the network " + network + " elements and resources as a part of vm nic ip update");
+                try {
+                    // implement the network elements and rules again
+                    _networkMgr.implementNetworkElementsAndResources(dest, context, network, offering);
+                } catch (Exception ex) {
+                    s_logger.warn("Failed to implement network " + network + " elements and resources as a part of vm nic ip update due to ", ex);
+                    CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of vm nic ip update");
+                    e.addProxyObject(network.getUuid(), "networkId");
+                    // restore to old ip address
+                    if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) {
+                        IPAddressVO oldIP = _ipAddressDao.findByAssociatedVmId(vm.getId());
+                        if (oldIP != null) {
+                            oldIP.setVmIp(nicVO.getIPv4Address());
+                            _ipAddressDao.persist(oldIP);
+                        }
+                    }
+                    throw e;
+                }
+            }
         } else if (dc.getNetworkType() == NetworkType.Basic || network.getGuestType()  == Network.GuestType.Shared) {
             //handle the basic networks here
             //for basic zone, need to provide the podId to ensure proper ip alloation

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ccf77063/server/test/com/cloud/vm/UserVmManagerTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java
index a94b765..cffb506 100644
--- a/server/test/com/cloud/vm/UserVmManagerTest.java
+++ b/server/test/com/cloud/vm/UserVmManagerTest.java
@@ -55,6 +55,7 @@ import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
 import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -66,6 +67,7 @@ import com.cloud.configuration.ConfigurationManager;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DeployDestination;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -75,6 +77,7 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.IpAddressManager;
+import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkModel;
@@ -82,6 +85,8 @@ import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.offering.ServiceOffering;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.Storage.ImageFormat;
@@ -196,6 +201,12 @@ public class UserVmManagerTest {
     IpAddressManager _ipAddrMgr;
     @Mock
     IPAddressDao _ipAddressDao;
+    @Mock
+    NetworkOfferingDao _networkOfferingDao;
+    @Mock
+    NetworkOfferingVO _networkOfferingMock;
+    @Mock
+    NetworkOrchestrationService _networkMgr;
 
     @Before
     public void setup() {
@@ -227,6 +238,8 @@ public class UserVmManagerTest {
         _userVmMgr._dcDao = _dcDao;
         _userVmMgr._ipAddrMgr = _ipAddrMgr;
         _userVmMgr._ipAddressDao = _ipAddressDao;
+        _userVmMgr._networkOfferingDao = _networkOfferingDao;
+        _userVmMgr._networkMgr = _networkMgr;
 
         doReturn(3L).when(_account).getId();
         doReturn(8L).when(_vmMock).getAccountId();
@@ -705,6 +718,10 @@ public class UserVmManagerTest {
         NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
         when(_nicDao.findById(anyLong())).thenReturn(nic);
         when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        doReturn(9L).when(_networkMock).getNetworkOfferingId();
+        when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock);
+        doReturn(10L).when(_networkOfferingMock).getId();
 
         List<Service> services = new ArrayList<Service>();
         services.add(Service.Dhcp);
@@ -713,13 +730,14 @@ public class UserVmManagerTest {
         doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
         when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
 
-        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getState()).thenReturn(Network.State.Implemented);
         when(_networkMock.getDataCenterId()).thenReturn(3L);
         when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated);
         when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
         when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced);
 
         when(_ipAddrMgr.allocateGuestIP(Mockito.eq(_networkMock), anyString())).thenReturn("10.10.10.10");
+        doNothing().when(_networkMgr).implementNetworkElementsAndResources(Mockito.any(DeployDestination.class), Mockito.any(ReservationContext.class), Mockito.eq(_networkMock), Mockito.eq(_networkOfferingMock));
         when(_nicDao.persist(any(NicVO.class))).thenReturn(nic);
 
         Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
@@ -748,6 +766,10 @@ public class UserVmManagerTest {
         NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
         when(_nicDao.findById(anyLong())).thenReturn(nic);
         when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        doReturn(9L).when(_networkMock).getNetworkOfferingId();
+        when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock);
+        doReturn(10L).when(_networkOfferingMock).getId();
 
         List<Service> services = new ArrayList<Service>();
         when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
@@ -755,7 +777,7 @@ public class UserVmManagerTest {
         doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
         when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
 
-        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getState()).thenReturn(Network.State.Implemented);
         when(_networkMock.getDataCenterId()).thenReturn(3L);
         when(_networkMock.getGuestType()).thenReturn(GuestType.Shared);
         when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
@@ -792,6 +814,11 @@ public class UserVmManagerTest {
         NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
         when(_nicDao.findById(anyLong())).thenReturn(nic);
         when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getState()).thenReturn(Network.State.Implemented);
+        doReturn(9L).when(_networkMock).getNetworkOfferingId();
+        when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock);
+        doReturn(10L).when(_networkOfferingMock).getId();
 
         List<Service> services = new ArrayList<Service>();
         services.add(Service.Dhcp);
@@ -825,6 +852,10 @@ public class UserVmManagerTest {
         NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
         when(_nicDao.findById(anyLong())).thenReturn(nic);
         when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        doReturn(9L).when(_networkMock).getNetworkOfferingId();
+        when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock);
+        doReturn(10L).when(_networkOfferingMock).getId();
 
         List<Service> services = new ArrayList<Service>();
         services.add(Service.Dhcp);
@@ -833,7 +864,7 @@ public class UserVmManagerTest {
         doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
         when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
 
-        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getState()).thenReturn(Network.State.Implemented);
         when(_networkMock.getDataCenterId()).thenReturn(3L);
         when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated);
         when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
@@ -868,6 +899,10 @@ public class UserVmManagerTest {
         NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
         when(_nicDao.findById(anyLong())).thenReturn(nic);
         when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        doReturn(9L).when(_networkMock).getNetworkOfferingId();
+        when(_networkOfferingDao.findByIdIncludingRemoved(anyLong())).thenReturn(_networkOfferingMock);
+        doReturn(10L).when(_networkOfferingMock).getId();
 
         List<Service> services = new ArrayList<Service>();
         services.add(Service.Dhcp);
@@ -876,7 +911,7 @@ public class UserVmManagerTest {
         doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
         when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
 
-        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getState()).thenReturn(Network.State.Implemented);
         when(_networkMock.getDataCenterId()).thenReturn(3L);
         when(_networkMock.getGuestType()).thenReturn(GuestType.Shared);
         when(_dcDao.findById(anyLong())).thenReturn(_dcMock);


[4/4] git commit: updated refs/heads/master to bbe891b

Posted by da...@apache.org.
Merge pull request #1086 from ustcweizhou/update-nic-ipaddr

CLOUDSTACK-9051: update nic IP address of stopped vmThis provides the feature to change ip address of NIC on a stopped vm by API and UI.

* pr/1086:
  CLOUDSTACK-9051: reprogram network as a part of vm nic ip update
  CLOUDSTACK-9051: add unit tests for UpdateVmNicIp
  CLOUDSTACK-9051: update nic IP address of stopped vm

Signed-off-by: Daan Hoogland <da...@onecht.net>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/bbe891bf
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/bbe891bf
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/bbe891bf

Branch: refs/heads/master
Commit: bbe891bfc30feadc3b900b73728a9d04f8b98c72
Parents: e37842c ccf7706
Author: Daan Hoogland <da...@onecht.net>
Authored: Sun Dec 6 19:37:03 2015 +0100
Committer: Daan Hoogland <da...@onecht.net>
Committed: Sun Dec 6 19:37:04 2015 +0100

----------------------------------------------------------------------
 api/src/com/cloud/vm/UserVmService.java         |   8 +
 .../api/command/user/vm/UpdateVmNicIpCmd.java   | 186 ++++++++++++
 .../api/command/test/UpdateVmNicIpTest.java     |  91 ++++++
 .../classes/resources/messages.properties       |   2 +
 client/tomcatconf/commands.properties.in        |   1 +
 .../com/cloud/network/IpAddressManagerImpl.java | 228 +++++++--------
 .../com/cloud/server/ManagementServerImpl.java  |   2 +
 server/src/com/cloud/vm/UserVmManagerImpl.java  | 141 ++++++++++
 server/test/com/cloud/vm/UserVmManagerTest.java | 280 +++++++++++++++++++
 tools/apidoc/gen_toc.py                         |   1 +
 ui/css/cloudstack3.css                          |   3 +
 ui/dictionary.jsp                               |   1 +
 ui/dictionary2.jsp                              |   1 +
 ui/scripts/instances.js                         | 101 ++++++-
 14 files changed, 930 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bbe891bf/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bbe891bf/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bbe891bf/ui/dictionary2.jsp
----------------------------------------------------------------------


[2/4] git commit: updated refs/heads/master to bbe891b

Posted by da...@apache.org.
CLOUDSTACK-9051: add unit tests for UpdateVmNicIp


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/c01c73e4
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/c01c73e4
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/c01c73e4

Branch: refs/heads/master
Commit: c01c73e44dd98db317b4e2ec5f5ece4fbfc8c26d
Parents: b79d338
Author: Wei Zhou <w....@tech.leaseweb.com>
Authored: Thu Nov 19 11:00:39 2015 +0100
Committer: Wei Zhou <w....@tech.leaseweb.com>
Committed: Mon Nov 30 09:20:26 2015 +0100

----------------------------------------------------------------------
 .../api/command/test/UpdateVmNicIpTest.java     |  91 +++++++
 server/src/com/cloud/vm/UserVmManagerImpl.java  |   7 +-
 server/test/com/cloud/vm/UserVmManagerTest.java | 245 +++++++++++++++++++
 3 files changed, 338 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c01c73e4/api/test/org/apache/cloudstack/api/command/test/UpdateVmNicIpTest.java
----------------------------------------------------------------------
diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateVmNicIpTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateVmNicIpTest.java
new file mode 100644
index 0000000..9a42aa1
--- /dev/null
+++ b/api/test/org/apache/cloudstack/api/command/test/UpdateVmNicIpTest.java
@@ -0,0 +1,91 @@
+// 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.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
+import org.apache.cloudstack.api.response.UserVmResponse;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.uservm.UserVm;
+import com.cloud.vm.UserVmService;
+
+public class UpdateVmNicIpTest extends TestCase {
+
+    private UpdateVmNicIpCmd updateVmNicIpCmd;
+    private ResponseGenerator responseGenerator;
+
+    @Override
+    @Before
+    public void setUp() {
+
+    }
+
+    @Test
+    public void testSuccess() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
+
+        UserVmService userVmService = Mockito.mock(UserVmService.class);
+        updateVmNicIpCmd = Mockito.mock(UpdateVmNicIpCmd.class);
+        UserVm userVm = Mockito.mock(UserVm.class);
+
+        Mockito.when(userVmService.updateNicIpForVirtualMachine(Mockito.any(UpdateVmNicIpCmd.class))).thenReturn(userVm);
+
+        updateVmNicIpCmd._userVmService = userVmService;
+        responseGenerator = Mockito.mock(ResponseGenerator.class);
+
+        List<UserVmResponse> list = new LinkedList<UserVmResponse>();
+        UserVmResponse userVmResponse = Mockito.mock(UserVmResponse.class);
+        list.add(userVmResponse);
+        Mockito.when(responseGenerator.createUserVmResponse(ResponseView.Restricted, "virtualmachine", userVm)).thenReturn(list);
+
+        updateVmNicIpCmd._responseGenerator = responseGenerator;
+        updateVmNicIpCmd.execute();
+    }
+
+    @Test
+    public void testFailure() throws ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
+        UserVmService userVmService = Mockito.mock(UserVmService.class);
+        updateVmNicIpCmd = Mockito.mock(UpdateVmNicIpCmd.class);
+
+        Mockito.when(userVmService.updateNicIpForVirtualMachine(Mockito.any(UpdateVmNicIpCmd.class))).thenReturn(null);
+
+        updateVmNicIpCmd._userVmService = userVmService;
+
+        updateVmNicIpCmd._responseGenerator = responseGenerator;
+        try {
+            updateVmNicIpCmd.execute();
+        } catch (ServerApiException exception) {
+            Assert.assertEquals("Failed to update ip address on vm NIC. Refer to server logs for details.", exception.getDescription());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c01c73e4/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 02c58b1..27c0328 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -1433,9 +1433,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
         if (vm == null) {
             throw new InvalidParameterValueException("There is no vm with the nic");
         }
-        if (vm.getState() != State.Stopped) {
-            throw new InvalidParameterValueException("The vm is not Stopped, please stop it before update Vm nic Ip");
-        }
 
         if (!_networkModel.listNetworkOfferingServices(nicVO.getNetworkId()).isEmpty() && vm.getState() != State.Stopped) {
             InvalidParameterValueException ex = new InvalidParameterValueException(
@@ -1482,8 +1479,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
                     Transaction.execute(new TransactionCallbackNoReturn() {
                         @Override
                         public void doInTransactionWithoutResult(TransactionStatus status) {
-                    _ipAddrMgr.markIpAsUnavailable(ip.getId());
-                    _ipAddressDao.unassignIpAddress(ip.getId());
+                            _ipAddrMgr.markIpAsUnavailable(ip.getId());
+                            _ipAddressDao.unassignIpAddress(ip.getId());
                         }
                     });
                 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c01c73e4/server/test/com/cloud/vm/UserVmManagerTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java
index 17054c2..a94b765 100644
--- a/server/test/com/cloud/vm/UserVmManagerTest.java
+++ b/server/test/com/cloud/vm/UserVmManagerTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -42,6 +43,7 @@ import com.cloud.event.dao.UsageEventDao;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
 
@@ -51,6 +53,7 @@ import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
 import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
 import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -60,6 +63,9 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
 
 import com.cloud.capacity.CapacityManager;
 import com.cloud.configuration.ConfigurationManager;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -68,6 +74,13 @@ import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.IpAddressManager;
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.Service;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
@@ -87,6 +100,8 @@ import com.cloud.user.dao.AccountDao;
 import com.cloud.user.dao.UserDao;
 import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.cloud.vm.snapshot.VMSnapshotVO;
@@ -161,6 +176,26 @@ public class UserVmManagerTest {
     UsageEventDao _usageEventDao;
     @Mock
     VMSnapshotDao _vmSnapshotDao;
+    @Mock
+    UpdateVmNicIpCmd _updateVmNicIpCmd;
+    @Mock
+    NicDao _nicDao;
+    @Mock
+    NicVO _nicMock;
+    @Mock
+    NetworkModel _networkModel;
+    @Mock
+    NetworkDao _networkDao;
+    @Mock
+    NetworkVO _networkMock;
+    @Mock
+    DataCenterDao _dcDao;
+    @Mock
+    DataCenterVO _dcMock;
+    @Mock
+    IpAddressManager _ipAddrMgr;
+    @Mock
+    IPAddressDao _ipAddressDao;
 
     @Before
     public void setup() {
@@ -186,6 +221,12 @@ public class UserVmManagerTest {
         _userVmMgr._entityMgr = _entityMgr;
         _userVmMgr._storagePoolDao = _storagePoolDao;
         _userVmMgr._vmSnapshotDao = _vmSnapshotDao;
+        _userVmMgr._nicDao = _nicDao;
+        _userVmMgr._networkModel = _networkModel;
+        _userVmMgr._networkDao = _networkDao;
+        _userVmMgr._dcDao = _dcDao;
+        _userVmMgr._ipAddrMgr = _ipAddrMgr;
+        _userVmMgr._ipAddressDao = _ipAddressDao;
 
         doReturn(3L).when(_account).getId();
         doReturn(8L).when(_vmMock).getAccountId();
@@ -648,4 +689,208 @@ public class UserVmManagerTest {
         }
     }
 
+    @Test
+    public void testUpdateVmNicIpSuccess1() throws Exception {
+        UpdateVmNicIpCmd cmd = new UpdateVmNicIpCmd();
+        Class<?> _class = cmd.getClass();
+
+        Field virtualmachineIdField = _class.getDeclaredField("nicId");
+        virtualmachineIdField.setAccessible(true);
+        virtualmachineIdField.set(cmd, 1L);
+
+        Field accountNameField = _class.getDeclaredField("ipAddr");
+        accountNameField.setAccessible(true);
+        accountNameField.set(cmd, "10.10.10.10");
+
+        NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+        when(_nicDao.findById(anyLong())).thenReturn(nic);
+        when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+
+        List<Service> services = new ArrayList<Service>();
+        services.add(Service.Dhcp);
+        when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
+        when(_vmMock.getState()).thenReturn(State.Stopped);
+        doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
+        when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
+
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getDataCenterId()).thenReturn(3L);
+        when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated);
+        when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
+        when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced);
+
+        when(_ipAddrMgr.allocateGuestIP(Mockito.eq(_networkMock), anyString())).thenReturn("10.10.10.10");
+        when(_nicDao.persist(any(NicVO.class))).thenReturn(nic);
+
+        Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, caller);
+        try {
+            _userVmMgr.updateNicIpForVirtualMachine(cmd);
+        } finally {
+            CallContext.unregister();
+        }
+    }
+
+    @Test
+    public void testUpdateVmNicIpSuccess2() throws Exception {
+        UpdateVmNicIpCmd cmd = new UpdateVmNicIpCmd();
+        Class<?> _class = cmd.getClass();
+
+        Field virtualmachineIdField = _class.getDeclaredField("nicId");
+        virtualmachineIdField.setAccessible(true);
+        virtualmachineIdField.set(cmd, 1L);
+
+        Field accountNameField = _class.getDeclaredField("ipAddr");
+        accountNameField.setAccessible(true);
+        accountNameField.set(cmd, "10.10.10.10");
+
+        NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+        when(_nicDao.findById(anyLong())).thenReturn(nic);
+        when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+
+        List<Service> services = new ArrayList<Service>();
+        when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
+        when(_vmMock.getState()).thenReturn(State.Running);
+        doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
+        when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
+
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getDataCenterId()).thenReturn(3L);
+        when(_networkMock.getGuestType()).thenReturn(GuestType.Shared);
+        when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
+        when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced);
+
+        when(_ipAddrMgr.allocatePublicIpForGuestNic(Mockito.eq(_networkMock), anyLong(), Mockito.eq(_accountMock), anyString())).thenReturn("10.10.10.10");
+        when(_ipAddressDao.findByIpAndSourceNetworkId(anyLong(), anyString())).thenReturn(null);
+        when(_nicDao.persist(any(NicVO.class))).thenReturn(nic);
+
+        Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, caller);
+        try {
+            _userVmMgr.updateNicIpForVirtualMachine(cmd);
+        } finally {
+            CallContext.unregister();
+        }
+    }
+
+    // vm is running in network with dhcp support
+    @Test(expected = InvalidParameterValueException.class)
+    public void testUpdateVmNicIpFailure1() throws Exception {
+        UpdateVmNicIpCmd cmd = new UpdateVmNicIpCmd();
+        Class<?> _class = cmd.getClass();
+
+        Field virtualmachineIdField = _class.getDeclaredField("nicId");
+        virtualmachineIdField.setAccessible(true);
+        virtualmachineIdField.set(cmd, 1L);
+
+        Field accountNameField = _class.getDeclaredField("ipAddr");
+        accountNameField.setAccessible(true);
+        accountNameField.set(cmd, "10.10.10.10");
+
+        NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+        when(_nicDao.findById(anyLong())).thenReturn(nic);
+        when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+
+        List<Service> services = new ArrayList<Service>();
+        services.add(Service.Dhcp);
+        when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
+        when(_vmMock.getState()).thenReturn(State.Running);
+
+        Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, caller);
+        try {
+            _userVmMgr.updateNicIpForVirtualMachine(cmd);
+        } finally {
+            CallContext.unregister();
+        }
+    }
+
+    // vm is stopped in isolated network in advanced zone
+    @Test(expected = InvalidParameterValueException.class)
+    public void testUpdateVmNicIpFailure2() throws Exception {
+        UpdateVmNicIpCmd cmd = new UpdateVmNicIpCmd();
+        Class<?> _class = cmd.getClass();
+
+        Field virtualmachineIdField = _class.getDeclaredField("nicId");
+        virtualmachineIdField.setAccessible(true);
+        virtualmachineIdField.set(cmd, 1L);
+
+        Field accountNameField = _class.getDeclaredField("ipAddr");
+        accountNameField.setAccessible(true);
+        accountNameField.set(cmd, "10.10.10.10");
+
+        NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+        when(_nicDao.findById(anyLong())).thenReturn(nic);
+        when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+
+        List<Service> services = new ArrayList<Service>();
+        services.add(Service.Dhcp);
+        when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
+        when(_vmMock.getState()).thenReturn(State.Stopped);
+        doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
+        when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
+
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getDataCenterId()).thenReturn(3L);
+        when(_networkMock.getGuestType()).thenReturn(GuestType.Isolated);
+        when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
+        when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced);
+
+        when(_ipAddrMgr.allocateGuestIP(Mockito.eq(_networkMock), anyString())).thenReturn(null);
+
+        Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, caller);
+        try {
+            _userVmMgr.updateNicIpForVirtualMachine(cmd);
+        } finally {
+            CallContext.unregister();
+        }
+    }
+
+    // vm is stopped in shared network in advanced zone
+    @Test(expected = InvalidParameterValueException.class)
+    public void testUpdateVmNicIpFailure3() throws Exception {
+        UpdateVmNicIpCmd cmd = new UpdateVmNicIpCmd();
+        Class<?> _class = cmd.getClass();
+
+        Field virtualmachineIdField = _class.getDeclaredField("nicId");
+        virtualmachineIdField.setAccessible(true);
+        virtualmachineIdField.set(cmd, 1L);
+
+        Field accountNameField = _class.getDeclaredField("ipAddr");
+        accountNameField.setAccessible(true);
+        accountNameField.set(cmd, "10.10.10.10");
+
+        NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User);
+        when(_nicDao.findById(anyLong())).thenReturn(nic);
+        when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
+
+        List<Service> services = new ArrayList<Service>();
+        services.add(Service.Dhcp);
+        when(_networkModel.listNetworkOfferingServices(anyLong())).thenReturn(services);
+        when(_vmMock.getState()).thenReturn(State.Stopped);
+        doNothing().when(_accountMgr).checkAccess(_account, null, true, _vmMock);
+        when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(_accountMock);
+
+        when(_networkDao.findById(anyLong())).thenReturn(_networkMock);
+        when(_networkMock.getDataCenterId()).thenReturn(3L);
+        when(_networkMock.getGuestType()).thenReturn(GuestType.Shared);
+        when(_dcDao.findById(anyLong())).thenReturn(_dcMock);
+        when(_dcMock.getNetworkType()).thenReturn(NetworkType.Advanced);
+
+        when(_ipAddrMgr.allocatePublicIpForGuestNic(Mockito.eq(_networkMock), anyLong(), Mockito.eq(_accountMock), anyString())).thenReturn(null);
+
+        Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, caller);
+        try {
+            _userVmMgr.updateNicIpForVirtualMachine(cmd);
+        } finally {
+            CallContext.unregister();
+        }
+    }
 }