Restructure the repository according to OpenStack

This patch is restructuring the VirtualBMC repository according to the
OpenStack template for projects (Cookiecutter).

This patch also removes the dependency on the python-daemon library
since it is not present in the OpenStack global-requirements, now a new
class called "detach_process" has been added to the virtualbmc/utils.py
module that will take care of detaching the process context from its
parent and session.

Change-Id: Id4ae1db5b73a18abc54276fe1dfbf3ceff7adc06
This commit is contained in:
Lucas Alvares Gomes 2016-05-05 16:30:17 +01:00
parent 05ffd8ba71
commit 85a0b201ff
32 changed files with 520 additions and 113 deletions

59
.gitignore vendored
View File

@ -1,7 +1,54 @@
*.py[co]
.*.swp
*~
build
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
*egg-info
*egg
build
.eggs
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
nosetests.xml
.testrepository
.venv
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
doc/build
# pbr generates these
AUTHORS
ChangeLog
# Editors
*~
.*.swp
.*sw?

4
.gitreview Normal file
View File

@ -0,0 +1,4 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/virtualbmc.git

7
.testr.conf Normal file
View File

@ -0,0 +1,7 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

17
CONTRIBUTING.rst Normal file
View File

@ -0,0 +1,17 @@
If you would like to contribute to the development of OpenStack, you must
follow the steps in this page:
http://docs.openstack.org/infra/manual/developers.html
If you already have a good understanding of how the system works and your
OpenStack accounts are set up, you can skip to the development workflow
section of this documentation to learn how changes to OpenStack should be
submitted for review via the Gerrit tool:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.
Bugs should be filed on Launchpad, not GitHub:
https://bugs.launchpad.net/virtualbmc

4
HACKING.rst Normal file
View File

@ -0,0 +1,4 @@
virtualbmc Style Commandments
===============================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/

6
MANIFEST.in Normal file
View File

