Beispiel #1
0
    def _check_default_networks(self):
        networks = list(set(tmpl_defaults['networks']))
        conn = self.conn.get()

        error_msg = ("Please, check the configuration in %s/template.conf to "
                     "ensure it lists only valid networks." %
                     PluginPaths('kimchi').conf_dir)

        for net_name in networks:
            try:
                net = conn.networkLookupByName(net_name)
            except libvirt.libvirtError, e:
                msg = "Fatal: Unable to find network %s."
                wok_log.error(msg, net_name)
                wok_log.error(error_msg)
                wok_log.error("Details: %s", e.message)
                sys.exit(1)

            if net.isActive() == 0:
                try:
                    net.create()
                except libvirt.libvirtError as e:
                    msg = "Fatal: Unable to activate network %s."
                    wok_log.error(msg, net_name)
                    wok_log.error(error_msg)
                    wok_log.error("Details: %s", e.message)
                    sys.exit(1)
Beispiel #2
0
def get_plugin_config_file(name):
    plugin_conf = PluginPaths(name).conf_file
    if not os.path.exists(plugin_conf):
        cherrypy.log.error_log.error(
            f"Plugin configuration file {plugin_conf} doesn't exist.")
        return None
    return plugin_conf
Beispiel #3
0
def _tar_create_archive(directory_path, archive_id, include, exclude_flag):
    archive_file = os.path.join(directory_path, archive_id + '.tar.gz')
    backup_dir = os.path.join(
        PluginPaths('ginger').state_dir, 'ginger_backups')

    bkp = re.compile(backup_dir)
    if filter(bkp.match, include) and (len(include) == 1):
        raise InvalidOperation('GINHBK0012E', {'dir': backup_dir})

    exclude = ['--exclude=' + backup_dir]
    if exclude_flag:
        exclude.extend(
            ['--exclude=' + toExclude for toExclude in exclude_flag])
    cmd = [
        'tar', '--create', '--ignore-failed-read', '--gzip',
        '--absolute-names', '--file', archive_file, '--selinux', '--acl',
        '--xattrs'
    ] + exclude + include
    out, err, rc = run_command(cmd)
    if rc != 0:
        if 'file changed as we read it' in err:
            raise OperationFailed('GINHBK0010E', {'file': err.split(': ')[1]})
        raise OperationFailed('GINHBK0001E', {
            'name': archive_file,
            'cmd': ' '.join(cmd)
        })

    return archive_file
Beispiel #4
0
 def _restore_tar(self, archive_id):
     backup_dir = os.path.join(PluginPaths('ginger').state_dir,
                               'ginger_backups')
     backup_file = os.path.join(backup_dir, archive_id + '.tar.gz')
     cmd = ['tar', '-xzf', backup_file, '-C', '/']
     out, err, rc = run_command(cmd)
     if rc != 0:
         raise OperationFailed('GINHBK0001E', {'name': backup_file,
                                               'cmd': ' '.join(cmd)})
Beispiel #5
0
 def __init__(self, wok_options):
     Resource.__init__(self, model)
     self.description = Description(model)
     self.rectangles = Rectangles(model)
     self.circles = Circles(model)
     self.paths = PluginPaths('sample')
     self.domain = 'sample'
     self.messages = messages
     self.api_schema = json.load(open(os.path.join(os.path.dirname(
                                 os.path.abspath(__file__)), 'API.json')))
Beispiel #6
0
def href(url, plugin=None):
    if plugin is None:
        base_path = paths.ui_dir
    else:
        base_path = PluginPaths(plugin).ui_dir

    # for error.html, url is absolute path
    f = os.path.join(base_path, url.lstrip('/'))
    mtime = os.path.getmtime(f)
    return f'{url}?cacheBust={mtime}'
Beispiel #7
0
def href(url, plugin=None):
    if plugin is None:
        basePath = paths.ui_dir
    else:
        basePath = PluginPaths(plugin).ui_dir

    # for error.html, url is absolute path
    f = os.path.join(basePath, url.lstrip("/"))
    mtime = os.path.getmtime(f)
    return "%s?cacheBust=%s" % (url, mtime)
Beispiel #8
0
def _load_plugin_conf(name):
    plugin_conf = PluginPaths(name).conf_file
    if not os.path.exists(plugin_conf):
        cherrypy.log.error_log.error("Plugin configuration file %s"
                                     " doesn't exist." % plugin_conf)
        return
    try:
        return Parser().dict_from_file(plugin_conf)
    except ValueError as e:
        cherrypy.log.error_log.error("Failed to load plugin "
                                     "conf from %s: %s" %
                                     (plugin_conf, e.message))
