Add the "vbmc" utility
This patch is refactoring the code and adding the vbmc utility.
This commit is contained in:
parent
d985f52cc6
commit
f6e7153e2b
|
@ -1,3 +1,7 @@
|
|||
*.py[co]
|
||||
.*.swp
|
||||
*~
|
||||
build
|
||||
dist
|
||||
*egg-info
|
||||
*egg
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
Virtual BMC
|
||||
===========
|
||||
|
||||
A virtual BMC for controlling virtual machines using IPMI commands.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
```bash
|
||||
pip install virtualbmc
|
||||
```
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
![alt text](images/demo.gif "Virtual BMC demo")
|
||||
|
||||
Other supported commands
|
||||
------------------------
|
||||
|
||||
```bash
|
||||
# Power the virtual machine on or off
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 power on|off
|
||||
|
||||
# Check the power status
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 power status
|
||||
|
||||
# Set the boot device to network, hd or cdrom
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 chassis bootdev pxe|disk|cdrom
|
||||
|
||||
# Get the current boot device
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 chassis bootparam get 5
|
||||
```
|
27
README.rst
27
README.rst
|
@ -1,27 +0,0 @@
|
|||
Virtual BMC
|
||||
===========
|
||||
|
||||
A virtual BMC for controlling virtual machines with IPMI commands
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
#. Create a virtual machine
|
||||
|
||||
#. Run the virtual BMC::
|
||||
|
||||
python ./virtualbmc.py --domain-name <virtual machine name>
|
||||
|
||||
#. Control it via IPMI::
|
||||
|
||||
# Power the virtual machine on or off
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 power on|off
|
||||
|
||||
# Check the power status
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 power status
|
||||
|
||||
# Set the boot device to network, hd or cdrom
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 chassis bootdev pxe|disk|cdrom
|
||||
|
||||
# Get the current boot device
|
||||
ipmitool -I lanplus -U admin -P password -H 127.0.0.1 chassis bootparam get 5
|
Binary file not shown.
After Width: | Height: | Size: 298 KiB |
|
@ -0,0 +1,40 @@
|
|||
# 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.
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(name='virtualbmc',
|
||||
version='0.0.1',
|
||||
description=('Create virtual BMCs for controlling virtual instances '
|
||||
'via IPMI'),
|
||||
url='http://github.com/umago/virtualbmc',
|
||||
author='Lucas Alvares Gomes',
|
||||
author_email='lucasagomes@gmail.com',
|
||||
license='Apache License 2.0',
|
||||
packages=['virtualbmc', 'virtualbmc.cmd'],
|
||||
install_requires=['six',
|
||||
'python-daemon',
|
||||
'prettytable',
|
||||
'libvirt-python',
|
||||
'pyghmi>=0.9.8'],
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'vbmc = virtualbmc.cmd.vbmc:main',
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Topic :: Utilities',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Programming Language :: Python',
|
||||
],
|
||||
)
|
163
virtualbmc.py
163
virtualbmc.py
|
@ -1,163 +0,0 @@
|
|||
# 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 argparse
|
||||
import signal
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import libvirt
|
||||
import pyghmi.ipmi.bmc as bmc
|
||||
|
||||
# Power states
|
||||
POWEROFF = 0
|
||||
POWERON = 1
|
||||
|
||||
# Boot device maps
|
||||
GET_BOOT_DEVICES_MAP = {
|
||||
'network': 4,
|
||||
'hd': 8,
|
||||
'cdrom': 0x14,
|
||||
}
|
||||
|
||||
SET_BOOT_DEVICES_MAP = {
|
||||
'network': 'network',
|
||||
'hd': 'hd',
|
||||
'optical': 'cdrom',
|
||||
}
|
||||
|
||||
|
||||
class VirtualBMC(bmc.Bmc):
|
||||
def __init__(self, username, password, port, address,
|
||||
domain_name, libvirt_uri):
|
||||
super(VirtualBMC, self).__init__({username: password},
|
||||
port=port, address=address)
|
||||
self.domain_name = domain_name
|
||||
|
||||
# Create the connection
|
||||
self.conn = libvirt.open(libvirt_uri)
|
||||
if self.conn is None:
|
||||
print('Failed to open connection to the hypervisor '
|
||||
'using the libvirt URI: "%s"' % libvirt_uri)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
self.domain = self.conn.lookupByName(self.domain_name)
|
||||
except libvirt.libvirtError:
|
||||
print('Failed to find the domain "%s"' % self.domain_name)
|
||||
sys.exit(1)
|
||||
|
||||
def get_boot_device(self):
|
||||
parsed = ET.fromstring(self.domain.XMLDesc())
|
||||
boot_devs = parsed.findall('.//os/boot')
|
||||
boot_dev = boot_devs[0].attrib['dev']
|
||||
return GET_BOOT_DEVICES_MAP.get(boot_dev, 0)
|
||||
|
||||
def set_boot_device(self, bootdevice):
|
||||
device = SET_BOOT_DEVICES_MAP.get(bootdevice)
|
||||
if device is None:
|
||||
print('Uknown boot device: %s' % bootdevice)
|
||||
return 0xd5
|
||||
|
||||
parsed = ET.fromstring(self.domain.XMLDesc())
|
||||
os = parsed.find('os')
|
||||
boot_list = os.findall('boot')
|
||||
|
||||
# Clear boot list
|
||||
for boot_el in boot_list:
|
||||
os.remove(boot_el)
|
||||
|
||||
boot_el = ET.SubElement(os, 'boot')
|
||||
boot_el.set('dev', device)
|
||||
|
||||
try:
|
||||
self.conn.defineXML(ET.tostring(parsed))
|
||||
except libvirt.libvirtError as e:
|
||||
print('Failed setting the boot device to "%s" on the '
|
||||
'"%s" domain' % (device, self.domain_name))
|
||||
|
||||
def get_power_state(self):
|
||||
try:
|
||||
if self.domain.isActive():
|
||||
return POWERON
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error getting the power state of domain "%s". '
|
||||
'Error: %s' % (self.domain_name, e))
|
||||
return
|
||||
|
||||
return POWEROFF
|
||||
|
||||
def power_off(self):
|
||||
try:
|
||||
self.domain.destroy()
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error powering off the domain "%s". Error: %s' %
|
||||
(self.domain_name, e))
|
||||
return
|
||||
|
||||
def power_on(self):
|
||||
try:
|
||||
self.domain.create()
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error powering on the domain "%s". Error: %s' %
|
||||
(self.domain_name, e))
|
||||
return
|
||||
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
print('SIGINT received, stopping the Virtual BMC...')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='Virtual BMC',
|
||||
description='Virtual BMC for controlling virtual instances',
|
||||
)
|
||||
parser.add_argument('--username',
|
||||
dest='username',
|
||||
default='admin',
|
||||
help='The BMC username; defaults to "admin"')
|
||||
parser.add_argument('--password',
|
||||
dest='password',
|
||||
default='password',
|
||||
help='The BMC password; defaults to "password"')
|
||||
parser.add_argument('--port',
|
||||
dest='port',
|
||||
type=int,
|
||||
default=623,
|
||||
help='Port to listen on; defaults to 623')
|
||||
parser.add_argument('--address',
|
||||
dest='address',
|
||||
default='::',
|
||||
help='Address to bind to; defaults to ::')
|
||||
parser.add_argument('--domain-name',
|
||||
dest='domain_name',
|
||||
required=True,
|
||||
help='The name of the virtual machine')
|
||||
parser.add_argument('--libvirt-uri',
|
||||
dest='libvirt_uri',
|
||||
default="qemu:///system",
|
||||
help='The libvirt URI; defaults to "qemu:///system"')
|
||||
args = parser.parse_args()
|
||||
vbmc = VirtualBMC(username=args.username,
|
||||
password=args.password,
|
||||
port=args.port,
|
||||
address=args.address,
|
||||
domain_name=args.domain_name,
|
||||
libvirt_uri=args.libvirt_uri)
|
||||
|
||||
# Register the signal handler
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
# Start the virtual BMC
|
||||
vbmc.listen()
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2016 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
__all__ = ['exception', 'VirtualBMC', 'VirtualBMCManager']
|
||||
|
||||
import exception
|
||||
from virtualbmc import VirtualBMC
|
||||
from virtualbmc import VirtualBMCManager
|
|
@ -0,0 +1,127 @@
|
|||
# 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.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
from virtualbmc import exception
|
||||
from virtualbmc import VirtualBMCManager
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='Virtual BMC',
|
||||
description='A virtual BMC for controlling virtual instances',
|
||||
)
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
# create the parser for the "add" command
|
||||
parser_add = subparsers.add_parser('add', help='Add a new virtual BMC')
|
||||
parser_add.set_defaults(command='add')
|
||||
parser_add.add_argument('domain_name',
|
||||
help='The name of the virtual machine')
|
||||
parser_add.add_argument('--username',
|
||||
dest='username',
|
||||
default='admin',
|
||||
help='The BMC username; defaults to "admin"')
|
||||
parser_add.add_argument('--password',
|
||||
dest='password',
|
||||
default='password',
|
||||
help='The BMC password; defaults to "password"')
|
||||
parser_add.add_argument('--port',
|
||||
dest='port',
|
||||
type=int,
|
||||
default=623,
|
||||
help='Port to listen on; defaults to 623')
|
||||
parser_add.add_argument('--address',
|
||||
dest='address',
|
||||
default='::',
|
||||
help='Address to bind to; defaults to ::')
|
||||
parser_add.add_argument('--libvirt-uri',
|
||||
dest='libvirt_uri',
|
||||
default="qemu:///system",
|
||||
help=('The libvirt URI; defaults to '
|
||||
'"qemu:///system"'))
|
||||
|
||||
# create the parser for the "delete" command
|
||||
parser_delete = subparsers.add_parser('delete',
|
||||
help='Delete a virtual BMC')
|
||||
parser_delete.set_defaults(command='delete')
|
||||
parser_delete.add_argument('domain_name',
|
||||
help='The name of the virtual machine')
|
||||
|
||||
# create the parser for the "start" command
|
||||
parser_start = subparsers.add_parser('start', help='Start a virtual BMC')
|
||||
parser_start.set_defaults(command='start')
|
||||
parser_start.add_argument('domain_name',
|
||||
help='The name of the virtual machine')
|
||||
|
||||
# create the parser for the "stop" command
|
||||
parser_stop = subparsers.add_parser('stop', help='Stop a virtual BMC')
|
||||
parser_stop.set_defaults(command='stop')
|
||||
parser_stop.add_argument('domain_name',
|
||||
help='The name of the virtual machine')
|
||||
|
||||
# create the parser for the "list" command
|
||||
parser_stop = subparsers.add_parser('list', help='list all virtual BMCs')
|
||||
parser_stop.set_defaults(command='list')
|
||||
|
||||
# create the parser for the "show" command
|
||||
parser_stop = subparsers.add_parser('show', help='Show a virtual BMCs')
|
||||
parser_stop.set_defaults(command='show')
|
||||
parser_stop.add_argument('domain_name',
|
||||
help='The name of the virtual machine')
|
||||
|
||||
args = parser.parse_args()
|
||||
manager = VirtualBMCManager()
|
||||
|
||||
try:
|
||||
if args.command == 'add':
|
||||
manager.add(username=args.username, password=args.password,
|
||||
port=args.port, address=args.address,
|
||||
domain_name=args.domain_name,
|
||||
libvirt_uri=args.libvirt_uri)
|
||||
|
||||
elif args.command == 'delete':
|
||||
manager.delete(args.domain_name)
|
||||
|
||||
elif args.command == 'start':
|
||||
manager.start(args.domain_name)
|
||||
|
||||
elif args.command == 'stop':
|
||||
manager.stop(args.domain_name)
|
||||
|
||||
elif args.command == 'list':
|
||||
ptable = PrettyTable(['Domain name', 'Status', 'Address', 'Port'])
|
||||
for bmc in manager.list():
|
||||
ptable.add_row([bmc['domain_name'], bmc['status'],
|
||||
bmc['address'], bmc['port']])
|
||||
print(ptable)
|
||||
|
||||
elif args.command == 'show':
|
||||
bmc = manager.show(args.domain_name)
|
||||
for key, val in bmc.items():
|
||||
ptable.add_row([key, val])
|
||||
print(ptable)
|
||||
|
||||
except (exception.LibvirtConnectionOpenError,
|
||||
exception.DomainNotFound) as e:
|
||||
print(e, file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,31 @@
|
|||
# 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.
|
||||
|
||||
|
||||
class VirtualBMCError(Exception):
|
||||
|
||||
message = None
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
if self.message and kwargs:
|
||||
self.message = self.message % kwargs
|
||||
|
||||
super(VirtualBMCError, self).__init__(self.message)
|
||||
|
||||
|
||||
class DomainNotFound(VirtualBMCError):
|
||||
message = 'No domain with matching name %(domain)s was found'
|
||||
|
||||
|
||||
class LibvirtConnectionOpenError(VirtualBMCError):
|
||||
message = ('Fail to establish a connection with libvirt URI "%(uri)s". '
|
||||
'Error: %(error)s')
|
|
@ -0,0 +1,300 @@
|
|||
# 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.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import shutil
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import daemon
|
||||
import libvirt
|
||||
import pyghmi.ipmi.bmc as bmc
|
||||
from six.moves import configparser
|
||||
|
||||
import exception
|
||||
|
||||
|
||||
# Power states
|
||||
POWEROFF = 0
|
||||
POWERON = 1
|
||||
|
||||
# BMC status
|
||||
RUNNING = 'running'
|
||||
DOWN = 'down'
|
||||
|
||||
# Boot device maps
|
||||
GET_BOOT_DEVICES_MAP = {
|
||||
'network': 4,
|
||||
'hd': 8,
|
||||
'cdrom': 0x14,
|
||||
}
|
||||
|
||||
SET_BOOT_DEVICES_MAP = {
|
||||
'network': 'network',
|
||||
'hd': 'hd',
|
||||
'optical': 'cdrom',
|
||||
}
|
||||
|
||||
|
||||
DEFAULT_SECTION = 'VirtualBMC'
|
||||
CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.vbmc')
|
||||
|
||||
|
||||
class libvirt_open(object):
|
||||
|
||||
def __init__(self, uri, readonly=False):
|
||||
self.uri = uri
|
||||
self.readonly = readonly
|
||||
|
||||
def __enter__(self):
|
||||
try:
|
||||
if self.readonly:
|
||||
self.conn = libvirt.openReadOnly(self.uri)
|
||||
else:
|
||||
self.conn = libvirt.open(self.uri)
|
||||
|
||||
return self.conn
|
||||
|
||||
except libvirt.libvirtError as e:
|
||||
raise exception.LibvirtConnectionOpenError(uri=self.uri, error=e)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.conn.close()
|
||||
|
||||
|
||||
def get_libvirt_domain(conn, domain):
|
||||
try:
|
||||
return conn.lookupByName(domain)
|
||||
except libvirt.libvirtError:
|
||||
raise exception.DomainNotFound(domain=domain)
|
||||
|
||||
|
||||
def check_libvirt_connection_and_domain(uri, domain):
|
||||
with libvirt_open(uri, readonly=True) as conn:
|
||||
get_libvirt_domain(conn, domain)
|
||||
|
||||
|
||||
def is_pid_running(pid):
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
class VirtualBMC(bmc.Bmc):
|
||||
|
||||
def __init__(self, username, password, port, address,
|
||||
domain_name, libvirt_uri):
|
||||
super(VirtualBMC, self).__init__({username: password},
|
||||
port=port, address=address)
|
||||
self.libvirt_uri = libvirt_uri
|
||||
self.domain_name = domain_name
|
||||
|
||||
def get_boot_device(self):
|
||||
with libvirt_open(self.libvirt_uri, readonly=True) as conn:
|
||||
domain = get_libvirt_domain(conn, self.domain_name)
|
||||
parsed = ET.fromstring(domain.XMLDesc())
|
||||
boot_devs = parsed.findall('.//os/boot')
|
||||
boot_dev = boot_devs[0].attrib['dev']
|
||||
return GET_BOOT_DEVICES_MAP.get(boot_dev, 0)
|
||||
|
||||
def set_boot_device(self, bootdevice):
|
||||
device = SET_BOOT_DEVICES_MAP.get(bootdevice)
|
||||
if device is None:
|
||||
print('Uknown boot device: %s' % bootdevice)
|
||||
return 0xd5
|
||||
|
||||
with libvirt_open(self.libvirt_uri) as conn:
|
||||
domain = get_libvirt_domain(conn, self.domain_name)
|
||||
parsed = ET.fromstring(domain.XMLDesc())
|
||||
os = parsed.find('os')
|
||||
boot_list = os.findall('boot')
|
||||
|
||||
# Clear boot list
|
||||
for boot_el in boot_list:
|
||||
os.remove(boot_el)
|
||||
|
||||
boot_el = ET.SubElement(os, 'boot')
|
||||
boot_el.set('dev', device)
|
||||
|
||||
try:
|
||||
conn.defineXML(ET.tostring(parsed))
|
||||
except libvirt.libvirtError as e:
|
||||
print('Failed setting the boot device to "%s" on the '
|
||||
'"%s" domain' % (device, self.domain_name),
|
||||
file=sys.stderr)
|
||||
|
||||
def get_power_state(self):
|
||||
try:
|
||||
with libvirt_open(self.libvirt_uri, readonly=True) as conn:
|
||||
domain = get_libvirt_domain(conn, self.domain_name)
|
||||
if domain.isActive():
|
||||
return POWERON
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error getting the power state of domain "%s". '
|
||||
'Error: %s' % (self.domain_name, e), file=sys.stderr)
|
||||
return
|
||||
|
||||
return POWEROFF
|
||||
|
||||
def power_off(self):
|
||||
try:
|
||||
with libvirt_open(self.libvirt_uri) as conn:
|
||||
domain = get_libvirt_domain(conn, self.domain_name)
|
||||
domain.destroy()
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error powering off the domain "%s". Error: %s' %
|
||||
(self.domain_name, e), file=sys.stderr)
|
||||
return
|
||||
|
||||
def power_on(self):
|
||||
try:
|
||||
with libvirt_open(self.libvirt_uri) as conn:
|
||||
domain = get_libvirt_domain(conn, self.domain_name)
|
||||
domain.create()
|
||||
except libvirt.libvirtError as e:
|
||||
print('Error powering on the domain "%s". Error: %s' %
|
||||
(self.domain_name, e))
|
||||
return
|
||||
|
||||
|
||||
class VirtualBMCManager(object):
|
||||
|
||||
def _parse_config(self, domain_name):
|
||||
config_path = os.path.join(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'):
|
||||
bmc[item] = config.get(DEFAULT_SECTION, item)
|
||||
|
||||
# Port needs to be int
|
||||
bmc['port'] = int(config.get(DEFAULT_SECTION, 'port'))
|
||||
|
||||
return bmc
|
||||
|
||||
def _show(self, domain_name):
|
||||
running = False
|
||||
try:
|
||||
pidfile_path = os.path.join(CONFIG_PATH, domain_name, 'pid')
|
||||
with open(pidfile_path, 'r') as f:
|
||||
pid = int(f.read())
|
||||
|
||||
running = is_pid_running(pid)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
bmc_config = self._parse_config(domain_name)
|
||||
bmc_config['status'] = RUNNING if running else DOWN
|
||||
return bmc_config
|
||||
|
||||
def add(self, username, password, port, address,
|
||||
domain_name, libvirt_uri):
|
||||
# Check libvirt and domain
|
||||
check_libvirt_connection_and_domain(libvirt_uri, domain_name)
|
||||
|
||||
domain_path = os.path.join(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)
|
||||
config.write(f)
|
||||
|
||||
def delete(self, domain_name):
|
||||
domain_path = os.path.join(CONFIG_PATH, domain_name)
|
||||
if not os.path.exists(domain_path):
|
||||
raise exception.DomainNotFound(domain=domain_name)
|
||||
|
||||
self.stop(domain_name)
|
||||
shutil.rmtree(domain_path)
|
||||
|
||||
def start(self, domain_name):
|
||||
domain_path = os.path.join(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 and domain
|
||||
check_libvirt_connection_and_domain(
|
||||
bmc_config['libvirt_uri'], domain_name)
|
||||
|
||||
pidfile_path = os.path.join(domain_path, 'pid')
|
||||
|
||||
with daemon.DaemonContext(stderr=sys.stderr):
|
||||
# FIXME(lucasagomes): pyghmi start the sockets when the
|
||||
# class is instantiated, therefore we need to create the object
|
||||
# within the daemon context
|
||||
vbmc = VirtualBMC(**bmc_config)
|
||||
|
||||
# Save the PID number
|
||||
with open(pidfile_path, 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
|
||||
vbmc.listen()
|
||||
|
||||
def stop(sel, domain_name):
|
||||
domain_path = os.path.join(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:
|
||||
# LOG
|
||||
return
|
||||
else:
|
||||
os.remove(pidfile_path)
|
||||
|
||||
try:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def list(self):
|
||||
bmcs = []
|
||||
try:
|
||||
for domain in os.listdir(CONFIG_PATH):
|
||||
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)
|
Loading…
Reference in New Issue