@ -0,0 +1,6 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@ -1,33 +0,0 @@
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
```

28
README.rst Normal file
View File

@ -0,0 +1,28 @@
Virtual BMC
===========
A virtual BMC for controlling virtual machines using IPMI commands.
Installation
------------
.. code-block:: bash
pip install virtualbmc
Supported IPMI commands
-----------------------
.. code-block:: 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

2
babel.cfg Normal file
View File

@ -0,0 +1,2 @@
[python: **.py]

75
doc/source/conf.py Executable file
View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# 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 os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
#'sphinx.ext.intersphinx',
'oslosphinx'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'virtualbmc'
copyright = u'2016, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index',
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
#intersphinx_mapping = {'http://docs.python.org/': None}

View File

@ -0,0 +1,4 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

25
doc/source/index.rst Normal file
View File

@ -0,0 +1,25 @@
.. virtualbmc documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to virtualbmc's documentation!
========================================================
Contents:
.. toctree::
:maxdepth: 2
readme
installation
usage
contributing
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,12 @@
============
Installation
============
At the command line::
$ pip install virtualbmc
Or, if you have virtualenvwrapper installed::
$ mkvirtualenv virtualbmc
$ pip install virtualbmc

1
doc/source/readme.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../../README.rst

7
doc/source/usage.rst Normal file
View File

@ -0,0 +1,7 @@
========
Usage
========
To use virtualbmc in a project::
import virtualbmc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

9
requirements.txt Normal file
View File

@ -0,0 +1,9 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=1.6 # Apache-2.0
six>=1.9.0 # MIT
libvirt-python>=1.2.5 # LGPLv2+
pyghmi>=0.6.11 # Apache-2.0
PrettyTable>=0.7,<0.8 # BSD

50
setup.cfg Normal file
View File

@ -0,0 +1,50 @@
[metadata]
name = virtualbmc
summary = Create virtual BMCs for controlling virtual instances via IPMI
description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
Programming Language :: Python :: 3.4
[files]
packages =
virtualbmc
[entry_points]
console_scripts =
vbmc = virtualbmc.cmd.vbmc:main
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
all_files = 1
[upload_sphinx]
upload-dir = doc/build/html
[compile_catalog]
directory = virtualbmc/locale
domain = virtualbmc
[update_catalog]
domain = virtualbmc
output_dir = virtualbmc/locale
input_file = virtualbmc/locale/virtualbmc.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = virtualbmc/locale/virtualbmc.pot

View File

@ -1,42 +1,27 @@
# 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
# 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
# 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.
# 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
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
from virtualbmc import version
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setup(name='virtualbmc',
version=version,
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',
],
)
setuptools.setup(
setup_requires=['pbr'],
pbr=True)

19
test-requirements.txt Normal file
View File

@ -0,0 +1,19 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking>=0.10.2,<0.11 # Apache-2.0
coverage>=3.6 # Apache-2.0
doc8 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD
oslosphinx>=2.5.0,!=3.4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
os-testr>=0.4.1 # Apache-2.0
reno>=1.6.2 # Apache2
mock>=1.2 # BSD

43
tox.ini Normal file
View File

@ -0,0 +1,43 @@
[tox]
minversion = 1.8
skipsdist = True
envlist = py34,py27,pep8
[testenv]
usedevelop = True
install_command = pip install -U --force-reinstall -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
setenv = VIRTUAL_ENV={envdir}
PYTHONDONTWRITEBYTECODE = 1
LANGUAGE=en_US
LC_ALL=en_US.UTF-8
TESTS_DIR=./virtualbmc/tests/unit/
deps =
-r{toxinidir}/test-requirements.txt
commands = ostestr {posargs}
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
[testenv:pep8]
commands =
flake8 {posargs}
doc8 README.rst CONTRIBUTING.rst HACKING.rst doc/source
[testenv:venv]
commands = {posargs}
[testenv:cover]
commands = python setup.py test --coverage --testr-args='{posargs}'
[testenv:docs]
commands = python setup.py build_sphinx
[testenv:debug]
commands = oslo_debug_helper {posargs}
[testenv:releasenotes]
commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
[flake8]
ignore = E129
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build
max-complexity=17

View File

@ -10,10 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import exception
from virtualbmc import VirtualBMC
from manager import VirtualBMCManager
import pbr.version
version = '0.0.4'
__all__ = ['version', 'exception', 'VirtualBMC', 'VirtualBMCManager']
__version__ = pbr.version.VersionInfo('virtualbmc').version_string()

View File

@ -17,9 +17,9 @@ import sys
from prettytable import PrettyTable
import virtualbmc
from virtualbmc import exception
from virtualbmc import version
from virtualbmc import VirtualBMCManager
from virtualbmc.manager import VirtualBMCManager
def main():
@ -27,7 +27,8 @@ def main():
prog='Virtual BMC',
description='A virtual BMC for controlling virtual instances',
)
parser.add_argument('--version', action='version', version=version)
parser.add_argument('--version', action='version',
version=virtualbmc.__version__)
subparsers = parser.add_subparsers()
# create the parser for the "add" command

View File

@ -14,7 +14,7 @@ import os
from six.moves import configparser
import utils
from virtualbmc import utils
__all__ = ['get_config']

View File

@ -29,3 +29,8 @@ class DomainNotFound(VirtualBMCError):
class LibvirtConnectionOpenError(VirtualBMCError):
message = ('Fail to establish a connection with libvirt URI "%(uri)s". '
'Error: %(error)s')
class DetachProcessError(VirtualBMCError):
message = ('Error when forking (detaching) the VirtualBMC process '
'from its parent and session. Error: %(error)s')

View File

@ -10,11 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
import errno
import sys
import logging
import config
from virtualbmc import config
__all__ = ['get_logger']
@ -42,7 +41,7 @@ class VirtualBMCLogger(logging.Logger):
else:
self.setLevel(logging.INFO)
except IOError, e:
except IOError as e:
if e.errno == errno.EACCES:
pass

View File

@ -12,18 +12,17 @@
import errno
import os
import sys
import shutil
import signal
import sys
import daemon
from six.moves import configparser
import exception
import log
from virtualbmc import VirtualBMC
import utils
import config as vbmc_config
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()
@ -70,7 +69,7 @@ class VirtualBMCManager(object):
pid = int(f.read())
running = utils.is_pid_running(pid)
except IOError:
except (IOError, ValueError):
pass
bmc_config = self._parse_config(domain_name)
@ -153,12 +152,7 @@ class VirtualBMCManager(object):
'config': ' '.join(['%s="%s"' % (k, log_config[k])
for k in log_config])})
with daemon.DaemonContext(stderr=sys.stderr,
files_preserve=[LOG.handler.stream, ]):
# FIXME(lucasagomes): pyghmi start the sockets when the
# class is instantiated, therefore we need to create the object
# within the daemon context
with utils.detach_process() as pid_num:
try:
vbmc = VirtualBMC(**bmc_config)
except Exception as e:
@ -171,7 +165,7 @@ class VirtualBMCManager(object):
# Save the PID number
pidfile_path = os.path.join(domain_path, 'pid')
with open(pidfile_path, 'w') as f:
f.write(str(os.getpid()))
f.write(str(pid_num))
LOG.info('Virtual BMC for domain %s started', domain_name)
vbmc.listen()
@ -187,7 +181,7 @@ class VirtualBMCManager(object):
try:
with open(pidfile_path, 'r') as f:
pid = int(f.read())
except IOError:
except (IOError, ValueError):
raise exception.VirtualBMCError(
'Error stopping the domain %s: PID file not '
'found' % domain_name)

View File

23
virtualbmc/tests/base.py Normal file
View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# 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 oslotest import base
class TestCase(base.BaseTestCase):
"""Test case base class for all unit tests."""

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# 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.
"""
test_virtualbmc
----------------------------------
Tests for `virtualbmc` module.
"""
from virtualbmc.tests import base
class TestVirtualbmc(base.TestCase):
def test_something(self):
pass

View File

@ -10,10 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import libvirt
import os
import exception
from virtualbmc import exception
CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.vbmc')
@ -94,3 +94,54 @@ def mask_dict_password(dictionary, secret='***'):
if 'password' in k:
d[k] = secret
return d
class detach_process(object):
"""Detach the process from its parent and session."""
def _fork(self):
try:
ret = os.fork()
if ret > 0:
# Exit the parent process
os._exit(0)
except OSError as e:
raise exception.DetachProcessError(error=e)
def _change_root_directory(self):
"""Change to root directory.
Ensure that our process doesn't keep any directory in use. Failure
to do this could make it so that an administrator couldn't
unmount a filesystem, because it was our current directory.
"""
try:
os.chdir('/')
except Exception as e:
error = ('Failed to change root directory. Error: %s' % e)
raise exception.DetachProcessError(error=error)
def _change_file_creation_mask(self):
"""Set the umask for new files.
Set the umask for new files the process creates so that it does
have complete control over the permissions of them. We don't
know what umask we may have inherited.
"""
try:
os.umask(0)
except Exception as e:
error = ('Failed to change file creation mask. Error: %s' % e)
raise exception.DetachProcessError(error=error)
def __enter__(self):
self._fork()
os.setsid()
self._fork()
self._change_root_directory()
self._change_file_creation_mask()
return os.getpid()
def __exit__(self, type, value, traceback):
pass

View File

@ -10,15 +10,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import xml.etree.ElementTree as ET
import libvirt
import pyghmi.ipmi.bmc as bmc
import exception
import log
import utils
from virtualbmc import log
from virtualbmc import utils
LOG = log.get_logger()
@ -85,7 +83,7 @@ class VirtualBMC(bmc.Bmc):
try:
conn.defineXML(ET.tostring(tree))
except libvirt.libvirtError as e:
except libvirt.libvirtError:
LOG.error('Failed setting the boot device %(bootdev)s for '
'domain %(domain)s', {'bootdev': device,
'domain': self.domain_name})