private void releaseNetworkServices( final VmInstanceSpec spec, NetworkServiceExtensionPosition position, final NoErrorCompletion completion) { if (!spec.getVmInventory().getType().equals(VmInstanceConstant.USER_VM_TYPE)) { completion.done(); return; } if (nsExts.isEmpty()) { completion.done(); return; } // we run into this situation when VM nics are all detached and the // VM is being rebooted if (spec.getDestNics().isEmpty()) { completion.done(); return; } List<String> nsTypes = spec.getRequiredNetworkServiceTypes(); FlowChain schain = FlowChainBuilder.newSimpleFlowChain() .setName( String.format( "release-network-services-from-vm-%s", spec.getVmInventory().getUuid())); schain.allowEmptyFlow(); for (final NetworkServiceExtensionPoint ns : nsExts) { if (position != null && ns.getNetworkServiceExtensionPosition() != position) { continue; } if (!nsTypes.contains(ns.getNetworkServiceType().toString())) { continue; } NoRollbackFlow flow = new NoRollbackFlow() { String __name__ = String.format("release-network-service-%s", ns.getNetworkServiceType()); @Override public void run(final FlowTrigger chain, Map data) { logger.debug( String.format( "NetworkServiceExtensionPoint[%s] is asking back ends to release network service[%s] if needed", ns.getClass().getName(), ns.getNetworkServiceType())); ns.releaseNetworkService( spec, data, new NoErrorCompletion() { @Override public void done() { chain.next(); } }); } }; schain.then(flow); } schain .done( new FlowDoneHandler(completion) { @Override public void handle(Map data) { logger.debug( String.format( "successfully released network services for vm[uuid:%s, name:%s]", spec.getVmInventory().getUuid(), spec.getVmInventory().getName())); completion.done(); } }) .start(); }