Add support for SASL authentication with libvirt

This commit is contained in:
Lucas Alvares Gomes 2016-02-19 14:41:37 +00:00
parent 03ee8d0c2e
commit b7455ffdf4
4 changed files with 86 additions and 21 deletions

View File

@ -57,6 +57,16 @@ def main():
default="qemu:///system",
help=('The libvirt URI; defaults to '
'"qemu:///system"'))
parser_add.add_argument('--libvirt-sasl-username',
dest='libvirt_sasl_username',
default=None,
help=('The libvirt SASL username; defaults to '
'None'))
parser_add.add_argument('--libvirt-sasl-password',
dest='libvirt_sasl_password',
default=None,
help=('The libvirt SASL password; defaults to '
'None'))
# create the parser for the "delete" command
parser_delete = subparsers.add_parser('delete',
@ -92,10 +102,22 @@ def main():
try:
if args.command == 'add':
# Check if the username and password were given for SASL
sasl_user = args.libvirt_sasl_username
sasl_pass = args.libvirt_sasl_password
if any((sasl_user, sasl_pass)):
if not all((sasl_user, sasl_pass)):
print("A password and username are required to use "
"Libvirt's SASL authentication", file=sys.stderr)
exit(1)
manager.add(username=args.username, password=args.password,
port=args.port, address=args.address,
domain_name=args.domain_name,
libvirt_uri=args.libvirt_uri)
libvirt_uri=args.libvirt_uri,
libvirt_sasl_username=sasl_user,
libvirt_sasl_password=sasl_pass)
elif args.command == 'delete':
for domain in args.domain_names:
@ -118,7 +140,7 @@ def main():
elif args.command == 'show':
ptable = PrettyTable(['Property', 'Value'])
bmc = manager.show(args.domain_name)
for key, val in bmc.items():
for key, val in sorted(bmc.items()):
ptable.add_row([key, val])
print(ptable)

View File

