Alon Bar-Lev has uploaded a new change for review.

Change subject: ovirt-vmconsole: initial implementation
......................................................................

ovirt-vmconsole: initial implementation

Change-Id: I45e0b91bb678008dc74ced8622251beccefc82b9
Signed-off-by: Alon Bar-Lev <alo...@redhat.com>
---
M ChangeLog
M configure.ac
M ovirt-host-deploy-offline.spec.in
M src/ovirt_host_deploy/constants.py
M src/plugins/ovirt-host-deploy/Makefile.am
M src/plugins/ovirt-host-deploy/core/offlinepackager.py
A src/plugins/ovirt-host-deploy/vmconsole/Makefile.am
A src/plugins/ovirt-host-deploy/vmconsole/__init__.py
A src/plugins/ovirt-host-deploy/vmconsole/packages.py
A src/plugins/ovirt-host-deploy/vmconsole/pki.py
10 files changed, 439 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-host-deploy 
refs/changes/91/38091/6

diff --git a/ChangeLog b/ChangeLog
index e4136f6..3130627 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,7 @@
    rhbz#1209418.
  * mgmt: new component to enable host management.
  * offline: pull iptables-services where available, rhbz#1224804.
+ * ovirt-vmconsole: initial add.
 
 2015-01-15 - Version 1.3.1
 
diff --git a/configure.ac b/configure.ac
index fd0c5eb..76921b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -187,6 +187,7 @@
        src/plugins/ovirt-host-deploy/tune/Makefile
        src/plugins/ovirt-host-deploy/vdsm/Makefile
        src/plugins/ovirt-host-deploy/vdsmhooks/Makefile
+       src/plugins/ovirt-host-deploy/vmconsole/Makefile
        src/plugins/ovirt-host-mgmt/Makefile
        src/plugins/ovirt-host-mgmt/core/Makefile
        src/plugins/ovirt-host-mgmt/packages/Makefile
diff --git a/ovirt-host-deploy-offline.spec.in 
b/ovirt-host-deploy-offline.spec.in
index f2df16d..2a1cf10 100644
--- a/ovirt-host-deploy-offline.spec.in
+++ b/ovirt-host-deploy-offline.spec.in
@@ -32,6 +32,7 @@
 Requires:      iproute
 Requires:      libselinux-python
 Requires:      m2crypto
+Requires:      ovirt-vmconsole-host
 Requires:      python
 Requires:      tar
 Requires:      tuned
diff --git a/src/ovirt_host_deploy/constants.py 
b/src/ovirt_host_deploy/constants.py
index 3949c08..c99f7ae 100644
--- a/src/ovirt_host_deploy/constants.py
+++ b/src/ovirt_host_deploy/constants.py
@@ -21,6 +21,9 @@
 """Constants."""
 
 
+import os
+
+
 from otopi import util
 
 
@@ -63,6 +66,18 @@
 
     KDUMP_CONFIG_FILE = '/etc/kdump.conf'
 
+    VMCONSOLE_STORE = '/etc/pki/ovirt-vmconsole'
+    VMCONSOLE_CA_FILE = os.path.join(VMCONSOLE_STORE, 'ca.pub')
+    VMCONSOLE_CERT_FILE = os.path.join(
+        VMCONSOLE_STORE,
+        'host-ssh_host_rsa-cert.pub',
+    )
+    VMCONSOLE_KEY_FILE = os.path.join(VMCONSOLE_STORE, 'host-ssh_host_rsa')
+    VMCONSOLE_KEY_PENDING_FILE = os.path.join(
+        VMCONSOLE_STORE,
+        'host-ssh_host_rsa.pending',
+    )
+
 
 @util.export
 class Defaults(object):
@@ -76,6 +91,9 @@
     CERTIFICATE_ENROLLMENT_INLINE = 'inline'
     CERTIFICATE_ENROLLMENT_REQUEST = 'request'
     CERTIFICATE_ENROLLMENT_ACCEPT = 'accept'
+
+    VMCONSOLE_SUPPORT_NONE = 0
+    VMCONSOLE_SUPPORT_V1 = 1
 
 
 @util.export
@@ -123,6 +141,16 @@
 
 @util.export
 @util.codegen
+class VMConsoleEnv(object):
+    SUPPORT = 'VMCONSOLE/support'
+    ENABLE = 'VMCONSOLE/enable'
+    CAKEY = 'VMCONSOLE/caKey'
+    KEY_SIZE = 'VMCONSOLE/keySize'
+    CERTIFICATE = 'VMCONSOLE/certificate'
+
+
+@util.export
+@util.codegen
 class VirtEnv(object):
     ENABLE = 'VIRT/enable'
 
