diff mbox series

[v2,04/16] tests/docker: reduce scary warnings from failed inspect

Message ID 20190919171015.12681-5-alex.bennee@linaro.org
State New
Headers show
Series testing/next (docker/podman, tcg, build fixes) | expand

Commit Message

Alex Bennée Sept. 19, 2019, 5:10 p.m. UTC
There is a race here in the clean-up code so lets just accept that
sometimes the active task we just looked up might have finished before
we got to inspect it.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
 tests/docker/docker.py | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

-- 
2.20.1

Comments

Cleber Rosa Sept. 23, 2019, 8:51 p.m. UTC | #1
On Thu, Sep 19, 2019 at 06:10:03PM +0100, Alex Bennée wrote:
> There is a race here in the clean-up code so lets just accept that

> sometimes the active task we just looked up might have finished before

> we got to inspect it.

> 

> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

> ---

>  tests/docker/docker.py | 32 ++++++++++++++++++--------------

>  1 file changed, 18 insertions(+), 14 deletions(-)

> 

> diff --git a/tests/docker/docker.py b/tests/docker/docker.py

> index 29613afd489..4dca6006d2f 100755

> --- a/tests/docker/docker.py

> +++ b/tests/docker/docker.py

> @@ -235,20 +235,24 @@ class Docker(object):

>          if not only_active:

>              cmd.append("-a")

>          for i in self._output(cmd).split():

> -            resp = self._output(["inspect", i])

> -            labels = json.loads(resp)[0]["Config"]["Labels"]

> -            active = json.loads(resp)[0]["State"]["Running"]

> -            if not labels:

> -                continue

> -            instance_uuid = labels.get("com.qemu.instance.uuid", None)

> -            if not instance_uuid:

> -                continue

> -            if only_known and instance_uuid not in self._instances:

> -                continue

> -            print("Terminating", i)

> -            if active:

> -                self._do(["kill", i])

> -            self._do(["rm", i])

> +            try:

> +                resp = self._output(["inspect", i])

> +                labels = json.loads(resp)[0]["Config"]["Labels"]

> +                active = json.loads(resp)[0]["State"]["Running"]

> +                if not labels:

> +                    continue

> +                instance_uuid = labels.get("com.qemu.instance.uuid", None)

> +                if not instance_uuid:

> +                    continue

> +                if only_known and instance_uuid not in self._instances:

> +                    continue

> +                print("Terminating", i)

> +                if active:

> +                    self._do(["kill", i])

> +                    self._do(["rm", i])


Both podman and docker seem to handle "rm -f $INSTANCE" well, which
would by itself consolidate the two commands in one and minimize the
race condition.

For unexisting containers, and no other errors, podman will return "1
if one of the specified containers did not exist, and no other
failure", as per its man page.  I couldn't find any guarantee that
docker will also return 1 on a similar situation, but that's what
I've experienced too:

 $ docker rm -f CONTAINER_IS_NOW_FONE
 Error response from daemon: No such container: CONTAINER_IS_NOW_GONE
 $ echo $?
 1

Maybe waiving exit status 1 and nothing else would do the trick here
and not hide other real problems?

- Cleber.

> +            except subprocess.CalledProcessError:

> +                # i likely finished running before we got here

> +                pass

>  

>      def clean(self):

>          self._do_kill_instances(False, False)

> -- 

> 2.20.1

> 

>
Alex Bennée Sept. 23, 2019, 11 p.m. UTC | #2
Cleber Rosa <crosa@redhat.com> writes:

> On Thu, Sep 19, 2019 at 06:10:03PM +0100, Alex Bennée wrote:

>> There is a race here in the clean-up code so lets just accept that

>> sometimes the active task we just looked up might have finished before

>> we got to inspect it.

>>

>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

>> ---

>>  tests/docker/docker.py | 32 ++++++++++++++++++--------------

>>  1 file changed, 18 insertions(+), 14 deletions(-)

>>

>> diff --git a/tests/docker/docker.py b/tests/docker/docker.py

>> index 29613afd489..4dca6006d2f 100755

