core3: move qmemman

This is part of fixing qvm-start.

qmemman was moved with minimal touching, mainly module names.

Moved function parsing human-readable sizes from core2. This function is
wrong, because it treats k/M/G as 1024-based, but leave it for now.
This commit is contained in:
Wojtek Porczyk 2015-10-01 22:14:35 +02:00
parent fcdb579bab
commit c538d536c8
14 changed files with 142 additions and 160 deletions

View File

@ -41,14 +41,12 @@ rpms-dom0:
clean:
make -C dispvm clean
make -C qmemman clean
all:
python setup.py build
# make all -C tests
# Currently supported only on xen
ifeq ($(BACKEND_VMM),xen)
make all -C qmemman
make all -C dispvm
endif
@ -63,7 +61,8 @@ endif
$(MAKE) install -C relaxng
ifeq ($(BACKEND_VMM),xen)
# Currently supported only on xen
$(MAKE) install -C qmemman
mkdir -p $(DESTDIR)/etc/qubes
cp etc/qmemman.conf $(DESTDIR)/etc/qubes/
endif
$(MAKE) install -C dispvm
mkdir -p $(DESTDIR)/etc/qubes-rpc/policy
@ -78,9 +77,11 @@ endif
cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/
cp qubes-rpc/qubes-notify-updates $(DESTDIR)/usr/libexec/qubes/
cp qubes-rpc/qubes-notify-tools $(DESTDIR)/usr/libexec/qubes/
mkdir -p "$(DESTDIR)$(FILESDIR)"
cp vm-config/$(BACKEND_VMM)-vm-template.xml "$(DESTDIR)$(FILESDIR)/vm-template.xml"
cp vm-config/$(BACKEND_VMM)-vm-template-hvm.xml "$(DESTDIR)$(FILESDIR)/vm-template-hvm.xml"
mkdir -p $(DESTDIR)$(DATADIR)
mkdir -p $(DESTDIR)$(DATADIR)/vm-templates
mkdir -p $(DESTDIR)$(DATADIR)/appvms

View File

@ -79,23 +79,6 @@ def size_to_human (size):
else:
return str(round(size/(1024.0*1024*1024),1)) + ' GiB'
def parse_size(size):
units = [ ('K', 1024), ('KB', 1024),
('M', 1024*1024), ('MB', 1024*1024),
('G', 1024*1024*1024), ('GB', 1024*1024*1024),
]
size = size.strip().upper()
if size.isdigit():
return int(size)
for unit, multiplier in units:
if size.endswith(unit):
size = size[:-len(unit)].strip()
return int(size)*multiplier
raise QubesException("Invalid size: {0}.".format(size))
def get_disk_usage_one(st):
try:
return st.st_blocks * BLKSIZE

View File

@ -11,3 +11,4 @@ install:
cp qubes-vm@.service $(DESTDIR)$(UNITDIR)
cp qubes-reload-firewall@.service $(DESTDIR)$(UNITDIR)
cp qubes-reload-firewall@.timer $(DESTDIR)$(UNITDIR)
cp qubes-qmemman.service $(DESTDIR)$(UNITDIR)

View File

@ -4,7 +4,7 @@ After=qubes-core.service
[Service]
Type=notify
ExecStart=/usr/lib/qubes/qmemman_daemon.py
ExecStart=/usr/bin/qmemmand
StandardOutput=syslog
[Install]

View File

@ -1,24 +0,0 @@
PYTHON_QUBESPATH = $(PYTHON_SITEPATH)/qubes
SYSCONFDIR ?= /etc
UNITDIR ?= /usr/lib/systemd/system
all:
python -m compileall .
python -O -m compileall .
clean:
rm -f *.pyo
install:
ifndef PYTHON_SITEPATH
$(error PYTHON_SITEPATH not defined)
endif
mkdir -p $(DESTDIR)$(PYTHON_QUBESPATH)
cp qmemman*py $(DESTDIR)$(PYTHON_QUBESPATH)
cp qmemman*py[co] $(DESTDIR)$(PYTHON_QUBESPATH)
mkdir -p $(DESTDIR)$(SYSCONFDIR)/qubes
cp qmemman.conf $(DESTDIR)$(SYSCONFDIR)/qubes/
mkdir -p $(DESTDIR)/usr/lib/qubes
cp server.py $(DESTDIR)/usr/lib/qubes/qmemman_daemon.py
mkdir -p $(DESTDIR)$(UNITDIR)
cp qubes-qmemman.service $(DESTDIR)$(UNITDIR)

