quick pass at small xen code cleanup and usage of double quotes

This commit is contained in:
Blake J. Harnden 2017-08-03 12:04:22 -07:00
parent bc1a24e880
commit 1f9a8879c1
2 changed files with 223 additions and 203 deletions

View file

@ -54,8 +54,7 @@ UDEVADM_PATH = "/sbin/udevadm"
class XenVEth(PyCoreNetIf): class XenVEth(PyCoreNetIf):
def __init__(self, node, name, localname, mtu=1500, net=None, def __init__(self, node, name, localname, mtu=1500, net=None, start=True, hwaddr=None):
start=True, hwaddr=None):
# note that net arg is ignored # note that net arg is ignored
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu) PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
self.localname = localname self.localname = localname
@ -65,10 +64,9 @@ class XenVEth(PyCoreNetIf):
self.startup() self.startup()
def startup(self): def startup(self):
cmd = [XM_PATH, 'network-attach', self.node.vmname, cmd = [XM_PATH, "network-attach", self.node.vmname, "vifname=%s" % self.localname, "script=vif-core"]
'vifname=%s' % self.localname, 'script=vif-core']
if self.hwaddr is not None: if self.hwaddr is not None:
cmd.append('mac=%s' % self.hwaddr) cmd.append("mac=%s" % self.hwaddr)
subprocess.check_call(cmd) subprocess.check_call(cmd)
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"]) subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True self.up = True
@ -79,8 +77,8 @@ class XenVEth(PyCoreNetIf):
if self.localname: if self.localname:
if self.hwaddr is not None: if self.hwaddr is not None:
pass pass
# this should be doable, but some argument isn't a string # this should be doable, but some argument isn"t a string
# check_call([XM_PATH, 'network-detach', self.node.vmname, # check_call([XM_PATH, "network-detach", self.node.vmname,
# self.hwaddr]) # self.hwaddr])
self.up = False self.up = False
@ -88,51 +86,50 @@ class XenVEth(PyCoreNetIf):
class XenNode(PyCoreNode): class XenNode(PyCoreNode):
apitype = NodeTypes.XEN.value apitype = NodeTypes.XEN.value
FilesToIgnore = frozenset([ files_to_ignore = frozenset([
# 'ipforward.sh', # "ipforward.sh",
'quaggaboot.sh', "quaggaboot.sh",
]) ])
FilesRedirection = { files_redirection = {
'ipforward.sh': '/core-tmp/ipforward.sh', "ipforward.sh": "/core-tmp/ipforward.sh",
} }
CmdsToIgnore = frozenset([ cmds_to_ignore = frozenset([
# 'sh ipforward.sh', # "sh ipforward.sh",
# 'sh quaggaboot.sh zebra', # "sh quaggaboot.sh zebra",
# 'sh quaggaboot.sh ospfd', # "sh quaggaboot.sh ospfd",
# 'sh quaggaboot.sh ospf6d', # "sh quaggaboot.sh ospf6d",
'killall zebra', "killall zebra",
'killall ospfd', "killall ospfd",
'killall ospf6d', "killall ospf6d",
'pidof zebra', 'pidof ospfd', 'pidof ospf6d', "pidof zebra", "pidof ospfd", "pidof ospf6d",
]) ])
def RedirCmd_ipforward(self): def redir_cmd_ipforward(self):
sysctlFile = open(os.path.join(self.mountdir, self.etcdir, 'sysctl.conf'), 'a') sysctl_file = open(os.path.join(self.mountdir, self.etcdir, "sysctl.conf"), "a")
p1 = subprocess.Popen([AWK_PATH, '/^\/sbin\/sysctl -w/ {print $NF}', p1 = subprocess.Popen([AWK_PATH, "/^\/sbin\/sysctl -w/ {print $NF}",
os.path.join(self.nodedir, 'core-tmp/ipforward.sh')], stdout=sysctlFile) os.path.join(self.nodedir, "core-tmp/ipforward.sh")], stdout=sysctl_file)
p1.wait() p1.wait()
sysctlFile.close() sysctl_file.close()
def RedirCmd_zebra(self): def redir_cmd_zebra(self):
subprocess.check_call([SED_PATH, '-i', '-e', 's/^zebra=no/zebra=yes/', subprocess.check_call([SED_PATH, "-i", "-e", "s/^zebra=no/zebra=yes/",
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')]) os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
def RedirCmd_ospfd(self): def redir_cmd_ospfd(self):
subprocess.check_call([SED_PATH, '-i', '-e', 's/^ospfd=no/ospfd=yes/', subprocess.check_call([SED_PATH, "-i", "-e", "s/^ospfd=no/ospfd=yes/",
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')]) os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
def RedirCmd_ospf6d(self): def redir_cmd_ospf6d(self):
subprocess.check_call([SED_PATH, '-i', '-e', subprocess.check_call([SED_PATH, "-i", "-e", "s/^ospf6d=no/ospf6d=yes/",
's/^ospf6d=no/ospf6d=yes/', os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
CmdsRedirection = { cmds_redirection = {
'sh ipforward.sh': RedirCmd_ipforward, "sh ipforward.sh": redir_cmd_ipforward,
'sh quaggaboot.sh zebra': RedirCmd_zebra, "sh quaggaboot.sh zebra": redir_cmd_zebra,
'sh quaggaboot.sh ospfd': RedirCmd_ospfd, "sh quaggaboot.sh ospfd": redir_cmd_ospfd,
'sh quaggaboot.sh ospf6d': RedirCmd_ospf6d, "sh quaggaboot.sh ospf6d": redir_cmd_ospf6d,
} }
# CoreNode: no __init__, take from LxcNode & SimpleLxcNode # CoreNode: no __init__, take from LxcNode & SimpleLxcNode
@ -154,34 +151,32 @@ class XenNode(PyCoreNode):
# domU name # domU name
self.vmname = "c" + str(session.session_id) + "-" + name self.vmname = "c" + str(session.session_id) + "-" + name
# LVM volume group name # LVM volume group name
self.vgname = self.getconfigitem('vg_name', vgname) self.vgname = self.getconfigitem("vg_name", vgname)
# LVM logical volume name # LVM logical volume name
self.lvname = self.vmname + '-' self.lvname = self.vmname + "-"
# LVM logical volume device path name # LVM logical volume device path name
self.lvpath = os.path.join('/dev', self.vgname, self.lvname) self.lvpath = os.path.join("/dev", self.vgname, self.lvname)
self.disksize = self.getconfigitem('disk_size', disksize) self.disksize = self.getconfigitem("disk_size", disksize)
self.ramsize = int(self.getconfigitem('ram_size', ramsize)) self.ramsize = int(self.getconfigitem("ram_size", ramsize))
self.isofile = self.getconfigitem('iso_file', isofile) self.isofile = self.getconfigitem("iso_file", isofile)
# temporary mount point for paused VM persistent filesystem # temporary mount point for paused VM persistent filesystem
self.mountdir = None self.mountdir = None
self.etcdir = self.getconfigitem('etc_path') self.etcdir = self.getconfigitem("etc_path")
# TODO: remove this temporary hack # TODO: remove this temporary hack
self.FilesRedirection['/usr/local/etc/quagga/Quagga.conf'] = \ self.files_redirection["/usr/local/etc/quagga/Quagga.conf"] = os.path.join(
os.path.join(self.getconfigitem('mount_path'), self.etcdir, self.getconfigitem("mount_path"), self.etcdir, "quagga/Quagga.conf")
'quagga/Quagga.conf')
# LxcNode initialization # LxcNode initialization
# self.makenodedir() # self.makenodedir()
if self.nodedir is None: if self.nodedir is None:
self.nodedir = os.path.join(session.session_dir, self.name + ".conf") self.nodedir = os.path.join(session.session_dir, self.name + ".conf")
self.mountdir = self.nodedir + self.getconfigitem('mount_path') self.mountdir = self.nodedir + self.getconfigitem("mount_path")
if not os.path.isdir(self.mountdir): if not os.path.isdir(self.mountdir):
os.makedirs(self.mountdir) os.makedirs(self.mountdir)
self.tmpnodedir = True self.tmpnodedir = True
else: else:
raise Exception("Xen PVM node requires a temporary nodedir") raise Exception("Xen PVM node requires a temporary nodedir")
self.tmpnodedir = False
self.bootsh = bootsh self.bootsh = bootsh
if start: if start:
self.startup() self.startup()
@ -197,7 +192,7 @@ class XenNode(PyCoreNode):
# from class LxcNode (also SimpleLxcNode) # from class LxcNode (also SimpleLxcNode)
def startup(self): def startup(self):
logger.warn("XEN PVM startup() called: preparing disk for %s" % self.name) logger.warn("XEN PVM startup() called: preparing disk for %s", self.name)
self.lock.acquire() self.lock.acquire()
try: try:
if self.up: if self.up:
@ -205,12 +200,12 @@ class XenNode(PyCoreNode):
self.createlogicalvolume() self.createlogicalvolume()
self.createpartitions() self.createpartitions()
persistdev = self.createfilesystems() persistdev = self.createfilesystems()
subprocess.check_call([constants.MOUNT_BIN, '-t', 'ext4', persistdev, self.mountdir]) subprocess.check_call([constants.MOUNT_BIN, "-t", "ext4", persistdev, self.mountdir])
self.untarpersistent(tarname=self.getconfigitem('persist_tar_iso'), self.untarpersistent(tarname=self.getconfigitem("persist_tar_iso"),
iso=True) iso=True)
self.setrootpassword(pw=self.getconfigitem('root_password')) self.setrootpassword(pw=self.getconfigitem("root_password"))
self.sethostname(old='UBASE', new=self.name) self.sethostname(old="UBASE", new=self.name)
self.setupssh(keypath=self.getconfigitem('ssh_key_path')) self.setupssh(keypath=self.getconfigitem("ssh_key_path"))
self.createvm() self.createvm()
self.up = True self.up = True
finally: finally:
@ -229,22 +224,22 @@ class XenNode(PyCoreNode):
return return
self.session.services.bootnodeservices(self) self.session.services.bootnodeservices(self)
tarname = self.getconfigitem('persist_tar') tarname = self.getconfigitem("persist_tar")
if tarname: if tarname:
self.untarpersistent(tarname=tarname, iso=False) self.untarpersistent(tarname=tarname, iso=False)
try: try:
subprocess.check_call([constants.UMOUNT_BIN, self.mountdir]) subprocess.check_call([constants.UMOUNT_BIN, self.mountdir])
self.unmount_all(self.mountdir) self.unmount_all(self.mountdir)
subprocess.check_call([UDEVADM_PATH, 'settle']) subprocess.check_call([UDEVADM_PATH, "settle"])
subprocess.check_call([KPARTX_PATH, '-d', self.lvpath]) subprocess.check_call([KPARTX_PATH, "-d", self.lvpath])
# time.sleep(5) # time.sleep(5)
# time.sleep(1) # time.sleep(1)
# unpause VM # unpause VM
logger.warn("XEN PVM boot() unpause domU %s" % self.vmname) logger.warn("XEN PVM boot() unpause domU %s", self.vmname)
utils.mutecheck_call([XM_PATH, 'unpause', self.vmname]) utils.mutecheck_call([XM_PATH, "unpause", self.vmname])
self.booted = True self.booted = True
finally: finally:
@ -268,25 +263,25 @@ class XenNode(PyCoreNode):
try: try:
# RJE XXX what to do here # RJE XXX what to do here
if self.booted: if self.booted:
utils.mutecheck_call([XM_PATH, 'destroy', self.vmname]) utils.mutecheck_call([XM_PATH, "destroy", self.vmname])
self.booted = False self.booted = False
except (OSError, subprocess.CalledProcessError): except (OSError, subprocess.CalledProcessError):
# ignore this error too, the VM may have exited already # ignore this error too, the VM may have exited already
logger.exception("error during shutdown") logger.exception("error during shutdown")
# discard LVM volume # discard LVM volume
lvmRemoveCount = 0 lvm_remove_count = 0
while os.path.exists(self.lvpath): while os.path.exists(self.lvpath):
try: try:
subprocess.check_call([UDEVADM_PATH, 'settle']) subprocess.check_call([UDEVADM_PATH, "settle"])
utils.mutecall([LVCHANGE_PATH, '-an', self.lvpath]) utils.mutecall([LVCHANGE_PATH, "-an", self.lvpath])
lvmRemoveCount += 1 lvm_remove_count += 1
utils.mutecall([LVREMOVE_PATH, '-f', self.lvpath]) utils.mutecall([LVREMOVE_PATH, "-f", self.lvpath])
except OSError: except OSError:
logger.exception("error during shutdown") logger.exception("error during shutdown")
if lvmRemoveCount > 1: if lvm_remove_count > 1:
logger.warn("XEN PVM shutdown() required %d lvremove executions." % lvmRemoveCount) logger.warn("XEN PVM shutdown() required %d lvremove executions.", lvm_remove_count)
self._netif.clear() self._netif.clear()
del self.session del self.session
@ -303,8 +298,8 @@ class XenNode(PyCoreNode):
""" """
if os.path.exists(self.lvpath): if os.path.exists(self.lvpath):
raise Exception, "LVM volume already exists" raise Exception, "LVM volume already exists"
utils.mutecheck_call([LVCREATE_PATH, '--size', self.disksize, utils.mutecheck_call([LVCREATE_PATH, "--size", self.disksize,
'--name', self.lvname, self.vgname]) "--name", self.lvname, self.vgname])
def createpartitions(self): def createpartitions(self):
""" """
@ -313,7 +308,7 @@ class XenNode(PyCoreNode):
""" """
dev = parted.Device(path=self.lvpath) dev = parted.Device(path=self.lvpath)
dev.removeFromCache() dev.removeFromCache()
disk = parted.freshDisk(dev, 'msdos') disk = parted.freshDisk(dev, "msdos")
constraint = parted.Constraint(device=dev) constraint = parted.Constraint(device=dev)
persist_size = int(0.75 * constraint.maxSize) persist_size = int(0.75 * constraint.maxSize)
self.createpartition(device=dev, disk=disk, start=1, self.createpartition(device=dev, disk=disk, start=1,
@ -338,14 +333,14 @@ class XenNode(PyCoreNode):
Make an ext4 filesystem and swap space. Return the device name for Make an ext4 filesystem and swap space. Return the device name for
the persistent partition so we can mount it. the persistent partition so we can mount it.
""" """
output = subprocess.Popen([KPARTX_PATH, '-l', self.lvpath], output = subprocess.Popen([KPARTX_PATH, "-l", self.lvpath],
stdout=subprocess.PIPE).communicate()[0] stdout=subprocess.PIPE).communicate()[0]
lines = output.splitlines() lines = output.splitlines()
persistdev = '/dev/mapper/' + lines[0].strip().split(' ')[0].strip() persistdev = "/dev/mapper/" + lines[0].strip().split(" ")[0].strip()
swapdev = '/dev/mapper/' + lines[1].strip().split(' ')[0].strip() swapdev = "/dev/mapper/" + lines[1].strip().split(" ")[0].strip()
subprocess.check_call([KPARTX_PATH, '-a', self.lvpath]) subprocess.check_call([KPARTX_PATH, "-a", self.lvpath])
utils.mutecheck_call([MKFSEXT4_PATH, '-L', 'persist', persistdev]) utils.mutecheck_call([MKFSEXT4_PATH, "-L", "persist", persistdev])
utils.mutecheck_call([MKSWAP_PATH, '-f', '-L', 'swap', swapdev]) utils.mutecheck_call([MKSWAP_PATH, "-f", "-L", "swap", swapdev])
return persistdev return persistdev
def untarpersistent(self, tarname, iso): def untarpersistent(self, tarname, iso):
@ -353,7 +348,8 @@ class XenNode(PyCoreNode):
Unpack a persistent template tar file to the mounted mount dir. Unpack a persistent template tar file to the mounted mount dir.
Uses fsimage library to read from an ISO file. Uses fsimage library to read from an ISO file.
""" """
tarname = tarname.replace('%h', self.name) # filename may use hostname # filename may use hostname
tarname = tarname.replace("%h", self.name)
if iso: if iso:
try: try:
fs = fsimage.open(self.isofile, 0) fs = fsimage.open(self.isofile, 0)
@ -375,8 +371,8 @@ class XenNode(PyCoreNode):
except IOError: except IOError:
logger.exception("Failed to open tar file: %s", tarname) logger.exception("Failed to open tar file: %s", tarname)
return return
p = subprocess.Popen([TAR_PATH, '-C', self.mountdir, '--numeric-owner', p = subprocess.Popen([TAR_PATH, "-C", self.mountdir, "--numeric-owner",
'-xf', '-'], stdin=subprocess.PIPE) "-xf", "-"], stdin=subprocess.PIPE)
p.communicate(input=tardata) p.communicate(input=tardata)
p.wait() p.wait()
@ -385,39 +381,38 @@ class XenNode(PyCoreNode):
Set the root password by updating the shadow password file that Set the root password by updating the shadow password file that
is on the filesystem mounted in the temporary area. is on the filesystem mounted in the temporary area.
""" """
saltedpw = crypt.crypt(pw, '$6$' + base64.b64encode(os.urandom(12))) saltedpw = crypt.crypt(pw, "$6$" + base64.b64encode(os.urandom(12)))
subprocess.check_call([SED_PATH, '-i', '-e', subprocess.check_call([SED_PATH, "-i", "-e",
'/^root:/s_^root:\([^:]*\):_root:' + saltedpw + ':_', "/^root:/s_^root:\([^:]*\):_root:" + saltedpw + ":_",
os.path.join(self.mountdir, self.etcdir, 'shadow')]) os.path.join(self.mountdir, self.etcdir, "shadow")])
def sethostname(self, old, new): def sethostname(self, old, new):
""" """
Set the hostname by updating the hostname and hosts files that Set the hostname by updating the hostname and hosts files that
reside on the filesystem mounted in the temporary area. reside on the filesystem mounted in the temporary area.
""" """
subprocess.check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new), subprocess.check_call([SED_PATH, "-i", "-e", "s/%s/%s/" % (old, new),
os.path.join(self.mountdir, self.etcdir, 'hostname')]) os.path.join(self.mountdir, self.etcdir, "hostname")])
subprocess.check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new), subprocess.check_call([SED_PATH, "-i", "-e", "s/%s/%s/" % (old, new),
os.path.join(self.mountdir, self.etcdir, 'hosts')]) os.path.join(self.mountdir, self.etcdir, "hosts")])
def setupssh(self, keypath): def setupssh(self, keypath):
""" """
Configure SSH access by installing host keys and a system-wide Configure SSH access by installing host keys and a system-wide
authorized_keys file. authorized_keys file.
""" """
sshdcfg = os.path.join(self.mountdir, self.etcdir, 'ssh/sshd_config') sshdcfg = os.path.join(self.mountdir, self.etcdir, "ssh/sshd_config")
subprocess.check_call([SED_PATH, '-i', '-e', subprocess.check_call([SED_PATH, "-i", "-e", "s/PermitRootLogin no/PermitRootLogin yes/", sshdcfg])
's/PermitRootLogin no/PermitRootLogin yes/', sshdcfg]) sshdir = os.path.join(self.getconfigitem("mount_path"), self.etcdir, "ssh")
sshdir = os.path.join(self.getconfigitem('mount_path'), self.etcdir, # backslash slashes for use in sed
'ssh') sshdir = sshdir.replace("/", "\\/")
sshdir = sshdir.replace('/', '\\/') # backslash slashes for use in sed subprocess.check_call([SED_PATH, "-i", "-e",
subprocess.check_call([SED_PATH, '-i', '-e', "s/#AuthorizedKeysFile %h\/.ssh\/authorized_keys/" + \
's/#AuthorizedKeysFile %h\/.ssh\/authorized_keys/' + \ "AuthorizedKeysFile " + sshdir + "\/authorized_keys/",
'AuthorizedKeysFile ' + sshdir + '\/authorized_keys/',
sshdcfg]) sshdcfg])
for f in 'ssh_host_rsa_key', 'ssh_host_rsa_key.pub', 'authorized_keys': for f in "ssh_host_rsa_key", "ssh_host_rsa_key.pub", "authorized_keys":
src = os.path.join(keypath, f) src = os.path.join(keypath, f)
dst = os.path.join(self.mountdir, self.etcdir, 'ssh', f) dst = os.path.join(self.mountdir, self.etcdir, "ssh", f)
shutil.copy(src, dst) shutil.copy(src, dst)
if f[-3:] != "pub": if f[-3:] != "pub":
os.chmod(dst, 0600) os.chmod(dst, 0600)
@ -428,16 +423,16 @@ class XenNode(PyCoreNode):
Instantiate it now, so we can add network interfaces, Instantiate it now, so we can add network interfaces,
pause it so we can have the filesystem open for configuration. pause it so we can have the filesystem open for configuration.
""" """
args = [XM_PATH, 'create', os.devnull, '--paused'] args = [XM_PATH, "create", os.devnull, "--paused"]
args.extend(['name=' + self.vmname, 'memory=' + str(self.ramsize)]) args.extend(["name=" + self.vmname, "memory=" + str(self.ramsize)])
args.append('disk=tap:aio:' + self.isofile + ',hda,r') args.append("disk=tap:aio:" + self.isofile + ",hda,r")
args.append('disk=phy:' + self.lvpath + ',hdb,w') args.append("disk=phy:" + self.lvpath + ",hdb,w")
args.append('bootloader=pygrub') args.append("bootloader=pygrub")
bootargs = '--kernel=/isolinux/vmlinuz --ramdisk=/isolinux/initrd' bootargs = "--kernel=/isolinux/vmlinuz --ramdisk=/isolinux/initrd"
args.append('bootargs=' + bootargs) args.append("bootargs=" + bootargs)
for action in ('poweroff', 'reboot', 'suspend', 'crash', 'halt'): for action in ("poweroff", "reboot", "suspend", "crash", "halt"):
args.append('on_%s=destroy' % action) args.append("on_%s=destroy" % action)
args.append('extra=' + self.getconfigitem('xm_create_extra')) args.append("extra=" + self.getconfigitem("xm_create_extra"))
utils.mutecheck_call(args) utils.mutecheck_call(args)
# from class LxcNode # from class LxcNode
@ -456,7 +451,7 @@ class XenNode(PyCoreNode):
def openpausednodefile(self, filename, mode="w"): def openpausednodefile(self, filename, mode="w"):
dirname, basename = os.path.split(filename) dirname, basename = os.path.split(filename)
if not basename: if not basename:
raise ValueError, "no basename for filename: " + filename raise ValueError("no basename for filename: %s" % filename)
if dirname and dirname[0] == "/": if dirname and dirname[0] == "/":
dirname = dirname[1:] dirname = dirname[1:]
# dirname = dirname.replace("/", ".") # dirname = dirname.replace("/", ".")
@ -468,16 +463,16 @@ class XenNode(PyCoreNode):
# from class LxcNode # from class LxcNode
def nodefile(self, filename, contents, mode=0644): def nodefile(self, filename, contents, mode=0644):
if filename in self.FilesToIgnore: if filename in self.files_to_ignore:
# self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename]) # self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename])
return return
if filename in self.FilesRedirection: if filename in self.files_redirection:
redirFilename = self.FilesRedirection[filename] redirection_filename = self.files_redirection[filename]
logger.warn("XEN PVM nodefile(filename=%s) redirected to %s" % (filename, redirFilename)) logger.warn("XEN PVM nodefile(filename=%s) redirected to %s", filename, redirection_filename)
filename = redirFilename filename = redirection_filename
logger.warn("XEN PVM nodefile(filename=%s) called" % [filename]) logger.warn("XEN PVM nodefile(filename=%s) called", filename)
self.lock.acquire() self.lock.acquire()
if not self.up: if not self.up:
self.lock.release() self.lock.release()
@ -492,7 +487,7 @@ class XenNode(PyCoreNode):
f.write(contents) f.write(contents)
os.chmod(f.name, mode) os.chmod(f.name, mode)
f.close() f.close()
logger.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode)) logger.info("created nodefile: %s; mode: 0%o", f.name, mode)
finally: finally:
self.lock.release() self.lock.release()
@ -502,33 +497,33 @@ class XenNode(PyCoreNode):
return False # XXX return False # XXX
def cmd(self, args, wait=True): def cmd(self, args, wait=True):
cmdAsString = string.join(args, ' ') cmd_string = string.join(args, " ")
if cmdAsString in self.CmdsToIgnore: if cmd_string in self.cmds_to_ignore:
# self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString) # self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return 0 return 0
if cmdAsString in self.CmdsRedirection: if cmd_string in self.cmds_redirection:
self.CmdsRedirection[cmdAsString](self) self.cmds_redirection[cmd_string](self)
return 0 return 0
logger("XEN PVM cmd(args=[%s]) called, but not yet implemented" % cmdAsString) logger("XEN PVM cmd(args=[%s]) called, but not yet implemented", cmd_string)
return 0 return 0
def cmdresult(self, args): def cmdresult(self, args):
cmdAsString = string.join(args, ' ') cmd_string = string.join(args, " ")
if cmdAsString in self.CmdsToIgnore: if cmd_string in self.cmds_to_ignore:
# self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString) # self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return 0, "" return 0, ""
logger.warn("XEN PVM cmdresult(args=[%s]) called, but not yet implemented" % cmdAsString) logger.warn("XEN PVM cmdresult(args=[%s]) called, but not yet implemented", cmd_string)
return 0, "" return 0, ""
def popen(self, args): def popen(self, args):
cmdAsString = string.join(args, ' ') cmd_string = string.join(args, " ")
logger.warn("XEN PVM popen(args=[%s]) called, but not yet implemented" % cmdAsString) logger.warn("XEN PVM popen(args=[%s]) called, but not yet implemented", cmd_string)
return return
def icmd(self, args): def icmd(self, args):
cmdAsString = string.join(args, ' ') cmd_string = string.join(args, " ")
logger.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented" % cmdAsString) logger.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented", cmd_string)
return return
def term(self, sh="/bin/sh"): def term(self, sh="/bin/sh"):
@ -537,30 +532,30 @@ class XenNode(PyCoreNode):
def termcmdstring(self, sh="/bin/sh"): def termcmdstring(self, sh="/bin/sh"):
""" """
We may add 'sudo' to the command string because the GUI runs as a We may add "sudo" to the command string because the GUI runs as a
normal user. Use SSH if control interface is available, otherwise normal user. Use SSH if control interface is available, otherwise
use Xen console with a keymapping for easy login. use Xen console with a keymapping for easy login.
""" """
controlifc = None controlifc = None
for ifc in self.netifs(): for ifc in self.netifs():
if hasattr(ifc, 'control') and ifc.control == True: if hasattr(ifc, "control") and ifc.control is True:
controlifc = ifc controlifc = ifc
break break
cmd = "xterm " cmd = "xterm "
# use SSH if control interface is available # use SSH if control interface is available
if controlifc: if controlifc:
controlip = controlifc.addrlist[0].split('/')[0] controlip = controlifc.addrlist[0].split("/")[0]
cmd += "-e ssh root@%s" % controlip cmd += "-e ssh root@%s" % controlip
return cmd return cmd
# otherwise use 'xm console' # otherwise use "xm console"
# pw = self.getconfigitem('root_password') # pw = self.getconfigitem("root_password")
# cmd += "-xrm 'XTerm*VT100.translations: #override <Key>F1: " # cmd += "-xrm "XTerm*VT100.translations: #override <Key>F1: "
# cmd += "string(\"root\\n\") \\n <Key>F2: string(\"%s\\n\")' " % pw # cmd += "string(\"root\\n\") \\n <Key>F2: string(\"%s\\n\")" " % pw
cmd += "-e sudo %s console %s" % (XM_PATH, self.vmname) cmd += "-e sudo %s console %s" % (XM_PATH, self.vmname)
return cmd return cmd
def shcmd(self, cmdstr, sh="/bin/sh"): def shcmd(self, cmdstr, sh="/bin/sh"):
logger("XEN PVM shcmd(args=[%s]) called, but not yet implemented" % cmdstr) logger("XEN PVM shcmd(args=[%s]) called, but not yet implemented", cmdstr)
return return
def mount(self, source, target): def mount(self, source, target):
@ -595,8 +590,7 @@ class XenNode(PyCoreNode):
PyCoreNode.delnetif(self, ifindex) PyCoreNode.delnetif(self, ifindex)
def newveth(self, ifindex=None, ifname=None, net=None, hwaddr=None): def newveth(self, ifindex=None, ifname=None, net=None, hwaddr=None):
logger.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called" % logger.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called", ifindex, ifname)
(ifindex, ifname))
self.lock.acquire() self.lock.acquire()
try: try:
@ -656,8 +650,7 @@ class XenNode(PyCoreNode):
addr = self.getaddr(self.ifname(ifindex), rescan=True) addr = self.getaddr(self.ifname(ifindex), rescan=True)
for t in addrtypes: for t in addrtypes:
if t not in self.valid_deladdrtype: if t not in self.valid_deladdrtype:
raise ValueError, "addr type must be in: " + \ raise ValueError("addr type must be in: " + " ".join(self.valid_deladdrtype))
" ".join(self.valid_deladdrtype)
for a in addr[t]: for a in addr[t]:
self.deladdr(ifindex, a) self.deladdr(ifindex, a)
# update cached information # update cached information
@ -668,10 +661,8 @@ class XenNode(PyCoreNode):
# if self.up: # if self.up:
# self.cmd([IP_BIN, "link", "set", self.ifname(ifindex), "up"]) # self.cmd([IP_BIN, "link", "set", self.ifname(ifindex), "up"])
def newnetif(self, net=None, addrlist=[], hwaddr=None, def newnetif(self, net=None, addrlist=[], hwaddr=None, ifindex=None, ifname=None):
ifindex=None, ifname=None): logger.warn("XEN PVM newnetif(ifindex=%s, ifname=%s) called", ifindex, ifname)
logger.warn("XEN PVM newnetif(ifindex=%s, ifname=%s) called" %
(ifindex, ifname))
self.lock.acquire() self.lock.acquire()
@ -705,18 +696,18 @@ class XenNode(PyCoreNode):
if net is not None: if net is not None:
self.attachnet(ifindex, net) self.attachnet(ifindex, net)
rulefile = os.path.join(self.getconfigitem('mount_path'), rulefile = os.path.join(self.getconfigitem("mount_path"),
self.etcdir, self.etcdir,
'udev/rules.d/70-persistent-net.rules') "udev/rules.d/70-persistent-net.rules")
f = self.openpausednodefile(rulefile, "a") f = self.openpausednodefile(rulefile, "a")
f.write( f.write(
'\n# Xen PVM virtual interface #%s %s with MAC address %s\n' % (ifindex, self.ifname(ifindex), hwaddr)) "\n# Xen PVM virtual interface #%s %s with MAC address %s\n" % (ifindex, self.ifname(ifindex), hwaddr))
# Using MAC address as we're now loading PVM net driver "early" # Using MAC address as we"re now loading PVM net driver "early"
# OLD: Would like to use MAC address, but udev isn't working with paravirtualized NICs. Perhaps the "set hw address" isn't triggering a rescan. # OLD: Would like to use MAC address, but udev isn"t working with paravirtualized NICs. Perhaps the "set hw address" isn"t triggering a rescan.
f.write( f.write(
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="%s", KERNEL=="eth*", NAME="%s"\n' % ( 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="%s", KERNEL=="eth*", NAME="%s"\n' % (
hwaddr, self.ifname(ifindex))) hwaddr, self.ifname(ifindex)))
# f.write('SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", DEVPATH=="/devices/vif-%s/?*", KERNEL=="eth*", NAME="%s"\n' % (ifindex, self.ifname(ifindex))) # f.write("SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", DEVPATH=="/devices/vif-%s/?*", KERNEL=="eth*", NAME="%s"\n" % (ifindex, self.ifname(ifindex)))
f.close() f.close()
if hwaddr: if hwaddr:
@ -748,7 +739,7 @@ class XenNode(PyCoreNode):
# othernode.addnetif(PyCoreNetIf(othernode, otherifname), # othernode.addnetif(PyCoreNetIf(othernode, otherifname),
# othernode.newifindex()) # othernode.newifindex())
def addfile(self, srcname, filename): def addfile(self, srcname, filename, mode=0644):
self.lock.acquire() self.lock.acquire()
if not self.up: if not self.up:
self.lock.release() self.lock.release()
@ -758,14 +749,14 @@ class XenNode(PyCoreNode):
self.lock.release() self.lock.release()
raise Exception("Can't access VM file as VM is already running") raise Exception("Can't access VM file as VM is already running")
if filename in self.FilesToIgnore: if filename in self.files_to_ignore:
# self.warn("XEN PVM addfile(filename=%s) ignored" % [filename]) # self.warn("XEN PVM addfile(filename=%s) ignored" % [filename])
return return
if filename in self.FilesRedirection: if filename in self.files_redirection:
redirFilename = self.FilesRedirection[filename] redirection_filename = self.files_redirection[filename]
logger.warn("XEN PVM addfile(filename=%s) redirected to %s" % (filename, redirFilename)) logger.warn("XEN PVM addfile(filename=%s) redirected to %s", filename, redirection_filename)
filename = redirFilename filename = redirection_filename
try: try:
fin = open(srcname, "r") fin = open(srcname, "r")
@ -776,13 +767,13 @@ class XenNode(PyCoreNode):
fout.write(contents) fout.write(contents)
os.chmod(fout.name, mode) os.chmod(fout.name, mode)
fout.close() fout.close()
logger.info("created nodefile: '%s'; mode: 0%o" % (fout.name, mode)) logger.info("created nodefile: %s; mode: 0%o", fout.name, mode)
finally: finally:
self.lock.release() self.lock.release()
logger.warn("XEN PVM addfile(filename=%s) called" % [filename]) logger.warn("XEN PVM addfile(filename=%s) called", filename)
# shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \ # shcmd = "mkdir -p $(dirname "%s") && mv "%s" "%s" && sync" % \
# (filename, srcname, filename) # (filename, srcname, filename)
# self.shcmd(shcmd) # self.shcmd(shcmd)

