Commit 63c2dea8 authored by Swann Perarnau's avatar Swann Perarnau

[feature] Add kill command

This patch adds a command to kill the parent process of a container
based on the container uuid, triggering the death of the container.

The os.kill command interacts pretty badly with the custom built
children handling, causing us to catch unwanted exceptions in an effort
to keep the code running. The waitpid code was also missing a bit about
catching children exiting because of signals, so we fixed that.

At this point, two things should be paid attention to:
  - we don't distinguish properly between a container and a command.
  This will probably cause issues later, as it should be possible to
  launch multiple programs in the same container, and for partitions to
  survive the death of the parent process.
  - the message format is growing more complex, but without any
  component having strong ownership over it. This will probably cause
  stability issues in the long term, as the format complexifies and we
  lose track of the fields expected from everyone.
parent 2f470afb
......@@ -98,6 +98,26 @@ class CommandLineInterface(object):
self.logger.info("list response: %r", msg)
break
def do_kill(self, argv):
"""Connect to the NRM and ask to kill a container by uuid.
The NRM should respond to us on the pub socket with a message
containing the exit status of the top process of the container."""
command = {'command': 'kill',
'uuid': argv.uuid
}
while(True):
self.upstream_pub_socket.send_json(command)
msg = self.upstream_sub_socket.recv_json()
self.logger.info("new message: %r", msg)
# ignore other messages
if isinstance(msg, dict) and msg.get('type') == 'container':
if msg['event'] == 'exit' and msg['uuid'] == argv.uuid:
self.logger.info("container exit: %r", msg)
break
def do_setpower(self, argv):
""" Connect to the NRM and ask to change the power limit.
......@@ -137,6 +157,11 @@ class CommandLineInterface(object):
nargs=argparse.REMAINDER)
parser_run.set_defaults(func=self.do_run)
# kill container
parser_kill = subparsers.add_parser("kill")
parser_kill.add_argument("uuid", help="uuid of the container")
parser_kill.set_defaults(func=self.do_kill)
# list containers
parser_list = subparsers.add_parser("list")
parser_list.set_defaults(func=self.do_list)
......
......@@ -4,9 +4,11 @@ from aci import ImageManifest
from collections import namedtuple
import logging
import os
import signal
from subprograms import ChrtClient, NodeOSClient, resources
import sys
Container = namedtuple('Container', ['uuid', 'manifest', 'pid'])
......@@ -93,6 +95,16 @@ class ContainerManager(object):
del self.containers[uuid]
del self.pids[c.pid]
def kill(self, uuid):
"""Kill all the processes of a container."""
if uuid in self.containers:
c = self.containers[uuid]
self.logger.debug("killing %r:", c)
try:
os.kill(c.pid, signal.SIGKILL)
except OSError:
pass
def list(self):
"""List the containers in the system."""
fields = ['uuid', 'pid']
......
......@@ -123,6 +123,7 @@ class Daemon(object):
self.containerpids[pid] = msg['uuid']
# TODO: obviously we need to send more info than that
update = {'type': 'container',
'event': 'start',
'uuid': msg['uuid'],
'errno': 0,
'pid': pid,
......@@ -130,10 +131,15 @@ class Daemon(object):
self.upstream_pub.send_json(update)
else:
update = {'type': 'container',
'event': 'start',
'uuid': msg['uuid'],
'errno': pid,
}
self.upstream_pub.send_json(update)
elif command == 'kill':
self.logger.info("asked to kill container: %r", msg)
response = self.container_manager.kill(msg['uuid'])
# no update here, as it will trigger child exit
elif command == 'list':
self.logger.info("asked for container list: %r", msg)
response = self.container_manager.list()
......@@ -194,13 +200,13 @@ class Daemon(object):
# check if its a pid we care about
if pid in self.containerpids:
# check if this is an exit
if os.WIFEXITED(status):
if os.WIFEXITED(status) or os.WIFSIGNALED(status):
uuid = self.containerpids[pid]
self.container_manager.delete(uuid)
msg = {'type': 'container',
'event': 'exit',
'status': status,
'uuid': None,
'uuid': uuid,
}
self.upstream_pub.send_json(msg)
else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment