aboutsummaryrefslogtreecommitdiff
path: root/contrib/python
diff options
context:
space:
mode:
authorJhon Honce <jhonce@redhat.com>2018-07-12 19:26:14 -0700
committerJhon Honce <jhonce@redhat.com>2018-07-13 12:50:12 -0700
commit74ccd9ce5f29a1df4ffe70b4d8bd00c29d5d9d15 (patch)
tree75ba256d70545d79aa61d7c57c20df886be1555f /contrib/python
parent44b523c946c88e540b50d7ba59f441b5f8e0bad0 (diff)
downloadpodman-74ccd9ce5f29a1df4ffe70b4d8bd00c29d5d9d15.tar.gz
podman-74ccd9ce5f29a1df4ffe70b4d8bd00c29d5d9d15.tar.bz2
podman-74ccd9ce5f29a1df4ffe70b4d8bd00c29d5d9d15.zip
Update python directories to better support setup.py
Signed-off-by: Jhon Honce <jhonce@redhat.com>
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/cmd/lib/__init__.py5
-rw-r--r--contrib/python/podman/CHANGES.txt (renamed from contrib/python/CHANGES.txt)0
-rw-r--r--contrib/python/podman/LICENSE.txt (renamed from contrib/python/LICENSE.txt)0
-rw-r--r--contrib/python/podman/MANIFEST.in (renamed from contrib/python/MANIFEST.in)0
-rw-r--r--contrib/python/podman/Makefile (renamed from contrib/python/Makefile)5
-rw-r--r--contrib/python/podman/README.md (renamed from contrib/python/README.md)2
-rw-r--r--contrib/python/podman/examples/eg_attach.py (renamed from contrib/python/examples/eg_attach.py)0
-rw-r--r--contrib/python/podman/examples/eg_containers_by_image.py (renamed from contrib/python/examples/eg_containers_by_image.py)0
-rw-r--r--contrib/python/podman/examples/eg_image_list.py (renamed from contrib/python/examples/eg_image_list.py)0
-rw-r--r--contrib/python/podman/examples/eg_inspect_fedora.py (renamed from contrib/python/examples/eg_inspect_fedora.py)0
-rw-r--r--contrib/python/podman/examples/eg_latest_containers.py (renamed from contrib/python/examples/eg_latest_containers.py)0
-rw-r--r--contrib/python/podman/examples/eg_new_image.py (renamed from contrib/python/examples/eg_new_image.py)0
-rwxr-xr-xcontrib/python/podman/examples/run_example.sh (renamed from contrib/python/examples/run_example.sh)0
-rw-r--r--contrib/python/podman/podman/__init__.py (renamed from contrib/python/podman/__init__.py)0
-rw-r--r--contrib/python/podman/podman/client.py (renamed from contrib/python/podman/client.py)26
-rw-r--r--contrib/python/podman/podman/libs/__init__.py (renamed from contrib/python/podman/libs/__init__.py)0
-rw-r--r--contrib/python/podman/podman/libs/_containers_attach.py (renamed from contrib/python/podman/libs/_containers_attach.py)0
-rw-r--r--contrib/python/podman/podman/libs/_containers_start.py (renamed from contrib/python/podman/libs/_containers_start.py)0
-rw-r--r--contrib/python/podman/podman/libs/containers.py (renamed from contrib/python/podman/libs/containers.py)0
-rw-r--r--contrib/python/podman/podman/libs/errors.py (renamed from contrib/python/podman/libs/errors.py)0
-rw-r--r--contrib/python/podman/podman/libs/images.py (renamed from contrib/python/podman/libs/images.py)0
-rw-r--r--contrib/python/podman/podman/libs/system.py (renamed from contrib/python/podman/libs/system.py)0
-rw-r--r--contrib/python/podman/podman/libs/tunnel.py (renamed from contrib/python/podman/libs/tunnel.py)25
-rw-r--r--contrib/python/podman/requirements.txt (renamed from contrib/python/requirements.txt)0
-rw-r--r--contrib/python/podman/setup.py (renamed from contrib/python/setup.py)0
-rw-r--r--contrib/python/podman/test/__init__.py (renamed from contrib/python/test/__init__.py)0
-rw-r--r--contrib/python/podman/test/podman_testcase.py (renamed from contrib/python/test/podman_testcase.py)0
-rw-r--r--contrib/python/podman/test/test_client.py (renamed from contrib/python/test/test_client.py)8
-rw-r--r--contrib/python/podman/test/test_containers.py (renamed from contrib/python/test/test_containers.py)0
-rw-r--r--contrib/python/podman/test/test_images.py (renamed from contrib/python/test/test_images.py)0
-rw-r--r--contrib/python/podman/test/test_libs.py (renamed from contrib/python/test/test_libs.py)0
-rwxr-xr-xcontrib/python/podman/test/test_runner.sh (renamed from contrib/python/test/test_runner.sh)4
-rw-r--r--contrib/python/podman/test/test_system.py (renamed from contrib/python/test/test_system.py)0
-rw-r--r--contrib/python/podman/test/test_tunnel.py (renamed from contrib/python/test/test_tunnel.py)2
-rw-r--r--contrib/python/pypodman/MANIFEST.in1
-rw-r--r--contrib/python/pypodman/Makefile21
-rw-r--r--contrib/python/pypodman/README.md32
-rw-r--r--contrib/python/pypodman/docs/pypodman.1.md82
-rw-r--r--contrib/python/pypodman/lib/__init__.py11
-rw-r--r--contrib/python/pypodman/lib/action_base.py (renamed from contrib/python/cmd/lib/action_base.py)16
-rw-r--r--contrib/python/pypodman/lib/actions/__init__.py (renamed from contrib/python/cmd/lib/actions/__init__.py)0
-rw-r--r--contrib/python/pypodman/lib/actions/images_action.py (renamed from contrib/python/cmd/lib/actions/images_action.py)2
-rw-r--r--contrib/python/pypodman/lib/actions/ps_action.py (renamed from contrib/python/cmd/lib/actions/ps_action.py)2
-rw-r--r--contrib/python/pypodman/lib/actions/rm_action.py (renamed from contrib/python/cmd/lib/actions/rm_action.py)2
-rw-r--r--contrib/python/pypodman/lib/actions/rmi_action.py (renamed from contrib/python/cmd/lib/actions/rmi_action.py)2
-rw-r--r--[-rwxr-xr-x]contrib/python/pypodman/lib/config.py (renamed from contrib/python/cmd/pydman.py)156
-rw-r--r--contrib/python/pypodman/lib/future_abstract.py (renamed from contrib/python/cmd/lib/future_abstract.py)0
-rwxr-xr-xcontrib/python/pypodman/lib/pypodman.py76
-rw-r--r--contrib/python/pypodman/lib/report.py (renamed from contrib/python/cmd/lib/report.py)0
-rw-r--r--contrib/python/pypodman/requirements.txt4
-rw-r--r--contrib/python/pypodman/setup.py44
-rw-r--r--contrib/python/pypodman/test/test_report.py23
52 files changed, 404 insertions, 147 deletions
diff --git a/contrib/python/cmd/lib/__init__.py b/contrib/python/cmd/lib/__init__.py
deleted file mode 100644
index db0f640b1..000000000
--- a/contrib/python/cmd/lib/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""Remote podman client support library."""
-from .action_base import AbstractActionBase
-from .report import Report, ReportColumn
-
-__all__ = ['AbstractActionBase', 'Report', 'ReportColumn']
diff --git a/contrib/python/CHANGES.txt b/contrib/python/podman/CHANGES.txt
index 2bac1c867..2bac1c867 100644
--- a/contrib/python/CHANGES.txt
+++ b/contrib/python/podman/CHANGES.txt
diff --git a/contrib/python/LICENSE.txt b/contrib/python/podman/LICENSE.txt
index decfce56d..decfce56d 100644
--- a/contrib/python/LICENSE.txt
+++ b/contrib/python/podman/LICENSE.txt
diff --git a/contrib/python/MANIFEST.in b/contrib/python/podman/MANIFEST.in
index 72e638cb9..72e638cb9 100644
--- a/contrib/python/MANIFEST.in
+++ b/contrib/python/podman/MANIFEST.in
diff --git a/contrib/python/Makefile b/contrib/python/podman/Makefile
index 6cb63c403..ea40cccac 100644
--- a/contrib/python/Makefile
+++ b/contrib/python/podman/Makefile
@@ -8,9 +8,14 @@ python-podman:
integration:
test/test_runner.sh
+.PHONY: install
+install:
+ $(PYTHON) setup.py install --user
+
.PHONY: clean
clean:
$(PYTHON) setup.py clean --all
+ pip3 uninstall podman ||:
rm -rf podman.egg-info dist
find . -depth -name __pycache__ -exec rm -rf {} \;
find . -depth -name \*.pyc -exec rm -f {} \;
diff --git a/contrib/python/README.md b/contrib/python/podman/README.md
index dcf40a1a9..fad03fd27 100644
--- a/contrib/python/README.md
+++ b/contrib/python/podman/README.md
@@ -9,7 +9,7 @@ See [libpod](https://github.com/projectatomic/libpod)
To build the podman egg:
```sh
-cd ~/libpod/contrib/pypodman
+cd ~/libpod/contrib/python
python3 setup.py clean -a && python3 setup.py bdist
```
diff --git a/contrib/python/examples/eg_attach.py b/contrib/python/podman/examples/eg_attach.py
index f5070dc53..f5070dc53 100644
--- a/contrib/python/examples/eg_attach.py
+++ b/contrib/python/podman/examples/eg_attach.py
diff --git a/contrib/python/examples/eg_containers_by_image.py b/contrib/python/podman/examples/eg_containers_by_image.py
index bf4fdebf1..bf4fdebf1 100644
--- a/contrib/python/examples/eg_containers_by_image.py
+++ b/contrib/python/podman/examples/eg_containers_by_image.py
diff --git a/contrib/python/examples/eg_image_list.py b/contrib/python/podman/examples/eg_image_list.py
index ef31fd708..ef31fd708 100644
--- a/contrib/python/examples/eg_image_list.py
+++ b/contrib/python/podman/examples/eg_image_list.py
diff --git a/contrib/python/examples/eg_inspect_fedora.py b/contrib/python/podman/examples/eg_inspect_fedora.py
index b5bbba46d..b5bbba46d 100644
--- a/contrib/python/examples/eg_inspect_fedora.py
+++ b/contrib/python/podman/examples/eg_inspect_fedora.py
diff --git a/contrib/python/examples/eg_latest_containers.py b/contrib/python/podman/examples/eg_latest_containers.py
index 446f670dd..446f670dd 100644
--- a/contrib/python/examples/eg_latest_containers.py
+++ b/contrib/python/podman/examples/eg_latest_containers.py
diff --git a/contrib/python/examples/eg_new_image.py b/contrib/python/podman/examples/eg_new_image.py
index 21e076dcb..21e076dcb 100644
--- a/contrib/python/examples/eg_new_image.py
+++ b/contrib/python/podman/examples/eg_new_image.py
diff --git a/contrib/python/examples/run_example.sh b/contrib/python/podman/examples/run_example.sh
index 0f6575073..0f6575073 100755
--- a/contrib/python/examples/run_example.sh
+++ b/contrib/python/podman/examples/run_example.sh
diff --git a/contrib/python/podman/__init__.py b/contrib/python/podman/podman/__init__.py
index 5a0356311..5a0356311 100644
--- a/contrib/python/podman/__init__.py
+++ b/contrib/python/podman/podman/__init__.py
diff --git a/contrib/python/podman/client.py b/contrib/python/podman/podman/client.py
index ad166eb06..404b7d117 100644
--- a/contrib/python/podman/client.py
+++ b/contrib/python/podman/podman/client.py
@@ -44,11 +44,11 @@ class BaseClient(object):
raise ValueError('path is required for uri,'
' expected format "unix://path_to_socket"')
- if kwargs.get('remote_uri') or kwargs.get('identity_file'):
+ if kwargs.get('remote_uri'):
# Remote access requires the full tuple of information
if kwargs.get('remote_uri') is None:
raise ValueError(
- 'remote is required,'
+ 'remote_uri is required,'
' expected format "ssh://user@hostname/path_to_socket".')
remote = urlparse(kwargs['remote_uri'])
if remote.username is None:
@@ -64,20 +64,16 @@ class BaseClient(object):
'hostname is required for remote_uri,'
' expected format "ssh://user@hostname/path_to_socket".')
- if kwargs.get('identity_file') is None:
- raise ValueError('identity_file is required.')
-
- if not os.path.isfile(kwargs['identity_file']):
- raise FileNotFoundError(
- errno.ENOENT,
- os.strerror(errno.ENOENT),
- kwargs['identity_file'],
- )
-
return RemoteClient(
- Context(uri, interface, local_path, remote.path,
- remote.username, remote.hostname,
- kwargs['identity_file']))
+ Context(
+ uri,
+ interface,
+ local_path,
+ remote.path,
+ remote.username,
+ remote.hostname,
+ kwargs.get('identity_file'),
+ ))
else:
return LocalClient(
Context(uri, interface, None, None, None, None, None))
diff --git a/contrib/python/podman/libs/__init__.py b/contrib/python/podman/podman/libs/__init__.py
index 3a8a35021..3a8a35021 100644
--- a/contrib/python/podman/libs/__init__.py
+++ b/contrib/python/podman/podman/libs/__init__.py
diff --git a/contrib/python/podman/libs/_containers_attach.py b/contrib/python/podman/podman/libs/_containers_attach.py
index df12fa998..df12fa998 100644
--- a/contrib/python/podman/libs/_containers_attach.py
+++ b/contrib/python/podman/podman/libs/_containers_attach.py
diff --git a/contrib/python/podman/libs/_containers_start.py b/contrib/python/podman/podman/libs/_containers_start.py
index ad9f32eab..ad9f32eab 100644
--- a/contrib/python/podman/libs/_containers_start.py
+++ b/contrib/python/podman/podman/libs/_containers_start.py
diff --git a/contrib/python/podman/libs/containers.py b/contrib/python/podman/podman/libs/containers.py
index 6dc2c141e..6dc2c141e 100644
--- a/contrib/python/podman/libs/containers.py
+++ b/contrib/python/podman/podman/libs/containers.py
diff --git a/contrib/python/podman/libs/errors.py b/contrib/python/podman/podman/libs/errors.py
index b98210481..b98210481 100644
--- a/contrib/python/podman/libs/errors.py
+++ b/contrib/python/podman/podman/libs/errors.py
diff --git a/contrib/python/podman/libs/images.py b/contrib/python/podman/podman/libs/images.py
index 334ff873c..334ff873c 100644
--- a/contrib/python/podman/libs/images.py
+++ b/contrib/python/podman/podman/libs/images.py
diff --git a/contrib/python/podman/libs/system.py b/contrib/python/podman/podman/libs/system.py
index c59867760..c59867760 100644
--- a/contrib/python/podman/libs/system.py
+++ b/contrib/python/podman/podman/libs/system.py
diff --git a/contrib/python/podman/libs/tunnel.py b/contrib/python/podman/podman/libs/tunnel.py
index 9effdff6c..440eb3951 100644
--- a/contrib/python/podman/libs/tunnel.py
+++ b/contrib/python/podman/podman/libs/tunnel.py
@@ -97,26 +97,27 @@ class Tunnel(object):
def bore(self, id):
"""Create SSH tunnel from given context."""
- ssh_opts = '-nNT'
+ cmd = ['ssh']
+
+ ssh_opts = '-fNT'
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
ssh_opts += 'v'
else:
ssh_opts += 'q'
+ cmd.append(ssh_opts)
+
+ cmd.extend(('-L', '{}:{}'.format(self.context.local_socket,
+ self.context.remote_socket)))
+ if self.context.identity_file:
+ cmd.extend(('-i', self.context.identity_file))
+
+ cmd.append('ssh://{}@{}'.format(self.context.username,
+ self.context.hostname))
- cmd = [
- 'ssh',
- ssh_opts,
- '-L',
- '{}:{}'.format(self.context.local_socket,
- self.context.remote_socket),
- '-i',
- self.context.identity_file,
- 'ssh://{}@{}'.format(self.context.username, self.context.hostname),
- ]
logging.debug('Tunnel cmd "{}"'.format(' '.join(cmd)))
self._tunnel = subprocess.Popen(cmd, close_fds=True)
- for i in range(10):
+ for i in range(300):
# TODO: Make timeout configurable
if os.path.exists(self.context.local_socket):
break
diff --git a/contrib/python/requirements.txt b/contrib/python/podman/requirements.txt
index d294af3c7..d294af3c7 100644
--- a/contrib/python/requirements.txt
+++ b/contrib/python/podman/requirements.txt
diff --git a/contrib/python/setup.py b/contrib/python/podman/setup.py
index c9db30199..c9db30199 100644
--- a/contrib/python/setup.py
+++ b/contrib/python/podman/setup.py
diff --git a/contrib/python/test/__init__.py b/contrib/python/podman/test/__init__.py
index e69de29bb..e69de29bb 100644
--- a/contrib/python/test/__init__.py
+++ b/contrib/python/podman/test/__init__.py
diff --git a/contrib/python/test/podman_testcase.py b/contrib/python/podman/test/podman_testcase.py
index f96a3a013..f96a3a013 100644
--- a/contrib/python/test/podman_testcase.py
+++ b/contrib/python/podman/test/podman_testcase.py
diff --git a/contrib/python/test/test_client.py b/contrib/python/podman/test/test_client.py
index e642c8add..2abc60a24 100644
--- a/contrib/python/test/test_client.py
+++ b/contrib/python/podman/test/test_client.py
@@ -21,11 +21,10 @@ class TestClient(unittest.TestCase):
self.assertIsInstance(p._client, LocalClient)
self.assertIsInstance(p._client, BaseClient)
- mock_ping.assert_called_once()
+ mock_ping.assert_called_once_with()
- @patch('os.path.isfile', return_value=True)
@patch('podman.libs.system.System.ping', return_value=True)
- def test_remote(self, mock_ping, mock_isfile):
+ def test_remote(self, mock_ping):
p = Client(
uri='unix:/run/podman',
interface='io.projectatomic.podman',
@@ -33,5 +32,4 @@ class TestClient(unittest.TestCase):
identity_file='~/.ssh/id_rsa')
self.assertIsInstance(p._client, BaseClient)
- mock_ping.assert_called_once()
- mock_isfile.assert_called_once()
+ mock_ping.assert_called_once_with()
diff --git a/contrib/python/test/test_containers.py b/contrib/python/podman/test/test_containers.py
index ec2dcde03..ec2dcde03 100644
--- a/contrib/python/test/test_containers.py
+++ b/contrib/python/podman/test/test_containers.py
diff --git a/contrib/python/test/test_images.py b/contrib/python/podman/test/test_images.py
index 14bf90992..14bf90992 100644
--- a/contrib/python/test/test_images.py
+++ b/contrib/python/podman/test/test_images.py
diff --git a/contrib/python/test/test_libs.py b/contrib/python/podman/test/test_libs.py
index 202bed1d8..202bed1d8 100644
--- a/contrib/python/test/test_libs.py
+++ b/contrib/python/podman/test/test_libs.py
diff --git a/contrib/python/test/test_runner.sh b/contrib/python/podman/test/test_runner.sh
index 602e0d6fd..b3d2ba15b 100755
--- a/contrib/python/test/test_runner.sh
+++ b/contrib/python/podman/test/test_runner.sh
@@ -7,11 +7,11 @@ if [[ $(id -u) != 0 ]]; then
fi
# setup path to find new binaries _NOT_ system binaries
-if [[ ! -x ../../bin/podman ]]; then
+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
+export PATH=../../../bin:$PATH
function usage {
echo 1>&2 $0 [-v] [-h] [test.TestCase|test.TestCase.step]
diff --git a/contrib/python/test/test_system.py b/contrib/python/podman/test/test_system.py
index 3f6ca57a2..3f6ca57a2 100644
--- a/contrib/python/test/test_system.py
+++ b/contrib/python/podman/test/test_system.py
diff --git a/contrib/python/test/test_tunnel.py b/contrib/python/podman/test/test_tunnel.py
index 2522df0ab..719a2f9a4 100644
--- a/contrib/python/test/test_tunnel.py
+++ b/contrib/python/podman/test/test_tunnel.py
@@ -66,7 +66,7 @@ class TestTunnel(unittest.TestCase):
cmd = [
'ssh',
- '-nNTq',
+ '-fNTq',
'-L',
'{}:{}'.format(context.local_socket, context.remote_socket),
'-i',
diff --git a/contrib/python/pypodman/MANIFEST.in b/contrib/python/pypodman/MANIFEST.in
new file mode 100644
index 000000000..bb3ec5f0d
--- /dev/null
+++ b/contrib/python/pypodman/MANIFEST.in
@@ -0,0 +1 @@
+include README.md
diff --git a/contrib/python/pypodman/Makefile b/contrib/python/pypodman/Makefile
new file mode 100644
index 000000000..4d76b1a1e
--- /dev/null
+++ b/contrib/python/pypodman/Makefile
@@ -0,0 +1,21 @@
+PYTHON ?= /usr/bin/python3
+
+.PHONY: python-pypodman
+python-pypodman:
+ $(PYTHON) setup.py bdist
+
+.PHONY: integration
+integration:
+ true
+
+.PHONY: install
+install:
+ $(PYTHON) setup.py install --user
+
+.PHONY: clean
+clean:
+ $(PYTHON) setup.py clean --all
+ pip3 uninstall pypodman ||:
+ rm -rf pypodman.egg-info dist
+ find . -depth -name __pycache__ -exec rm -rf {} \;
+ find . -depth -name \*.pyc -exec rm -f {} \;
diff --git a/contrib/python/pypodman/README.md b/contrib/python/pypodman/README.md
new file mode 100644
index 000000000..8a1c293f1
--- /dev/null
+++ b/contrib/python/pypodman/README.md
@@ -0,0 +1,32 @@
+# pypodman - CLI interface for podman written in python
+
+## Status: Active Development
+
+See [libpod](https://github.com/projectatomic/libpod/contrib/python/cmd)
+
+## Releases
+
+To build the pypodman egg:
+
+```sh
+cd ~/libpod/contrib/python/cmd
+python3 setup.py clean -a && python3 setup.py bdist
+```
+
+## Running command:
+
+### Against local podman service
+```sh
+$ pypodman images
+```
+### Against remote podman service
+```sh
+$ pypodman --host node001.example.org images
+```
+### Full help system available
+```sh
+$ pypodman -h
+```
+```sh
+$ pypodman images -h
+```
diff --git a/contrib/python/pypodman/docs/pypodman.1.md b/contrib/python/pypodman/docs/pypodman.1.md
new file mode 100644
index 000000000..1a6be994d
--- /dev/null
+++ b/contrib/python/pypodman/docs/pypodman.1.md
@@ -0,0 +1,82 @@
+% pypodman "1"
+
+## NAME
+
+pypodman - Simple management tool for containers and images
+
+## SYNOPSIS
+
+**pypodman** [*global options*] _command_ [*options*]
+
+## DESCRIPTION
+
+pypodman is a simple client only tool to help with debugging issues when daemons
+such as CRI runtime and the kubelet are not responding or failing. pypodman uses
+a VarLink API to commicate with a podman service running on either the local or
+remote machine. pypodman uses ssh to create secure tunnels when communicating
+with a remote service.
+
+## GLOBAL OPTIONS
+
+**--help, -h**
+
+Print usage statement.
+
+**--version**
+
+Print program version number and exit.
+
+**--config-home**
+
+Directory that will be namespaced with `pypodman` to hold `pypodman.conf`. See FILES below for more details.
+
+**--log-level**
+
+Log events above specified level: DEBUG, INFO, WARNING (default), ERROR, or CRITICAL.
+
+**--run-dir**
+
+Directory that will be namespaced with `pypodman` to hold local socket bindings. The default is ``$XDG_RUNTIME_DIR\`.
+
+**--user**
+
+Authenicating user on remote host. `pypodman` defaults to the logged in user.
+
+**--host**
+
+Name of remote host. There is no default, if not given `pypodman` attempts to connect to `--remote-socket-path` on local host.
+
+**--remote-socket-path**
+
+Path on remote host for podman service's `AF_UNIX` socket. The default is `/run/podman/io.projectatomic.podman`.
+
+**--identity-file**
+
+The optional `ssh` identity file to authenicate when tunnelling to remote host. Default is None and will allow `ssh` to follow it's default methods for resolving the identity and private key using the logged in user.
+
+## COMMANDS
+
+See [podman(1)](podman.1.md)
+
+## FILES
+
+**pypodman/pypodman.conf** (`Any element of XDG_CONFIG_DIRS` and/or `XDG_CONFIG_HOME` and/or **--config-home**)
+
+pypodman.conf is one or more configuration files for running the pypodman command. pypodman.conf is a TOML file with the stanza `[default]`, with a map of option: value.
+
+pypodman follows the XDG (freedesktop.org) conventions for resolving it's configuration. The list below are read from top to bottom with later items overwriting earlier. Any missing items are ignored.
+
+- `pypodman/pypodman.conf` from any path element in `XDG_CONFIG_DIRS` or `\etc\xdg`
+- `XDG_CONFIG_HOME` or $HOME/.config + `pypodman/pypodman.conf`
+- From `--config-home` command line option + `pypodman/pypodman.conf`
+- From environment variable, for example: RUN_DIR
+- From command line option, for example: --run-dir
+
+This should provide Operators the ability to setup basic configurations and allow users to customize them.
+
+**XDG_RUNTIME_DIR** (`XDG_RUNTIME_DIR/io.projectatomic.podman`)
+
+Directory where pypodman stores non-essential runtime files and other file objects (such as sockets, named pipes, ...).
+
+## SEE ALSO
+`podman(1)`, `libpod(8)`
diff --git a/contrib/python/pypodman/lib/__init__.py b/contrib/python/pypodman/lib/__init__.py
new file mode 100644
index 000000000..5a8303668
--- /dev/null
+++ b/contrib/python/pypodman/lib/__init__.py
@@ -0,0 +1,11 @@
+"""Remote podman client support library."""
+from .action_base import AbstractActionBase
+from .config import PodmanArgumentParser
+from .report import Report, ReportColumn
+
+__all__ = [
+ 'AbstractActionBase',
+ 'PodmanArgumentParser',
+ 'Report',
+ 'ReportColumn',
+]
diff --git a/contrib/python/cmd/lib/action_base.py b/contrib/python/pypodman/lib/action_base.py
index bafddea03..ff2922262 100644
--- a/contrib/python/cmd/lib/action_base.py
+++ b/contrib/python/pypodman/lib/action_base.py
@@ -14,8 +14,8 @@ class AbstractActionBase(abc.ABC):
"""Define parser for this action. Subclasses must implement.
API:
- Use set_defaults() to set attributes "klass" and "method". These will
- be invoked as klass(parsed_args).method()
+ Use set_defaults() to set attributes "class_" and "method". These will
+ be invoked as class_(parsed_args).method()
"""
parser.add_argument(
'--all',
@@ -64,10 +64,14 @@ class AbstractActionBase(abc.ABC):
@lru_cache(maxsize=1)
def client(self):
"""Podman remote client for communicating."""
- return podman.Client(
- uri=self.local_uri,
- remote_uri=self.remote_uri,
- identity_file=self.identity_file)
+ if self._args.host is None:
+ return podman.Client(
+ uri=self.local_uri)
+ else:
+ return podman.Client(
+ uri=self.local_uri,
+ remote_uri=self.remote_uri,
+ identity_file=self.identity_file)
def __repr__(self):
"""Compute the “official” string representation of object."""
diff --git a/contrib/python/cmd/lib/actions/__init__.py b/contrib/python/pypodman/lib/actions/__init__.py
index cdc58b6ab..cdc58b6ab 100644
--- a/contrib/python/cmd/lib/actions/__init__.py
+++ b/contrib/python/pypodman/lib/actions/__init__.py
diff --git a/contrib/python/cmd/lib/actions/images_action.py b/contrib/python/pypodman/lib/actions/images_action.py
index 74c77edbb..f6a7497e5 100644
--- a/contrib/python/cmd/lib/actions/images_action.py
+++ b/contrib/python/pypodman/lib/actions/images_action.py
@@ -29,7 +29,7 @@ class Images(AbstractActionBase):
'--digests',
action='store_true',
help='Include digests with images. (default: %(default)s)')
- parser.set_defaults(klass=cls, method='list')
+ parser.set_defaults(class_=cls, method='list')
def __init__(self, args):
"""Construct Images class."""
diff --git a/contrib/python/cmd/lib/actions/ps_action.py b/contrib/python/pypodman/lib/actions/ps_action.py
index 9fc3a155b..4bbec5578 100644
--- a/contrib/python/cmd/lib/actions/ps_action.py
+++ b/contrib/python/pypodman/lib/actions/ps_action.py
@@ -26,7 +26,7 @@ class Ps(AbstractActionBase):
type=str.lower,
help=('Change sort ordered of displayed containers.'
' (default: %(default)s)'))
- parser.set_defaults(klass=cls, method='list')
+ parser.set_defaults(class_=cls, method='list')
def __init__(self, args):
"""Construct Ps class."""
diff --git a/contrib/python/cmd/lib/actions/rm_action.py b/contrib/python/pypodman/lib/actions/rm_action.py
index 7595fee6a..bd8950bd6 100644
--- a/contrib/python/cmd/lib/actions/rm_action.py
+++ b/contrib/python/pypodman/lib/actions/rm_action.py
@@ -21,7 +21,7 @@ class Rm(AbstractActionBase):
' (default: %(default)s)'))
parser.add_argument(
'targets', nargs='*', help='container id(s) to delete')
- parser.set_defaults(klass=cls, method='remove')
+ parser.set_defaults(class_=cls, method='remove')
def __init__(self, args):
"""Construct Rm class."""
diff --git a/contrib/python/cmd/lib/actions/rmi_action.py b/contrib/python/pypodman/lib/actions/rmi_action.py
index db59fe030..91f0deeaf 100644
--- a/contrib/python/cmd/lib/actions/rmi_action.py
+++ b/contrib/python/pypodman/lib/actions/rmi_action.py
@@ -20,7 +20,7 @@ class Rmi(AbstractActionBase):
help=('force delete of image(s) and associated containers.'
' (default: %(default)s)'))
parser.add_argument('targets', nargs='*', help='image id(s) to delete')
- parser.set_defaults(klass=cls, method='remove')
+ parser.set_defaults(class_=cls, method='remove')
def __init__(self, args):
"""Construct Rmi class."""
diff --git a/contrib/python/cmd/pydman.py b/contrib/python/pypodman/lib/config.py
index 5008c706d..e687697ef 100755..100644
--- a/contrib/python/cmd/pydman.py
+++ b/contrib/python/pypodman/lib/config.py
@@ -1,6 +1,3 @@
-#!/usr/bin/env python3
-"""Remote podman client."""
-
import argparse
import curses
import getpass
@@ -11,14 +8,11 @@ import sys
import pkg_resources
-import lib.actions
import pytoml
-assert lib.actions # silence pyflakes
-
# TODO: setup.py and obtain __version__ from rpm.spec
try:
- __version__ = pkg_resources.get_distribution('pydman').version
+ __version__ = pkg_resources.get_distribution('pypodman').version
except Exception:
__version__ = '0.0.0'
@@ -59,36 +53,40 @@ class PodmanArgumentParser(argparse.ArgumentParser):
self.add_argument(
'--log-level',
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
- default='INFO',
+ default='WARNING',
type=str.upper,
help='set logging level for events. (default: %(default)s)',
)
self.add_argument(
'--run-dir',
+ metavar='DIRECTORY',
help=('directory to place local socket bindings.'
- ' (default: XDG_RUNTIME_DIR)'))
+ ' (default: XDG_RUNTIME_DIR/pypodman'))
self.add_argument(
'--user',
- help=('Authenicating user on remote host.'
- ' (default: {})').format(getpass.getuser()))
+ default=getpass.getuser(),
+ help='Authenicating user on remote host. (default: %(default)s)')
self.add_argument(
'--host', help='name of remote host. (default: None)')
self.add_argument(
'--remote-socket-path',
+ metavar='PATH',
help=('path of podman socket on remote host'
' (default: /run/podman/io.projectatomic.podman)'))
self.add_argument(
'--identity-file',
- help=('path to ssh identity file. (default: ~/.ssh/id_rsa)'))
+ metavar='PATH',
+ help=('path to ssh identity file. (default: ~user/.ssh/id_dsa)'))
self.add_argument(
- '--config',
- default='/etc/containers/podman_client.conf',
- dest='config_file',
- help='path of configuration file. (default: %(default)s)')
+ '--config-home',
+ metavar='DIRECTORY',
+ help=('home of configuration "pypodman.conf".'
+ ' (default: XDG_CONFIG_HOME/pypodman'))
actions_parser = self.add_subparsers(
dest='subparser_name', help='actions')
+ # pull in plugin(s) code for each subcommand
for name, obj in inspect.getmembers(
sys.modules['lib.actions'],
lambda member: inspect.isclass(member)):
@@ -110,47 +108,49 @@ class PodmanArgumentParser(argparse.ArgumentParser):
def resolve_configuration(self, args):
"""Find and fill in any arguments not passed on command line."""
- try:
- # Configuration file optionall, arguments may be provided elsewhere
- with open(args.config_file, 'r') as stream:
- config = pytoml.load(stream)
- except OSError:
- logging.info(
- 'Failed to read: {}'.format(args.config_file),
- exc_info=args.log_level == logging.DEBUG)
- config = {'default': {}}
- else:
- if 'default' not in config:
- config['default'] = {}
+ args.xdg_runtime_dir = os.environ.get('XDG_RUNTIME_DIR', '/tmp')
+ args.xdg_config_home = os.environ.get('XDG_CONFIG_HOME',
+ os.path.expanduser('~/.config'))
+ args.xdg_config_dirs = os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg')
+
+ # Configuration file(s) are optional,
+ # required arguments may be provided elsewhere
+ config = {'default': {}}
+ dirs = args.xdg_config_dirs.split(':')
+ dirs.extend((args.xdg_config_home, args.config_home))
+ for dir_ in dirs:
+ if dir_ is None:
+ continue
+ try:
+ with open(os.path.join(dir_, 'pypodman/pypodman.conf'),
+ 'r') as stream:
+ config.update(pytoml.load(stream))
+ except OSError:
+ pass
- def resolve(name, value):
+ def reqattr(name, value):
if value:
setattr(args, name, value)
return value
self.error('Required argument "%s" is not configured.' % name)
- xdg = os.path.join(os.environ['XDG_RUNTIME_DIR'], 'podman') \
- if os.environ.get('XDG_RUNTIME_DIR') else None
-
- resolve(
+ reqattr(
'run_dir',
getattr(args, 'run_dir')
or os.environ.get('RUN_DIR')
or config['default'].get('run_dir')
- or xdg
- or '/tmp/podman' if os.path.isdir('/tmp') else None
+ or os.path.join(args.xdg_runtime_dir, 'pypodman')
) # yapf: disable
- args.local_socket_path = os.path.join(args.run_dir, "podman.socket")
-
- resolve(
+ setattr(
+ args,
'host',
getattr(args, 'host')
or os.environ.get('HOST')
or config['default'].get('host')
) # yapf:disable
- resolve(
+ reqattr(
'user',
getattr(args, 'user')
or os.environ.get('USER')
@@ -158,7 +158,7 @@ class PodmanArgumentParser(argparse.ArgumentParser):
or getpass.getuser()
) # yapf:disable
- resolve(
+ reqattr(
'remote_socket_path',
getattr(args, 'remote_socket_path')
or os.environ.get('REMOTE_SOCKET_PATH')
@@ -166,14 +166,32 @@ class PodmanArgumentParser(argparse.ArgumentParser):
or '/run/podman/io.projectatomic.podman'
) # yapf:disable
- resolve(
+ reqattr(
+ 'log_level',
+ getattr(args, 'log_level')
+ or os.environ.get('LOG_LEVEL')
+ or config['default'].get('log_level')
+ or logging.WARNING
+ ) # yapf:disable
+
+ setattr(
+ args,
'identity_file',
getattr(args, 'identity_file')
or os.environ.get('IDENTITY_FILE')
or config['default'].get('identity_file')
- or os.path.expanduser('~{}/.ssh/id_rsa'.format(args.user))
+ or os.path.expanduser('~{}/.ssh/id_dsa'.format(args.user))
) # yapf:disable
+ if not os.path.isfile(args.identity_file):
+ args.identity_file = None
+
+ if args.host:
+ args.local_socket_path = os.path.join(args.run_dir,
+ "podman.socket")
+ else:
+ args.local_socket_path = args.remote_socket_path
+
args.local_uri = "unix:{}".format(args.local_socket_path)
args.remote_uri = "ssh://{}@{}{}".format(args.user, args.host,
args.remote_socket_path)
@@ -192,57 +210,3 @@ class PodmanArgumentParser(argparse.ArgumentParser):
logging.error("Try '{} --help' for more information.".format(
self.prog))
super().exit(2)
-
-
-if __name__ == '__main__':
- # Setup logging so we use stderr and can change logging level later
- # Do it now before there is any chance of a default setup.
- log = logging.getLogger()
- fmt = logging.Formatter('%(asctime)s | %(levelname)-8s | %(message)s',
- '%Y-%m-%d %H:%M:%S %Z')
- stderr = logging.StreamHandler(stream=sys.stderr)
- stderr.setFormatter(fmt)
- log.addHandler(stderr)
- log.setLevel(logging.INFO)
-
- parser = PodmanArgumentParser()
- args = parser.parse_args()
-
- log.setLevel(args.log_level)
- logging.debug('Logging initialized at level {}'.format(
- logging.getLevelName(logging.getLogger().getEffectiveLevel())))
-
- def istraceback():
- """Add traceback when logging events."""
- return log.getEffectiveLevel() == logging.DEBUG
-
- try:
- if not os.path.exists(args.run_dir):
- os.makedirs(args.run_dir)
- except PermissionError as e:
- logging.critical(e, exc_info=istraceback())
- sys.exit(6)
-
- # Klass(args).method() are setup by the sub-command's parser
- returncode = None
- try:
- obj = args.klass(args)
- except Exception as e:
- logging.critical(repr(e), exc_info=istraceback())
- logging.warning('See subparser "{}" configuration.'.format(
- args.subparser_name))
- sys.exit(5)
-
- try:
- returncode = getattr(obj, args.method)()
- except AttributeError as e:
- logging.critical(e, exc_info=istraceback())
- logging.warning('See subparser "{}" configuration.'.format(
- args.subparser_name))
- returncode = 3
- except (ConnectionResetError, TimeoutError) as e:
- logging.critical(e, exc_info=istraceback())
- logging.info('Review connection arguments for correctness.')
- returncode = 4
-
- sys.exit(0 if returncode is None else returncode)
diff --git a/contrib/python/cmd/lib/future_abstract.py b/contrib/python/pypodman/lib/future_abstract.py
index 75a1d42db..75a1d42db 100644
--- a/contrib/python/cmd/lib/future_abstract.py
+++ b/contrib/python/pypodman/lib/future_abstract.py
diff --git a/contrib/python/pypodman/lib/pypodman.py b/contrib/python/pypodman/lib/pypodman.py
new file mode 100755
index 000000000..4bc71a9cc
--- /dev/null
+++ b/contrib/python/pypodman/lib/pypodman.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+"""Remote podman client."""
+
+import logging
+import os
+import sys
+
+import lib.actions
+from lib import PodmanArgumentParser
+
+assert lib.actions # silence pyflakes
+
+
+def main():
+ """Entry point."""
+ # Setup logging so we use stderr and can change logging level later
+ # Do it now before there is any chance of a default setup hardcoding crap.
+ log = logging.getLogger()
+ fmt = logging.Formatter('%(asctime)s | %(levelname)-8s | %(message)s',
+ '%Y-%m-%d %H:%M:%S %Z')
+ stderr = logging.StreamHandler(stream=sys.stderr)
+ stderr.setFormatter(fmt)
+ log.addHandler(stderr)
+ log.setLevel(logging.WARNING)
+
+ parser = PodmanArgumentParser()
+ args = parser.parse_args()
+
+ log.setLevel(args.log_level)
+ logging.debug('Logging initialized at level {}'.format(
+ logging.getLevelName(logging.getLogger().getEffectiveLevel())))
+
+ def want_tb():
+ """Add traceback when logging events."""
+ return log.getEffectiveLevel() == logging.DEBUG
+
+ try:
+ if not os.path.exists(args.run_dir):
+ os.makedirs(args.run_dir)
+ except PermissionError as e:
+ logging.critical(e, exc_info=want_tb())
+ sys.exit(6)
+
+ # class_(args).method() are set by the sub-command's parser
+ returncode = None
+ try:
+ obj = args.class_(args)
+ except Exception as e:
+ logging.critical(repr(e), exc_info=want_tb())
+ logging.warning('See subparser "{}" configuration.'.format(
+ args.subparser_name))
+ sys.exit(5)
+
+ try:
+ returncode = getattr(obj, args.method)()
+ except AttributeError as e:
+ logging.critical(e, exc_info=want_tb())
+ logging.warning('See subparser "{}" configuration.'.format(
+ args.subparser_name))
+ returncode = 3
+ except KeyboardInterrupt:
+ pass
+ except (
+ ConnectionRefusedError,
+ ConnectionResetError,
+ TimeoutError,
+ ) as e:
+ logging.critical(e, exc_info=want_tb())
+ logging.info('Review connection arguments for correctness.')
+ returncode = 4
+
+ return 0 if returncode is None else returncode
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/contrib/python/cmd/lib/report.py b/contrib/python/pypodman/lib/report.py
index 25fe2ae0d..25fe2ae0d 100644
--- a/contrib/python/cmd/lib/report.py
+++ b/contrib/python/pypodman/lib/report.py
diff --git a/contrib/python/pypodman/requirements.txt b/contrib/python/pypodman/requirements.txt
new file mode 100644
index 000000000..f9cd4f904
--- /dev/null
+++ b/contrib/python/pypodman/requirements.txt
@@ -0,0 +1,4 @@
+humanize
+podman
+pytoml
+setuptools>=39.2.0
diff --git a/contrib/python/pypodman/setup.py b/contrib/python/pypodman/setup.py
new file mode 100644
index 000000000..0483eb71c
--- /dev/null
+++ b/contrib/python/pypodman/setup.py
@@ -0,0 +1,44 @@
+import os
+
+from setuptools import find_packages, setup
+
+root = os.path.abspath(os.path.dirname(__file__))
+
+with open(os.path.join(root, 'README.md')) as me:
+ readme = me.read()
+
+with open(os.path.join(root, 'requirements.txt')) as r:
+ requirements = r.read().splitlines()
+
+print(find_packages(where='pypodman', exclude=['test']))
+
+setup(
+ name='pypodman',
+ version=os.environ.get('PODMAN_VERSION', '0.0.0'),
+ description='A client for communicating with a Podman server',
+ author_email='jhonce@redhat.com',
+ author='Jhon Honce',
+ license='Apache Software License',
+ long_description=readme,
+ entry_points={'console_scripts': [
+ 'pypodman = lib.pypodman:main',
+ ]},
+ include_package_data=True,
+ install_requires=requirements,
+ keywords='varlink libpod podman pypodman',
+ packages=find_packages(exclude=['test']),
+ python_requires='>=3',
+ zip_safe=True,
+ url='http://github.com/projectatomic/libpod',
+ classifiers=[
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX',
+ 'Programming Language :: Python :: 3.6',
+ 'Topic :: System :: Systems Administration',
+ 'Topic :: Utilities',
+ ])
diff --git a/contrib/python/pypodman/test/test_report.py b/contrib/python/pypodman/test/test_report.py
new file mode 100644
index 000000000..280a9a954
--- /dev/null
+++ b/contrib/python/pypodman/test/test_report.py
@@ -0,0 +1,23 @@
+from __future__ import absolute_import
+
+import unittest
+
+from report import Report, ReportColumn
+
+
+class TestReport(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def test_report_column(self):
+ rc = ReportColumn('k', 'v', 3)
+ self.assertEqual(rc.key, 'k')
+ self.assertEqual(rc.display, 'v')
+ self.assertEqual(rc.width, 3)
+ self.assertIsNone(rc.default)
+
+ rc = ReportColumn('k', 'v', 3, 'd')
+ self.assertEqual(rc.key, 'k')
+ self.assertEqual(rc.display, 'v')
+ self.assertEqual(rc.width, 3)
+ self.assertEqual(rc.default, 'd')