[elbe-devel] [PATCH v2 1/4] install_elbe_version: implement "elbe control install_elbe_version"

Torben Hohn torben.hohn at linutronix.de
Fri Nov 23 12:17:21 CET 2018


when elbe on the hostmachine is upgraded, it usually can not talk
to the elbe version installed in the initvm.

Add a command that can install a specific elbe version in the initvm.
Inside the initvm apt will install a different version of elbe.
This is picked up by cherrypy. And the restart will happen,
after the asyncqueue is drained.

We have to specify the complete list of packages that need to be
installed at new versions, as the solver is not able to solve
the version locking.

--------------------------------------------------------------------------
The following packages have unmet dependencies:
 elbe-soap : Depends: elbe-daemon (= 2.9.11~bpo8+build251) but it is not going to be installed
 python-elbe-common : Depends: elbe-schema (= 2.9.11~bpo8+build251) but 2.9.12+deb8+build311 is to be installed
                      Depends: python-elbe-bin (= 2.9.11~bpo8+build251) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
--------------------------------------------------------------------------

Therefore the soap API requires that the list of packages to update is passed
from the host into the initvm.

To pass the String Array, the parameter type is declared
as String(max_occurs='unbounded'). According to
https://grokbase.com/t/python/soap/119vw5n35b/python-using-arrays-with-suds#20110927qbg2fy2fdoznyem5lc3xezkjsi
this works properly with suds.

Signed-off-by: Torben Hohn <torben.hohn at linutronix.de>
---
 docs/elbe-control.txt              |  9 +++++++++
 elbepack/daemons/soap/datatypes.py | 14 +++++++++++++-
 elbepack/daemons/soap/esoap.py     | 32 ++++++++++++++++++++++++++++++--
 elbepack/soapclient.py             | 32 ++++++++++++++++++++++++++++++++
 elbepack/version.py                |  7 +++++++
 5 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/docs/elbe-control.txt b/docs/elbe-control.txt
index 44ac28c1..fe5d0b7f 100644
--- a/docs/elbe-control.txt
+++ b/docs/elbe-control.txt
@@ -30,6 +30,7 @@ SYNOPSIS
 'elbe control' [options] 'get_file' <build-dir> <filename>
 'elbe control' [options] 'dump_file' <build-dir> <filename>
 'elbe control' [options] 'shutdown_initvm'
+'elbe control' [options] 'install_elbe_version' <version>
 
 DESCRIPTION
 -----------
@@ -223,6 +224,14 @@ Dump a single File from the project to stdout.
 Make the initvm shutdown.
 
 
+'install_elbe_version' [version]::
+
+Make the initvm install a specific elbe version.
+Defaults to the version of the elbe executable.
+This requires, that the initvm has package sources
+configured properly.
+
+
 Examples
 --------
 
diff --git a/elbepack/daemons/soap/datatypes.py b/elbepack/daemons/soap/datatypes.py
index 159bf8c9..bc1cb891 100644
--- a/elbepack/daemons/soap/datatypes.py
+++ b/elbepack/daemons/soap/datatypes.py
@@ -5,7 +5,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from spyne.model.complex import ComplexModel
-from spyne.model.primitive import Unicode, DateTime
+from spyne.model.primitive import Unicode, DateTime, Integer
 
 
 class SoapProject (ComplexModel):
@@ -34,3 +34,15 @@ class SoapFile (ComplexModel):
     def __init__(self, fi):
         self.name = fi.name
         self.description = fi.description
+
+
+class SoapCmdReply (ComplexModel):
+    __namespace__ = 'soap'
+
+    ret = Integer()
+    out = Unicode()
+
+    def __init__(self, ret, out):
+        # pylint: disable=super-init-not-called
+        self.ret = ret
+        self.out = out
diff --git a/elbepack/daemons/soap/esoap.py b/elbepack/daemons/soap/esoap.py
index b973b592..8edaf3ca 100644
--- a/elbepack/daemons/soap/esoap.py
+++ b/elbepack/daemons/soap/esoap.py
@@ -16,12 +16,13 @@ import sys
 
 from tempfile import NamedTemporaryFile
 