Beispiel #9
0
    def _check_default_pools(self):
        pools = {}

        default_pool = tmpl_defaults['disks'][0]['pool']['name']
        default_pool = default_pool.split('/')[-1]

        pools[default_pool] = {}
        if default_pool == 'default':
            pools[default_pool] = {'path': '/var/lib/libvirt/images'}

        if config.get('kimchi', {}).get('create_iso_pool', False):
            pools['ISO'] = {'path': '/var/lib/kimchi/isos'}

        error_msg = ("Please, check the configuration in %s/template.conf to "
                     "ensure it has a valid storage pool." %
                     PluginPaths('kimchi').conf_dir)

        conn = self.conn.get()
        for pool_name in pools:
            try:
                pool = conn.storagePoolLookupByName(pool_name)
            except libvirt.libvirtError, e:
                pool_path = pools[pool_name].get('path')
                if pool_path is None:
                    msg = "Fatal: Unable to find storage pool %s. " + error_msg
                    wok_log.error(msg % pool_name)
                    wok_log.error("Details: %s", e.message)
                    sys.exit(1)

                # Try to create the pool
                pool = E.pool(E.name(pool_name), type='dir')
                pool.append(E.target(E.path(pool_path)))
                xml = ET.tostring(pool)
                try:
                    pool = conn.storagePoolDefineXML(xml, 0)
                except libvirt.libvirtError, e:
                    msg = "Fatal: Unable to create storage pool %s. "
                    msg += error_msg
                    wok_log.error(msg % pool_name)
                    wok_log.error("Details: %s", e.message)
                    sys.exit(1)

                # Build and set autostart value to pool
                # Ignore error as the pool was already successfully created
                try:
                    # Add build step to make sure target directory created
                    # The build process may fail when the pool directory
                    # already exists on system
                    pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW)
                    pool.setAutostart(1)
                except:
                    pass
Beispiel #10
0
def get_all_tabs():
    files = []

    for plugin, _ in get_enabled_plugins():
        files.append(
            os.path.join(PluginPaths(plugin).ui_dir, 'config/tab-ext.xml'))

    tabs = []
    for f in files:
        root = ET.parse(f)
        tabs.extend([t.text.lower() for t in root.getiterator('title')])

    return tabs
Beispiel #11
0
def get_all_tabs():
    files = []

    for plugin, _ in get_enabled_plugins():
        files.append(os.path.join(PluginPaths(plugin).ui_dir,
                     'config/tab-ext.xml'))

    tabs = []
    for f in files:
        try:
            root = ET.parse(f)
        except (IOError):
            wok_log.debug("Unable to load %s", f)
            continue
        tabs.extend([t.text.lower() for t in root.getiterator('title')])

    return tabs
Beispiel #12
0
def get_remote_iso_path():
    """
    Get a remote iso with the right arch from the distro files shipped
    with kimchi.
    """
    host_arch = os.uname()[4]
    remote_path = ''
    with open(os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d',
              'fedora.json')) as fedora_isos:
        # Get a list of dicts
        json_isos_list = json.load(fedora_isos)
        for iso in json_isos_list:
            if (iso.get('os_arch')) == host_arch:
                remote_path = iso.get('path')
                break

    return remote_path
Beispiel #13
0
    def __init__(self, wok_options=None):
        object_store = config.get_object_store()
        objstore_dir = os.path.dirname(os.path.abspath(object_store))
        if not os.path.isdir(objstore_dir):
            os.makedirs(objstore_dir)

        self.model = GingerModel()
        super(Ginger, self).__init__(self.model)

        for ident, node in sub_nodes.items():
            setattr(self, ident, node(self.model))

        self.api_schema = json.load(
            open(
                os.path.join(os.path.dirname(os.path.abspath(__file__)),
                             'API.json')))
        self.domain = "ginger"
        self.messages = messages
        self.paths = PluginPaths('ginger')
Beispiel #14
0
 def __init__(self, wok_options=None):
     self.model = GingerModel()
     super(Ginger, self).__init__(self.model)
     self.backup = Backup(self.model)
     self.capabilities = Capabilities(self.model)
     self.dasddevs = DASDdevs(self.model)
     self.dasdpartitions = DASDPartitions(self.model)
     self.filesystems = FileSystems(self.model)
     self.firmware = Firmware(self.model)
     self.powerprofiles = PowerProfiles(self.model)
     self.sensors = Sensors(self.model)
     self.users = Users(self.model)
     self.network = Network(self.model)
     self.api_schema = json.load(
         open(
             os.path.join(os.path.dirname(os.path.abspath(__file__)),
                          'API.json')))
     self.paths = PluginPaths('ginger')
     self.domain = "ginger"
     self.messages = messages
     self.san_adapters = SanAdapters(self.model)
     self.ibm_sep = Sep(self.model)
