From 75a5f45659847d623c83f3cf2e2fbbf8e621b15b Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Tue, 18 Mar 2008 13:02:14 +0000
Subject: [PATCH] Add function to write cluster SSH key to known_hosts file

The whole Ganeti cluster has a single SSH key. Its fingerprint is
written to Ganeti's known_hosts file, together with an alias. This
allows us to always use that alias instead of the real hostname,
making management of the known_hosts file much easier.

This patch does not handle an upgrade from an earlier version.

Reviewed-by: ultrotter
---
 lib/ssh.py                  |  9 +++++++
 test/Makefile.am            |  1 +
 test/ganeti.ssh_unittest.py | 52 +++++++++++++++++++++++++++++++++++++
 test/mocks.py               | 14 +++++++++-
 4 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100755 test/ganeti.ssh_unittest.py

diff --git a/lib/ssh.py b/lib/ssh.py
index 43bba94ba..7cc055b75 100644
--- a/lib/ssh.py
+++ b/lib/ssh.py
@@ -212,3 +212,12 @@ def VerifyNodeHostname(node):
     return False, "hostname mismatch, got %s" % remotehostname
 
   return True, "host matches"
+
+
+def WriteKnownHostsFile(cfg, sstore, file_name):
+  """Writes the cluster-wide equally known_hosts file.
+
+  """
+  utils.WriteFile(file_name, mode=0700,
+                  data="%s ssh-rsa %s\n" % (sstore.GetClusterName(),
+                                            cfg.GetHostKey()))
diff --git a/test/Makefile.am b/test/Makefile.am
index f07885440..6dd716900 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -3,6 +3,7 @@ TESTS = \
   ganeti.hooks_unittest.py \
   ganeti.utils_unittest.py \
   ganeti.bdev_unittest.py \
+  ganeti.ssh_unittest.py \
   ganeti.locking_unittest.py
 
 TESTS_ENVIRONMENT = PYTHONPATH=.:$(top_builddir)
diff --git a/test/ganeti.ssh_unittest.py b/test/ganeti.ssh_unittest.py
new file mode 100755
index 000000000..ac5821e76
--- /dev/null
+++ b/test/ganeti.ssh_unittest.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2006, 2007, 2008 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+"""Script for unittesting the ssh module"""
+
+import os
+import tempfile
+import unittest
+
+import testutils
+import mocks
+
+from ganeti import constants
+from ganeti import utils
+from ganeti import ssh
+
+
+class TestKnownHosts(testutils.GanetiTestCase):
+  """Test case for function writing the known_hosts file"""
+
+  def setUp(self):
+    self.tmpfile = tempfile.NamedTemporaryFile()
+
+  def test(self):
+    cfg = mocks.FakeConfig()
+    sstore = mocks.FakeSStore()
+    ssh.WriteKnownHostsFile(cfg, sstore, self.tmpfile.name)
+    self.assertFileContent(self.tmpfile.name,
+        "%s ssh-rsa %s\n" % (sstore.GetClusterName(),
+                             mocks.FAKE_CLUSTER_KEY))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/test/mocks.py b/test/mocks.py
index 70b6c400d..cfff9c25f 100644
--- a/test/mocks.py
+++ b/test/mocks.py
@@ -21,9 +21,18 @@
 
 """Module implementing a fake ConfigWriter"""
 
-import socket
 from ganeti import utils
 
+
+FAKE_CLUSTER_KEY = ("AAAAB3NzaC1yc2EAAAABIwAAAQEAsuGLw70et3eApJ/ZEJkAVZogIrm"
+                    "EYPQJvb1ll52Ti0nr80Wztxibaa8bYGzY22rQIAloIlePeTGcJceAYK"
+                    "PZgm0I/Mp2EUGg2NVsQZIzasz6cW0vYuiUbF9GkVlROmvOAykT58RfM"
+                    "L8RhPrjrQxZc+NXgZtgDugYSZcXHDLUyWM1xKUoYy0MqYG6ZXCC/Zno"
+                    "RThhmjOJgEmvwrMcTWQjmzH3NeJAxaBsEHR8tiVZ/Y23C/ULWLyNT6R"
+                    "fB+DE7IovsMQaS+83AK1Teg7RWNyQczachatf/JT8VjUqFYjJepPjMb"
+                    "vYdB2nQds7/+Bf40C/OpbvnAxna1kVtgFHAo18cQ==")
+
+
 class FakeConfig:
     """Fake configuration object"""
 
@@ -36,6 +45,9 @@ class FakeConfig:
     def GetMaster(self):
         return utils.HostInfo().name
 
+    def GetHostKey(self):
+        return FAKE_CLUSTER_KEY
+
 
 class FakeSStore:
     """Fake simplestore object"""
-- 
GitLab