mirror of
https://github.com/containers/podman.git
synced 2025-06-19 00:06:43 +08:00
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:
@ -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')
|
||||
|
@ -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',
|
||||
]
|
||||
|
76
contrib/python/pypodman/pypodman/lib/actions/start_action.py
Normal file
76
contrib/python/pypodman/pypodman/lib/actions/start_action.py
Normal 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
|
@ -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):
|
||||
|
Reference in New Issue
Block a user