210 lines
7.2 KiB
Python
210 lines
7.2 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import errno
|
|
import os
|
|
import shutil
|
|
import signal
|
|
import sys
|
|
|
|
from six.moves import configparser
|
|
|
|
from virtualbmc import config as vbmc_config
|
|
from virtualbmc import exception
|
|
from virtualbmc import log
|
|
from virtualbmc import utils
|
|
from virtualbmc.vbmc import VirtualBMC
|
|
|
|
LOG = log.get_logger()
|
|
|
|
# BMC status
|
|
RUNNING = 'running'
|
|
DOWN = 'down'
|
|
|
|
DEFAULT_SECTION = 'VirtualBMC'
|
|
|
|
CONF = vbmc_config.get_config()
|
|
|
|
|
|
class VirtualBMCManager(object):
|
|
|
|
def _parse_config(self, domain_name):
|
|
config_path = os.path.join(utils.CONFIG_PATH, domain_name, 'config')
|
|
if not os.path.exists(config_path):
|
|
raise exception.DomainNotFound(domain=domain_name)
|
|
|
|
config = configparser.ConfigParser()
|
|
config.read(config_path)
|
|
|
|
bmc = {}
|
|
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'] = config.getint(DEFAULT_SECTION, 'port')
|
|
|
|
return bmc
|
|
|
|
def _show(self, domain_name):
|
|
running = False
|
|
try:
|
|
pidfile_path = os.path.join(utils.CONFIG_PATH, domain_name, 'pid')
|
|
with open(pidfile_path, 'r') as f:
|
|
pid = int(f.read())
|
|
|
|
running = utils.is_pid_running(pid)
|
|
except (IOError, ValueError):
|
|
pass
|
|
|
|
bmc_config = self._parse_config(domain_name)
|
|
bmc_config['status'] = RUNNING if running else DOWN
|
|
|
|
# mask the passwords if requested
|
|
if not CONF['default']['show_passwords']:
|
|
bmc_config = utils.mask_dict_password(bmc_config)
|
|
|
|
return bmc_config
|
|
|
|
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:
|
|
os.makedirs(domain_path)
|
|
except OSError as e:
|
|
if e.errno == errno.EEXIST:
|
|
sys.exit('Domain %s already exist' % domain_name)
|
|
|
|
config_path = os.path.join(domain_path, 'config')
|
|
with open(config_path, 'w') as f:
|
|
config = configparser.ConfigParser()
|
|
config.add_section(DEFAULT_SECTION)
|
|
config.set(DEFAULT_SECTION, 'username', username)
|
|
config.set(DEFAULT_SECTION, 'password', password)
|
|
config.set(DEFAULT_SECTION, 'port', port)
|
|
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):
|
|
domain_path = os.path.join(utils.CONFIG_PATH, domain_name)
|
|
if not os.path.exists(domain_path):
|
|
raise exception.DomainNotFound(domain=domain_name)
|
|
|
|
try:
|
|
self.stop(domain_name)
|
|
except exception.VirtualBMCError:
|
|
pass
|
|
|
|
shutil.rmtree(domain_path)
|
|
|
|
def start(self, domain_name):
|
|
domain_path = os.path.join(utils.CONFIG_PATH, domain_name)
|
|
if not os.path.exists(domain_path):
|
|
raise exception.DomainNotFound(domain=domain_name)
|
|
|
|
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,
|
|
sasl_username=bmc_config['libvirt_sasl_username'],
|
|
sasl_password=bmc_config['libvirt_sasl_password'])
|
|
|
|
# mask the passwords if requested
|
|
log_config = bmc_config.copy()
|
|
if not CONF['default']['show_passwords']:
|
|
log_config = utils.mask_dict_password(bmc_config)
|
|
|
|
LOG.debug('Starting a Virtual BMC for domain %(domain)s with the '
|
|
'following configuration options: %(config)s',
|
|
{'domain': domain_name,
|
|
'config': ' '.join(['%s="%s"' % (k, log_config[k])
|
|
for k in log_config])})
|
|
|
|
with utils.detach_process() as pid_num:
|
|
try:
|
|
vbmc = VirtualBMC(**bmc_config)
|
|
except Exception as e:
|
|
msg = ('Error starting a Virtual BMC for domain %(domain)s. '
|
|
'Error: %(error)s' % {'domain': domain_name,
|
|
'error': e})
|
|
LOG.error(msg)
|
|
raise exception.VirtualBMCError(msg)
|
|
|
|
# Save the PID number
|
|
pidfile_path = os.path.join(domain_path, 'pid')
|
|
with open(pidfile_path, 'w') as f:
|
|
f.write(str(pid_num))
|
|
|
|
LOG.info('Virtual BMC for domain %s started', domain_name)
|
|
vbmc.listen()
|
|
|
|
def stop(sel, domain_name):
|
|
LOG.debug('Stopping Virtual BMC for domain %s', domain_name)
|
|
domain_path = os.path.join(utils.CONFIG_PATH, domain_name)
|
|
if not os.path.exists(domain_path):
|
|
raise exception.DomainNotFound(domain=domain_name)
|
|
|
|
pidfile_path = os.path.join(domain_path, 'pid')
|
|
pid = None
|
|
try:
|
|
with open(pidfile_path, 'r') as f:
|
|
pid = int(f.read())
|
|
except (IOError, ValueError):
|
|
raise exception.VirtualBMCError(
|
|
'Error stopping the domain %s: PID file not '
|
|
'found' % domain_name)
|
|
else:
|
|
os.remove(pidfile_path)
|
|
|
|
try:
|
|
os.kill(pid, signal.SIGKILL)
|
|
except OSError:
|
|
pass
|
|
|
|
def list(self):
|
|
bmcs = []
|
|
try:
|
|
for domain in os.listdir(utils.CONFIG_PATH):
|
|
if os.path.isdir(os.path.join(utils.CONFIG_PATH, domain)):
|
|
bmcs.append(self._show(domain))
|
|
except OSError as e:
|
|
if e.errno == errno.EEXIST:
|
|
return bmcs
|
|
|
|
return bmcs
|
|
|
|
def show(self, domain_name):
|
|
return self._show(domain_name)
|