[node-patches] Change in ovirt-node[master]: defaults: Add activation stuff

fabiand at fedoraproject.org fabiand at fedoraproject.org
Tue Dec 11 20:09:41 UTC 2012


Fabian Deutsch has uploaded a new change for review.

Change subject: defaults: Add activation stuff
......................................................................

defaults: Add activation stuff

Change-Id: I0c6b09e6ab4c03ef62b53517a9e869f8a2854888
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/TODO
M scripts/tui/src/ovirt/node/config/defaults.py
M scripts/tui/src/ovirt/node/setup/remote_storage_page.py
M scripts/tui/src/ovirt/node/utils/security.py
4 files changed, 324 insertions(+), 22 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/54/9954/1

diff --git a/scripts/tui/TODO b/scripts/tui/TODO
index c20eabf..882af49 100644
--- a/scripts/tui/TODO
+++ b/scripts/tui/TODO
@@ -1,4 +1,3 @@
 - Pull common functionality into NodePlugins (changes helper)
 - Ensure that 80x23 size works
 - Improve List widget - It needs to have a scrollbar or display it's status in another way
-- Add NFSv4 support to storage page
diff --git a/scripts/tui/src/ovirt/node/config/defaults.py b/scripts/tui/src/ovirt/node/config/defaults.py
index 81f9815..5851951 100644
--- a/scripts/tui/src/ovirt/node/config/defaults.py
+++ b/scripts/tui/src/ovirt/node/config/defaults.py
@@ -18,6 +18,11 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
+from ovirt.node import base, exceptions, valid, utils
+import glob
+import logging
+import os
+import ovirt.node.config
 
 """
 Classes and functions related to model of the configuration of oVirt Node.
@@ -34,13 +39,6 @@
 Each class should implement a configure method, mainly to define all the
 required arguments (or keys).
 """
-
-import logging
-import glob
-
-import ovirt.node.config
-from ovirt.node import base, exceptions, valid, utils
-
 
 LOGGER = logging.getLogger(__name__)
 
@@ -516,17 +514,119 @@
     >>> nfs_url = "host.example.com"
     >>> ssh_url = "root at host.example.com"
     >>> n = KDump(cfgfile)
-    >>> n.update(nfs_url, ssh_url)
-    >>> n.retrieve()
+    >>> n.update(nfs_url, ssh_url, '')
+    >>> d = n.retrieve()
+    >>> d[:2]
     [('nfs', 'host.example.com'), ('ssh', 'root at host.example.com')]
