--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: stretch
User: release.debian....@packages.debian.org
Usertags: pu
Dear SRMs,
I'd like to update ganeti in Stretch once more, fixing the following
issues:
- The fix for #895599 that was included in +deb9u2 unfortunately was
incomplete; I failed to cherry-pick an additional patch rendering the
fix ineffective.
- Ganeti uses an embedded CA to establish trust between cluster nodes.
This CA signs certificates using SHA-1 digests by default and
SHA-1-signed certificates are not acceptable by OpenSSL when a
security level of 2 or higher is in effect. OpenSSL in Buster will
(most probably) have a security level of 2 on by default, meaning
that upon upgrading to Buster ganeti clusters will experience
breakage. Since SHA-1 is weak and deprecated anyway, I would like to
backport a change from unstable to make the CA use SHA-256 for
certificate signatures, to allow cluster administrators to upgrade
their crypto before actually upgrading to Buster. See #907216 and
#907569 for more information.
- The bash completion script shipped in Stretch is ineffective.
Although nothing changed on Ganeti's side between Jessie and Stretch,
bash completion stopped working when dh_bash-completion stopped
placing scripts in /etc/bash_completion.d/ (see #668254) and moved to
/usr/share/bash-completion/ instead. This change broke ganeti's
completion because it is not autoloadable: there's only one script
which does not match any command name (see #864755). This has already
been fixed in unstable by symlinking the completion file to all
supported command names. This being really a regression from a
functional point of view, I would like to backport the fix to
Stretch.
Attached is the full source debdiff for the proposed update. I might
update the wording in d/NEWS and the `gnt-cluster verify' output before
uploading, but functionally I don't expect any further changes.
Regards,
Apollon
diff -Nru ganeti-2.15.2/debian/changelog ganeti-2.15.2/debian/changelog
--- ganeti-2.15.2/debian/changelog 2018-06-11 17:42:10.000000000 +0300
+++ ganeti-2.15.2/debian/changelog 2018-09-08 20:22:03.000000000 +0300
@@ -1,3 +1,14 @@
+ganeti (2.15.2-7+deb9u3) stretch; urgency=medium
+
+ * Properly verify SSL certificates during VM export (#2) (Closes: #895599,
#908112)
+ * Sign generated certificates using SHA256 instead of SHA1 (Closes: #907569)
+ + d/NEWS: ask users to run gnt-cluster renew-crypto
+ + cluster verify: warn about weak certificates
+ * Make bash completions autoloadable (Closes: #864755)
+ + Cleanup obsolete /etc/bash_completion.d/ganeti
+
+ -- Apollon Oikonomopoulos <apoi...@debian.org> Sat, 08 Sep 2018 20:22:03
+0300
+
ganeti (2.15.2-7+deb9u2) stretch; urgency=medium
* Properly verify SSL certificates during VM export (Closes: #895599)
diff -Nru ganeti-2.15.2/debian/ganeti.maintscript
ganeti-2.15.2/debian/ganeti.maintscript
--- ganeti-2.15.2/debian/ganeti.maintscript 1970-01-01 02:00:00.000000000
+0200
+++ ganeti-2.15.2/debian/ganeti.maintscript 2018-09-08 20:22:03.000000000
+0300
@@ -0,0 +1 @@
+rm_conffile /etc/bash_completion.d/ganeti 2.15.2-7+deb9u3~
diff -Nru ganeti-2.15.2/debian/gbp.conf ganeti-2.15.2/debian/gbp.conf
--- ganeti-2.15.2/debian/gbp.conf 2018-06-11 17:42:10.000000000 +0300
+++ ganeti-2.15.2/debian/gbp.conf 2018-09-08 20:22:03.000000000 +0300
@@ -4,6 +4,8 @@
upstream-tag = v%(version)s
upstream-tree = tag
upstream-branch = stable-2.15
+debian-branch = debian/stable/stretch
+dist = stretch
[git-buildpackage]
export-dir = ../build-area/
diff -Nru ganeti-2.15.2/debian/NEWS ganeti-2.15.2/debian/NEWS
--- ganeti-2.15.2/debian/NEWS 2018-06-11 17:42:10.000000000 +0300
+++ ganeti-2.15.2/debian/NEWS 2018-09-08 20:22:03.000000000 +0300
@@ -1,3 +1,27 @@
+ganeti (2.15.2-7+deb9u2) stretch; urgency=medium
+
+ This version changes Ganeti's internal CA, which is used to secure
+ intra-cluster RPC, to use SHA256 digests when signing certificates.
+ Previously issued certificates were signed using SHA1 and will be rejected
+ by newer OpenSSL versions, causing cluster malfunction. This will be a
+ problem with the upcoming Debian Buster release, so Ganeti's CA must be
+ switched over to SHA-256 before upgrading to Buster.
+
+ After upgrading all nodes to this package version, please run
+
+ gnt-cluster renew-crypto --new-cluster-certificate
+
+ at a convenient time to re-generate the cluster's certificates using the new
+ signing algorithm. This operation does not incur any instance downtime,
+ however you will not be able to issue any gnt-* commands while renew-crypto
+ is running.
+
+ If you are using built-in certificates for RAPI and/or spice, please
+ consider adding --new-rapi-certificate and --new-spice-certificate
+ respectively to the above command.
+
+ -- Apollon Oikonomopoulos <apoi...@debian.org> Mon, 03 Sep 2018 14:36:39
+0300
+
ganeti (2.15.2-7+deb9u1) stretch; urgency=medium
This version introduces support for non-DSA SSH keys. Previously, Ganeti
diff -Nru ganeti-2.15.2/debian/patches/ca-use-sha256-md.patch
ganeti-2.15.2/debian/patches/ca-use-sha256-md.patch
--- ganeti-2.15.2/debian/patches/ca-use-sha256-md.patch 1970-01-01
02:00:00.000000000 +0200
+++ ganeti-2.15.2/debian/patches/ca-use-sha256-md.patch 2018-09-08
20:22:03.000000000 +0300
@@ -0,0 +1,49 @@
+Author: Apollon Oikonomopoulos <apoi...@debian.org>
+Description: Sign generated certs using SHA256
+ Ganeti uses SHA1 digests for signed certificates, which are then rejected by
+ OpenSSL when using SECLEVEL >= 2. Since SHA1 is deprecated and considered weak
+ by several parties, we switch to using SHA256 instead.
+ .
+ While at it, drop the private definition of X509_CERT_SIGN_DIGEST from
+ utils.x509 and use the global definition from constants instead.
+Last-Update: 2018-08-27
+Bug-Debian: https://bugs.debian.org/907216
+--- a/lib/utils/x509.py
++++ b/lib/utils/x509.py
+@@ -54,7 +54,6 @@
+ (re.escape(constants.X509_CERT_SIGNATURE_HEADER),
+ HEX_CHAR_RE, HEX_CHAR_RE),
+ re.S | re.I)
+-X509_CERT_SIGN_DIGEST = "SHA1"
+
+ # Certificate verification results
+ (CERT_WARNING,
+@@ -349,7 +348,7 @@
+ req = OpenSSL.crypto.X509Req()
+ req.get_subject().CN = common_name
+ req.set_pubkey(key_pair)
+- req.sign(key_pair, X509_CERT_SIGN_DIGEST)
++ req.sign(key_pair, constants.X509_CERT_SIGN_DIGEST)
+
+ # Load the certificates used for signing.
+ signing_key = OpenSSL.crypto.load_privatekey(
+@@ -365,7 +364,7 @@
+ cert.gmtime_adj_notAfter(validity)
+ cert.set_issuer(signing_cert.get_subject())
+ cert.set_pubkey(req.get_pubkey())
+- cert.sign(signing_key, X509_CERT_SIGN_DIGEST)
++ cert.sign(signing_key, constants.X509_CERT_SIGN_DIGEST)
+
+ # Encode the key and certificate in PEM format.
+ key_pem = OpenSSL.crypto.dump_privatekey(
+--- a/src/Ganeti/Constants.hs
++++ b/src/Ganeti/Constants.hs
+@@ -617,7 +617,7 @@
+
+ -- | Digest used to sign certificates ("openssl x509" uses SHA1 by default)
+ x509CertSignDigest :: String
+-x509CertSignDigest = "SHA1"
++x509CertSignDigest = "SHA256"
+
+ -- * Import/export daemon mode
+
diff -Nru
ganeti-2.15.2/debian/patches/impexpd-fix-certificate-verification-with-new-socat-2.patch
ganeti-2.15.2/debian/patches/impexpd-fix-certificate-verification-with-new-socat-2.patch
---
ganeti-2.15.2/debian/patches/impexpd-fix-certificate-verification-with-new-socat-2.patch
1970-01-01 02:00:00.000000000 +0200
+++
ganeti-2.15.2/debian/patches/impexpd-fix-certificate-verification-with-new-socat-2.patch
2018-09-08 20:22:03.000000000 +0300
@@ -0,0 +1,38 @@
+From 5f90a0f64bf5fee7fe353a95d02c79736a5943c5 Mon Sep 17 00:00:00 2001
+From: Federico Morg Pareschi <m...@google.com>
+Date: Thu, 4 Jan 2018 14:54:59 +0000
+Subject: [PATCH] Fix incorrect SOCAT_PATH constant and match typo
+
+This is a small fix to correct the previous socat change which broke
+python and tests.
+
+Signed-off-by: Federico Morg Pareschi <m...@google.com>
+---
+ lib/impexpd/__init__.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/lib/impexpd/__init__.py b/lib/impexpd/__init__.py
+index 850bdb987..cb1b9c489 100644
+--- a/lib/impexpd/__init__.py
++++ b/lib/impexpd/__init__.py
+@@ -200,7 +200,7 @@ class CommandBuilder(object):
+ # For socat versions >= 1.7.3, we need to also specify
+ # openssl-commonname, otherwise server certificate verification will
+ # fail.
+- socat = utils.RunCmd([SOCAT_PATH, "-V"])
++ socat = utils.RunCmd([constants.SOCAT_PATH, "-V"])
+ # No need to check for errors here. If -V is not there, socat is really
+ # old. Any other failure will be handled when running the actual socat
+ # command.
+@@ -208,7 +208,7 @@ class CommandBuilder(object):
+ match = re.match(r"socat version ((\d+\.)*(\d+))", line)
+ if match:
+ try:
+- version = tuple(int(x) for x in m.group(1).split('.'))
++ version = tuple(int(x) for x in match.group(1).split('.'))
+ if version >= (1, 7, 3):
+ addr2 += ["openssl-commonname=%s" % constants.X509_CERT_CN]
+ except TypeError:
+--
+2.18.0
+
diff -Nru ganeti-2.15.2/debian/patches/series
ganeti-2.15.2/debian/patches/series
--- ganeti-2.15.2/debian/patches/series 2018-06-11 17:42:10.000000000 +0300
+++ ganeti-2.15.2/debian/patches/series 2018-09-08 20:22:03.000000000 +0300
@@ -17,3 +17,6 @@
do-not-specify-socat-ssl-method.patch
fix-failover-from-dead-node.patch
impexpd-fix-certificate-verification-with-new-socat.patch
+impexpd-fix-certificate-verification-with-new-socat-2.patch
+ca-use-sha256-md.patch
+verify-warn-about-weak-certs.patch
diff -Nru ganeti-2.15.2/debian/patches/verify-warn-about-weak-certs.patch
ganeti-2.15.2/debian/patches/verify-warn-about-weak-certs.patch
--- ganeti-2.15.2/debian/patches/verify-warn-about-weak-certs.patch
1970-01-01 02:00:00.000000000 +0200
+++ ganeti-2.15.2/debian/patches/verify-warn-about-weak-certs.patch
2018-09-08 20:22:03.000000000 +0300
@@ -0,0 +1,306 @@
+From 943270936e76648d8626e4b81f9ae14de668075f Mon Sep 17 00:00:00 2001
+From: Apollon Oikonomopoulos <apoi...@debian.org>
+Date: Mon, 3 Sep 2018 15:54:10 +0300
+Subject: [PATCH] verify: warn about weak cert keys or signing algos
+
+Extend x509.VerifyX509Certificate() to also check certificates for weak
+keys or signing algorithms. Rename _VerifyCertificateInner() to
+_VerifyX509CertificateValidity() to better match what it does, and add a
+new _VerifyX509CertificateStrength() function that checks:
+
+ - whether the public key's length is smaller than
+ constants.RSA_KEY_BITS
+ - whether the certificate is signed using a known-weak signature
+ algorithm
+
+Apart from cluster verify, VerifyX509Certificate() is also called in a
+number of places as a pre-flight check with expiration warnings
+disabled, where every non-empty response is treated as a hard error. In
+order not to break these uses, we need to change
+VerifyX509Certificate()'s API to make strength checks optional. Also we
+refactor the error handling logic to return multiple error XOR warning
+message that originate from different checks.
+
+Signed-off-by: Apollon Oikonomopoulos <apoi...@debian.org>
+---
+ lib/cmdlib/backup.py | 2 +-
+ lib/cmdlib/instance_create.py | 2 +-
+ lib/utils/security.py | 2 +-
+ lib/utils/x509.py | 61 +++++++++++++++++++++--
+ src/Ganeti/Constants.hs | 8 ++++
+ test/py/ganeti.utils.x509_unittest.py | 69 +++++++++++++++++++++------
+ 6 files changed, 122 insertions(+), 22 deletions(-)
+
+--- a/lib/cmdlib/backup.py
++++ b/lib/cmdlib/backup.py
+@@ -251,7 +251,7 @@
+ raise errors.OpPrereqError("Unable to load destination X509 CA (%s)" %
+ (err, ), errors.ECODE_INVAL)
+
+- (errcode, msg) = utils.VerifyX509Certificate(cert, None, None)
++ (errcode, msg) = utils.VerifyX509Certificate(cert, None, None, False)
+ if errcode is not None:
+ raise errors.OpPrereqError("Invalid destination X509 CA (%s)" %
+ (msg, ), errors.ECODE_INVAL)
+--- a/lib/cmdlib/instance_create.py
++++ b/lib/cmdlib/instance_create.py
+@@ -316,7 +316,7 @@
+ raise errors.OpPrereqError("Unable to load source X509 CA (%s)" %
+ (err, ), errors.ECODE_INVAL)
+
+- (errcode, msg) = utils.VerifyX509Certificate(cert, None, None)
++ (errcode, msg) = utils.VerifyX509Certificate(cert, None, None, False)
+ if errcode is not None:
+ raise errors.OpPrereqError("Invalid source X509 CA (%s)" % (msg, ),
+ errors.ECODE_INVAL)
+--- a/lib/utils/security.py
++++ b/lib/utils/security.py
+@@ -119,7 +119,7 @@
+
+ (errcode, msg) = \
+ x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
+- constants.SSL_CERT_EXPIRATION_ERROR)
++ constants.SSL_CERT_EXPIRATION_ERROR, True)
+
+ if msg:
+ fnamemsg = "While verifying %s: %s" % (filename, msg)
+--- a/lib/utils/x509.py
++++ b/lib/utils/x509.py
+@@ -38,6 +38,8 @@
+ import calendar
+ import errno
+ import logging
++import itertools
++import operator
+
+ from ganeti import errors
+ from ganeti import constants
+@@ -127,8 +129,8 @@
+ return (not_before, not_after)
+
+
+-def _VerifyCertificateInner(expired, not_before, not_after, now,
+- warn_days, error_days):
++def _VerifyX509CertificateValidity(expired, not_before, not_after, now,
++ warn_days, error_days):
+ """Verifies certificate validity.
+
+ @type expired: bool
+@@ -178,7 +180,33 @@
+ return (None, None)
+
+
+-def VerifyX509Certificate(cert, warn_days, error_days):
++def _VerifyX509CertificateStrength(cert):
++ """Verifies the strength of a certificate
++
++ @type sig_algo: string
++ @param sig_algo: Name of the algorithm used to sign the certificate
++ @type key_bits: int
++ @param key_bits: Length of the public/private key in bits
++ """
++ sig_algo = cert.get_signature_algorithm()
++ key_bits = cert.get_pubkey().bits()
++
++ warnings = []
++ if sig_algo in constants.X509_WEAK_SIGNATURE_ALGORITHMS:
++ warnings.append("weak signature algorithm '%s'" % sig_algo)
++
++ if key_bits < constants.RSA_KEY_BITS:
++ warnings.append("weak public/private keypair: %d bits,"
++ " should be at least %d bits" %
++ (key_bits, constants.RSA_KEY_BITS))
++
++ if warnings:
++ warnings.append("see /usr/share/doc/ganeti/NEWS.Debian.gz")
++ return (CERT_WARNING, ", ".join(warnings))
++ return (None, None)
++
++
++def VerifyX509Certificate(cert, warn_days, error_days, check_strength):
+ """Verifies a certificate for LUClusterVerify.
+
+ @type cert: OpenSSL.crypto.X509
+@@ -187,6 +215,8 @@
+ @param warn_days: How many days before expiration a warning should be
reported
+ @type error_days: number or None
+ @param error_days: How many days before expiration an error should be
reported
++ @type check_strength: bool
++ @param check_strength: Whether to check the certificate's strength
+
+ """
+ # Depending on the pyOpenSSL version, this can just return (None, None)
+@@ -194,8 +224,28 @@
+
+ now = time.time() + constants.NODE_MAX_CLOCK_SKEW
+
+- return _VerifyCertificateInner(cert.has_expired(), not_before, not_after,
+- now, warn_days, error_days)
++ checks = []
++ checks.append(_VerifyX509CertificateValidity(cert.has_expired(), not_before,
++ not_after, now, warn_days,
++ error_days))
++
++ if check_strength:
++ checks.append(_VerifyX509CertificateStrength(cert))
++
++
++ keyfunc = operator.itemgetter(0)
++
++ # Drop non-error results
++ checks = [c for c in checks if keyfunc(c) is not None]
++
++ if not checks:
++ return (None, None)
++
++ # Return all errors of the most severe level
++ for level, errors in itertools.groupby(sorted(checks, key=keyfunc,
++ reverse=True),
++ keyfunc):
++ return (level, ", ".join(e[1] for e in errors))
+
+
+ def SignX509Certificate(cert, key, salt):
+--- a/src/Ganeti/Constants.hs
++++ b/src/Ganeti/Constants.hs
+@@ -619,6 +619,14 @@
+ x509CertSignDigest :: String
+ x509CertSignDigest = "SHA256"
+
++-- | Known-weak certificate signature algorithms
++x509SignatureAlgoSha1 :: String
++x509SignatureAlgoSha1 = "sha1WithRSAEncryption"
++
++x509WeakSignatureAlgorithms :: FrozenSet String
++x509WeakSignatureAlgorithms = ConstantUtils.mkSet [x509SignatureAlgoSha1]
++
++
+ -- * Import/export daemon mode
+
+ iemExport :: String
+--- a/test/py/ganeti.utils.x509_unittest.py
++++ b/test/py/ganeti.utils.x509_unittest.py
+@@ -159,9 +159,13 @@
+ testutils.GanetiTestCase.setUp(self)
+
+ self.tmpdir = tempfile.mkdtemp()
++ self.orig_rsa_key_bits = constants.RSA_KEY_BITS
++ self.orig_x509_weak_signature_algorithms =
constants.X509_WEAK_SIGNATURE_ALGORITHMS
+
+ def tearDown(self):
+ shutil.rmtree(self.tmpdir)
++ constants.RSA_KEY_BITS = self.orig_rsa_key_bits
++ constants.X509_WEAK_SIGNATURE_ALGORITHMS =
self.orig_x509_weak_signature_algorithms
+
+ def testVerifyCertificate(self):
+ cert_pem = testutils.ReadTestData("cert1.pem")
+@@ -169,7 +173,7 @@
+ cert_pem)
+
+ # Not checking return value as this certificate is expired
+- utils.VerifyX509Certificate(cert, 30, 7)
++ utils.VerifyX509Certificate(cert, 30, 7, True)
+
+ @staticmethod
+ def _GenCert(key, before, validity):
+@@ -198,50 +202,87 @@
+ # few lines take more than NODE_MAX_CLOCK_SKEW / 2
+ for before in [-1, 0, SKEW / 4, SKEW / 2]:
+ cert = self._GenCert(key, before, validity)
+- result = utils.VerifyX509Certificate(cert, 1, 2)
++ result = utils.VerifyX509Certificate(cert, 1, 2, True)
+ self.assertEqual(result, (None, None))
+
+ # skew too great, not accepting certs
+ for before in [SKEW * 2, SKEW * 10]:
+ cert = self._GenCert(key, before, validity)
+- (status, msg) = utils.VerifyX509Certificate(cert, 1, 2)
++ (status, msg) = utils.VerifyX509Certificate(cert, 1, 2, True)
+ self.assertEqual(status, utils.CERT_WARNING)
+ self.assertTrue(msg.startswith("Certificate not yet valid"))
+
++ def testKeyStrength(self):
++ # Create private and public key
++ key = OpenSSL.crypto.PKey()
++ key.generate_key(OpenSSL.crypto.TYPE_RSA, constants.RSA_KEY_BITS)
++
++ validity = 7 * 86400
++ cert = self._GenCert(key, 0, validity)
++
++ result = utils.VerifyX509Certificate(cert, None, None, True)
++ self.assertEqual(result, (None, None))
++
++ constants.RSA_KEY_BITS *= 2
++ status, msg = utils.VerifyX509Certificate(cert, None, None, True)
++ self.assertTrue(status == utils.CERT_WARNING)
++ self.assertTrue(msg.startswith("weak public/private key"))
++ constants.RSA_KEY_BITS = self.orig_rsa_key_bits
++
++ def testSigningAlgoStrength(self):
++ # Create private and public key
++ key = OpenSSL.crypto.PKey()
++ key.generate_key(OpenSSL.crypto.TYPE_RSA, constants.RSA_KEY_BITS)
++
++ validity = 7 * 86400
++ cert = self._GenCert(key, 0, validity)
++
++ result = utils.VerifyX509Certificate(cert, None, None, True)
++ self.assertEqual(result, (None, None))
++
++ signing_algo = cert.get_signature_algorithm()
++
++ constants.X509_WEAK_SIGNATURE_ALGORITHMS = \
++ constants.X509_WEAK_SIGNATURE_ALGORITHMS.union([signing_algo])
++ status, msg = utils.VerifyX509Certificate(cert, None, None, True)
++ self.assertTrue(status == utils.CERT_WARNING)
++ self.assertTrue(msg.startswith("weak signature algorithm"))
++ constants.X509_WEAK_SIGNATURE_ALGORITHMS =
self.orig_x509_weak_signature_algorithms
++
+
+-class TestVerifyCertificateInner(unittest.TestCase):
++class TestVerifyX509CertificateValidity(unittest.TestCase):
+ def test(self):
+- vci = utils.x509._VerifyCertificateInner
++ vcv = utils.x509._VerifyX509CertificateValidity
+
+ # Valid
+- self.assertEqual(vci(False, 1263916313, 1298476313, 1266940313, 30, 7),
++ self.assertEqual(vcv(False, 1263916313, 1298476313, 1266940313, 30, 7),
+ (None, None))
+
+ # Not yet valid
+- (errcode, msg) = vci(False, 1266507600, 1267544400, 1266075600, 30, 7)
++ (errcode, msg) = vcv(False, 1266507600, 1267544400, 1266075600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_WARNING)
+
+ # Expiring soon
+- (errcode, msg) = vci(False, 1266507600, 1267544400, 1266939600, 30, 7)
++ (errcode, msg) = vcv(False, 1266507600, 1267544400, 1266939600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_ERROR)
+
+- (errcode, msg) = vci(False, 1266507600, 1267544400, 1266939600, 30, 1)
++ (errcode, msg) = vcv(False, 1266507600, 1267544400, 1266939600, 30, 1)
+ self.assertEqual(errcode, utils.CERT_WARNING)
+
+- (errcode, msg) = vci(False, 1266507600, None, 1266939600, 30, 7)
++ (errcode, msg) = vcv(False, 1266507600, None, 1266939600, 30, 7)
+ self.assertEqual(errcode, None)
+
+ # Expired
+- (errcode, msg) = vci(True, 1266507600, 1267544400, 1266939600, 30, 7)
++ (errcode, msg) = vcv(True, 1266507600, 1267544400, 1266939600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_ERROR)
+
+- (errcode, msg) = vci(True, None, 1267544400, 1266939600, 30, 7)
++ (errcode, msg) = vcv(True, None, 1267544400, 1266939600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_ERROR)
+
+- (errcode, msg) = vci(True, 1266507600, None, 1266939600, 30, 7)
++ (errcode, msg) = vcv(True, 1266507600, None, 1266939600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_ERROR)
+
+- (errcode, msg) = vci(True, None, None, 1266939600, 30, 7)
++ (errcode, msg) = vcv(True, None, None, 1266939600, 30, 7)
+ self.assertEqual(errcode, utils.CERT_ERROR)
+
+
diff -Nru ganeti-2.15.2/debian/rules ganeti-2.15.2/debian/rules
--- ganeti-2.15.2/debian/rules 2018-06-11 17:42:10.000000000 +0300
+++ ganeti-2.15.2/debian/rules 2018-09-08 20:22:03.000000000 +0300
@@ -147,6 +147,13 @@
# Now let dh_link fix all symlinks
dh_link
+
+ # Make bash completion autoloadable
+ for script in $$(grep ^complete
$(CURDIR)/debian/ganeti/usr/share/bash-completion/completions/ganeti \
+ | awk '/ +[a-z_-]+$$/ { print $$NF }') ; do \
+ dh_link -pganeti "usr/share/bash-completion/completions/ganeti"
\
+
"usr/share/bash-completion/completions/$$script" ; \
+ done
# Disable dh_sphinxdoc for binary-arch, as it will raise an error
override_dh_sphinxdoc-arch:
--- End Message ---