diff --git a/include/Attribute.h b/include/Attribute.h index eebef005ab..4852f44ea9 100644 --- a/include/Attribute.h +++ b/include/Attribute.h @@ -459,8 +459,8 @@ public: void replace(const string& name, const string& value); /** - * Removes given the vector attribute - * @param name of the vector attribute + * Removes the given attribute from the vector + * @param name of the attribute */ void remove(const string& name); diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 38d6afa119..01d52a1847 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -847,6 +847,19 @@ public: previous_history->req_id = rid; }; + /** + * Release the previous VNC port when a VM is migrated to another cluster + * (GRAPHICS/PREVIOUS_PORT present) + */ + void release_previous_vnc_port(); + + /** + * Frees current PORT from **current** cluster and sets it to PREVIOUS_PORT + * (which is allocated in previous cluster). This function is called when + * the migration fails. + */ + void rollback_previous_vnc_port(); + // ------------------------------------------------------------------------ // Template & Object Representation // ------------------------------------------------------------------------ diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index c7516e8e6c..d823cec65a 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -334,6 +334,8 @@ void LifeCycleManager::migrate_action(const LCMAction& la) if ( vm->get_hid() != vm->get_previous_hid() ) { hpool->del_capacity(vm->get_previous_hid(), sr); + + vm->release_previous_vnc_port(); } vm->set_stime(the_time); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 14afda474b..8761fb753e 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -54,6 +54,8 @@ void LifeCycleManager::start_prolog_migrate(VirtualMachine* vm) if ( vm->get_hid() != vm->get_previous_hid() ) { hpool->del_capacity(vm->get_previous_hid(), sr); + + vm->release_previous_vnc_port(); } vmpool->update(vm); @@ -84,6 +86,8 @@ void LifeCycleManager::revert_migrate_after_failure(VirtualMachine* vm) if ( vm->get_hid() != vm->get_previous_hid() ) { hpool->del_capacity(vm->get_hid(), sr); + + vm->rollback_previous_vnc_port(); } vm->set_previous_etime(the_time); @@ -261,6 +265,8 @@ void LifeCycleManager::deploy_success_action(int vid) hpool->del_capacity(vm->get_previous_hid(), sr); + vm->release_previous_vnc_port(); + vm->set_state(VirtualMachine::RUNNING); if ( !vmm->is_keep_snapshots(vm->get_vmm_mad()) ) @@ -349,6 +355,8 @@ void LifeCycleManager::deploy_failure_action(int vid) hpool->del_capacity(vm->get_hid(), sr); + vm->rollback_previous_vnc_port(); + // --- Add new record by copying the previous one vm->cp_previous_history(); diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 8e8059559c..ffcea5dac1 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -746,6 +746,52 @@ int set_vnc_port(VirtualMachine *vm, int cluster_id, RequestAttributes& att) return rc; } + +static int set_migrate_vnc_port(VirtualMachine *vm, int cluster_id, bool keep) +{ + ClusterPool * cpool = Nebula::instance().get_clpool(); + + VectorAttribute * graphics = vm->get_template_attribute("GRAPHICS"); + + unsigned int previous_port; + unsigned int port; + + int rc; + + // Do not update VM if no GRAPHICS or GRAPHICS/PORT defined + if (graphics == nullptr) + { + return 0; + } + + if (graphics->vector_value("PORT", previous_port) != 0) + { + return 0; + } + + //live migrations need to keep VNC port + if (keep) + { + rc = cpool->set_vnc_port(cluster_id, previous_port); + + port = previous_port; + } + else + { + rc = cpool->get_vnc_port(cluster_id, vm->get_oid(), port); + } + + if ( rc != 0 ) + { + return -1; + } + + graphics->replace("PREVIOUS_PORT", previous_port); + graphics->replace("PORT", port); + + return 0; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -1067,6 +1113,7 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList PoolObjectAuth * auth_ds_perms; int c_hid; + int c_cluster_id; int c_ds_id; string c_tm_mad, tm_mad; bool c_is_public_cloud; @@ -1286,6 +1333,7 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList } c_is_public_cloud = host->is_public_cloud(); + c_cluster_id = host->get_cluster_id(); host->unlock(); @@ -1384,7 +1432,8 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList { ostringstream oss; - oss << "Cannot migrate VM [" << id << "] to host [" << hid << "] and system datastore [" << ds_id << "]. Host is in cluster [" + oss << "Cannot migrate VM [" << id << "] to host [" << hid + << "] and system datastore [" << ds_id << "]. Host is in cluster [" << cluster_id << "], and the datastore is in cluster [" << one_util::join(ds_cluster_ids, ',') << "]"; @@ -1396,6 +1445,22 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList return; } + // ------------------------------------------------------------------------- + // Request a new VNC port in the new cluster + // ------------------------------------------------------------------------- + if ( c_cluster_id != cluster_id ) + { + if ( set_migrate_vnc_port(vm, cluster_id, live) == -1 ) + { + att.resp_msg = "No free VNC port available in the new cluster"; + failure_response(ACTION, att); + + vm->unlock(); + + return; + } + } + // ------------------------------------------------------------------------ // Add a new history record and update volatile DISK attributes // ------------------------------------------------------------------------ @@ -1420,7 +1485,7 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList // Migrate the VM // ------------------------------------------------------------------------ - if (live == true && vm->get_lcm_state() == VirtualMachine::RUNNING ) + if (live && vm->get_lcm_state() == VirtualMachine::RUNNING ) { dm->live_migrate(vm, att); } diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 1b46be5962..ba1ec37396 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -3657,3 +3657,49 @@ void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void VirtualMachine::release_previous_vnc_port() +{ + ClusterPool * cpool = Nebula::instance().get_clpool(); + + VectorAttribute * graphics = get_template_attribute("GRAPHICS"); + + unsigned int previous_port; + + if (graphics == nullptr || + graphics->vector_value("PREVIOUS_PORT", previous_port) != 0) + { + return; + } + + cpool->release_vnc_port(previous_history->cid, previous_port); + + graphics->remove("PREVIOUS_PORT"); +}; + +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::rollback_previous_vnc_port() +{ + ClusterPool * cpool = Nebula::instance().get_clpool(); + + VectorAttribute * graphics = get_template_attribute("GRAPHICS"); + + unsigned int previous_port; + unsigned int port; + + if (graphics == nullptr || + graphics->vector_value("PREVIOUS_PORT", previous_port) != 0) + { + return; + } + + if ( graphics->vector_value("PORT", port) == 0 ) + { + cpool->release_vnc_port(history->cid, port); + } + + graphics->replace("PORT", previous_port); + + graphics->remove("PREVIOUS_PORT"); +}; +