diff --git a/lib/backend.py b/lib/backend.py index 51a06bbfaa3e28d3df162bf72f83e725ac674b8d..48cfde0b9c253bb63a80444b8ace4d1322aba768 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -1519,6 +1519,34 @@ def GetMigrationStatus(instance): except Exception, err: # pylint: disable=W0703 _Fail("Failed to get migration status: %s", err, exc=True) +def HotAddDisk(instance, disk, dev_path, seq): + """Hot add a nic + + """ + hyper = hypervisor.GetHypervisor(instance.hypervisor) + return hyper.HotAddDisk(instance, disk, dev_path, seq) + +def HotDelDisk(instance, disk, seq): + """Hot add a nic + + """ + hyper = hypervisor.GetHypervisor(instance.hypervisor) + return hyper.HotDelDisk(instance, disk, seq) + +def HotAddNic(instance, nic, seq): + """Hot add a nic + + """ + hyper = hypervisor.GetHypervisor(instance.hypervisor) + return hyper.HotAddNic(instance, nic, seq) + +def HotDelNic(instance, nic, seq): + """Hot add a nic + + """ + hyper = hypervisor.GetHypervisor(instance.hypervisor) + return hyper.HotDelNic(instance, nic, seq) + def BlockdevCreate(disk, size, owner, on_primary, info): """Creates a block device for an instance. diff --git a/lib/rpc.py b/lib/rpc.py index 136532ff5a290880c0e3b8abfa92a84723a1b3cf..cceebe29fc2912effca577b3f006aeeb4731a495 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -35,6 +35,7 @@ import zlib import base64 import pycurl import threading +import copy from ganeti import utils from ganeti import objects @@ -663,6 +664,7 @@ class RpcRunner(_RpcClientBase, rpc_defs.ED_INST_DICT: self._InstDict, rpc_defs.ED_INST_DICT_HVP_BEP: self._InstDictHvpBep, rpc_defs.ED_INST_DICT_OSP_DP: self._InstDictOspDp, + rpc_defs.ED_NIC_DICT: self._NicDict, # Encoders annotating disk parameters rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP, @@ -688,6 +690,13 @@ class RpcRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly.__init__(self) _generated_rpc.RpcClientDefault.__init__(self) + def _NicDict(self, nic): + """Convert the given nic to a dict and encapsulate netinfo + + """ + n = copy.deepcopy(nic) + return n.ToDict() + def _InstDict(self, instance, hvp=None, bep=None, osp=None): """Convert the given instance to a dict. diff --git a/lib/rpc_defs.py b/lib/rpc_defs.py index 2e8841b430261b94344ffbdec54ab2b293415efa..965d968d5610d567c179b81f72c061c4b9a8d6e9 100644 --- a/lib/rpc_defs.py +++ b/lib/rpc_defs.py @@ -73,7 +73,8 @@ ACCEPT_OFFLINE_NODE = object() ED_COMPRESS, ED_BLOCKDEV_RENAME, ED_DISKS_DICT_DP, - ED_SINGLE_DISK_DICT_DP) = range(1, 14) + ED_SINGLE_DISK_DICT_DP, + ED_NIC_DICT) = range(1, 15) def _Prepare(calls): @@ -274,6 +275,27 @@ _INSTANCE_CALLS = [ ("reinstall", None, None), ("debug", None, None), ], None, None, "Starts an instance"), + ("hot_add_nic", SINGLE, None, TMO_NORMAL, [ + ("instance", ED_INST_DICT, "Instance object"), + ("nic", ED_NIC_DICT, "Nic dict to hotplug"), + ("seq", None, "Nic seq to hotplug"), + ], None, None, "Adds a nic to a running instance"), + ("hot_del_nic", SINGLE, None, TMO_NORMAL, [ + ("instance", ED_INST_DICT, "Instance object"), + ("nic", ED_NIC_DICT, "nic dict to remove"), + ("seq", None, "Nic seq to hotplug"), + ], None, None, "Removes a nic to a running instance"), + ("hot_add_disk", SINGLE, None, TMO_NORMAL, [ + ("instance", ED_INST_DICT, "Instance object"), + ("disk", ED_OBJECT_DICT, "Disk dict to hotplug"), + ("dev_path", None, "Device path"), + ("seq", None, "Disk seq to hotplug"), + ], None, None, "Adds a nic to a running instance"), + ("hot_del_disk", SINGLE, None, TMO_NORMAL, [ + ("instance", ED_INST_DICT, "Instance object"), + ("disk", ED_OBJECT_DICT, "Disk dict to remove"), + ("seq", None, "Disk seq to hotplug"), + ], None, None, "Removes a nic to a running instance"), ] _IMPEXP_CALLS = [ diff --git a/lib/server/noded.py b/lib/server/noded.py index d95680a55655827b119abd7b0bc1887ed75cd375..1f3de35b8ead9e5fb675d71aad080d3ed5f81a6a 100644 --- a/lib/server/noded.py +++ b/lib/server/noded.py @@ -558,6 +558,50 @@ class NodeRequestHandler(http.server.HttpServerHandler): instance = objects.Instance.FromDict(instance_name) return backend.StartInstance(instance, startup_paused) + @staticmethod + def perspective_hot_add_disk(params): + """Hotplugs a nic to a running instance. + + """ + (idict, ddict, dev_path, seq) = params + logging.info("%s %s", idict, ddict) + instance = objects.Instance.FromDict(idict) + disk = objects.Disk.FromDict(ddict) + return backend.HotAddDisk(instance, disk, dev_path, seq) + + @staticmethod + def perspective_hot_del_disk(params): + """Hotplugs a nic to a running instance. + + """ + (idict, ddict, seq) = params + logging.info("%s %s", idict, ddict) + instance = objects.Instance.FromDict(idict) + disk = objects.Disk.FromDict(ddict) + return backend.HotDelDisk(instance, disk, seq) + + @staticmethod + def perspective_hot_add_nic(params): + """Hotplugs a nic to a running instance. + + """ + (idict, ndict, seq) = params + logging.info("%s %s", idict, ndict) + instance = objects.Instance.FromDict(idict) + nic = objects.NIC.FromDict(ndict) + return backend.HotAddNic(instance, nic, seq) + + @staticmethod + def perspective_hot_del_nic(params): + """Hotplugs a nic to a running instance. + + """ + (idict, ndict, seq) = params + logging.info("%s %s", idict, ndict) + instance = objects.Instance.FromDict(idict) + nic = objects.NIC.FromDict(ndict) + return backend.HotDelNic(instance, nic, seq) + @staticmethod def perspective_migration_info(params): """Gather information about an instance to be migrated.