Implement pypodman start command

* Improve error messages from argparse Actions
* Silence more pylint errors when supporting a given API
* Refactor BooleanAction to support lower and mixed case input
* Remove spurious print()

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2018-11-16 14:54:07 -07:00
parent cd5742ff47
commit 0d21b90016
4 changed files with 97 additions and 18 deletions

View File

@ -19,9 +19,13 @@ class Mixin:
"""
if stdin is None:
stdin = sys.stdin.fileno()
elif hasattr(stdin, 'fileno'):
stdin = stdin.fileno()
if stdout is None:
stdout = sys.stdout.fileno()
elif hasattr(stdout, 'fileno'):
stdout = stdout.fileno()
with self._client() as podman:
attach = podman.GetAttachSockets(self._id)
@ -49,7 +53,7 @@ class Mixin:
def resize_handler(self):
"""Send the new window size to conmon."""
def wrapped(signum, frame):
def wrapped(signum, frame): # pylint: disable=unused-argument
packed = fcntl.ioctl(self.pseudo_tty.stdout, termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0))
rows, cols, _, _ = struct.unpack('HHHH', packed)
@ -67,7 +71,7 @@ class Mixin:
def log_handler(self):
"""Send command to reopen log to conmon."""
def wrapped(signum, frame):
def wrapped(signum, frame): # pylint: disable=unused-argument
with open(self.pseudo_tty.control_socket, 'w') as skt:
# send conmon reopen log message
skt.write('2\n')

View File

@ -22,6 +22,7 @@ from pypodman.lib.actions.rm_action import Rm
from pypodman.lib.actions.rmi_action import Rmi
from pypodman.lib.actions.run_action import Run
from pypodman.lib.actions.search_action import Search
from pypodman.lib.actions.start_action import Start
from pypodman.lib.actions.version_action import Version
__all__ = [
@ -48,5 +49,6 @@ __all__ = [
'Rmi',
'Run',
'Search',
'Start',
'Version',
]

View File

@ -0,0 +1,76 @@
"""Remote client command for starting containers."""
import sys
import podman
from pypodman.lib import AbstractActionBase, BooleanAction
class Start(AbstractActionBase):
"""Class for starting container."""
@classmethod
def subparser(cls, parent):
"""Add Start command to parent parser."""
parser = parent.add_parser('start', help='start container')
parser.add_argument(
'--attach',
'-a',
action=BooleanAction,
default=False,
help="Attach container's STDOUT and STDERR (default: %(default)s)")
parser.add_argument(
'--detach-keys',
metavar='KEY(s)',
default=4,
help='Override the key sequence for detaching a container.'
' (format: a single character [a-Z] or ctrl-<value> where'
' <value> is one of: a-z, @, ^, [, , or _) (default: ^D)')
parser.add_argument(
'--interactive',
'-i',
action=BooleanAction,
default=False,
help="Attach container's STDIN (default: %(default)s)")
# TODO: Implement sig-proxy
parser.add_argument(
'--sig-proxy',
action=BooleanAction,
default=False,
help="Proxy received signals to the process (default: %(default)s)"
)
parser.add_argument(
'containers',
nargs='+',
help='containers to start',
)
parser.set_defaults(class_=cls, method='start')
def start(self):
"""Start provided containers."""
stdin = sys.stdin if self.opts['interactive'] else None
stdout = sys.stdout if self.opts['attach'] else None
try:
for ident in self._args.containers:
try:
ctnr = self.client.containers.get(ident)
ctnr.attach(
eot=self.opts['detach_keys'],
stdin=stdin,
stdout=stdout)
ctnr.start()
except podman.ContainerNotFound as e:
sys.stdout.flush()
print(
'Container "{}" not found'.format(e.name),
file=sys.stderr,
flush=True)
else:
print(ident)
except podman.ErrorOccurred as e:
sys.stdout.flush()
print(
'{}'.format(e.reason).capitalize(),
file=sys.stderr,
flush=True)
return 1

View File

@ -37,7 +37,7 @@ class BooleanAction(argparse.Action):
const=None,
default=None,
type=None,
choices=('True', 'False'),
choices=None,
required=False,
help=None,
metavar='{True,False}'):
@ -59,7 +59,7 @@ class BooleanAction(argparse.Action):
try:
val = BooleanValidate()(values)
except ValueError:
parser.error('{} must be True or False.'.format(self.dest))
parser.error('"{}" must be True or False.'.format(option_string))
else:
setattr(namespace, self.dest, val)
@ -96,7 +96,6 @@ class ChangeAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
"""Convert and Validate input."""
print(self.dest)
items = getattr(namespace, self.dest, None) or []
items = copy.copy(items)
@ -105,9 +104,9 @@ class ChangeAction(argparse.Action):
opt, val = values.split('=', 1)
if opt not in choices:
parser.error('{} is not a supported "--change" option,'
parser.error('Option "{}" is not supported by argument "{}",'
' valid options are: {}'.format(
opt, ', '.join(choices)))
opt, option_string, ', '.join(choices)))
items.append(values)
setattr(namespace, self.dest, items)
@ -127,8 +126,8 @@ class UnitAction(argparse.Action):
help=None,
metavar='UNIT'):
"""Create UnitAction object."""
help = (help or metavar or dest
) + ' (format: <number>[<unit>], where unit = b, k, m or g)'
help = (help or metavar or dest)\
+ ' (format: <number>[<unit>], where unit = b, k, m or g)'
super().__init__(
option_strings=option_strings,
dest=dest,
@ -148,15 +147,15 @@ class UnitAction(argparse.Action):
except ValueError:
if not values[:-1].isdigit():
msg = ('{} must be a positive integer,'
' with optional suffix').format(self.dest)
' with optional suffix').format(option_string)
parser.error(msg)
if not values[-1] in ('b', 'k', 'm', 'g'):
msg = '{} only supports suffices of: b, k, m, g'.format(
self.dest)
option_string)
parser.error(msg)
else:
if val <= 0:
msg = '{} must be a positive integer'.format(self.dest)
msg = '{} must be a positive integer'.format(option_string)
parser.error(msg)
setattr(namespace, self.dest, values)
@ -174,19 +173,16 @@ class PositiveIntAction(argparse.Action):
type=int,
choices=None,
required=False,
help=None,
help='Must be a positive integer.',
metavar=None):
"""Create PositiveIntAction object."""
self.message = '{} must be a positive integer'.format(dest)
help = help or self.message
super().__init__(
option_strings=option_strings,
dest=dest,
nargs=nargs,
const=const,
default=default,
type=int,
type=type,
choices=choices,
required=required,
help=help,
@ -198,7 +194,8 @@ class PositiveIntAction(argparse.Action):
setattr(namespace, self.dest, values)
return
parser.error(self.message)
msg = '{} must be a positive integer'.format(option_string)
parser.error(msg)
class PathAction(argparse.Action):