@@ -158,12 +186,14 @@
 @util.codegen
 class Queries(object):
     CERTIFICATE_CHAIN = 'VDSM_CERTIFICATE_CHAIN'
+    VMCONSOLE_CERTIFICATE = 'VMCONSOLE_CERTIFICATE'
 
 
 @util.export
 @util.codegen
 class Displays(object):
     CERTIFICATE_REQUEST = 'VDSM_CERTIFICATE_REQUEST'
+    VMCONSOLE_CERTIFICATE_REQUEST = 'VMCONSOLE_CERTIFICATE_REQUEST'
 
 
 @util.export
diff --git a/src/plugins/ovirt-host-deploy/Makefile.am 
b/src/plugins/ovirt-host-deploy/Makefile.am
index 6de5c4d..e1c8e1d 100644
--- a/src/plugins/ovirt-host-deploy/Makefile.am
+++ b/src/plugins/ovirt-host-deploy/Makefile.am
@@ -30,6 +30,7 @@
        tune \
        vdsm \
        vdsmhooks \
+       vmconsole \
        $(NULL)
 
 install-data-local:
diff --git a/src/plugins/ovirt-host-deploy/core/offlinepackager.py 
b/src/plugins/ovirt-host-deploy/core/offlinepackager.py
index cb72b85..1eed2a0 100644
--- a/src/plugins/ovirt-host-deploy/core/offlinepackager.py
+++ b/src/plugins/ovirt-host-deploy/core/offlinepackager.py
@@ -52,6 +52,7 @@
             if pattern in (
                 'vdsm',
                 'vdsm-gluster',
+                'ovirt-vmconsole-host',
             ):
                 ret.append(
                     {
diff --git a/src/plugins/ovirt-host-deploy/vmconsole/Makefile.am 
b/src/plugins/ovirt-host-deploy/vmconsole/Makefile.am
new file mode 100644
index 0000000..16a4240
--- /dev/null
+++ b/src/plugins/ovirt-host-deploy/vmconsole/Makefile.am
@@ -0,0 +1,39 @@
+#
+# ovirt-host-deploy -- ovirt host deployer
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# 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
+#
+
+include $(top_srcdir)/build/python.inc
+
+MAINTAINERCLEANFILES = \
+       $(srcdir)/Makefile.in \
+       $(NULL)
+
+mydir=$(ovirthostdeployplugindir)/ovirt-host-deploy/sercon
+dist_my_PYTHON = \
+       __init__.py \
+       packages.py \
+       pki.py \
+       $(NULL)
+
+clean-local: \
+       python-clean \
+       $(NULL)
+
+all-local: \
+       python-syntax-check \
+       $(NULL)
diff --git a/src/plugins/ovirt-host-deploy/vmconsole/__init__.py 
b/src/plugins/ovirt-host-deploy/vmconsole/__init__.py
new file mode 100644
index 0000000..b6bd807
--- /dev/null
+++ b/src/plugins/ovirt-host-deploy/vmconsole/__init__.py
@@ -0,0 +1,37 @@
+#
+# ovirt-host-deploy -- ovirt host deployer
+# Copyright (C) 2012-2015 Red Hat, Inc.
+#
+# 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
+#
+
+
+"""serial console plugin."""
+
+
+from otopi import util
+
+
+from . import packages
+from . import pki
+
+
+@util.export
+def createPlugins(context):
+    packages.Plugin(context=context)
+    pki.Plugin(context=context)
+
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/plugins/ovirt-host-deploy/vmconsole/packages.py 
b/src/plugins/ovirt-host-deploy/vmconsole/packages.py
new file mode 100644
index 0000000..5b430f8
--- /dev/null
+++ b/src/plugins/ovirt-host-deploy/vmconsole/packages.py
@@ -0,0 +1,99 @@
+#
+# ovirt-host-deploy -- ovirt host deployer
+# Copyright (C) 2012-2015 Red Hat, Inc.
+#
+# 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
+#
+
+
+"""Serial console PKI artifacts."""
+
+
+import gettext
+
+
+from otopi import plugin
+from otopi import util
+
+
+from ovirt_host_deploy import constants as odeploycons
+
+
+def _(m):
+    return gettext.dgettext(message=m, domain='ovirt-host-deploy')
+
+
+@util.export
+class Plugin(plugin.PluginBase):
+
+    def __init__(self, context):
+        super(Plugin, self).__init__(context=context)
+        self._enabled = False
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_INIT,
+    )
+    def _init(self):
+        self._enabled = False
+        self.environment.setdefault(
+            odeploycons.VMConsoleEnv.ENABLE,
+            False
+        )
+        self.environment.setdefault(
+            odeploycons.VMConsoleEnv.SUPPORT,
+            odeploycons.Const.VMCONSOLE_SUPPORT_NONE
+        )
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_CUSTOMIZATION,
+        priority=plugin.Stages.PRIORITY_HIGH,
+    )
+    def _customization(self):
+        if self.packager.queryPackages(
+            patterns=('ovirt-vmconsole-host',),
+        ):
+            self.environment[
+                odeploycons.VMConsoleEnv.SUPPORT
+            ] = odeploycons.Const.VMCONSOLE_SUPPORT_V1
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_VALIDATION,
+        condition=lambda self: self.environment[
+            odeploycons.VMConsoleEnv.ENABLE
+        ]
+    )
+    def _validation(self):
+        self._enabled = True
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_PACKAGES,
+        condition=lambda self: self._enabled,
+    )
+    def _packages(self):
+        self.packager.installUpdate(('ovirt-vmconsole-host',))
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_CLOSEUP,
+        priority=plugin.Stages.PRIORITY_LOW,
+        condition=lambda self: self._enabled,
+    )
+    def _start(self):
+        self.logger.info(_('Starting ovirt-vmconsole-host-sshd'))
+        if self.services.exists('ovirt-vmconsole-host-sshd'):
+            self.services.state('ovirt-vmconsole-host-sshd', False)
+            self.services.state('ovirt-vmconsole-host-sshd', True)
+
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/plugins/ovirt-host-deploy/vmconsole/pki.py 
b/src/plugins/ovirt-host-deploy/vmconsole/pki.py
new file mode 100644
index 0000000..6433c05
--- /dev/null
+++ b/src/plugins/ovirt-host-deploy/vmconsole/pki.py
@@ -0,0 +1,229 @@
+#
+# ovirt-host-deploy -- ovirt host deployer
+# Copyright (C) 2012-2015 Red Hat, Inc.
+#
+# 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
+#
+
+
+"""Serial console PKI artifacts."""
+
+
+import gettext
+import os
+
+
+from otopi import constants as otopicons
+from otopi import filetransaction
+from otopi import plugin
+from otopi import util
+
+
+from ovirt_host_deploy import constants as odeploycons
+
+
+def _(m):
+    return gettext.dgettext(message=m, domain='ovirt-host-deploy')
+
+
+@util.export
+class Plugin(plugin.PluginBase):
+    def _genReqM2Crypto(self):
+        from M2Crypto import X509, RSA, EVP
+
+        rsa = RSA.gen_key(
+            self.environment[odeploycons.VdsmEnv.KEY_SIZE],
+            65537,
+        )
+        rsapem = rsa.as_pem(cipher=None)
+        evp = EVP.PKey()
+        evp.assign_rsa(rsa)
+        rsa = None  # should not be freed here
+        req = X509.Request()
+        req.set_pubkey(evp)
+        req.sign(evp, 'sha1')
+        return rsapem, req.as_pem()
+
+    def __init__(self, context):
+        super(Plugin, self).__init__(context=context)
+        self._enabled = False
+        self._cleanupFiles = []
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_INIT,
+    )
+    def _init(self):
+        self._enabled = False
+        self.environment.setdefault(
+            odeploycons.VMConsoleEnv.CERTIFICATE,
+            None
+        )
+        self.environment.setdefault(
+            odeploycons.VMConsoleEnv.KEY_SIZE,
+            odeploycons.Defaults.DEFAULT_KEY_SIZE
+        )
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_VALIDATION,
+        condition=lambda self: self.environment[
+            odeploycons.VMConsoleEnv.ENABLE
+        ]
+    )
+    def _validation(self):
+        self._enabled = True
+
+        if self.environment[
+            odeploycons.VdsmEnv.CERTIFICATE_ENROLLMENT
+        ] == odeploycons.Const.CERTIFICATE_ENROLLMENT_ACCEPT:
+            # we cannot perform the following
+            # in validation stage, as we do not have
+            # the trust store location.
+            if not os.path.exists(
+                odeploycons.FileLocations.VMCONSOLE_KEY_PENDING_FILE
+            ):
+                raise RuntimeError(
+                    _('PKI accept mode while no pending request')
+                )
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_PACKAGES,
+        condition=lambda self: self._enabled,
+    )
+    def _packages(self):
+        self.packager.install(('m2crypto',))
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_MISC,
+        priority=plugin.Stages.PRIORITY_LOW,
+        condition=lambda self: self._enabled,
+    )
+    def _misc(self):
+        self.dialog.note(_('Setting up Serial Console PKI'))
+
+        enrollment = self.environment[
+            odeploycons.VdsmEnv.CERTIFICATE_ENROLLMENT
+        ]
+
+        if enrollment == odeploycons.Const.CERTIFICATE_ENROLLMENT_ACCEPT:
+            with open(
+                odeploycons.FileLocations.VMCONSOLE_KEY_PENDING_FILE
+            ) as f:
+                key = f.read()
+        else:
+            key, req = self._genReqM2Crypto()
+
+            self.dialog.displayMultiString(
+                name=odeploycons.Displays.VMCONSOLE_CERTIFICATE_REQUEST,
+                value=req.splitlines(),
+                note=_(
+                    '\n\nPlease issue serial console certificate based '
+                    'on this certificate request\n\n'
+                ),
+            )
+
+        if enrollment == odeploycons.Const.CERTIFICATE_ENROLLMENT_REQUEST:
+            self.environment[odeploycons.CoreEnv.INSTALL_INCOMPLETE] = True
+            self.environment[
+                odeploycons.CoreEnv.INSTALL_INCOMPLETE_REASONS
+            ].append(_('Serial console certificate enrollment required'))
+
+            self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
+                filetransaction.FileTransaction(
+                    name=odeploycons.FileLocations.VMCONSOLE_KEY_PENDING_FILE,
+                    mode=0o400,
+                    enforcePermissions=True,
+                    content=key,
+                    modifiedList=self.environment[
+                        otopicons.CoreEnv.MODIFIED_FILES
+                    ],
+                )
+            )
+        else:
+            self._cleanupFiles.append(
+                odeploycons.FileLocations.VMCONSOLE_KEY_PENDING_FILE
+            )
+
+            cert = self.environment[
+                odeploycons.VMConsoleEnv.CERTIFICATE
+            ]
+
+            if cert is None:
+                cert = self.environment[
+                    odeploycons.VMConsoleEnv.CERTIFICATE
+                ] = self.dialog.queryValue(
+                    name=odeploycons.Queries.VMCONSOLE_CERTIFICATE,
+                    note=_(
+                        '\n\nPlease input serial console certificate chain '
+                        'that matches certificate request, top is issuer\n\n'
+                    ),
+                )
+
+            self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
+                filetransaction.FileTransaction(
+                    name=odeploycons.FileLocations.VMCONSOLE_CA_FILE,
+                    enforcePermissions=True,
+                    content='%s\n' % self.environment[
+                        odeploycons.VMConsoleEnv.CAKEY
+                    ],
+                    modifiedList=self.environment[
+                        otopicons.CoreEnv.MODIFIED_FILES
+                    ],
+                )
+            )
+
+            self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
+                filetransaction.FileTransaction(
+                    name=odeploycons.FileLocations.VMCONSOLE_CERT_FILE,
+                    enforcePermissions=True,
+                    content='%s\n' % cert,
+                    modifiedList=self.environment[
+                        otopicons.CoreEnv.MODIFIED_FILES
+                    ],
+                )
+            )
+
+            self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
+                filetransaction.FileTransaction(
+                    name=odeploycons.FileLocations.VMCONSOLE_KEY_FILE,
+                    owner='ovirt-vmconsole',
+                    group='ovirt-vmconsole',
+                    mode=0o400,
+                    enforcePermissions=True,
+                    content=key,
+                    modifiedList=self.environment[
+                        otopicons.CoreEnv.MODIFIED_FILES
+                    ],
+                )
+            )
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_CLOSEUP,
+        condition=lambda self: self._enabled,
+    )
+    def _closeup(self):
+        for f in self._cleanupFiles:
+            if os.path.exists(f):
+                try:
+                    os.unlink(f)
+                except OSError:
+                    self.logger.warning(
+                        _("Cannot remove file '{name}'.").format(
+                            name=f,
+                        )
+                    )
+                    self.logger.debug(exc_info=True)
+
+
+# vim: expandtab tabstop=4 shiftwidth=4


-- 
To view, visit https://gerrit.ovirt.org/38091
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I45e0b91bb678008dc74ced8622251beccefc82b9
Gerrit-PatchSet: 6
Gerrit-Project: ovirt-host-deploy
Gerrit-Branch: master
Gerrit-Owner: Alon Bar-Lev <alo...@redhat.com>
Gerrit-Reviewer: Alon Bar-Lev <alo...@redhat.com>
Gerrit-Reviewer: Francesco Romani <from...@redhat.com>
Gerrit-Reviewer: Jenkins CI
Gerrit-Reviewer: automat...@ovirt.org
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to