Merge pull request #1743 from jwhonce/issue/1702

Add ChangeAction to parse sub-options from --change
This commit is contained in:
OpenShift Merge Robot
2018-11-05 04:50:16 -08:00
committed by GitHub
6 changed files with 96 additions and 57 deletions

View File

@ -137,7 +137,7 @@ class Images():
results = podman.DeleteUnusedImages() results = podman.DeleteUnusedImages()
return results['images'] return results['images']
def import_image(self, source, reference, message=None, changes=None): def import_image(self, source, reference, message='', changes=None):
"""Read image tarball from source and save in image store.""" """Read image tarball from source and save in image store."""
with self._client() as podman: with self._client() as podman:
results = podman.ImportImage(source, reference, message, changes) results = podman.ImportImage(source, reference, message, changes)

View File

@ -4,14 +4,15 @@ import sys
import podman import podman
from pypodman.lib.action_base import AbstractActionBase from pypodman.lib.action_base import AbstractActionBase
from pypodman.lib.parser_actions import (BooleanAction, BooleanValidate, from pypodman.lib.parser_actions import (BooleanAction, BooleanValidate,
PathAction, PositiveIntAction, ChangeAction, PathAction,
UnitAction) PositiveIntAction, UnitAction)
from pypodman.lib.podman_parser import PodmanArgumentParser from pypodman.lib.podman_parser import PodmanArgumentParser
from pypodman.lib.report import Report, ReportColumn from pypodman.lib.report import Report, ReportColumn
# Silence pylint overlording... # Silence pylint overlording...
assert BooleanAction assert BooleanAction
assert BooleanValidate assert BooleanValidate
assert ChangeAction
assert PathAction assert PathAction
assert PositiveIntAction assert PositiveIntAction
assert UnitAction assert UnitAction

View File

@ -2,7 +2,7 @@
import sys import sys
import podman import podman
from pypodman.lib import AbstractActionBase, BooleanAction from pypodman.lib import AbstractActionBase, BooleanAction, ChangeAction
class Commit(AbstractActionBase): class Commit(AbstractActionBase):
@ -12,7 +12,9 @@ class Commit(AbstractActionBase):
def subparser(cls, parent): def subparser(cls, parent):
"""Add Commit command to parent parser.""" """Add Commit command to parent parser."""
parser = parent.add_parser( parser = parent.add_parser(
'commit', help='create image from container') 'commit',
help='create image from container',
)
parser.add_argument( parser.add_argument(
'--author', '--author',
help='Set the author for the committed image', help='Set the author for the committed image',
@ -20,11 +22,7 @@ class Commit(AbstractActionBase):
parser.add_argument( parser.add_argument(
'--change', '--change',
'-c', '-c',
choices=('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL', 'ONBUILD', action=ChangeAction,
'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'),
action='append',
type=str.upper,
help='Apply the following possible changes to the created image',
) )
parser.add_argument( parser.add_argument(
'--format', '--format',
@ -69,27 +67,11 @@ class Commit(AbstractActionBase):
) )
parser.set_defaults(class_=cls, method='commit') parser.set_defaults(class_=cls, method='commit')
def __init__(self, args):
"""Construct Commit class."""
if not args.container:
raise ValueError('You must supply one container id'
' or name to be used as source.')
if not args.image:
raise ValueError('You must supply one image id'
' or name to be created.')
super().__init__(args)
# used only on client
del self.opts['image']
del self.opts['container']
def commit(self): def commit(self):
"""Create image from container.""" """Create image from container."""
try: try:
try: try:
ctnr = self.client.containers.get(self._args.container[0]) ctnr = self.client.containers.get(self._args.container[0])
ident = ctnr.commit(**self.opts)
print(ident)
except podman.ContainerNotFound as e: except podman.ContainerNotFound as e:
sys.stdout.flush() sys.stdout.flush()
print( print(
@ -97,6 +79,9 @@ class Commit(AbstractActionBase):
file=sys.stderr, file=sys.stderr,
flush=True) flush=True)
return 1 return 1
else:
ident = ctnr.commit(self.opts['image'][0], **self.opts)
print(ident)
except podman.ErrorOccurred as e: except podman.ErrorOccurred as e:
sys.stdout.flush() sys.stdout.flush()
print( print(
@ -104,3 +89,4 @@ class Commit(AbstractActionBase):
file=sys.stderr, file=sys.stderr,
flush=True) flush=True)
return 1 return 1
return 0

View File

@ -12,13 +12,16 @@ class Export(AbstractActionBase):
def subparser(cls, parent): def subparser(cls, parent):
"""Add Export command to parent parser.""" """Add Export command to parent parser."""
parser = parent.add_parser( parser = parent.add_parser(
'export', help='export container to tarball') 'export',
help='export container to tarball',
)
parser.add_argument( parser.add_argument(
'--output', '--output',
'-o', '-o',
metavar='PATH', metavar='PATH',
nargs=1, nargs=1,
help='Write to a file', required=True,
help='Write to this file on host',
) )
parser.add_argument( parser.add_argument(
'container', 'container',
@ -27,23 +30,11 @@ class Export(AbstractActionBase):
) )
parser.set_defaults(class_=cls, method='export') parser.set_defaults(class_=cls, method='export')
def __init__(self, args):
"""Construct Export class."""
if not args.container:
raise ValueError('You must supply one container id'
' or name to be used as source.')
if not args.output:
raise ValueError('You must supply one filename'
' to be created as tarball using --output.')
super().__init__(args)
def export(self): def export(self):
"""Create tarball from container filesystem.""" """Create tarball from container filesystem."""
try: try:
try: try:
ctnr = self.client.containers.get(self._args.container[0]) ctnr = self.client.containers.get(self._args.container[0])
ctnr.export(self._args.output[0])
except podman.ContainerNotFound as e: except podman.ContainerNotFound as e:
sys.stdout.flush() sys.stdout.flush()
print( print(
@ -51,6 +42,8 @@ class Export(AbstractActionBase):
file=sys.stderr, file=sys.stderr,
flush=True) flush=True)
return 1 return 1
else:
ctnr.export(self._args.output[0])
except podman.ErrorOccurred as e: except podman.ErrorOccurred as e:
sys.stdout.flush() sys.stdout.flush()
print( print(
@ -58,3 +51,4 @@ class Export(AbstractActionBase):
file=sys.stderr, file=sys.stderr,
flush=True) flush=True)
return 1 return 1
return 0

View File

@ -2,7 +2,7 @@
import sys import sys
import podman import podman
from pypodman.lib import AbstractActionBase from pypodman.lib import AbstractActionBase, ChangeAction
class Import(AbstractActionBase): class Import(AbstractActionBase):
@ -12,18 +12,19 @@ class Import(AbstractActionBase):
def subparser(cls, parent): def subparser(cls, parent):
"""Add Import command to parent parser.""" """Add Import command to parent parser."""
parser = parent.add_parser( parser = parent.add_parser(
'import', help='import tarball as image filesystem') 'import',
help='import tarball as image filesystem',
)
parser.add_argument( parser.add_argument(
'--change', '--change',
'-c', '-c',
action='append', action=ChangeAction,
choices=('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL',
'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'),
type=str.upper,
help='Apply the following possible instructions',
) )
parser.add_argument( parser.add_argument(
'--message', '-m', help='Set commit message for imported image.') '--message',
'-m',
help='Set commit message for imported image.',
)
parser.add_argument( parser.add_argument(
'source', 'source',
metavar='PATH', metavar='PATH',
@ -38,18 +39,25 @@ class Import(AbstractActionBase):
) )
parser.set_defaults(class_=cls, method='import_') parser.set_defaults(class_=cls, method='import_')
def __init__(self, args):
"""Construct Import class."""
super().__init__(args)
def import_(self): def import_(self):
"""Import tarball as image filesystem.""" """Import tarball as image filesystem."""
# ImportImage() validates it's parameters therefore we need to create
# pristine dict() for keywords
options = {}
if 'message' in self.opts:
options['message'] = self.opts['message']
if 'change' in self.opts and self.opts['change']:
options['changes'] = self.opts['change']
reference = self.opts['reference'][0] if 'reference' in self.opts\
else None
try: try:
ident = self.client.images.import_image( ident = self.client.images.import_image(
self.opts.source, self.opts['source'][0],
self.opts.reference, reference,
message=self.opts.message, **options,
changes=self.opts.change) )
print(ident) print(ident)
except podman.ErrorOccurred as e: except podman.ErrorOccurred as e:
sys.stdout.flush() sys.stdout.flush()
@ -58,3 +66,4 @@ class Import(AbstractActionBase):
file=sys.stderr, file=sys.stderr,
flush=True) flush=True)
return 1 return 1
return 0