Beispiel #15
0
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

import base64
import json
import os
import random
import string
import time

from Crypto.Cipher import AES

from wok.config import PluginPaths
from wok.exception import OperationFailed, MissingParameter, InvalidParameter
from wok.utils import run_command

SERVERCONFIGPATH = os.path.join(PluginPaths('ginger').state_dir,
                                'server.config')
ALPHABET = string.digits + string.ascii_letters
SDR_LOCAL_CACHE_DIR = PluginPaths('ginger').state_dir
SDR_CACHE = 'sdr_cache'


def _check_if_server_with_name_exists(nameToCheck, existingServers):
    for server in existingServers:
        if nameToCheck == server['name']:
            return True
        else:
            continue
    return False

Beispiel #16
0
class ArchivesModel(object):
    _objstore_type = 'ginger_backup_archive'
    _archive_dir = os.path.join(PluginPaths('ginger').state_dir,
                                'ginger_backups')

    def __init__(self, **kargs):
        self._objstore = kargs['objstore']
        self._create_archive_dir()

    @classmethod
    def _create_archive_dir(cls):
        try:
            os.makedirs(cls._archive_dir)
        except OSError as e:
            # It's OK if archive_dir already exists
            if e.errno != errno.EEXIST:
                wok_log.error('Error creating archive dir %s: %s',
                              cls._archive_dir, e)
                raise OperationFailed('GINHBK0003E',
                                      {'dir': cls._archive_dir})

    @property
    def _default_include(self):
        # This function builds a new copy of the list for each invocation,
        # so that the caller can modify the returned list as wish without
        # worrying about changing the original reference.
        return list(cherrypy.request.app.config['backup']['default_include'])

    @property
    def _default_exclude(self):
        # See _default_include() comments for explanation.
        return list(cherrypy.request.app.config['backup']['default_exclude'])

    def _create_archive(self, params):
        error = None
        try:
            params['file'] = _tar_create_archive(
                self._archive_dir, params['identity'], params['include'],
                params['exclude'])
            params['checksum'] = {'algorithm': 'sha256',
                                  'value': _sha256sum(params['file'])}

            with self._objstore as session:
                session.store(self._objstore_type, params['identity'], params)
        except TimeoutExpired as e:
            error = e
            reason = 'GINHBK0010E'
        except Exception as e:
            error = e
            reason = 'GINHBK0009E'

        if error is not None:
            msg = 'Error creating archive %s: %s' % (params['identity'], error)
            wok_log.error(msg)

            try:
                with self._objstore as session:
                    session.delete(self._objstore_type, params['identity'],
                                   ignore_missing=True)
            except Exception as e_session:
                wok_log.error('Error cleaning archive meta data %s. '
                              'Error: %s', params['identity'], e_session)

            if params['file'] != '':
                try:
                    os.unlink(params['file'])
                except Exception as e_file:
                    wok_log.error('Error cleaning archive file %s. '
                                  'Error: %s', params['file'], e_file)

            raise OperationFailed(reason, {'identity': params['identity']})

    def create(self, params):
        archive_id = str(uuid.uuid4())
        stamp = int(time.mktime(time.localtime()))

        # Though formally we ask front-end to not send "include" at all when
        # it's empty, but in implementation we try to be tolerant.
        # Front-end can also send [] to indicate the "include" is empty.
        include = params.get('include')
        exclude = params.get('exclude', [])
        if not include:
            include = self._default_include
            if not exclude:
                exclude = self._default_exclude

        ar_params = {'identity': archive_id,
                     'include': include,
                     'exclude': exclude,
                     'description': params.get('description', ''),
                     'checksum': {},
                     'timestamp': stamp,
                     'file': ''}
        self._create_archive(ar_params)

        return archive_id

    def _session_get_list(self, session):
        # Assume session is already locked.
        return session.get_list(self._objstore_type, sort_key='timestamp')

    def get_list(self):
        with self._objstore as session:
            return self._session_get_list(session)
Beispiel #17
0
import base64
import json
import os
import random
import string
import time

from Crypto.Cipher import AES

from wok.config import PluginPaths
from wok.exception import OperationFailed, MissingParameter, InvalidParameter
from wok.utils import run_command

SERVERCONFIGPATH = os.path.join(
    PluginPaths('ginger').conf_dir, 'server.config')
ALPHABET = string.digits + string.ascii_letters
SDR_LOCAL_CACHE_DIR = PluginPaths('ginger').conf_dir
SDR_CACHE = 'sdr_cache'