+    >>> d[2:]
+    [('local', '')]
     """
     keys = ("OVIRT_KDUMP_NFS",
-            "OVIRT_KDUMP_SSH")
+            "OVIRT_KDUMP_SSH",
+            "OVIRT_KDUMP_LOCAL")
 
     @NodeConfigFileSection.map_and_update_defaults_decorator
-    def update(self, nfs, ssh):
-        valid.FQDNOrIPAddress()(nfs)
-        valid.URL()(ssh)
+    def update(self, nfs, ssh, local):
+        (valid.Empty(or_none=True) | valid.FQDNOrIPAddress())(nfs)
+        (valid.Empty(or_none=True) | valid.URL())(ssh)
+
+    def transaction(self):
+        cfg = dict(self.retrieve())
+        nfs, ssh, restore = (cfg["nfs"], cfg["ssh"], cfg["local"])
+
+        class BackupKdumpConfig(utils.Transaction.Element):
+            def __init__(self):
+                self.backups = utils.fs.BackupedFiles(["/etc/kdump.conf"])
+
+            def commit(self):
+                self.backups.create()
+
+        class RestoreKdumpConfig(utils.Transaction.Element):
+            def commit(self):
+                import ovirtnode.kdump as okdump
+                okdump.restore_kdump_config()
+
+        class CreateNfsKdumpConfig(utils.Transaction.Element):
+            def commit(self):
+                import ovirtnode.kdump as okdump
+                okdump.write_kdump_config(nfs)
+
+        class CreateSshKdumpConfig(utils.Transaction.Element):
+            def commit(self):
+                import ovirtnode.kdump as okdump
+                from ovirtnode.ovirtfunctions import ovirt_store_config
+
+                okdump.write_kdump_config(ssh)
+
+                if os.path.exists("/usr/bin/kdumpctl"):
+                    cmd = "kdumpctl propagate"
+                else:
+                    cmd = "service kdump propagate"
+                cmd += "2>&1"
+
+                success, stdout = utils.process.pipe(cmd)
+
+                if success:
+                    ovirt_store_config(["/root/.ssh/kdump_id_rsa.pub",
+                                        "/root/.ssh/kdump_id_rsa",
+                                        "/root/.ssh/known_hosts",
+                                        "/root/.ssh/config"])
+                else:
+                    self.logger.warning("Failed to activate KDump with " +
+                                        "SSH: %s" % stdout)
+
+        class RemoveKdumpConfig(utils.Transaction.Element):
+            def __init__(self, backups):
+                self.backups = backups
+
+            def commit(self):
+                from ovirtnode.ovirtfunctions import remove_config
+
+                remove_config("/etc/kdump.conf")
+                utils.process.system("service kdump stop")
+                open('/etc/kdump.conf', 'w').close()
+
+                self.backups.remove()
+
+        class RestartKdumpService(utils.Transaction.Element):
+            def __init__(self, backups):
+                self.backups = backups
+
+            def commit(self):
+                from ovirtnode.ovirtfunctions import unmount_config, \
+                                                     ovirt_store_config
+                from ovirt.node.utils.process import system
+
+                if utils.process.system("service kdump restart") > 0:
+                    unmount_config("/etc/kdump.conf")
+                    self.backups.restore("/etc/kdump.conf")
+                    system("service kdump restart")
+
+                    raise RuntimeError("KDump configuration failed, " +
+                                       "location unreachable. Previous " +
+                                       "configuration was restored.")
+
+                ovirt_store_config("/etc/kdump.conf")
+                self.backups.remove()
+
+        tx = utils.Transaction("Configuring kdump")
+
+        backup_txe = BackupKdumpConfig()
+        tx.append(backup_txe)
+
+        final_txe = RestartKdumpService(backup_txe.backups)
+        if nfs:
+            tx.append(CreateNfsKdumpConfig())
+        elif ssh:
+            tx.append(CreateSshKdumpConfig())
+        elif restore:
+            tx.append(RestoreKdumpConfig())
+        else:
+            final_txe = RemoveKdumpConfig(backup_txe.backups)
+
+        tx.append(final_txe)
+
+        return tx
 
 
 class iSCSI(NodeConfigFileSection):
@@ -551,6 +651,19 @@
     def update(self, name, target_name, target_host, target_port):
         # FIXME add validation
         pass
+
+    def transaction(self):
+        cfg = dict(self.retrieve())
+        initiator_name = cfg["name"]
+
+        class ConfigureIscsiInitiator(utils.Transaction.Element):
+            def commit(self):
+                from ovirtnode.iscsi import set_iscsi_initiator
+                set_iscsi_initiator(initiator_name)
+
+        tx = utils.Transaction("Configuring the iSCSI Initiator")
+        tx.append(ConfigureIscsiInitiator())
+        return tx
 
 
 class SNMP(NodeConfigFileSection):
@@ -690,3 +803,93 @@
         tx = utils.Transaction("Configuring keyboard layout")
         tx.append(CreateKeyboardConfig())
         return tx
+
+
+class NFSv4(NodeConfigFileSection):
+    """Configure NFSv4
+
+    >>> fn = "/tmp/cfg_dummy"
+    >>> cfgfile = ConfigFile(fn, SimpleProvider)
+    >>> n = NFSv4(cfgfile)
+    >>> domain = "foo.example"
+    >>> n.update(domain)
+    >>> n.retrieve()
+    [('domain', 'foo.example')]
+    """
+    # FIXME this key is new!
+    keys = ("OVIRT_NFSV4_DOMAIN",)
+
+    @NodeConfigFileSection.map_and_update_defaults_decorator
+    def update(self, domain):
+        # FIXME Some validation that layout is in the list of available layouts
+        pass
+
+    def transaction(self):
+        cfg = dict(self.retrieve())
+        domain = cfg["domain"]
+
+        class ConfigureNfsv4(utils.Transaction.Element):
+            def commit(self):
+                from ovirtnode.network import set_nfsv4_domain
+                set_nfsv4_domain(domain)
+
+        tx = utils.Transaction("Configuring NFSv4")
+        if domain:
+            tx.append(ConfigureNfsv4())
+        return tx
+
+
+class SSH(NodeConfigFileSection):
+    """Configure SSH
+
+    >>> fn = "/tmp/cfg_dummy"
+    >>> cfgfile = ConfigFile(fn, SimpleProvider)
+    >>> n = SSH(cfgfile)
+    >>> pwauth = True
+    >>> n.update(pwauth)
+    >>> n.retrieve()
+    [('pwauth', True)]
+    """
+    keys = ("OVIRT_SSH_PWAUTH",
+            "OVIRT_USE_STRONG_RNG",
+            "OVIRT_ENABLE_AES_NI")
+
+    @NodeConfigFileSection.map_and_update_defaults_decorator
+    def update(self, pwauth, num_bytes, aesni):
+        valid.Boolean()(pwauth)
+        valid.Number()(num_bytes)
+        valid.Boolean()(aesni)
+
+    def retrieve(self):
+        cfg = dict(NodeConfigFileSection.retrieve(self))
+        return {
+                "pwauth": True if cfg["pwauth"] == "yes" else False
+                }
+
+    def transaction(self):
+        cfg = dict(self.retrieve())
+        pwauth, num_bytes, aesni = (cfg["pwauth"], cfg["num_bytes"],
+                                    cfg["aesni"])
+
+        ssh = utils.security.Ssh()
+
+        class ConfigurePasswordAuthentication(utils.Transaction.Element):
+            def commit(self):
+                ssh.password_authentication(pwauth)
+
+        class ConfigureStrongRNG(utils.Transaction.Element):
+            def commit(self):
+                ssh.strong_rng(num_bytes)
+
+        class ConfigureAESNI(utils.Transaction.Element):
+            def commit(self):
+                ssh.aes_ni(aesni)
+
+        tx = utils.Transaction("Configuring SSH")
+        if pwauth:
+            tx.append(ConfigurePasswordAuthentication())
+        if num_bytes:
+            tx.append(ConfigureStrongRNG())
+        if aesni:
+            tx.append(ConfigureAESNI())
+        return tx
diff --git a/scripts/tui/src/ovirt/node/setup/remote_storage_page.py b/scripts/tui/src/ovirt/node/setup/remote_storage_page.py
index 2ca19c6..cb40d0f 100644
--- a/scripts/tui/src/ovirt/node/setup/remote_storage_page.py
+++ b/scripts/tui/src/ovirt/node/setup/remote_storage_page.py
@@ -18,13 +18,15 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
+from ovirt.node import utils
+from ovirt.node.config import defaults
+from ovirt.node.plugins import ChangesHelper
+import ovirt.node.plugins
+import ovirt.node.ui
 
 """
 Configure Remote Storage
 """
-
-import ovirt.node.plugins
-import ovirt.node.ui
 
 
 class Plugin(ovirt.node.plugins.NodePlugin):
@@ -70,4 +72,25 @@
         self._model.update(changes)
 
     def on_merge(self, effective_changes):
-        pass
+        self.logger.debug("Saving remote storage page")
+        changes = ChangesHelper(self.pending_changes(False))
+        model = self.model()
+        model.update(effective_changes)
+        effective_model = ChangesHelper(model)
+
+        self.logger.debug("Saving remote storage page: %s" % changes.changes)
+        self.logger.debug("Remote storage page model: %s" %
+                          effective_model.changes)
+
+        iscsi_keys = ["iscsi.initiator_name"]
+        # FIXME nfsv4 is missing
+
+        txs = utils.Transaction("Updating remote storage configuration")
+
+        if changes.any_key_in_change(iscsi_keys):
+            model = defaults.iSCSI()
+            model.update(*effective_model.get_key_values(iscsi_keys))
+            txs += model.transaction()
+
+        txs.prepare()  # Just to display something in dry mode
+        self.dry_or(lambda: txs())
diff --git a/scripts/tui/src/ovirt/node/utils/security.py b/scripts/tui/src/ovirt/node/utils/security.py
index 387d324..e236ca7 100644
--- a/scripts/tui/src/ovirt/node/utils/security.py
+++ b/scripts/tui/src/ovirt/node/utils/security.py
@@ -18,14 +18,13 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
+from ovirt.node import base, valid, utils
+import process
+import os.path
 
 """
 Some convenience functions related to security
 """
-
-import os.path
-
-import process
 
 
 def get_ssh_hostkey(variant="rsa"):
@@ -40,3 +39,81 @@
     stdout = process.pipe(hostkey_fp_cmd, without_retval=True)
     fingerprint = stdout.strip().split(" ")[1]
     return (fingerprint, hostkey)
+
+
+class Passwd(base.Base):
+    def set_password(self, username, password):
+        import ovirtnode.password as opasswd
+        opasswd.set_password(password, username)
+
+
+class Ssh(base.Base):
+    def __init__(self):
+        super(Ssh, self).__init__()
+        import ovirtnode.ovirtfunctions as ofunc
+        self.ofunc = ofunc
+
+    def __update_profile(self, rng_num_bytes, enable_aes):
+        additional_lines = []
+        self.ofunc.unmount_config("/etc/profile")
+
+        process.system("sed -i '/OPENSSL_DISABLE_AES_NI/d' /etc/profile")
+        if not enable_aes:
+            additional_lines += ["export OPENSSL_DISABLE_AES_NI=1"]
+
+        process.system("sed -i '/SSH_USE_STRONG_RNG/d' /etc/profile")
+        if rng_num_bytes:
+            additional_lines += ["export SSH_USE_STRONG_RNG=%s" %
+                                 rng_num_bytes]
+
+        if additional_lines:
+            self.logger.debug("Updating /etc/profile")
+            with open("/etc/profile", "a") as f:
+                lines = "\n" + "\n".join(additional_lines)
+                f.write(lines)
+            self.ofunc.ovirt_store_config("/etc/profile")
+
+            self.restart()
+
+    def aes_ni(self, enable=None):
+        """Set/Get AES NI for OpenSSL
+        Args:
+            enable: True or False
+        Returns:
+            The status of aes_ni
+        """
+        rng, aes = self.ofunc.rng_status()
+        if enable in [True, False]:
+            self.__update_profile(rng, enable)
+        else:
+            self.logger.warning("Unknown value for AES NI: %s" % enable)
+        return self.ofunc.rng_status()[1]  # FIXME should rurn bool
+        # and does it return disable_aes_ni?
+
+    def strong_rng(self, num_bytes=None):
+        rng, aes = self.ofunc.rng_status()
+        if valid.Number(range=[0, None]).validate(num_bytes):
+            self.__update_profile(num_bytes, aes)
+        elif num_bytes is None:
+            pass
+        else:
+            self.logger.warning("Unknown value for RNG num bytes: " +
+                                "%s" % num_bytes)
+        return self.ofunc.rng_status()[0]
+
+    def restart(self):
+        self.logger.debug("Restarting SSH")
+        process.system("service sshd restart &>/dev/null")
+
+    def password_authentication(self, enable=None):
+        augpath = "/files/etc/ssh/sshd_config/PasswordAuthentication"
+        aug = utils.AugeasWrapper()
+        if enable in [True, False]:
+            import ovirtnode.ovirtfunctions as ofunc
+            value = "yes" if enable else "no"
+            self.logger.debug("Setting SSH PasswordAuthentication to " +
+                              "%s" % value)
+            aug.set(augpath, value)
+            ofunc.ovirt_store_config("/etc/ssh/sshd_config")
+            self.restart()
+        return aug.get(augpath)


--
To view, visit http://gerrit.ovirt.org/9954
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0c6b09e6ab4c03ef62b53517a9e869f8a2854888
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>



More information about the node-patches mailing list