Initial Commit

Signed-off-by: Munoz, Obed N <obed.n.munoz@intel.com>
This commit is contained in:
Munoz, Obed N
2015-12-14 13:50:18 -06:00
commit ca55bd76b6
9 changed files with 714 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
# Created by https://www.gitignore.io/api/python,emacs,vim
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
### Vim ###
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~
+4
View File
@@ -0,0 +1,4 @@
Munoz, Obed N <obed.n.munoz@intel.com>
Simental Magana, Marcos <marcos.simental.magana@intel.com>
Victor Morales <victor.morales@intel.com>
+29
View File
@@ -0,0 +1,29 @@
CHANGES
=======
* Fix Readme
* Add license
* Add python logging support
* Implement function to get more information about the instances
* Implement sandbox method
* Implement setup method
* Fix identation code
* Add example into documentation
* Send process to background (the hard way)
* Change background process validation
* Fix import module (for real)
* Fix import lkvm module
* Ignore build/ dir
* Add setup.py install capability
* Add the implementation of balloon method
* Change root_helper to string variable
* Add root helper property
* Add draft is_support function
* Add the implementation of stat method
* Add the implementation of resume method
* Add the implementation of pause method
* Add the implementation of stop method
* Add the implemention of run method
* Add list_instance method implementation
* Change name to list_instances
* Initial structure
+24
View File
@@ -0,0 +1,24 @@
Summary
===========
**python-lkvm** is a python wrapper for lkvm command line which exposes its
methods through a simple API. This allows other python applications to manage
instances.
Getting started
---------------
As most of python modules, *python-lkvm* can be installed via setuptools: ::
$ python setup.py install
Once this module is installed, it can be used their method creating a client
instance, for example, for listing existing instances: ::
import lkvm
client = lkvm.Client()
for ins in client.list_instances():
print ins.name, ins.state
+19
View File
@@ -0,0 +1,19 @@
#
# Copyright (c) 2015 Intel Corporation
#
# Author: Munoz, Obed N <obed.n.munoz@intel.com>
# Author: Simental Magana, Marcos <marcos.simental.magana@intel.com>
#
# 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.
#
+484
View File
@@ -0,0 +1,484 @@
#
# Copyright (c) 2015 Intel Corporation
#
# Author: Morales, Victor <victor.morales@intel.com>
# Author: Munoz, Obed N <obed.n.munoz@intel.com>
# Author: Simental Magana, Marcos <marcos.simental.magana@intel.com>
#
# 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 logging
import os
import psutil
import six
import subprocess
import sys
LKVM_PATH='/usr/bin/lkvm'
logging.basicConfig(format='%(message)s', level=logging.INFO)
LOG = logging.getLogger(__name__)
class LKVMException(Exception):
pass
class LKVMInstance(object):
pass
class Client(object):
def __init__(self):
self._root_helper = None
@property
def root_helper(self):
return self._root_helper
@root_helper.setter
def root_helper(self, value):
self._root_helper = value
def _get_instance_info(self, pid):
if isinstance(pid, six.string_types):
pid = int(pid)
try:
args = psutil.Process(pid).cmdline[2:]
except NoSuchProcess:
raise LKVMException("PID %s not found" % pid)
props = {args[i][2:]: args[i+1] for i in range(0, len(args), 2)}
LOG.debug('Properties found : ' + str(props))
return type('LKVMInstance', (object,), props)
def _execute(self, cmd, *args, **kwargs):
"""Helper method to shell out and execute a command through subprocess.
:param cmd: Command
:type cmd: string
:param args: Arguments
:type args: string
"""
if hasattr(os, 'geteuid') and os.geteuid() != 0 and not self._root_helper:
return
command = [LKVM_PATH]
if self._root_helper:
command = [self._root_helper] + command
command.append(cmd)
command.extend(*args)
command = [str(c) for c in command]
LOG.debug('Executing command : %s ', command)
if kwargs.get('background'):
command.insert(0, 'nohup')
command = ' '.join(command) + ' >/dev/null 2>&1'
subprocess.Popen(command, shell=True)
else:
_PIPE = subprocess.PIPE
obj = subprocess.Popen(command,
stdin=_PIPE,
stdout=_PIPE,
stderr=_PIPE)
try:
result = obj.communicate()
obj.stdin.close()
except OSError as err:
if isinstance(err, ProcessExecutionError):
err_msg = ('{e[description]}\ncommand: {e[cmd]}\n'
'exit code: {e[exit_code]}\nstdout: {e[stdout]}\n'
'stderr: {e[stderr]}').format(e=err)
raise LKVMException(err_msg)
if result[1]:
raise LKVMException(result[1])
return result[0]
def run(self, cpus, mem, shmem, console, kernel, params,
network, name=None, disk=None, balloon=False,
vnc=False, gtk=False, sdl=False, rng=False,
plan9=False, dev=None, tty=None, sandbox=None,
hugetlbs=None, initrd=None, firmware=None,
no_dhcp=False):
"""Start the virtual machine
:param name: Name of the guest
:type name: string
:param cpus: Number of CPUs
:type cpus: integer
:param mem: Virtual machine memory size in MiB.
:type mem: integer
:param shmem: Share host shmem with guest via pci device
:type shmem: string
:param disk: Disk image or rootfs directory
:type disk: string
:param balloon: Enable virtio balloon
:type balloon: boolean
:param vnc: Enable VNC framebuffer
:type vnc: boolean
:param gtk: Enable GTK framebuffer
:type gtk: boolean
:param sdl: Enable SDL framebuffer
:type sdl: boolean
:param rng: Enable virtio Random Number Generator
:type rng: boolean
:param plan9: Enable virtio 9p to share files between host and guest
:type plan9: boolean
:param console: Console to use
:type console: string
:param dev: KVM device file
:type dev: string
:param tty: Remap guest TTY into a pty on the host
:type tty: string
:param sandbox: Run this script when booting into custom rootfs
:type sandbox: string
:param hugetlbfs: Hugetlbfs path
:type hugetlbfs: string
:param kernel: Kernel to boot in virtual machine
:type kernel: string
:param initrd: Initial RAM disk image
:type initrd: integer
:param params: Kernel command line arguments
:type params: string
:param firmware: Firmware image to boot in virtual machine
:type firmware: string
:param network: Create a new guest NIC
:type network: string
:param no_dhcp: Disable kernel DHCP in rootfs mode
:type no_dhcp: boolean
"""
_params = []
# Basic options
_params.extend(['--cpus', cpus,
'--mem', mem,
'--shmem', shmem])
if name:
_params.extend(['--name', name])
if console in ['serial', 'virtio', 'hv']:
_params.extend(['--console', console])
if balloon:
_params.append('--balloon')
if vnc:
_params.append('--vnc')
if gtk:
_params.append('--gtk')
if sdl:
_params.append('--sdl')
if rng:
_params.append('--rng')
if plan9:
_params.append('--9p')
if disk:
_params.extend(['--disk', disk])
if dev:
_params.extend(['--dev', dev])
if tty:
_params.extend(['--tty', tty])
if sandbox:
_params.extend(['--sandbox', sandbox])
if hugetlbs:
_params.extend(['--hugetlbs', hugetlbs])
# Kernel options
_params.extend(['--kernel', kernel,
'--params', '"%s"' % params])
if initrd:
_params.extend(['--initrd', initrd])
if firmware:
_params.extend(['--firmware', firmware])
# Networking options
_params.extend(['--network', network])
if no_dhcp:
_params.append('--no-dhcp')
self._execute('run', _params, background=True)
def setup(self, name):
"""
Setup a new virtual machine
:param name: Instance name
:type name: string
"""
params = ['--name', name]
return self._execute('setup', params)
def pause(self, all=False, name=None):
"""Pause the virtual machine
:param all: Pause all instances
:type all: boolean
:param name: Instance name
:type name: string
"""
params = []
if all:
params.append('--all')
elif name:
params.extend(['--name', name])
else:
return
self._execute('pause', params)
def resume(self, all=False, name=None):
"""Resume the virtual machine
:param all: Resume all instances
:type all: boolean
:param name: Instance name
:type name: string
"""
params = []
if all:
params.append('--all')
elif name:
params.extend(['--name', name])
else:
return
self._execute('resume', params)
def list_instances(self, run=True, rootfs=True):
"""Print a list of running instances on the host.
:param run: List running instances
:type cmd: boolean
:param rootfs: List rootfs instances
:type args: boolean
"""
params = []
if run:
params.append('--run')
if rootfs:
params.append('--rootfs')
output = self._execute('list', params)
instances = []
if output:
results = output.split('\n')
if len(results) > 2 :
for result in results[2:-1]:
ins = result.split()
instance = self._get_instance_info(ins[0])
instance.pid = ins[0]
instance.name = ins[1]
instance.state = ins[2]
instances.append(instance)
return instances
def balloon(self, name, amount, balloon_options):
"""Inflate or deflate the virtio balloon
:param name: Instance name
:type name: string
:param amount: Amount to inflate/deflate (in MB)
:type amount: integer
:param ballon_options:
"""
params = ['name', name]
if balloon_options == 'inflate':
params.extend(['--inflate', amount])
elif balloon_options == 'deflate':
params.extend(['--deflate', amount])
self._execute('balloon', params)
def stop(self, all=False, name=None):
"""Stop a running instance
:param all: Stop all instances
:type all: boolean
:param name: Instance name
:type name: string
"""
params = []
if all:
params.append('--all')
elif name:
params.extend(['--name', name])
else:
return
self._execute('stop', params)
def stat(self, memory=True, all=False, name=None):
"""Print statistics about a running instance
:param memory: Display memory statistics
:type memory: boolean
:param all: All instances
:type all: boolean
:param name: Instance name
:type name: string
"""
return # This method is not supported by lkvm client
params = ['--memory']
if all:
params.append('--all')
elif name:
params.extend(['--name', name])
else:
return
output = self._execute('stat', params)
instances = []
if len(output) > 1:
if len(results) > 2 :
for result in results[2:-1]:
ins = result.split()
instance = KVMInstance(ins[0], ins[1], ins[2])
instances.append(instance)
return instances
def sandbox(self, cpus, mem, shmem, console, kernel, params,
network, name=None, disk=None, balloon=False,
vnc=False, gtk=False, sdl=False, rng=False,
plan9=False, dev=None, tty=None, sandbox=None,
hugetlbs=None, initrd=None, firmware=None,
no_dhcp=False):
"""Run a command in a sandboxed guest
:param name: Name of the guest
:type name: string
:param cpus: Number of CPUs
:type cpus: integer
:param mem: Virtual machine memory size in MiB.
:type mem: integer
:param shmem: Share host shmem with guest via pci device
:type shmem: string
:param disk: Disk image or rootfs directory
:type disk: string
:param balloon: Enable virtio balloon
:type balloon: boolean
:param vnc: Enable VNC framebuffer
:type vnc: boolean
:param gtk: Enable GTK framebuffer
:type gtk: boolean
:param sdl: Enable SDL framebuffer
:type sdl: boolean
:param rng: Enable virtio Random Number Generator
:type rng: boolean
:param plan9: Enable virtio 9p to share files between host and guest
:type plan9: boolean
:param console: Console to use
:type console: string
:param dev: KVM device file
:type dev: string
:param tty: Remap guest TTY into a pty on the host
:type tty: string
:param sandbox: Run this script when booting into custom rootfs
:type sandbox: string
:param hugetlbfs: Hugetlbfs path
:type hugetlbfs: string
:param kernel: Kernel to boot in virtual machine
:type kernel: string
:param initrd: Initial RAM disk image
:type initrd: integer
:param params: Kernel command line arguments
:type params: string
:param firmware: Firmware image to boot in virtual machine
:type firmware: string
:param network: Create a new guest NIC
:type network: string
:param no_dhcp: Disable kernel DHCP in rootfs mode
:type no_dhcp: boolean
"""
_params = []
# Basic options
_params.extend(['--cpus', cpus,
'--mem', mem,
'--shmem', shmem])
if name:
_params.extend(['--name', name])
if console in ['serial', 'virtio', 'hv']:
_params.extend(['--console', console])
if balloon:
_params.append('--balloon')
if vnc:
_params.append('--vnc')
if gtk:
_params.append('--gtk')
if sdl:
_params.append('--sdl')
if rng:
_params.append('--rng')
if plan9:
_params.append('--9p')
if disk:
_params.extend(['--disk', disk])
if dev:
_params.extend(['--dev', dev])
if tty:
_params.extend(['--tty', tty])
if sandbox:
_params.extend(['--sandbox', sandbox])
if hugetlbs:
_params.extend(['--hugetlbs', hugetlbs])
# Kernel options
_params.extend(['--kernel', kernel,
'--params', '"%s"' % params])
if initrd:
_params.extend(['--initrd', initrd])
if firmware:
_params.extend(['--firmware', firmware])
# Networking options
_params.extend(['--network', network])
if no_dhcp:
_params.append('--no-dhcp')
self._execute('sandbox', _params, background=True)
def is_supported(self):
return os.path.isfile(LKVM_PATH)
+4
View File
@@ -0,0 +1,4 @@
pbr>=1.8
psutil==3.3.0
six==1.10.0
wheel==0.24.0
+17
View File
@@ -0,0 +1,17 @@
[metadata]
name = python-lkvm
summary = Library for lkvm
description-file =
README.rst
author = Obed N Munoz
author-email = obed.n.munoz@intel.com
home-page =
classifier =
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
+26
View File
@@ -0,0 +1,26 @@
#
# Copyright (c) 2015 Intel Corporation
#
# Author: Munoz, Obed N <obed.n.munoz@intel.com>
# Author: Simental Magana, Marcos <marcos.simental.magana@intel.com>
#
# 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 setuptools
setuptools.setup(
setup_requires=['pbr>=1.8'],
pbr=True,
packages=[''],
package_dir={'': 'python_lkvm'})