def _check_if_server_with_name_exists(nameToCheck, existingServers):
    for server in existingServers:
        if nameToCheck == server['name']:
            return True
        else:
            continue
    return False


def _check_if_server_with_ipaddr_exists(ipaddrToCheck, existingServers):
Beispiel #18
0
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

import base64
import errno
import os
from multiprocessing import Process
from websockify import WebSocketProxy

from wok.config import config, paths, PluginPaths

WS_TOKENS_DIR = os.path.join(PluginPaths('kimchi').state_dir, 'vnc-tokens')


def new_ws_proxy():
    try:
        os.makedirs(WS_TOKENS_DIR, mode=0755)
    except OSError as e:
        if e.errno == errno.EEXIST:
            pass

    cert = config.get('server', 'ssl_cert')
    key = config.get('server', 'ssl_key')
    if not (cert and key):
        cert = '%s/wok-cert.pem' % paths.conf_dir
        key = '%s/wok-key.pem' % paths.conf_dir
Beispiel #19
0
class ArchivesModel(object):
    _objstore_type = 'ginger_backup_archive'
    _archive_dir = os.path.join(
        PluginPaths('ginger').state_dir, 'ginger_backups')

    def __init__(self, **kargs):
        self._objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self._create_archive_dir()

    @classmethod
    def _create_archive_dir(cls):
        try:
            os.makedirs(cls._archive_dir)
        except OSError as e:
            # It's OK if archive_dir already exists
            if e.errno != errno.EEXIST:
                wok_log.error('Error creating archive dir %s: %s',
                              cls._archive_dir, e)
                raise OperationFailed('GINHBK0003E', {'dir': cls._archive_dir})

    @property
    def _default_include(self):
        # This function builds a new copy of the list for each invocation,
        # so that the caller can modify the returned list as wish without
        # worrying about changing the original reference.
        return list(cherrypy.request.app.config['backup']['default_include'])

    @property
    def _default_exclude(self):
        # See _default_include() comments for explanation.
        return list(cherrypy.request.app.config['backup']['default_exclude'])

    def _create_archive(self, params):
        error = None
        try:
            params['file'] = _tar_create_archive(self._archive_dir,
                                                 params['identity'],
                                                 params['include'],
                                                 params['exclude'])
            params['checksum'] = {
                'algorithm': 'sha256',
                'value': _sha256sum(params['file'])
            }

            with self._objstore as session:
                session.store(self._objstore_type, params['identity'], params)
        except InvalidOperation:
            raise
        except OperationFailed:
            raise
        except Exception as e:
            error = e
            reason = 'GINHBK0009E'

        if error is not None:
            msg = 'Error creating archive %s: %s' % (params['identity'],
                                                     error.message)
            wok_log.error(msg)

            try:
                with self._objstore as session:
                    session.delete(self._objstore_type,
                                   params['identity'],
                                   ignore_missing=True)
            except Exception as e_session:
                wok_log.error(
                    'Error cleaning archive meta data %s. '
                    'Error: %s', params['identity'], e_session)

            if params['file'] != '':
                try:
                    os.unlink(params['file'])
                except Exception as e_file:
                    wok_log.error(
                        'Error cleaning archive file %s. '
                        'Error: %s', params['file'], e_file)

            raise OperationFailed(reason, {'identity': params['identity']})

    def create(self, params):
        uuid_uuid4 = uuid.uuid4()
        if isinstance(uuid_uuid4, unicode):
            uuid_uuid4 = uuid_uuid4.encode('utf-8')
        archive_id = str(uuid_uuid4)
        stamp = int(time.mktime(time.localtime()))

        # Though formally we ask front-end to not send "include" at all when
        # it's empty, but in implementation we try to be tolerant.
        # Front-end can also send [] to indicate the "include" is empty.
        include = params.get('include')
        exclude = params.get('exclude', [])
        if not include:
            include = self._default_include
            if not exclude:
                exclude = self._default_exclude

        ar_params = {
            'identity': archive_id,
            'include': include,
            'exclude': exclude,
            'description': params.get('description', ''),
            'checksum': {},
            'timestamp': stamp,
            'file': ''
        }

        taskid = AsyncTask(u'/backup/create/%s' % (archive_id),
                           self._create_task, ar_params).id
        return self.task.lookup(taskid)

    def _create_task(self, cb, params):

        cb('entering task to create config backup')
        try:
            self._create_archive(params)
            cb('OK', True)
        except (InvalidOperation) as e:
            cb(e.message, False)
        except (OperationFailed) as e:
            cb(e.message, False)
            raise OperationFailed('GINHBK0011E', {
                'params': 'params',
                'err': e.message
            })

    def _session_get_list(self, session):
        # Assume session is already locked.
        return session.get_list(self._objstore_type, sort_key='timestamp')

    def get_list(self):
        with self._objstore as session:
            files = [x.split('.')[0] for x in os.listdir(self._archive_dir)]
            for db_file in self._session_get_list(session):
                if db_file not in files:
                    session.delete(ArchivesModel._objstore_type, db_file)
            return self._session_get_list(session)
