From: Aline Manera <alinefm(a)br.ibm.com>
Separate StoragePoolDef from model as it handles the xml generation for
libvirt storage pools.
Signed-off-by: Aline Manera <alinefm(a)br.ibm.com>
---
src/kimchi/model.py | 202 +--------------------------
src/kimchi/model_/libvirtstoragepool.py | 225 +++++++++++++++++++++++++++++++
2 files changed, 226 insertions(+), 201 deletions(-)
create mode 100644 src/kimchi/model_/libvirtstoragepool.py
diff --git a/src/kimchi/model.py b/src/kimchi/model.py
index 0577088..027d6d5 100644
--- a/src/kimchi/model.py
+++ b/src/kimchi/model.py
@@ -65,9 +65,9 @@ from kimchi.distroloader import DistroLoader
from kimchi.exception import InvalidOperation, InvalidParameter, IsoFormatError
from kimchi.exception import MissingParameter, NotFoundError, OperationFailed
from kimchi.featuretests import FeatureTests
-from kimchi.iscsi import TargetClient
from kimchi.isoinfo import IsoImage
from kimchi.model_.libvirtconnection import LibvirtConnection
+from kimchi.model_.libvirtstoragepool import StoragePoolDef
from kimchi.objectstore import ObjectStore
from kimchi.scan import Scanner
from kimchi.screenshot import VMScreenshot
@@ -1510,206 +1510,6 @@ class LibvirtVMScreenshot(VMScreenshot):
finally:
os.close(fd)
-
-class StoragePoolDef(object):
- @classmethod
- def create(cls, poolArgs):
- for klass in cls.__subclasses__():
- if poolArgs['type'] == klass.poolType:
- return klass(poolArgs)
- raise OperationFailed('Unsupported pool type: %s' %
poolArgs['type'])
-
- def __init__(self, poolArgs):
- self.poolArgs = poolArgs
-
- def prepare(self, conn):
- ''' Validate pool arguments and perform preparations. Operation
which
- would cause side effect should be put here. Subclasses can optionally
- override this method, or it always succeeds by default. '''
- pass
-
- @property
- def xml(self):
- ''' Subclasses have to override this method to actually generate the
- storage pool XML definition. Should cause no side effect and be
- idempotent'''
- # TODO: When add new pool type, should also add the related test in
- # tests/test_storagepool.py
- raise OperationFailed('self.xml is not implemented: %s' % self)
-
-
-class DirPoolDef(StoragePoolDef):
- poolType = 'dir'
-
- @property
- def xml(self):
- # Required parameters
- # name:
- # type:
- # path:
- xml = """
- <pool type='dir'>
- <name>{name}</name>
- <target>
- <path>{path}</path>
- </target>
- </pool>
- """.format(**self.poolArgs)
- return xml
-
-
-class NetfsPoolDef(StoragePoolDef):
- poolType = 'netfs'
-
- def __init__(self, poolArgs):
- super(NetfsPoolDef, self).__init__(poolArgs)
- self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name']
-
- def prepare(self, conn):
- # TODO: Verify the NFS export can be actually mounted.
- pass
-
- @property
- def xml(self):
- # Required parameters
- # name:
- # type:
- # source[host]:
- # source[path]:
- poolArgs = copy.deepcopy(self.poolArgs)
- poolArgs['path'] = self.path
- xml = """
- <pool type='netfs'>
- <name>{name}</name>
- <source>
- <host name='{source[host]}'/>
- <dir path='{source[path]}'/>
- </source>
- <target>
- <path>{path}</path>
- </target>
- </pool>
- """.format(**poolArgs)
- return xml
-
-
-class LogicalPoolDef(StoragePoolDef):
- poolType = 'logical'
-
- def __init__(self, poolArgs):
- super(LogicalPoolDef, self).__init__(poolArgs)
- self.path = '/var/lib/kimchi/logical_mount/' +
self.poolArgs['name']
-
- @property
- def xml(self):
- # Required parameters
- # name:
- # type:
- # source[devices]:
- poolArgs = copy.deepcopy(self.poolArgs)
- devices = []
- for device_path in poolArgs['source']['devices']:
- devices.append('<device path="%s" />' % device_path)
-
- poolArgs['source']['devices'] = ''.join(devices)
- poolArgs['path'] = self.path
-
- xml = """
- <pool type='logical'>
- <name>{name}</name>
- <source>
- {source[devices]}
- </source>
- <target>
- <path>{path}</path>
- </target>
- </pool>
- """.format(**poolArgs)
- return xml
-
-
-class IscsiPoolDef(StoragePoolDef):
- poolType = 'iscsi'
-
- def prepare(self, conn):
- source = self.poolArgs['source']
- if not TargetClient(**source).validate():
- raise OperationFailed("Can not login to iSCSI host %s target %s" %
- (source['host'], source['target']))
- self._prepare_auth(conn)
-
- def _prepare_auth(self, conn):
- try:
- auth = self.poolArgs['source']['auth']
- except KeyError:
- return
-
- try:
- virSecret = conn.secretLookupByUsage(
- libvirt.VIR_SECRET_USAGE_TYPE_ISCSI, self.poolArgs['name'])
- except libvirt.libvirtError:
- xml = '''
- <secret ephemeral='no' private='yes'>
- <description>Secret for iSCSI storage pool
{name}</description>
- <auth type='chap' username='{username}'/>
- <usage type='iscsi'>
- <target>{name}</target>
- </usage>
- </secret>'''.format(name=self.poolArgs['name'],
- username=auth['username'])
- virSecret = conn.secretDefineXML(xml)
-
- virSecret.setValue(auth['password'])
-
- def _format_port(self, poolArgs):
- try:
- port = poolArgs['source']['port']
- except KeyError:
- return ""
- return "port='%s'" % port
-
- def _format_auth(self, poolArgs):
- try:
- auth = poolArgs['source']['auth']
- except KeyError:
- return ""
-
- return '''
- <auth type='chap' username='{username}'>
- <secret type='iscsi' usage='{name}'/>
- </auth>'''.format(name=poolArgs['name'],
username=auth['username'])
-
- @property
- def xml(self):
- # Required parameters
- # name:
- # type:
- # source[host]:
- # source[target]:
- #
- # Optional parameters
- # source[port]:
- poolArgs = copy.deepcopy(self.poolArgs)
- poolArgs['source'].update({'port': self._format_port(poolArgs),
- 'auth': self._format_auth(poolArgs)})
- poolArgs['path'] = '/dev/disk/by-id'
-
- xml = """
- <pool type='iscsi'>
- <name>{name}</name>
- <source>
- <host name='{source[host]}' {source[port]}/>
- <device path='{source[target]}'/>
- {source[auth]}
- </source>
- <target>
- <path>{path}</path>
- </target>
- </pool>
- """.format(**poolArgs)
- return xml
-
-
def _get_volume_xml(**kwargs):
# Required parameters
# name:
diff --git a/src/kimchi/model_/libvirtstoragepool.py
b/src/kimchi/model_/libvirtstoragepool.py
new file mode 100644
index 0000000..e9b9aa8
--- /dev/null
+++ b/src/kimchi/model_/libvirtstoragepool.py
@@ -0,0 +1,225 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Authors:
+# Aline Manera <alinefm(a)linux.vnet.ibm.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# 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 copy
+import libvirt
+
+from kimchi.exception import OperationFailed
+from kimchi.iscsi import TargetClient
+
+class StoragePoolDef(object):
+ @classmethod
+ def create(cls, poolArgs):
+ for klass in cls.__subclasses__():
+ if poolArgs['type'] == klass.poolType:
+ return klass(poolArgs)
+ raise OperationFailed('Unsupported pool type: %s' %
poolArgs['type'])
+
+ def __init__(self, poolArgs):
+ self.poolArgs = poolArgs
+
+ def prepare(self, conn):
+ ''' Validate pool arguments and perform preparations. Operation
which
+ would cause side effect should be put here. Subclasses can optionally
+ override this method, or it always succeeds by default. '''
+ pass
+
+ @property
+ def xml(self):
+ ''' Subclasses have to override this method to actually generate the
+ storage pool XML definition. Should cause no side effect and be
+ idempotent'''
+ # TODO: When add new pool type, should also add the related test in
+ # tests/test_storagepool.py
+ raise OperationFailed('self.xml is not implemented: %s' % self)
+
+
+class DirPoolDef(StoragePoolDef):
+ poolType = 'dir'
+
+ @property
+ def xml(self):
+ # Required parameters
+ # name:
+ # type:
+ # path:
+ xml = """
+ <pool type='dir'>
+ <name>{name}</name>
+ <target>
+ <path>{path}</path>
+ </target>
+ </pool>
+ """.format(**self.poolArgs)
+ return xml
+
+
+class NetfsPoolDef(StoragePoolDef):
+ poolType = 'netfs'
+
+ def __init__(self, poolArgs):
+ super(NetfsPoolDef, self).__init__(poolArgs)
+ self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name']
+
+ def prepare(self, conn):
+ # TODO: Verify the NFS export can be actually mounted.
+ pass
+
+ @property
+ def xml(self):
+ # Required parameters
+ # name:
+ # type:
+ # source[host]:
+ # source[path]:
+ poolArgs = copy.deepcopy(self.poolArgs)
+ poolArgs['path'] = self.path
+ xml = """
+ <pool type='netfs'>
+ <name>{name}</name>
+ <source>
+ <host name='{source[host]}'/>
+ <dir path='{source[path]}'/>
+ </source>
+ <target>
+ <path>{path}</path>
+ </target>
+ </pool>
+ """.format(**poolArgs)
+ return xml
+
+
+class LogicalPoolDef(StoragePoolDef):
+ poolType = 'logical'
+
+ def __init__(self, poolArgs):
+ super(LogicalPoolDef, self).__init__(poolArgs)
+ self.path = '/var/lib/kimchi/logical_mount/' +
self.poolArgs['name']
+
+ @property
+ def xml(self):
+ # Required parameters
+ # name:
+ # type:
+ # source[devices]:
+ poolArgs = copy.deepcopy(self.poolArgs)
+ devices = []
+ for device_path in poolArgs['source']['devices']:
+ devices.append('<device path="%s" />' % device_path)
+
+ poolArgs['source']['devices'] = ''.join(devices)
+ poolArgs['path'] = self.path
+
+ xml = """
+ <pool type='logical'>
+ <name>{name}</name>
+ <source>
+ {source[devices]}
+ </source>
+ <target>
+ <path>{path}</path>
+ </target>
+ </pool>
+ """.format(**poolArgs)
+ return xml
+
+
+class IscsiPoolDef(StoragePoolDef):
+ poolType = 'iscsi'
+
+ def prepare(self, conn):
+ source = self.poolArgs['source']
+ if not TargetClient(**source).validate():
+ raise OperationFailed("Can not login to iSCSI host %s target %s" %
+ (source['host'], source['target']))
+ self._prepare_auth(conn)
+
+ def _prepare_auth(self, conn):
+ try:
+ auth = self.poolArgs['source']['auth']
+ except KeyError:
+ return
+
+ try:
+ virSecret = conn.secretLookupByUsage(
+ libvirt.VIR_SECRET_USAGE_TYPE_ISCSI, self.poolArgs['name'])
+ except libvirt.libvirtError:
+ xml = '''
+ <secret ephemeral='no' private='yes'>
+ <description>Secret for iSCSI storage pool
{name}</description>
+ <auth type='chap' username='{username}'/>
+ <usage type='iscsi'>
+ <target>{name}</target>
+ </usage>
+ </secret>'''.format(name=self.poolArgs['name'],
+ username=auth['username'])
+ virSecret = conn.secretDefineXML(xml)
+
+ virSecret.setValue(auth['password'])
+
+ def _format_port(self, poolArgs):
+ try:
+ port = poolArgs['source']['port']
+ except KeyError:
+ return ""
+ return "port='%s'" % port
+
+ def _format_auth(self, poolArgs):
+ try:
+ auth = poolArgs['source']['auth']
+ except KeyError:
+ return ""
+
+ return '''
+ <auth type='chap' username='{username}'>
+ <secret type='iscsi' usage='{name}'/>
+ </auth>'''.format(name=poolArgs['name'],
username=auth['username'])
+
+ @property
+ def xml(self):
+ # Required parameters
+ # name:
+ # type:
+ # source[host]:
+ # source[target]:
+ #
+ # Optional parameters
+ # source[port]:
+ poolArgs = copy.deepcopy(self.poolArgs)
+ poolArgs['source'].update({'port': self._format_port(poolArgs),
+ 'auth': self._format_auth(poolArgs)})
+ poolArgs['path'] = '/dev/disk/by-id'
+
+ xml = """
+ <pool type='iscsi'>
+ <name>{name}</name>
+ <source>
+ <host name='{source[host]}' {source[port]}/>
+ <device path='{source[target]}'/>
+ {source[auth]}
+ </source>
+ <target>
+ <path>{path}</path>
+ </target>
+ </pool>
+ """.format(**poolArgs)
+ return xml
--
1.7.10.4