diff options
-rw-r--r-- | contrib/python/podman/client.py | 2 | ||||
-rw-r--r-- | contrib/python/podman/libs/images.py | 34 | ||||
-rw-r--r-- | contrib/python/test/test_images.py | 35 | ||||
-rwxr-xr-x | contrib/python/test/test_runner.sh | 50 |
4 files changed, 84 insertions, 37 deletions
diff --git a/contrib/python/podman/client.py b/contrib/python/podman/client.py index c6112aae8..89fcf5c15 100644 --- a/contrib/python/podman/client.py +++ b/contrib/python/podman/client.py @@ -38,7 +38,7 @@ class Client(object): @contextlib.contextmanager def _podman(uri, interface): - """Context manager for API children to access varlink.""" + """Context manager for API workers to access varlink.""" client = VarlinkClient(address=uri) try: iface = client.open(interface) diff --git a/contrib/python/podman/libs/images.py b/contrib/python/podman/libs/images.py index f28cb64aa..3beadec1d 100644 --- a/contrib/python/podman/libs/images.py +++ b/contrib/python/podman/libs/images.py @@ -30,23 +30,18 @@ class Image(collections.UserDict): return super().__getitem__(key) def _split_token(self, values=None, sep='='): - mapped = {} - if values: - for var in values: - k, v = var.split(sep, 1) - mapped[k] = v - return mapped + return dict([v.split(sep, 1) for v in values if values]) def create(self, *args, **kwargs): """Create container from image. Pulls defaults from image.inspect() """ - # Inialize config from parameters with self._client() as podman: details = self.inspect() # TODO: remove network settings once defaults implemented in service + # Inialize config from parameters, then add image information config = Config(image_id=self.id, **kwargs) config['command'] = details.containerconfig['cmd'] config['env'] = self._split_token(details.containerconfig['env']) @@ -75,9 +70,8 @@ class Image(collections.UserDict): for r in podman.HistoryImage(self.id)['history']: yield collections.namedtuple('HistoryDetail', r.keys())(**r) + # Convert all keys to lowercase. def _lower_hook(self): - """Convert all keys to lowercase.""" - @functools.wraps(self._lower_hook) def wrapped(input): return {k.lower(): v for (k, v) in input.items()} @@ -127,14 +121,26 @@ class Images(object): for img in results['images']: yield Image(self._client, img['id'], img) - def build(self, *args, **kwargs): + def build(self, dockerfile=None, tags=None, **kwargs): """Build container from image. See podman-build.1.md for kwargs details. """ + if dockerfile is None: + raise ValueError('"dockerfile" is a required argument.') + elif not hasattr(dockerfile, '__iter__'): + raise ValueError('"dockerfile" is required to be an iter.') + + if tags is None: + raise ValueError('"tags" is a required argument.') + elif not hasattr(tags, '__iter__'): + raise ValueError('"tags" is required to be an iter.') + + config = Config(dockerfile=dockerfile, tags=tags, **kwargs) with self._client() as podman: - # TODO: Need arguments - podman.BuildImage() + result = podman.BuildImage(config) + return self.get(result['image']['id']), \ + (line for line in result['image']['logs']) def delete_unused(self): """Delete Images not associated with a container.""" @@ -163,4 +169,6 @@ class Images(object): def get(self, id): """Get Image from id.""" - return next((i for i in self.list() if i.id == id), None) + with self._client() as podman: + result = podman.GetImage(id) + return Image(self._client, result['image']['id'], result['image']) diff --git a/contrib/python/test/test_images.py b/contrib/python/test/test_images.py index f9eaee139..c8c1814dc 100644 --- a/contrib/python/test/test_images.py +++ b/contrib/python/test/test_images.py @@ -1,6 +1,7 @@ import itertools import os import unittest +from datetime import datetime, timezone from test.podman_testcase import PodmanTestCase import podman @@ -34,6 +35,7 @@ class TestImages(PodmanTestCase): i for i in self.images if 'docker.io/library/alpine:latest' in i['repoTags'] ] or []), None) + return self.images def test_list(self): @@ -42,15 +44,29 @@ class TestImages(PodmanTestCase): self.assertIsNotNone(self.alpine_image) def test_build(self): - with self.assertRaisesNotImplemented(): - self.pclient.images.build() + path = os.path.join(self.tmpdir, 'ctnr', 'Dockerfile') + img, logs = self.pclient.images.build( + dockerfile=[path], + tags=['alpine-unittest'], + ) + self.assertIsNotNone(img) + self.assertIn('localhost/alpine-unittest:latest', img.repoTags) + self.assertLess( + podman.datetime_parse(img.created), datetime.now(timezone.utc)) + self.assertTrue(logs) def test_create(self): + img_details = self.alpine_image.inspect() + actual = self.alpine_image.container() self.assertIsNotNone(actual) self.assertEqual(actual.status, 'configured') - cntr = actual.start() - self.assertIn(cntr.status, ['running', 'exited']) + ctnr = actual.start() + self.assertIn(ctnr.status, ['running', 'exited']) + + ctnr_details = ctnr.inspect() + for e in img_details.containerconfig['env']: + self.assertIn(e, ctnr_details.config['env']) def test_export(self): path = os.path.join(self.tmpdir, 'alpine_export.tar') @@ -60,6 +76,10 @@ class TestImages(PodmanTestCase): self.assertTrue(actual) self.assertTrue(os.path.isfile(path)) + def test_get(self): + actual = self.pclient.images.get(self.alpine_image.id) + self.assertEqual(actual, self.alpine_image) + def test_history(self): for count, record in enumerate(self.alpine_image.history()): self.assertEqual(record.id, self.alpine_image.id) @@ -102,8 +122,11 @@ class TestImages(PodmanTestCase): before = self.loadCache() # create unused image, so we have something to delete source = os.path.join(self.tmpdir, 'alpine_gold.tar') - new_img = self.pclient.images.import_image(source, 'alpine2:latest', - 'unittest.test_import') + new_img = self.pclient.images.import_image( + source, + 'alpine2:latest', + 'unittest.test_import', + ) after = self.loadCache() self.assertEqual(len(before) + 1, len(after)) diff --git a/contrib/python/test/test_runner.sh b/contrib/python/test/test_runner.sh index 1cccbe1f5..4e5844831 100755 --- a/contrib/python/test/test_runner.sh +++ b/contrib/python/test/test_runner.sh @@ -6,6 +6,13 @@ if [[ $(id -u) != 0 ]]; then exit 2 fi +# setup path to find new binaries _NOT_ system binaries +if [[ ! -x ../../bin/podman ]]; then + echo 1>&2 Cannot find podman binary from libpod root directory. Run \"make binaries\" + exit 1 +fi +export PATH=../../bin:$PATH + while getopts "vh" arg; do case $arg in v ) VERBOSE='-v' ;; @@ -14,8 +21,16 @@ while getopts "vh" arg; do done shift $((OPTIND-1)) +function cleanup { + # aggressive cleanup as tests may crash leaving crap around + umount '^(shm|nsfs)' + umount '\/run\/netns' + rm -r "$1" +} + # Create temporary directory for storage export TMPDIR=`mktemp -d /tmp/podman.XXXXXXXXXX` +trap "cleanup $TMPDIR" EXIT function umount { # xargs -r always ran once, so write any mount points to file first @@ -25,26 +40,16 @@ function umount { fi } -function cleanup { - umount '^(shm|nsfs)' - umount '\/run\/netns' - rm -fr ${TMPDIR} -} -trap cleanup EXIT - -# setup path to find new binaries _NOT_ system binaries -if [[ ! -x ../../bin/podman ]]; then - echo 1>&2 Cannot find podman binary from libpod root directory, Or, run \"make binaries\" - exit 1 -fi -export PATH=../../bin:$PATH - function showlog { - [ -s "$1" ] && (echo $1 =====; cat "$1"; echo) + [[ -s $1 ]] && cat <<-EOT +$1 ===== +$(cat "$1") + +EOT } -# Need a location to store the podman socket -mkdir -p ${TMPDIR}/{podman,crio,crio-run,cni/net.d} +# Need locations to store stuff +mkdir -p ${TMPDIR}/{podman,crio,crio-run,cni/net.d,ctnr} # Cannot be done in python unittest fixtures. EnvVar not picked up. export REGISTRIES_CONFIG_PATH=${TMPDIR}/registry.conf @@ -85,6 +90,17 @@ cat >$CNI_CONFIG_PATH/87-podman-bridge.conflist <<-EOT } EOT +cat >$TMPDIR/ctnr/hello.sh <<-EOT +echo 'Hello, World' +EOT + +cat >$TMPDIR/ctnr/Dockerfile <<-EOT +FROM alpine:latest +COPY ./hello.sh /tmp/hello.sh +RUN chmod 755 /tmp/hello.sh +ENTRYPOINT ["/tmp/hello.sh"] +EOT + export PODMAN_HOST="unix:${TMPDIR}/podman/io.projectatomic.podman" PODMAN_ARGS="--storage-driver=vfs\ --root=${TMPDIR}/crio\ |