mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
Merge pull request #1743 from jwhonce/issue/1702
Add ChangeAction to parse sub-options from --change
This commit is contained in:
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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."""
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user