@ -44,12 +44,18 @@ class VirtualBMCManager(object):
config.read(config_path)
bmc = {}
for item in ('username', 'password', 'address',
'domain_name', 'libvirt_uri'):
bmc[item] = config.get(DEFAULT_SECTION, item)
for item in ('username', 'password', 'address', 'domain_name',
'libvirt_uri', 'libvirt_sasl_username',
'libvirt_sasl_password'):
try:
value = config.get(DEFAULT_SECTION, item)
except configparser.NoOptionError:
value = None
bmc[item] = value
# Port needs to be int
bmc['port'] = int(config.get(DEFAULT_SECTION, 'port'))
bmc['port'] = config.getint(DEFAULT_SECTION, 'port')
return bmc
@ -68,9 +74,14 @@ class VirtualBMCManager(object):
bmc_config['status'] = RUNNING if running else DOWN
return bmc_config
def add(self, username, password, port, address,
domain_name, libvirt_uri):
utils.check_libvirt_connection_and_domain(libvirt_uri, domain_name)
def add(self, username, password, port, address, domain_name, libvirt_uri,
libvirt_sasl_username, libvirt_sasl_password):
# check libvirt's connection and if domain exist prior to adding it
utils.check_libvirt_connection_and_domain(
libvirt_uri, domain_name,
sasl_username=libvirt_sasl_username,
sasl_password=libvirt_sasl_password)
domain_path = os.path.join(utils.CONFIG_PATH, domain_name)
try:
@ -89,6 +100,13 @@ class VirtualBMCManager(object):
config.set(DEFAULT_SECTION, 'address', address)
config.set(DEFAULT_SECTION, 'domain_name', domain_name)
config.set(DEFAULT_SECTION, 'libvirt_uri', libvirt_uri)
if libvirt_sasl_username and libvirt_sasl_password:
config.set(DEFAULT_SECTION, 'libvirt_sasl_username',
libvirt_sasl_username)
config.set(DEFAULT_SECTION, 'libvirt_sasl_password',
libvirt_sasl_password)
config.write(f)
def delete(self, domain_name):
@ -110,8 +128,11 @@ class VirtualBMCManager(object):
bmc_config = self._parse_config(domain_name)
# check libvirt's connection and domain prior to starting the BMC
utils.check_libvirt_connection_and_domain(
bmc_config['libvirt_uri'], domain_name)
bmc_config['libvirt_uri'], domain_name,
sasl_username=bmc_config['libvirt_sasl_username'],
sasl_password=bmc_config['libvirt_sasl_password'])
LOG.debug('Starting a Virtual BMC for domain %(domain)s with the '
'following configuration options: %(config)s',

View File

@ -20,13 +20,30 @@ CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.vbmc')
class libvirt_open(object):
def __init__(self, uri, readonly=False):
def __init__(self, uri, sasl_username=None, sasl_password=None,
readonly=False):
self.uri = uri
self.sasl_username = sasl_username
self.sasl_password = sasl_password
self.readonly = readonly
def __enter__(self):
try:
if self.readonly:
if self.sasl_username and self.sasl_password:
def request_cred(credentials, user_data):
for credential in credentials:
if credential[0] == libvirt.VIR_CRED_AUTHNAME:
credential[4] = self.sasl_username
elif credential[0] == libvirt.VIR_CRED_PASSPHRASE:
credential[4] = self.sasl_password
return 0
auth = [[libvirt.VIR_CRED_AUTHNAME,
libvirt.VIR_CRED_PASSPHRASE], request_cred, None]
flags = libvirt.VIR_CONNECT_RO if self.readonly else 0
self.conn = libvirt.openAuth(self.uri, auth, flags)
elif self.readonly:
self.conn = libvirt.openReadOnly(self.uri)
else:
self.conn = libvirt.open(self.uri)
@ -47,8 +64,10 @@ def get_libvirt_domain(conn, domain):
raise exception.DomainNotFound(domain=domain)
def check_libvirt_connection_and_domain(uri, domain):
with libvirt_open(uri, readonly=True) as conn:
def check_libvirt_connection_and_domain(uri, domain, sasl_username=None,
sasl_password=None):
with libvirt_open(uri, readonly=True, sasl_username=sasl_username,
sasl_password=sasl_password) as conn:
get_libvirt_domain(conn, domain)

View File

@ -43,15 +43,18 @@ SET_BOOT_DEVICES_MAP = {
class VirtualBMC(bmc.Bmc):
def __init__(self, username, password, port, address,
domain_name, libvirt_uri):
domain_name, libvirt_uri, libvirt_sasl_username=None,
libvirt_sasl_password=None):
super(VirtualBMC, self).__init__({username: password},
port=port, address=address)
self.libvirt_uri = libvirt_uri
self.domain_name = domain_name
self._conn_args = {'uri': libvirt_uri,
'sasl_username': libvirt_sasl_username,
'sasl_password': libvirt_sasl_password}
def get_boot_device(self):
LOG.debug('Get boot device called for %s', self.domain_name)
with utils.libvirt_open(self.libvirt_uri, readonly=True) as conn:
with utils.libvirt_open(readonly=True, **self._conn_args) as conn:
domain = utils.get_libvirt_domain(conn, self.domain_name)
boot_element = ET.fromstring(domain.XMLDesc()).find('.//os/boot')
boot_dev = None
@ -67,7 +70,7 @@ class VirtualBMC(bmc.Bmc):
if device is None:
return 0xd5
with utils.libvirt_open(self.libvirt_uri) as conn:
with utils.libvirt_open(**self._conn_args) as conn:
domain = utils.get_libvirt_domain(conn, self.domain_name)
tree = ET.fromstring(domain.XMLDesc())
@ -90,7 +93,7 @@ class VirtualBMC(bmc.Bmc):
def get_power_state(self):
LOG.debug('Get power state called for domain %s', self.domain_name)
try:
with utils.libvirt_open(self.libvirt_uri, readonly=True) as conn:
with utils.libvirt_open(readonly=True, **self._conn_args) as conn:
domain = utils.get_libvirt_domain(conn, self.domain_name)
if domain.isActive():
return POWERON
@ -105,7 +108,7 @@ class VirtualBMC(bmc.Bmc):
def power_off(self):
LOG.debug('Power off called for domain %s', self.domain_name)
try:
with utils.libvirt_open(self.libvirt_uri) as conn:
with utils.libvirt_open(**self._conn_args) as conn:
domain = utils.get_libvirt_domain(conn, self.domain_name)
if domain.isActive():
domain.destroy()
@ -118,7 +121,7 @@ class VirtualBMC(bmc.Bmc):
def power_on(self):
LOG.debug('Power on called for domain %s', self.domain_name)
try:
with utils.libvirt_open(self.libvirt_uri) as conn:
with utils.libvirt_open(**self._conn_args) as conn:
domain = utils.get_libvirt_domain(conn, self.domain_name)
if not domain.isActive():
domain.create()