View File

@ -1,23 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
from qubes.qmemman_server import QMemmanServer
QMemmanServer.main()

26
qmemman/qmemman.py → qubes/qmemman/__init__.py Executable file → Normal file
View File

@ -31,7 +31,7 @@ import xen.lowlevel.xc
import xen.lowlevel.xs
import qubes
import qubes.qmemman_algo
import qubes.qmemman.algo
no_progress_msg="VM refused to give back requested memory"
@ -102,14 +102,24 @@ class SystemState(object):
self.domdict[i].memory_actual <= self.domdict[i].last_target + self.XEN_FREE_MEM_LEFT/4:
dom_name = self.xs.read('', '/local/domain/%s/name' % str(i))
if dom_name is not None:
clear_error_qubes_manager(dom_name, slow_memset_react_msg)
try:
qubes.Qubes()[str(dom_name)].fire_event(
'status:no-error', 'no-error',
slow_memset_react_msg)
except LookupError:
pass
self.domdict[i].slow_memset_react = False
if self.domdict[i].no_progress and \
self.domdict[i].memory_actual <= self.domdict[i].last_target + self.XEN_FREE_MEM_LEFT/4:
dom_name = self.xs.read('', '/local/domain/%s/name' % str(i))
if dom_name is not None:
clear_error_qubes_manager(dom_name, no_progress_msg)
try:
qubes.Qubes()[str(dom_name)].fire_event(
'status:no-error', 'no-error',
no_progress_msg)
except LookupError:
pass
self.domdict[i].no_progress = False
#the below works (and is fast), but then 'xm list' shows unchanged memory value
@ -160,7 +170,7 @@ class SystemState(object):
#domain not responding to memset requests, remove it from donors
self.domdict[i].no_progress = True
self.log.info('domain {} stuck at {}'.format(i, self.domdict[i].memory_actual))
memset_reqs = qmemman_algo.balloon(memsize + self.XEN_FREE_MEM_LEFT - xenfree, self.domdict)
memset_reqs = qubes.qmemman.algo.balloon(memsize + self.XEN_FREE_MEM_LEFT - xenfree, self.domdict)
self.log.info('memset_reqs={!r}'.format(memset_reqs))
if niter > MAX_TRIES or len(memset_reqs) == 0:
return False
@ -178,7 +188,7 @@ class SystemState(object):
'refresh_meminfo(domid={}, untrusted_meminfo_key={!r})'.format(
domid, untrusted_meminfo_key))
qmemman_algo.refresh_meminfo_for_domain(
qubes.qmemman.algo.refresh_meminfo_for_domain(
self.domdict[domid], untrusted_meminfo_key)
self.do_balance()
@ -203,7 +213,7 @@ class SystemState(object):
last_target = self.domdict[dom].last_target
memory_change = mem - last_target
total_memory_transfer += abs(memory_change)
pref = qmemman_algo.prefmem(self.domdict[dom])
pref = qubes.qmemman.algo.prefmem(self.domdict[dom])
if last_target > 0 and last_target < pref and memory_change > MIN_MEM_CHANGE_WHEN_UNDER_PREF:
self.log.info(
@ -220,7 +230,7 @@ class SystemState(object):
if self.domdict[i].meminfo is not None:
self.log.info('stat: dom {!r} act={} pref={}'.format(i,
self.domdict[i].memory_actual,
qmemman_algo.prefmem(self.domdict[i])))
qubes.qmemman.algo.prefmem(self.domdict[i])))
self.log.info('stat: xenfree={} memset_reqs={}'.format(xenfree, memset_reqs))
@ -234,7 +244,7 @@ class SystemState(object):
self.refresh_memactual()
self.clear_outdated_error_markers()
xenfree = self.get_free_xen_memory()
memset_reqs = qmemman_algo.balance(xenfree - self.XEN_FREE_MEM_LEFT, self.domdict)
memset_reqs = qubes.qmemman.algo.balance(xenfree - self.XEN_FREE_MEM_LEFT, self.domdict)
if not self.is_balance_req_significant(memset_reqs, xenfree):
return