Beispiel #20
0
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

import json
import os

from wok.config import CACHEEXPIRES, PluginConfig, PluginPaths
from wok.control.base import Collection, Resource
from wok.control.utils import UrlSubNode
from wok.plugins.sample.i18n import messages
from wok.plugins.sample.model import Model
from wok.root import WokRoot


samplePaths = PluginPaths('sample')


"""
The main class must be the plugin name starting with upper case. In this case,
Sample. The Sample class is a WokRoot instance with plugin specific details.

Each class attribute which is a Resource or a Collection will be translated as
a new REST API. So self.config to /config API, self.description to
/description API and so on.

self.paths represents the plugin paths. Usually it is PluginPath(<plugin-name>)

self.domain is the gettext domain name. Usually it is the plugin name.

self.messages is a list of all i18n messages used on backend side.
Beispiel #21
0
        'opensuse': '13.1',
        'sles': '11sp3'
    },
    'ppc64le': {
        'rhel': '6.5',
        'fedora': '19',
        'ubuntu': '14.04',
        'opensuse': '13.1',
        'sles': '11sp3'
    }
}

icon_available_distros = [
    icon[5:-4]
    for icon in glob.glob1('%s/images/' %
                           PluginPaths('kimchi').ui_dir, 'icon-*.png')
]


def _get_arch():
    for arch, sub_archs in SUPPORTED_ARCHS.iteritems():
        if os.uname()[4] in sub_archs:
            return arch


def _get_default_template_mem():
    if hasattr(psutil, 'virtual_memory'):
        mem = psutil.virtual_memory().total >> 10 >> 10
    else:
        mem = psutil.TOTAL_PHYMEM >> 10 >> 10
    if _get_arch() == 'x86':
Beispiel #22
0
def _get_tmpl_defaults():
    """
    ConfigObj returns a dict like below when no changes were made in the
    template configuration file (template.conf)

    {'main': {}, 'storage': {'disk.0': {}}, 'processor': {}, 'graphics': {}}

    The default values should be like below:

    {'main': {'networks': ['default'], 'memory': '1024'},
     'storage': {'pool': 'default',
                 'disk.0': {'format': 'qcow2', 'size': '10'}},
     'processor': {'cpus': '1'},
     'graphics': {'type': 'spice', 'listen': '127.0.0.1'}}
    """
    # Create dict with default values
    tmpl_defaults = defaultdict(dict)
    tmpl_defaults['main']['networks'] = ['default']
    tmpl_defaults['main']['memory'] = _get_default_template_mem()
    tmpl_defaults['storage']['pool'] = 'default'
    tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2'}
    tmpl_defaults['processor']['cpus'] = 1
    tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'}

    default_config = ConfigObj(tmpl_defaults)

    # Load template configuration file
    config_file = os.path.join(PluginPaths('kimchi').conf_dir, 'template.conf')
    config = ConfigObj(config_file)

    # Merge default configuration with file configuration
    default_config.merge(config)

    # Create a dict with default values according to data structure
    # expected by VMTemplate
    defaults = {
        'domain': 'kvm',
        'arch': os.uname()[4],
        'cdrom_bus': 'ide',
        'cdrom_index': 2,
        'mouse_bus': 'ps2'
    }

    # Parse main section to get networks and memory values
    main_section = default_config.pop('main')
    defaults.update(main_section)

    # Parse storage section to get storage pool and disks values
    storage_section = default_config.pop('storage')
    defaults['storagepool'] = '/plugins/kimchi/storagepools/' + \
                              storage_section.pop('pool')
    defaults['disks'] = []
    for disk in storage_section.keys():
        data = storage_section[disk]
        data['index'] = int(disk.split('.')[1])
        defaults['disks'].append(data)

    # Parse processor section to get cpus and cpu_topology values
    processor_section = default_config.pop('processor')
    defaults['cpus'] = processor_section.pop('cpus')
    defaults['cpu_info'] = {}
    if len(processor_section.keys()) > 0:
        defaults['cpu_info']['topology'] = processor_section

    # Update defaults values with graphics values
    defaults['graphics'] = default_config.pop('graphics')

    return defaults