View File

@ -4,9 +4,10 @@ Supplimental argparse.Action converters and validaters.
The constructors are very verbose but remain for IDE support. The constructors are very verbose but remain for IDE support.
""" """
import argparse import argparse
import copy
import os import os
# API defined by argparse.Action shut up pylint # API defined by argparse.Action therefore shut up pylint
# pragma pylint: disable=redefined-builtin # pragma pylint: disable=redefined-builtin
# pragma pylint: disable=too-few-public-methods # pragma pylint: disable=too-few-public-methods
# pragma pylint: disable=too-many-arguments # pragma pylint: disable=too-many-arguments
@ -63,6 +64,54 @@ class BooleanAction(argparse.Action):
setattr(namespace, self.dest, val) setattr(namespace, self.dest, val)
class ChangeAction(argparse.Action):
"""Convert and validate change argument."""
def __init__(self,
option_strings,
dest,
nargs=None,
const=None,
default=[],
type=None,
choices=None,
required=False,
help=None,
metavar='OPT=VALUE'):
"""Create ChangeAction object."""
help = (help or '') + ('Apply change(s) to the new image.'
' May be given multiple times.')
super().__init__(
option_strings=option_strings,
dest=dest,
nargs=nargs,
const=const,
default=default,
type=type,
choices=choices,
required=required,
help=help,
metavar=metavar)
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)
choices = ('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL', 'ONBUILD',
'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR')
opt, val = values.split('=', 1)
if opt not in choices:
parser.error('{} is not a supported "--change" option,'
' valid options are: {}'.format(
opt, ', '.join(choices)))
items.append(values)
setattr(namespace, self.dest, items)
class UnitAction(argparse.Action): class UnitAction(argparse.Action):
"""Validate number given is positive integer, with optional suffix.""" """Validate number given is positive integer, with optional suffix."""