>> --- a/tests/docker/docker.py

>> +++ b/tests/docker/docker.py

>> @@ -235,20 +235,24 @@ class Docker(object):

>>          if not only_active:

>>              cmd.append("-a")

>>          for i in self._output(cmd).split():

>> -            resp = self._output(["inspect", i])

>> -            labels = json.loads(resp)[0]["Config"]["Labels"]

>> -            active = json.loads(resp)[0]["State"]["Running"]

>> -            if not labels:

>> -                continue

>> -            instance_uuid = labels.get("com.qemu.instance.uuid", None)

>> -            if not instance_uuid:

>> -                continue

>> -            if only_known and instance_uuid not in self._instances:

>> -                continue

>> -            print("Terminating", i)

>> -            if active:

>> -                self._do(["kill", i])

>> -            self._do(["rm", i])

>> +            try:

>> +                resp = self._output(["inspect", i])

>> +                labels = json.loads(resp)[0]["Config"]["Labels"]

>> +                active = json.loads(resp)[0]["State"]["Running"]

>> +                if not labels:

>> +                    continue

>> +                instance_uuid = labels.get("com.qemu.instance.uuid", None)

>> +                if not instance_uuid:

>> +                    continue

>> +                if only_known and instance_uuid not in self._instances:

>> +                    continue

>> +                print("Terminating", i)

>> +                if active:

>> +                    self._do(["kill", i])

>> +                    self._do(["rm", i])

>

> Both podman and docker seem to handle "rm -f $INSTANCE" well, which

> would by itself consolidate the two commands in one and minimize the

> race condition.


It's the self.__output which is the real race condition because
check_output complains if the command doesn't succeed with 0. What we
really need is to find somewhat of filtering the ps just for qemu
instances and then just rm -f them as you suggest.

>

> For unexisting containers, and no other errors, podman will return "1

> if one of the specified containers did not exist, and no other

> failure", as per its man page.  I couldn't find any guarantee that

> docker will also return 1 on a similar situation, but that's what

> I've experienced too:

>

>  $ docker rm -f CONTAINER_IS_NOW_FONE

>  Error response from daemon: No such container: CONTAINER_IS_NOW_GONE

>  $ echo $?

>  1

>

> Maybe waiving exit status 1 and nothing else would do the trick here

> and not hide other real problems?

>

> - Cleber.

>

>> +            except subprocess.CalledProcessError:

>> +                # i likely finished running before we got here

>> +                pass

>>

>>      def clean(self):

>>          self._do_kill_instances(False, False)

>> --

>> 2.20.1

>>

>>



--
Alex Bennée
diff mbox series

Patch

diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index 29613afd489..4dca6006d2f 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -235,20 +235,24 @@  class Docker(object):
         if not only_active:
             cmd.append("-a")
         for i in self._output(cmd).split():
-            resp = self._output(["inspect", i])
-            labels = json.loads(resp)[0]["Config"]["Labels"]
-            active = json.loads(resp)[0]["State"]["Running"]
-            if not labels:
-                continue
-            instance_uuid = labels.get("com.qemu.instance.uuid", None)
-            if not instance_uuid:
-                continue
-            if only_known and instance_uuid not in self._instances:
-                continue
-            print("Terminating", i)
-            if active:
-                self._do(["kill", i])
-            self._do(["rm", i])
+            try:
+                resp = self._output(["inspect", i])
+                labels = json.loads(resp)[0]["Config"]["Labels"]
+                active = json.loads(resp)[0]["State"]["Running"]
+                if not labels:
+                    continue
+                instance_uuid = labels.get("com.qemu.instance.uuid", None)
+                if not instance_uuid:
+                    continue
+                if only_known and instance_uuid not in self._instances:
+                    continue
+                print("Terminating", i)
+                if active:
+                    self._do(["kill", i])
+                    self._do(["rm", i])
+            except subprocess.CalledProcessError:
+                # i likely finished running before we got here
+                pass
 
     def clean(self):
         self._do_kill_instances(False, False)