View file

@ -3,10 +3,10 @@ xenconfig.py: Implementation of the XenConfigManager class for managing
configurable items for XenNodes. configurable items for XenNodes.
Configuration for a XenNode is available at these three levels: Configuration for a XenNode is available at these three levels:
Global config: XenConfigManager.configs[0] = (type='xen', values) Global config: XenConfigManager.configs[0] = (type="xen", values)
Nodes of this machine type have this config. These are the default values. Nodes of this machine type have this config. These are the default values.
XenConfigManager.default_config comes from defaults + xen.conf XenConfigManager.default_config comes from defaults + xen.conf
Node type config: XenConfigManager.configs[0] = (type='mytype', values) Node type config: XenConfigManager.configs[0] = (type="mytype", values)
All nodes of this type have this config. All nodes of this type have this config.
Node-specific config: XenConfigManager.configs[nodenumber] = (type, values) Node-specific config: XenConfigManager.configs[nodenumber] = (type, values)
The node having this specific number has this config. The node having this specific number has this config.
@ -50,27 +50,43 @@ class XenConfigManager(ConfigurableManager):
def setconfig(self, nodenum, conftype, values): def setconfig(self, nodenum, conftype, values):
""" """
add configuration values for a node to a dictionary; values are Add configuration values for a node to a dictionary; values are
usually received from a Configuration Message, and may refer to a usually received from a Configuration Message, and may refer to a
node for which no object exists yet node for which no object exists yet
:param int nodenum: node id to configure
:param str conftype: configuration type
:param tuple values: values to configure
:return: None
""" """
# used for storing the global default config
if nodenum is None: if nodenum is None:
nodenum = 0 # used for storing the global default config nodenum = 0
return ConfigurableManager.setconfig(self, nodenum, conftype, values) return ConfigurableManager.setconfig(self, nodenum, conftype, values)
def getconfig(self, nodenum, conftype, defaultvalues): def getconfig(self, nodenum, conftype, defaultvalues):
""" """
get configuration values for a node; if the values don't exist in Get configuration values for a node; if the values don"t exist in
our dictionary then return the default values supplied; if conftype our dictionary then return the default values supplied; if conftype
is None then we return a match on any conftype. is None then we return a match on any conftype.
:param int nodenum: node id to configure
:param str conftype: configuration type
:param tuple defaultvalues: default values to return
:return: configuration for node and config type
:rtype: tuple
""" """
# used for storing the global default config
if nodenum is None: if nodenum is None:
nodenum = 0 # used for storing the global default config nodenum = 0
return ConfigurableManager.getconfig(self, nodenum, conftype, defaultvalues) return ConfigurableManager.getconfig(self, nodenum, conftype, defaultvalues)
def clearconfig(self, nodenum): def clearconfig(self, nodenum):
""" """
remove configuration values for a node Remove configuration values for a node
:param int nodenum: node id to clear config
:return: nothing
""" """
ConfigurableManager.clearconfig(self, nodenum) ConfigurableManager.clearconfig(self, nodenum)
if 0 in self.configs: if 0 in self.configs:
@ -87,16 +103,19 @@ class XenConfigManager(ConfigurableManager):
def loadconfigfile(self, filename=None): def loadconfigfile(self, filename=None):
""" """
Load defaults from the /etc/core/xen.conf file into dict object. Load defaults from the /etc/core/xen.conf file into dict object.
:param str filename: file name of configuration to load
:return: nothing
""" """
if filename is None: if filename is None:
filename = os.path.join(constants.CORE_CONF_DIR, 'xen.conf') filename = os.path.join(constants.CORE_CONF_DIR, "xen.conf")
cfg = ConfigParser.SafeConfigParser() cfg = ConfigParser.SafeConfigParser()
if filename not in cfg.read(filename): if filename not in cfg.read(filename):
logger.warn("unable to read Xen config file: %s" % filename) logger.warn("unable to read Xen config file: %s", filename)
return return
section = "xen" section = "xen"
if not cfg.has_section(section): if not cfg.has_section(section):
logger.warn("%s is missing a xen section!" % filename) logger.warn("%s is missing a xen section!", filename)
return return
self.configfile = dict(cfg.items(section)) self.configfile = dict(cfg.items(section))
# populate default config items from config file entries # populate default config items from config file entries
@ -105,7 +124,7 @@ class XenConfigManager(ConfigurableManager):
for i in range(len(names)): for i in range(len(names)):
if names[i] in self.configfile: if names[i] in self.configfile:
vals[i] = self.configfile[names[i]] vals[i] = self.configfile[names[i]]
# this sets XenConfigManager.configs[0] = (type='xen', vals) # this sets XenConfigManager.configs[0] = (type="xen", vals)
self.setconfig(None, self.default_config.name, vals) self.setconfig(None, self.default_config.name, vals)
def getconfigitem(self, name, model=None, node=None, value=None): def getconfigitem(self, name, model=None, node=None, value=None):
@ -113,6 +132,12 @@ class XenConfigManager(ConfigurableManager):
Get a config item of the given name, first looking for node-specific Get a config item of the given name, first looking for node-specific
configuration, then model specific, and finally global defaults. configuration, then model specific, and finally global defaults.
If a value is supplied, it will override any stored config. If a value is supplied, it will override any stored config.
:param str name: name of config item to get
:param model: model config to get
:param node: node config to get
:param value: value to override stored config, if provided
:return: nothing
""" """
if value is not None: if value is not None:
return value return value
@ -122,13 +147,10 @@ class XenConfigManager(ConfigurableManager):
(t, v) = self.getconfig(nodenum=n, conftype=model, defaultvalues=None) (t, v) = self.getconfig(nodenum=n, conftype=model, defaultvalues=None)
if n is not None and v is None: if n is not None and v is None:
# get item from default config for the node type # get item from default config for the node type
(t, v) = self.getconfig(nodenum=None, conftype=model, (t, v) = self.getconfig(nodenum=None, conftype=model, defaultvalues=None)
defaultvalues=None)
if v is None: if v is None:
# get item from default config for the machine type # get item from default config for the machine type
(t, v) = self.getconfig(nodenum=None, (t, v) = self.getconfig(nodenum=None, conftype=self.default_config.name, defaultvalues=None)
conftype=self.default_config.name,
defaultvalues=None)
confignames = self.default_config.getnames() confignames = self.default_config.getnames()
if v and name in confignames: if v and name in confignames:
@ -139,7 +161,7 @@ class XenConfigManager(ConfigurableManager):
if name in self.configfile: if name in self.configfile:
return self.configfile[name] return self.configfile[name]
else: else:
# logger.warn("missing config item '%s'" % name) # logger.warn("missing config item "%s"" % name)
return None return None
@ -167,7 +189,7 @@ class XenConfig(Configurable):
nodetype = object_name nodetype = object_name
if opaque is not None: if opaque is not None:
opaque_items = opaque.split(':') opaque_items = opaque.split(":")
if len(opaque_items) != 2: if len(opaque_items) != 2:
logger.warn("xen config: invalid opaque data in conf message") logger.warn("xen config: invalid opaque data in conf message")
return None return None
@ -211,7 +233,7 @@ class XenConfig(Configurable):
values = xen.getconfig(node_id, cls.name, defaults)[1] values = xen.getconfig(node_id, cls.name, defaults)[1]
else: else:
# use new values supplied from the conf message # use new values supplied from the conf message
values = values_str.split('|') values = values_str.split("|")
xen.setconfig(node_id, nodetype, values) xen.setconfig(node_id, nodetype, values)
return reply return reply
@ -222,8 +244,15 @@ class XenConfig(Configurable):
Convert this class to a Config API message. Some TLVs are defined Convert this class to a Config API message. Some TLVs are defined
by the class, but node number, conf type flags, and values must by the class, but node number, conf type flags, and values must
be passed in. be passed in.
:param int flags: configuration flags
:param int node_id: node id
:param int type_flags: type flags
:param int nodetype: node type
:param tuple values: values
:return: configuration message
""" """
values_str = string.join(values, '|') values_str = string.join(values, "|")
tlvdata = "" tlvdata = ""
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.NODE.value, node_id) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.NODE.value, node_id)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, cls.name) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, cls.name)
@ -231,9 +260,9 @@ class XenConfig(Configurable):
datatypes = tuple(map(lambda x: x[1], cls.config_matrix)) datatypes = tuple(map(lambda x: x[1], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, datatypes) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, datatypes)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, values_str) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, values_str)
captions = reduce(lambda a, b: a + '|' + b, map(lambda x: x[4], cls.config_matrix)) captions = reduce(lambda a, b: a + "|" + b, map(lambda x: x[4], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.CAPTIONS, captions) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.CAPTIONS, captions)
possiblevals = reduce(lambda a, b: a + '|' + b, map(lambda x: x[3], cls.config_matrix)) possiblevals = reduce(lambda a, b: a + "|" + b, map(lambda x: x[3], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.POSSIBLE_VALUES.value, possiblevals) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.POSSIBLE_VALUES.value, possiblevals)
if cls.bitmap is not None: if cls.bitmap is not None:
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.BITMAP.value, cls.bitmap) tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.BITMAP.value, cls.bitmap)
@ -251,24 +280,24 @@ class XenDefaultConfig(XenConfig):
""" """
name = "xen" name = "xen"
# Configuration items: # Configuration items:
# ('name', 'type', 'default', 'possible-value-list', 'caption') # ("name", "type", "default", "possible-value-list", "caption")
config_matrix = [ config_matrix = [
('ram_size', ConfigDataTypes.STRING.value, '256', '', ("ram_size", ConfigDataTypes.STRING.value, "256", "",
'ram size (MB)'), "ram size (MB)"),
('disk_size', ConfigDataTypes.STRING.value, '256M', '', ("disk_size", ConfigDataTypes.STRING.value, "256M", "",
'disk size (use K/M/G suffix)'), "disk size (use K/M/G suffix)"),
('iso_file', ConfigDataTypes.STRING.value, '', '', ("iso_file", ConfigDataTypes.STRING.value, "", "",
'iso file'), "iso file"),
('mount_path', ConfigDataTypes.STRING.value, '', '', ("mount_path", ConfigDataTypes.STRING.value, "", "",
'mount path'), "mount path"),
('etc_path', ConfigDataTypes.STRING.value, '', '', ("etc_path", ConfigDataTypes.STRING.value, "", "",
'etc path'), "etc path"),
('persist_tar_iso', ConfigDataTypes.STRING.value, '', '', ("persist_tar_iso", ConfigDataTypes.STRING.value, "", "",
'iso persist tar file'), "iso persist tar file"),
('persist_tar', ConfigDataTypes.STRING.value, '', '', ("persist_tar", ConfigDataTypes.STRING.value, "", "",
'persist tar file'), "persist tar file"),
('root_password', ConfigDataTypes.STRING.value, 'password', '', ("root_password", ConfigDataTypes.STRING.value, "password", "",
'root password'), "root password"),
] ]
config_groups = "domU properties:1-%d" % len(config_matrix) config_groups = "domU properties:1-%d" % len(config_matrix)