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