public Network updateGuestNetwork()

in server/src/main/java/com/cloud/network/NetworkServiceImpl.java [3083:3592]


    public Network updateGuestNetwork(final UpdateNetworkCmd cmd) {
        User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
        Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
        final long networkId = cmd.getId();
        String name = cmd.getNetworkName();
        String displayText = cmd.getDisplayText();
        String domainSuffix = cmd.getNetworkDomain();
        final Long networkOfferingId = cmd.getNetworkOfferingId();
        Boolean changeCidr = cmd.getChangeCidr();
        String guestVmCidr = cmd.getGuestVmCidr();
        Boolean displayNetwork = cmd.getDisplayNetwork();
        String customId = cmd.getCustomId();
        boolean updateInSequence = cmd.getUpdateInSequence();
        Integer publicMtu = cmd.getPublicMtu();
        Integer privateMtu = cmd.getPrivateMtu();
        boolean forced = cmd.getForced();
        String ip4Dns1 = cmd.getIp4Dns1();
        String ip4Dns2 = cmd.getIp4Dns2();
        String ip6Dns1 = cmd.getIp6Dns1();
        String ip6Dns2 = cmd.getIp6Dns2();

        boolean restartNetwork = false;

        // verify input parameters
        final NetworkVO network = getNetworkVO(networkId, "Specified network id doesn't exist in the system");

        //perform below validation if the network is vpc network
        if (network.getVpcId() != null && networkOfferingId != null) {
            Vpc vpc = _entityMgr.findById(Vpc.class, network.getVpcId());
            _vpcMgr.validateNtwkOffForNtwkInVpc(networkId, networkOfferingId, null, null, vpc, null, _accountMgr.getAccount(network.getAccountId()), network.getNetworkACLId());
        }

        // don't allow to update network in Destroy state
        if (network.getState() == Network.State.Destroy) {
            throw new InvalidParameterValueException("Don't allow to update network in state " + Network.State.Destroy);
        }

        // Don't allow to update system network
        NetworkOffering offering = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
        if (offering.isSystemOnly()) {
            throw new InvalidParameterValueException("Can't update system networks");
        }

        // allow to upgrade only Guest networks
        if (network.getTrafficType() != Networks.TrafficType.Guest) {
            throw new InvalidParameterValueException("Can't allow networks which traffic type is not " + TrafficType.Guest);
        }

        _accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network);
        _accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId()));

        restartNetwork |= checkAndUpdateRouterSourceNatIp(cmd, network);

        if (cmd instanceof UpdateNetworkCmdByAdmin) {
            final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage();
            if (hideIpAddressUsage != null) {
                final NetworkDetailVO detail = _networkDetailsDao.findDetail(network.getId(), Network.hideIpAddressUsage);
                if (detail != null) {
                    detail.setValue(hideIpAddressUsage.toString());
                    _networkDetailsDao.update(detail.getId(), detail);
                } else {
                    _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, hideIpAddressUsage.toString(), false));
                }
            }
        }

        if (name != null) {
            network.setName(name);
        }

        if (displayText != null) {
            network.setDisplayText(displayText);
        }

        if (customId != null) {
            network.setUuid(customId);
        }

        // display flag is not null and has changed
        if (displayNetwork != null && displayNetwork != network.getDisplayNetwork()) {
            // Update resource count if it needs to be updated
            NetworkOffering networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId());
            if (_networkMgr.resourceCountNeedsUpdate(networkOffering, network.getAclType())) {
                _resourceLimitMgr.changeResourceCount(network.getAccountId(), Resource.ResourceType.network, displayNetwork);
            }

            network.setDisplayNetwork(displayNetwork);
        }

        // network offering and domain suffix can be updated for Isolated networks only in 3.0
        if (networkOfferingId != null && network.getGuestType() != GuestType.Isolated) {
            throw new InvalidParameterValueException("NetworkOffering update can be performed for Isolated networks only.");
        }
        // network offering and domain suffix can be updated for Isolated networks only in 3.0
        if (domainSuffix != null && ! Arrays.asList(GuestType.Isolated, GuestType.Shared).contains(network.getGuestType())) {
            throw new InvalidParameterValueException("Domain suffix update can only be performed for Isolated and shared networks.");
        }

        boolean networkOfferingChanged = false;

        final long oldNetworkOfferingId = network.getNetworkOfferingId();
        NetworkOffering oldNtwkOff = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId);
        NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
        if (networkOfferingId != null) {
            if (networkOffering == null || networkOffering.isSystemOnly()) {
                throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), NETWORK_OFFERING_ID);
            }

            // network offering should be in Enabled state
            if (networkOffering.getState() != NetworkOffering.State.Enabled) {
                throwInvalidIdException("Network offering with specified id is not in " + NetworkOffering.State.Enabled + " state, can't upgrade to it", networkOffering.getUuid(),
                        NETWORK_OFFERING_ID);
            }
            //can't update from vpc to non-vpc network offering
            boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering);
            boolean vorVpcOriginal = _configMgr.isOfferingForVpc(_entityMgr.findById(NetworkOffering.class, oldNetworkOfferingId));
            if (forVpcNew != vorVpcOriginal) {
                String errMsg = forVpcNew ? "a vpc offering " : "not a vpc offering";
                throw new InvalidParameterValueException("Can't update as the new offering is " + errMsg);
            }

            if (networkOfferingId != oldNetworkOfferingId) {
                Collection<String> newProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(networkOffering, network.getPhysicalNetworkId()).values();
                Collection<String> oldProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(oldNtwkOff, network.getPhysicalNetworkId()).values();

                if (providersConfiguredForExternalNetworking(newProviders) != providersConfiguredForExternalNetworking(oldProviders) && !changeCidr) {
                    throw new InvalidParameterValueException("Updating network failed since guest CIDR needs to be changed!");
                }
                if (changeCidr) {
                    if (!checkForNonStoppedVmInNetwork(network.getId())) {
                        throwInvalidIdException("All user vm of network of specified id should be stopped before changing CIDR!", network.getUuid(), "networkId");
                    }
                }
                // check if the network is upgradable
                if (!canUpgrade(network, oldNetworkOfferingId, networkOfferingId)) {
                    throw new InvalidParameterValueException("Can't upgrade from network offering " + oldNtwkOff.getUuid() + " to " + networkOffering.getUuid() + "; check logs for more information");
                }
                boolean isIpv6Supported = _networkOfferingDao.isIpv6Supported(oldNetworkOfferingId);
                boolean isIpv6SupportedNew = _networkOfferingDao.isIpv6Supported(networkOfferingId);
                if (!isIpv6Supported && isIpv6SupportedNew) {
                    try {
                        ipv6Service.checkNetworkIpv6Upgrade(network);
                    } catch (ResourceAllocationException | InsufficientAddressCapacityException ex) {
                        throw new CloudRuntimeException(String.format("Failed to upgrade network offering to '%s' as unable to allocate IPv6 network", networkOffering.getDisplayText()), ex);
                    }
                }
                restartNetwork = true;
                networkOfferingChanged = true;

                //Setting the new network's isReduntant to the new network offering's RedundantRouter.
                network.setRedundant(_networkOfferingDao.findById(networkOfferingId).isRedundantRouter());
            }
        }

        restartNetwork |= checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2,
                ip6Dns1, ip6Dns2);

        final Map<String, String> newSvcProviders = networkOfferingChanged
                ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId())
                : new HashMap<String, String>();

        // don't allow to modify network domain if the service is not supported
        if (domainSuffix != null) {
            // validate network domain
            if (!NetUtils.verifyDomainName(domainSuffix)) {
                throw new InvalidParameterValueException(
                        "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', "
                                + "and the hyphen ('-'); can't start or end with \"-\"");
            }

            long offeringId = oldNetworkOfferingId;
            if (networkOfferingId != null) {
                offeringId = networkOfferingId;
            }

            Map<Network.Capability, String> dnsCapabilities = getNetworkOfferingServiceCapabilities(_entityMgr.findById(NetworkOffering.class, offeringId), Service.Dns);
            String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification);
            if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) {
                // TBD: use uuid instead of networkOfferingId. May need to hardcode tablename in call to addProxyObject().
                throw new InvalidParameterValueException(String.format("Domain name change is not supported by the network offering %s", networkOffering));
            }

            network.setNetworkDomain(domainSuffix);
            // have to restart the network
            restartNetwork = true;
        }

        //IP reservation checks
        // allow reservation only to Isolated Guest networks
        DataCenter dc = _dcDao.findById(network.getDataCenterId());
        String networkCidr = network.getNetworkCidr();

        if (guestVmCidr != null) {
            if (dc.getNetworkType() == NetworkType.Basic) {
                throw new InvalidParameterValueException("Guest VM CIDR can't be specified for zone with " + NetworkType.Basic + " networking");
            }
            if (network.getGuestType() != GuestType.Isolated) {
                throw new InvalidParameterValueException("Can only allow IP Reservation in networks with guest type " + GuestType.Isolated);
            }
            if (networkOfferingChanged) {
                throw new InvalidParameterValueException("Cannot specify this network offering change and guestVmCidr at same time. Specify only one.");
            }
            if (network.getState() != Network.State.Implemented && network.getState() != Network.State.Allocated) {
                throw new InvalidParameterValueException(String.format("The network must be in %s or %s state. IP Reservation cannot be applied in %s state",
                        Network.State.Implemented, Network.State.Allocated, network.getState()));
            }
            if (!NetUtils.isValidIp4Cidr(guestVmCidr)) {
                throw new InvalidParameterValueException("Invalid format of Guest VM CIDR.");
            }
            if (!NetUtils.validateGuestCidr(guestVmCidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) {
                throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. ");
            }

            // If networkCidr is null it implies that there was no prior IP reservation, so the network cidr is network.getCidr()
            // But in case networkCidr is a non null value (IP reservation already exists), it implies network cidr is networkCidr
            if (networkCidr != null) {
                if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) {
                    throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR  should be a subset of network CIDR : " + networkCidr);
                }
            } else {
                if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, network.getCidr())) {
                    throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR  should be a subset of network CIDR :  " + network.getCidr());
                }
            }

            // This check makes sure there are no active IPs existing outside the guestVmCidr in the network
            String[] guestVmCidrPair = guestVmCidr.split("\\/");
            Long size = Long.valueOf(guestVmCidrPair[1]);
            List<NicVO> nicsPresent = _nicDao.listByNetworkId(networkId);

            String cidrIpRange[] = NetUtils.getIpRangeFromCidr(guestVmCidrPair[0], size);
            logger.info("The start IP of the specified guest vm cidr is: " + cidrIpRange[0] + " and end IP is: " + cidrIpRange[1]);
            long startIp = NetUtils.ip2Long(cidrIpRange[0]);
            long endIp = NetUtils.ip2Long(cidrIpRange[1]);
            long range = endIp - startIp + 1;
            logger.info("The specified guest vm cidr has " + range + " IPs");

            for (NicVO nic : nicsPresent) {
                if (nic.getIPv4Address() == null) {
                    continue;
                }
                long nicIp = NetUtils.ip2Long(nic.getIPv4Address());
                //check if nic IP is outside the guest vm cidr
                if ((nicIp < startIp || nicIp > endIp) && nic.getState() != Nic.State.Deallocating) {
                    throw new InvalidParameterValueException("Active IPs like " + nic.getIPv4Address() + " exist outside the Guest VM CIDR. Cannot apply reservation ");
                }
            }

            // In some scenarios even though guesVmCidr and network CIDR do not appear similar but
            // the IP ranges exactly matches, in these special cases make sure no Reservation gets applied
            if (network.getNetworkCidr() == null) {
                if (NetUtils.isSameIpRange(guestVmCidr, network.getCidr()) && !guestVmCidr.equals(network.getCidr())) {
                    throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and CIDR: " + network.getCidr() + " are same, "
                            + "even though both the cidrs appear to be different. As a precaution no IP Reservation will be applied.");
                }
            } else {
                if (NetUtils.isSameIpRange(guestVmCidr, network.getNetworkCidr()) && !guestVmCidr.equals(network.getNetworkCidr())) {
                    throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and Network CIDR: " + network.getNetworkCidr() + " are same, "
                            + "even though both the cidrs appear to be different. As a precaution IP Reservation will not be affected. If you want to reset IP Reservation, "
                            + "specify guestVmCidr to be: " + network.getNetworkCidr());
                }
            }

            // Check IP range overlap on shared networks and vpc private gateways associated to this network
            checkIpRangeOverlapWithAssociatedNetworks(networkId, cidrIpRange[0], cidrIpRange[1]);

            // When reservation is applied for the first time, network_cidr will be null
            // Populate it with the actual network cidr
            if (network.getNetworkCidr() == null) {
                network.setNetworkCidr(network.getCidr());
            }

            // Condition for IP Reservation reset : guestVmCidr and network CIDR are same
            if (network.getNetworkCidr().equals(guestVmCidr)) {
                logger.warn("Guest VM CIDR and Network CIDR both are same, reservation will reset.");
                network.setNetworkCidr(null);
            }
            // Finally update "cidr" with the guestVmCidr
            // which becomes the effective address space for CloudStack guest VMs
            network.setCidr(guestVmCidr);
            _networksDao.update(networkId, network);
            logger.info("IP Reservation has been applied. The new CIDR for Guests Vms is " + guestVmCidr);
        }

        Pair<Integer, Integer> mtus = validateMtuOnUpdate(network, dc.getId(), publicMtu, privateMtu);
        publicMtu = mtus.first();
        privateMtu = mtus.second();

        // List all routers for the given network:
        List<DomainRouterVO> routers = routerDao.findByNetwork(networkId);

        // Create Map to store the IPAddress List for each router
        Map<Long, Set<IpAddressTO>> routersToIpList = new HashMap<>();
        for (DomainRouterVO routerVO : routers) {
            Set<IpAddressTO> ips = new HashSet<>();
            List<DomainRouterJoinVO> routerJoinVOS = routerJoinDao.getRouterByIdAndTrafficType(routerVO.getId(), TrafficType.Guest, TrafficType.Public);
            for (DomainRouterJoinVO router : routerJoinVOS) {
                IpAddressTO ip = null;
                if (router.getTrafficType() == TrafficType.Guest && privateMtu != null) {
                    ip = new IpAddressTO(router.getIpAddress(), privateMtu, router.getNetmask());
                    ip.setTrafficType(TrafficType.Guest);
                } else if (router.getTrafficType() == TrafficType.Public && publicMtu != null) {
                    ip = new IpAddressTO(router.getIpAddress(), publicMtu, router.getNetmask());
                    ip.setTrafficType(TrafficType.Public);
                }
                if (ip != null) {
                    ips.add(ip);
                }
            }
            if (network.getGuestType() == GuestType.Isolated && network.getVpcId() == null && publicMtu != null) {
                List<IPAddressVO> addrs = _ipAddressDao.listByNetworkId(networkId);
                for(IPAddressVO addr : addrs) {
                    VlanVO vlan = _vlanDao.findById(addr.getVlanId());
                    IpAddressTO to = new IpAddressTO(addr.getAddress().addr(), publicMtu, vlan.getVlanNetmask());
                    ips.add(to);
                }
            }
            if (!ips.isEmpty()) {
                routersToIpList.put(routerVO.getId(), ips);
            }
        }

        if (!routersToIpList.isEmpty() && !restartNetwork) {
            boolean success = updateMtuOnVr(routersToIpList);
            if (success) {
                updateNetworkDetails(routersToIpList, network, publicMtu, privateMtu);
            } else {
                throw new CloudRuntimeException("Failed to update MTU on the network");
            }
        }

        ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount);
        // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate
        // states - Shutdown and Implementing
        int resourceCount = 1;
        if (updateInSequence && restartNetwork && _networkOfferingDao.findById(network.getNetworkOfferingId()).isRedundantRouter()
                && (networkOfferingId == null || _networkOfferingDao.findById(networkOfferingId).isRedundantRouter()) && network.getVpcId() == null) {
            _networkMgr.canUpdateInSequence(network, forced);
            NetworkDetailVO networkDetail = new NetworkDetailVO(network.getId(), Network.updatingInSequence, "true", true);
            _networkDetailsDao.persist(networkDetail);
            _networkMgr.configureUpdateInSequence(network);
            resourceCount = _networkMgr.getResourceCount(network);
        }
        List<String> servicesNotInNewOffering = null;
        if (networkOfferingId != null) {
            servicesNotInNewOffering = _networkMgr.getServicesNotSupportedInNewOffering(network, networkOfferingId);
        }
        if (!forced && servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) {
            NetworkOfferingVO newOffering = _networkOfferingDao.findById(networkOfferingId);
            throw new CloudRuntimeException("The new offering:" + newOffering.getUniqueName() + " will remove the following services " + servicesNotInNewOffering
                    + "along with all the related configuration currently in use. will not proceed with the network update." + "set forced parameter to true for forcing an update.");
        }
        try {
            if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) {
                _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network);
            }
        } catch (Exception e) { // old pokemon catch that used to catch throwable
            logger.debug("failed to cleanup config related to unused services error:" + e.getMessage());
        }

        boolean validStateToShutdown = (network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup || network.getState() == Network.State.Allocated);
        try {

            do {
                if (restartNetwork) {
                    if (validStateToShutdown) {
                        if (!changeCidr) {
                            logger.debug("Shutting down elements and resources for network {} as a part of network update", network);

                            if (!_networkMgr.shutdownNetworkElementsAndResources(context, true, network)) {
                                logger.warn("Failed to shutdown the network elements and resources as a part of network restart: " + network);
                                CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network elements and resources as a part of update to network of specified id");
                                ex.addProxyObject(network.getUuid(), "networkId");
                                throw ex;
                            }
                        } else {
                            // We need to shutdown the network, since we want to re-implement the network.
                            logger.debug("Shutting down network {} as a part of network update", network);

                            //check if network has reservation
                            if (NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr())) {
                                logger.warn("Existing IP reservation will become ineffective for the network {} You need to reapply reservation after network reimplementation.", network);
                                //set cidr to the network cidr
                                network.setCidr(network.getNetworkCidr());
                                //set networkCidr to null to bring network back to no IP reservation state
                                network.setNetworkCidr(null);
                            }

                            if (!_networkMgr.shutdownNetwork(network.getId(), context, true)) {
                                logger.warn("Failed to shutdown the network as a part of update to network with specified id");
                                CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network as a part of update of specified network id");
                                ex.addProxyObject(network.getUuid(), "networkId");
                                throw ex;
                            }
                        }
                    } else {
                        CloudRuntimeException ex = new CloudRuntimeException(
                                "Failed to shutdown the network elements and resources as a part of update to network with specified id; network is in wrong state: " + network.getState());
                        ex.addProxyObject(network.getUuid(), "networkId");
                        throw ex;
                    }
                }

                // 2) Only after all the elements and rules are shutdown properly, update the network VO
                // get updated network
                Network.State networkState = _networksDao.findById(networkId).getState();
                boolean validStateToImplement = (networkState == Network.State.Implemented || networkState == Network.State.Setup || networkState == Network.State.Allocated);
                if (restartNetwork && !validStateToImplement) {
                    CloudRuntimeException ex = new CloudRuntimeException(
                            "Failed to implement the network elements and resources as a part of update to network with specified id; network is in wrong state: " + networkState);
                    ex.addProxyObject(network.getUuid(), "networkId");
                    throw ex;
                }

                if (networkOfferingId != null) {
                    if (networkOfferingChanged) {
                        Transaction.execute(new TransactionCallbackNoReturn() {
                            @Override
                            public void doInTransactionWithoutResult(TransactionStatus status) {
                                updateNetworkIpv6(network, networkOfferingId);
                                network.setNetworkOfferingId(networkOfferingId);
                                _networksDao.update(networkId, network, newSvcProviders);
                                // get all nics using this network
                                // log remove usage events for old offering
                                // log assign usage events for new offering
                                List<NicVO> nics = _nicDao.listByNetworkId(networkId);
                                for (NicVO nic : nics) {
                                    if (Nic.ReservationStrategy.PlaceHolder.equals(nic.getReservationStrategy())) {
                                        continue;
                                    }
                                    long vmId = nic.getInstanceId();
                                    VMInstanceVO vm = _vmDao.findById(vmId);
                                    if (vm == null) {
                                        logger.error("Vm for nic {} not found with Vm Id: {}", nic, vmId);
                                        continue;
                                    }
                                    long isDefault = (nic.isDefaultNic()) ? 1 : 0;
                                    String nicIdString = Long.toString(nic.getId());
                                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, oldNetworkOfferingId,
                                            null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay());
                                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, networkOfferingId,
                                            null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay());
                                }
                            }
                        });
                    } else {
                        network.setNetworkOfferingId(networkOfferingId);
                        _networksDao.update(networkId, network,
                                _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId()));
                    }
                } else {
                    _networksDao.update(networkId, network);
                }

                // 3) Implement the elements and rules again
                if (restartNetwork) {
                    if (network.getState() != Network.State.Allocated) {
                        DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null);
                        logger.debug("Implementing the network " + network + " elements and resources as a part of network update");
                        try {
                            if (!changeCidr) {
                                _networkMgr.implementNetworkElementsAndResources(dest, context, network, _networkOfferingDao.findById(network.getNetworkOfferingId()));
                            } else {
                                _networkMgr.implementNetwork(network.getId(), dest, context);
                            }
                        } catch (Exception ex) {
                            logger.warn("Failed to implement network " + network + " elements and resources as a part of network update due to ", ex);
                            CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of network update");
                            e.addProxyObject(network.getUuid(), "networkId");
                            throw e;
                        }
                    }
                    if (networkOfferingChanged) {
                        replugNicsForUpdatedNetwork(network);
                    }
                }

                // 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering,
                // implement the network if its not already
                if (networkOfferingChanged && !oldNtwkOff.isPersistent() && networkOffering.isPersistent()) {
                    if (network.getState() == Network.State.Allocated) {
                        try {
                            DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null);
                            _networkMgr.implementNetwork(network.getId(), dest, context);
                        } catch (Exception ex) {
                            logger.warn("Failed to implement network " + network + " elements and resources as a part o" + "f network update due to ", ex);
                            CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified" + " id) elements and resources as a part of network update");
                            e.addProxyObject(network.getUuid(), "networkId");
                            throw e;
                        }
                    }
                }
                resourceCount--;
            } while (updateInSequence && resourceCount > 0);
        } catch (Exception exception) {
            if (updateInSequence) {
                _networkMgr.finalizeUpdateInSequence(network, false);
            }
            throw new CloudRuntimeException("failed to update network " + network.getUuid() + " due to " + exception.getMessage(), exception);
        } finally {
            if (updateInSequence) {
                if (_networkDetailsDao.findDetail(networkId, Network.updatingInSequence) != null) {
                    _networkDetailsDao.removeDetail(networkId, Network.updatingInSequence);
                }
            }
        }
        Network updatedNetwork = getNetwork(network.getId());
        UsageEventUtils.publishNetworkUpdate(updatedNetwork);
        return updatedNetwork;
    }