add pause/resume/memory hotplug
This commit is contained in:
parent
253df30371
commit
0d2a18d1f3
14
README.md
14
README.md
@ -12,9 +12,9 @@ Run `make serve-docs`. See [Development](#development) below.
|
|||||||
- [ ] CDROM
|
- [ ] CDROM
|
||||||
- [ ] cloud-init for provisioning instances
|
- [ ] cloud-init for provisioning instances
|
||||||
- [x] Instance power management
|
- [x] Instance power management
|
||||||
- [ ] Instance pause and resume
|
- [x] Instance pause and resume
|
||||||
- [x] vCPU hotplug
|
- [x] vCPU hotplug
|
||||||
- [ ] Memory hotplug
|
- [x] Memory hotplug
|
||||||
- [x] Hot disk resize [not tested]
|
- [x] Hot disk resize [not tested]
|
||||||
- [ ] CPU topology customization
|
- [ ] CPU topology customization
|
||||||
- [x] CPU customization (emulation mode, model, vendor, features)
|
- [x] CPU customization (emulation mode, model, vendor, features)
|
||||||
@ -27,18 +27,18 @@ Run `make serve-docs`. See [Development](#development) below.
|
|||||||
- [ ] Instance resources usage stats
|
- [ ] Instance resources usage stats
|
||||||
- [ ] SSH-keys management
|
- [ ] SSH-keys management
|
||||||
- [x] Setting user passwords in guest [not tested]
|
- [x] Setting user passwords in guest [not tested]
|
||||||
- [ ] LXC
|
|
||||||
- [x] QCOW2 disks support
|
- [x] QCOW2 disks support
|
||||||
- [ ] ZVOL support
|
- [ ] ZVOL support
|
||||||
- [ ] Network disks support
|
- [ ] Network disks support
|
||||||
- [ ] Images service integration (Images service is not implemented yet)
|
- [ ] Images service integration (Images service is not implemented yet)
|
||||||
- [ ] Manage storage pools
|
- [ ] Manage storage pools
|
||||||
|
- [ ] Idempotency
|
||||||
|
- [ ] CLI [in progress]
|
||||||
|
- [ ] HTTP API
|
||||||
|
- [ ] Instance migrations
|
||||||
- [ ] Instance snapshots
|
- [ ] Instance snapshots
|
||||||
- [ ] Instance backups
|
- [ ] Instance backups
|
||||||
- [ ] Instance migrations
|
- [ ] LXC
|
||||||
- [ ] Idempotency
|
|
||||||
- [ ] HTTP API
|
|
||||||
- [ ] CLI [in progress]
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
@ -219,12 +219,21 @@ def main(session: Session, args: argparse.Namespace) -> None:
|
|||||||
case 'reset':
|
case 'reset':
|
||||||
instance = session.get_instance(args.instance)
|
instance = session.get_instance(args.instance)
|
||||||
instance.reset()
|
instance.reset()
|
||||||
|
case 'pause':
|
||||||
|
instance = session.get_instance(args.instance)
|
||||||
|
instance.pause()
|
||||||
|
case 'resume':
|
||||||
|
instance = session.get_instance(args.instance)
|
||||||
|
instance.resume()
|
||||||
case 'status':
|
case 'status':
|
||||||
instance = session.get_instance(args.instance)
|
instance = session.get_instance(args.instance)
|
||||||
print(instance.status)
|
print(instance.status)
|
||||||
case 'setvcpus':
|
case 'setvcpus':
|
||||||
instance = session.get_instance(args.instance)
|
instance = session.get_instance(args.instance)
|
||||||
instance.set_vcpus(args.nvcpus, live=True)
|
instance.set_vcpus(args.nvcpus, live=True)
|
||||||
|
case 'setmem':
|
||||||
|
instance = session.get_instance(args.instance)
|
||||||
|
instance.set_memory(args.memory, live=True)
|
||||||
|
|
||||||
|
|
||||||
def cli() -> None: # noqa: PLR0915
|
def cli() -> None: # noqa: PLR0915
|
||||||
@ -352,6 +361,14 @@ def cli() -> None: # noqa: PLR0915
|
|||||||
reset = subparsers.add_parser('reset', help='reset instance')
|
reset = subparsers.add_parser('reset', help='reset instance')
|
||||||
reset.add_argument('instance')
|
reset.add_argument('instance')
|
||||||
|
|
||||||
|
# pause subcommand
|
||||||
|
pause = subparsers.add_parser('pause', help='pause instance')
|
||||||
|
pause.add_argument('instance')
|
||||||
|
|
||||||
|
# resume subcommand
|
||||||
|
resume = subparsers.add_parser('resume', help='resume paused instance')
|
||||||
|
resume.add_argument('instance')
|
||||||
|
|
||||||
# status subcommand
|
# status subcommand
|
||||||
status = subparsers.add_parser('status', help='display instance status')
|
status = subparsers.add_parser('status', help='display instance status')
|
||||||
status.add_argument('instance')
|
status.add_argument('instance')
|
||||||
@ -361,6 +378,11 @@ def cli() -> None: # noqa: PLR0915
|
|||||||
setvcpus.add_argument('instance')
|
setvcpus.add_argument('instance')
|
||||||
setvcpus.add_argument('nvcpus', type=int)
|
setvcpus.add_argument('nvcpus', type=int)
|
||||||
|
|
||||||
|
# setmem subcommand
|
||||||
|
setmem = subparsers.add_parser('setmem', help='set memory size')
|
||||||
|
setmem.add_argument('instance')
|
||||||
|
setmem.add_argument('memory', type=int, help='memory in MiB')
|
||||||
|
|
||||||
# Run parser
|
# Run parser
|
||||||
args = root.parse_args()
|
args = root.parse_args()
|
||||||
if args.command is None:
|
if args.command is None:
|
||||||
|
@ -218,13 +218,13 @@ class Instance:
|
|||||||
|
|
||||||
def get_info(self) -> InstanceInfo:
|
def get_info(self) -> InstanceInfo:
|
||||||
"""Return instance info."""
|
"""Return instance info."""
|
||||||
_info = self.domain.info()
|
info = self.domain.info()
|
||||||
return InstanceInfo(
|
return InstanceInfo(
|
||||||
state=self._expand_instance_state(_info[0]),
|
state=self._expand_instance_state(info[0]),
|
||||||
max_memory=_info[1],
|
max_memory=info[1],
|
||||||
memory=_info[2],
|
memory=info[2],
|
||||||
nproc=_info[3],
|
nproc=info[3],
|
||||||
cputime=_info[4],
|
cputime=info[4],
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_status(self) -> str:
|
def get_status(self) -> str:
|
||||||
@ -405,10 +405,10 @@ class Instance:
|
|||||||
:param nvcpus: Number of vCPUs
|
:param nvcpus: Number of vCPUs
|
||||||
:param live: Affect a running instance
|
:param live: Affect a running instance
|
||||||
"""
|
"""
|
||||||
if nvcpus == 0:
|
if nvcpus <= 0:
|
||||||
raise InstanceError(
|
raise InstanceError('Cannot set zero vCPUs')
|
||||||
f'Cannot set zero vCPUs for instance={self.name}'
|
if nvcpus > self.get_max_vcpus():
|
||||||
)
|
raise InstanceError('vCPUs count is greather than max_vcpus')
|
||||||
if nvcpus == self.get_info().nproc:
|
if nvcpus == self.get_info().nproc:
|
||||||
log.warning(
|
log.warning(
|
||||||
'Instance instance=%s already have %s vCPUs, nothing to do',
|
'Instance instance=%s already have %s vCPUs, nothing to do',
|
||||||
@ -461,11 +461,18 @@ class Instance:
|
|||||||
:param memory: Memory value in mebibytes
|
:param memory: Memory value in mebibytes
|
||||||
:param live: Affect a running instance
|
:param live: Affect a running instance
|
||||||
"""
|
"""
|
||||||
if memory == 0:
|
if memory <= 0:
|
||||||
raise InstanceError(
|
raise InstanceError('Cannot set zero memory')
|
||||||
f'Cannot set zero memory for instance={self.name}'
|
if (memory * 1024) > self.get_max_memory():
|
||||||
|
raise InstanceError('Memory is greather than max_memory')
|
||||||
|
if (memory * 1024) == self.get_info().memory:
|
||||||
|
log.warning(
|
||||||
|
"Instance '%s' already have %s memory, nothing to do",
|
||||||
|
self.name,
|
||||||
|
memory,
|
||||||
)
|
)
|
||||||
if live and self.info()['state'] == libvirt.VIR_DOMAIN_RUNNING:
|
return
|
||||||
|
if live and self.is_running():
|
||||||
flags = (
|
flags = (
|
||||||
libvirt.VIR_DOMAIN_AFFECT_LIVE
|
libvirt.VIR_DOMAIN_AFFECT_LIVE
|
||||||
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
||||||
@ -473,9 +480,6 @@ class Instance:
|
|||||||
else:
|
else:
|
||||||
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
||||||
try:
|
try:
|
||||||
self.domain.setMemoryFlags(
|
|
||||||
memory * 1024, flags=libvirt.VIR_DOMAIN_MEM_MAXIMUM
|
|
||||||
)
|
|
||||||
self.domain.setMemoryFlags(memory * 1024, flags=flags)
|
self.domain.setMemoryFlags(memory * 1024, flags=flags)
|
||||||
except libvirt.libvirtError as e:
|
except libvirt.libvirtError as e:
|
||||||
msg = f'Cannot set memory for instance={self.name} {memory=}: {e}'
|
msg = f'Cannot set memory for instance={self.name} {memory=}: {e}'
|
||||||
@ -535,11 +539,13 @@ class Instance:
|
|||||||
|
|
||||||
def pause(self) -> None:
|
def pause(self) -> None:
|
||||||
"""Pause instance."""
|
"""Pause instance."""
|
||||||
raise NotImplementedError
|
if not self.is_running():
|
||||||
|
raise InstanceError('Cannot pause inactive instance')
|
||||||
|
self.domain.suspend()
|
||||||
|
|
||||||
def resume(self) -> None:
|
def resume(self) -> None:
|
||||||
"""Resume paused instance."""
|
"""Resume paused instance."""
|
||||||
raise NotImplementedError
|
self.domain.resume()
|
||||||
|
|
||||||
def list_ssh_keys(self, user: str) -> list[str]:
|
def list_ssh_keys(self, user: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
|
@ -44,7 +44,7 @@ select = ['ALL']
|
|||||||
ignore = [
|
ignore = [
|
||||||
'Q000', 'Q003', 'D211', 'D212', 'ANN101', 'ISC001', 'COM812',
|
'Q000', 'Q003', 'D211', 'D212', 'ANN101', 'ISC001', 'COM812',
|
||||||
'D203', 'ANN204', 'T201',
|
'D203', 'ANN204', 'T201',
|
||||||
'EM102', 'TRY003', # maybe not ignore?
|
'EM102', 'TRY003', 'EM101', # maybe not ignore?
|
||||||
'TD003', 'TD006', 'FIX002', # todo strings linting
|
'TD003', 'TD006', 'FIX002', # todo strings linting
|
||||||
]
|
]
|
||||||
exclude = ['__init__.py']
|
exclude = ['__init__.py']
|
||||||
|
Loading…
Reference in New Issue
Block a user