0
qmemman/qmemman_algo.py → qubes/qmemman/algo.py Executable file → Normal file
View File

0
qmemman/qmemman_client.py → qubes/qmemman/client.py Executable file → Normal file
View File

111
qmemman/qmemman_server.py → qubes/tools/qmemmand.py Executable file → Normal file
View File

@ -20,31 +20,29 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
import ConfigParser
import SocketServer
import thread
import time
import xen.lowlevel.xs
import sys
import os
import socket
from qmemman import SystemState
import qmemman_algo
from ConfigParser import SafeConfigParser
from optparse import OptionParser
from qubesutils import parse_size
import logging
import logging.handlers
import os
import socket
import sys
import thread
config_path = '/etc/qubes/qmemman.conf'
SOCK_PATH='/var/run/qubes/qmemman.sock'
LOG_PATH='/var/log/qubes/qmemman.log'
import xen.lowlevel.xs
system_state = SystemState()
import qubes.qmemman
import qubes.qmemman.algo
import qubes.utils
SOCK_PATH = '/var/run/qubes/qmemman.sock'
LOG_PATH = '/var/log/qubes/qmemman.log'
system_state = qubes.qmemman.SystemState()
global_lock = thread.allocate_lock()
def only_in_first_list(l1, l2):
ret=[]
ret = []
for i in l1:
if not i in l2:
ret.append(i)
@ -54,12 +52,12 @@ def get_domain_meminfo_key(domain_id):
return '/local/domain/'+domain_id+'/memory/meminfo'
class WatchType:
class WatchType(object):
def __init__(self, fn, param):
self.fn = fn
self.param = param
class XS_Watcher:
class XS_Watcher(object):
def __init__(self):
self.log = logging.getLogger('qmemman.daemon.xswatcher')
self.log.debug('XS_Watcher()')
@ -104,7 +102,8 @@ class XS_Watcher:
def meminfo_changed(self, domain_id):
self.log.debug('meminfo_changed(domain_id={!r})'.format(domain_id))
untrusted_meminfo_key = self.handle.read('', get_domain_meminfo_key(domain_id))
untrusted_meminfo_key = self.handle.read(
'', get_domain_meminfo_key(domain_id))
if untrusted_meminfo_key == None or untrusted_meminfo_key == '':
return
@ -171,12 +170,20 @@ class QMemmanReqHandler(SocketServer.BaseRequestHandler):
# XXX no release of lock?
def start_server(server):
server.serve_forever()
parser = qubes.tools.get_parser_base()
parser.add_argument('--config', '-c', metavar='FILE',
action='store', default='/etc/qubes/qmemman.conf',
help='qmemman config file')
parser.add_argument('--foreground',
action='store_true', default=False,
help='do not close stdio')
def main():
args = parser.parse_args()
class QMemmanServer:
@staticmethod
def main():
# setup logging
ha_syslog = logging.handlers.SysLogHandler('/dev/log')
ha_syslog.setFormatter(
@ -189,33 +196,41 @@ class QMemmanServer:
logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s'))
logging.root.addHandler(ha_file)
log = logging.getLogger('qmemman.daemon')
usage = "usage: %prog [options]"
parser = OptionParser(usage)
parser.add_option("-c", "--config", action="store", dest="config", default=config_path)
(options, args) = parser.parse_args()
if args.foreground:
ha_stderr = logging.StreamHandler(sys.stderr)
ha_file.setFormatter(
logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s'))
logging.root.addHandler(ha_stderr)
else:
# close io
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
config = SafeConfigParser({
'vm-min-mem': str(qmemman_algo.MIN_PREFMEM),
'dom0-mem-boost': str(qmemman_algo.DOM0_MEM_BOOST),
'cache-margin-factor': str(qmemman_algo.CACHE_FACTOR)
})
config.read(options.config)
if config.has_section('global'):
qmemman_algo.MIN_PREFMEM = parse_size(config.get('global', 'vm-min-mem'))
qmemman_algo.DOM0_MEM_BOOST = parse_size(config.get('global', 'dom0-mem-boost'))
qmemman_algo.CACHE_FACTOR = config.getfloat('global', 'cache-margin-factor')
sys.stdin.close()
log.info('MIN_PREFMEM={qmemman_algo.MIN_PREFMEM}'
' DOM0_MEM_BOOST={qmemman_algo.DOM0_MEM_BOOST}'
' CACHE_FACTOR={qmemman_algo.CACHE_FACTOR}'.format(
qmemman_algo=qmemman_algo))
logging.root.setLevel((args.quiet - args.verbose) * 10 + logging.WARNING)
log = logging.getLogger('qmemman.daemon')
config = ConfigParser.SafeConfigParser({
'vm-min-mem': str(qubes.qmemman.algo.MIN_PREFMEM),
'dom0-mem-boost': str(qubes.qmemman.algo.DOM0_MEM_BOOST),
'cache-margin-factor': str(qubes.qmemman.algo.CACHE_FACTOR)
})
config.read(args.config)
if config.has_section('global'):
qubes.qmemman.algo.MIN_PREFMEM = \
qubes.utils.parse_size(config.get('global', 'vm-min-mem'))
qubes.qmemman.algo.DOM0_MEM_BOOST = \
qubes.utils.parse_size(config.get('global', 'dom0-mem-boost'))
qubes.qmemman.algo.CACHE_FACTOR = \
config.getfloat('global', 'cache-margin-factor')
log.info('MIN_PREFMEM={algo.MIN_PREFMEM}'
' DOM0_MEM_BOOST={algo.DOM0_MEM_BOOST}'
' CACHE_FACTOR={algo.CACHE_FACTOR}'.format(
algo=qubes.qmemman.algo))
try:
os.unlink(SOCK_PATH)
@ -238,5 +253,5 @@ class QMemmanServer:
s.sendall("READY=1")
s.close()
thread.start_new_thread(start_server, tuple([server]))
thread.start_new_thread(server.serve_forever, ())
XS_Watcher().watch_loop()

View File

@ -82,3 +82,22 @@ def format_doc(docstring):
settings=None, settings_spec=None, settings_overrides=None,
config_section=None, enable_exit_status=None)
return pub.writer.document.astext()
# FIXME those are wrong, k/M/G are SI prefixes and means 10**3
# maybe adapt https://code.activestate.com/recipes/578019
def parse_size(size):
units = [ ('K', 1024), ('KB', 1024),
('M', 1024*1024), ('MB', 1024*1024),
('G', 1024*1024*1024), ('GB', 1024*1024*1024),
]
size = size.strip().upper()
if size.isdigit():
return int(size)
for unit, multiplier in units:
if size.endswith(unit):
size = size[:-len(unit)].strip()
return int(size)*multiplier
raise QubesException("Invalid size: {0}.".format(size))

View File

@ -188,6 +188,7 @@ fi
%config(noreplace) %attr(0664,root,qubes) %{_sysconfdir}/qubes/qmemman.conf
/usr/bin/qvm-*
/usr/bin/qubes-*
/usr/bin/qmemmand
%dir %{python_sitelib}/qubes-*.egg-info
%{python_sitelib}/qubes-*.egg-info/*
@ -221,6 +222,7 @@ fi
%dir %{python_sitelib}/qubes/tools
%{python_sitelib}/qubes/tools/__init__.py*
%{python_sitelib}/qubes/tools/qmemmand.py*
%{python_sitelib}/qubes/tools/qubes_create.py*
%{python_sitelib}/qubes/tools/qvm_create.py*
%{python_sitelib}/qubes/tools/qvm_ls.py*
@ -249,15 +251,13 @@ fi
%{python_sitelib}/qubes/tests/tools/init.py*
%{python_sitelib}/qubes/tests/tools/qvm_ls.py*
# qmemman
%{python_sitelib}/qubes/qmemman.py*
%{python_sitelib}/qubes/qmemman_algo.py*
%{python_sitelib}/qubes/qmemman_client.py*
%{python_sitelib}/qubes/qmemman_server.py*
%dir %{python_sitelib}/qubes/qmemman
%{python_sitelib}/qubes/qmemman/__init__.py*
%{python_sitelib}/qubes/qmemman/algo.py*
%{python_sitelib}/qubes/qmemman/client.py*
/usr/lib/qubes/unbind-pci-device.sh
/usr/lib/qubes/cleanup-dispvms
/usr/lib/qubes/qmemman_daemon.py*
/usr/lib/qubes/qfile-daemon-dvm*
/usr/lib/qubes/block-cleaner-daemon.py*
/usr/lib/qubes/vusb-ctl.py*