-from elbepack.shellhelper import system
+from elbepack.shellhelper import system, command_out
 from elbepack.version import elbe_version
 from elbepack.elbexml import ValidationMode
+from elbepack.filesystem import hostfs
 
 from .faults import soap_faults
-from .datatypes import SoapProject, SoapFile
+from .datatypes import SoapProject, SoapFile, SoapCmdReply
 from .authentication import authenticated_admin, authenticated_uid
 
 try:
@@ -64,6 +65,33 @@ class ESoap (ServiceBase):
     def list_users(self):
         return [u.name for u in self.app.pm.db.list_users()]
 
+    @rpc(String, String(max_occurs='unbounded'), _returns=SoapCmdReply)
+    @soap_faults
+    @authenticated_admin
+    def install_elbe_version(self, version, pkglist):
+        pkgs = ['"%s=%s*"' % (p, version) for p in pkglist]
+
+        # Prevent, that elbe daemon is restarted by the
+        # prerm/postinst scripts.
+        # elbe daemon does it itself, because cherrypy
+        # notices that.
+        hostfs.write_file("usr/sbin/policy-rc.d",
+                          0o755, "#!/bin/sh\nexit 101\n")
+        try:
+            env = {'LANG': 'C',
+                   'LANGUAGE': 'C',
+                   'LC_ALL': 'C',
+                   'DEBIAN_FRONTEND': 'noninteractive',
+                   'DEBCONF_NONINTERACTIVE_SEEN': 'true'}
+
+            cmd = 'apt-get install -y --force-yes %s' % ' '.join(pkgs)
+
+            ret, out = command_out(cmd, env_add=env)
+        finally:
+            hostfs.remove('usr/sbin/policy-rc.d')
+
+        return SoapCmdReply(ret, out)
+
     @rpc(String,String,String,String,Boolean)
     @soap_faults
     @authenticated_admin
diff --git a/elbepack/soapclient.py b/elbepack/soapclient.py
index c7d822d3..b60c4d17 100644
--- a/elbepack/soapclient.py
+++ b/elbepack/soapclient.py
@@ -26,6 +26,7 @@ from suds import WebFault
 
 from elbepack.filesystem import Filesystem
 from elbepack.elbexml import ElbeXML, ValidationMode
+from elbepack.version import elbe_version, elbe_initvm_packagelist
 
 
 def set_suds_debug(debug):
@@ -791,6 +792,37 @@ class UpdatePbuilderAction(ClientAction):
 
 ClientAction.register(UpdatePbuilderAction)
 
+class InstallElbeVersion(ClientAction):
+
+    tag = 'install_elbe_version'
+
+    def __init__(self, node):
+        ClientAction.__init__(self, node)
+
+    def execute(self, client, _opt, args):
+        if len(args) > 1:
+            print(
+                "usage: elbe control install_elbe_version [version]",
+                file=sys.stderr)
+            sys.exit(20)
+
+        if args:
+            version = args[0]
+        else:
+            version = elbe_version
+
+        result = client.service.install_elbe_version(version,
+                                                     elbe_initvm_packagelist)
+
+        print(result.out)
+
+        if result.ret == 0:
+            print('\nSuccess !!!')
+        else:
+            print('\nError: apt returns %d' % result.ret)
+
+
+ClientAction.register(InstallElbeVersion)
 
 class RepoAction(ClientAction):
     repoactiondict = {}
diff --git a/elbepack/version.py b/elbepack/version.py
index 42575258..dd59268f 100644
--- a/elbepack/version.py
+++ b/elbepack/version.py
@@ -11,6 +11,13 @@ from elbepack.directories import pack_dir
 elbe_version = "2.9.13"
 running_os = linux_distribution()
 
+elbe_initvm_packagelist = ['python-elbe-buildenv',
+                           'elbe-soap',
+                           'python-elbe-common',
+                           'elbe-daemon',
+                           'elbe-schema',
+                           'python-elbe-bin']
+
 if pack_dir == '/usr/lib/python2.7/dist-packages/elbepack':
     is_devel = False
 else:
-- 
2.11.0




More information about the elbe-devel mailing list