diff --git a/pykube/__init__.py b/pykube/__init__.py index 012592d..6d9fe4a 100644 --- a/pykube/__init__.py +++ b/pykube/__init__.py @@ -6,7 +6,7 @@ from .config import KubeConfig # noqa from .exceptions import KubernetesError, PyKubeError, ObjectDoesNotExist # noqa -from .http import HTTPClient # noqa +from .http import HTTPClient, login # noqa from .objects import ( # noqa object_factory, ConfigMap, diff --git a/pykube/console.py b/pykube/console.py index 2ea46a6..1247b0b 100644 --- a/pykube/console.py +++ b/pykube/console.py @@ -20,12 +20,8 @@ def main(argv=None): parser.add_argument('-c', help='Python program passed in as string', metavar='SCRIPT') args = parser.parse_args(argv) - config = pykube.KubeConfig.from_file(args.kubeconfig) - - if args.context: - config.set_current_context(args.context) - - api = pykube.HTTPClient(config) + api = pykube.login(kubeconfig=args.kubeconfig, kubecontext=args.context) + config = api.config context = { '__name__': '__console__', diff --git a/pykube/http.py b/pykube/http.py index ccb5004..fdcee52 100644 --- a/pykube/http.py +++ b/pykube/http.py @@ -7,6 +7,7 @@ import posixpath import shlex import subprocess +from typing import Optional try: import google.auth @@ -342,3 +343,30 @@ def delete(self, *args, **kwargs): - `kwargs`: Keyword arguments """ return self.session.delete(*args, **self.get_kwargs(**kwargs)) + + +def login( + kubeconfig: Optional[str] = None, + kubecontext: Optional[str] = None, +) -> HTTPClient: + """Make Kubernetes API client. + + :param kubeconfig: (optional) path to kubeconfig, + if not passed will use in-cluster config or + default kubectl ones (in that order of preference) + :param kubecontext: (optional) name of the context in the kubeconfig file + :return: pykube.HTTPClient + """ + if kubeconfig: + # if passed kubeconfig file explicitly - use it + config = KubeConfig.from_file(kubeconfig) + else: + try: + # running in cluster + config = KubeConfig.from_service_account() + except FileNotFoundError: + # not running in cluster => load default local KUBECONFIG + config = KubeConfig.from_file() + if kubecontext: + config.set_current_context(kubecontext) + return HTTPClient(config) diff --git a/tests/test_login.py b/tests/test_login.py new file mode 100644 index 0000000..b44c65c --- /dev/null +++ b/tests/test_login.py @@ -0,0 +1,41 @@ +from unittest import mock + +from pykube.http import login +from . import TestCase + + +@mock.patch('pykube.http.KubeConfig') +@mock.patch('pykube.http.HTTPClient') +class TestLogin(TestCase): + def test_login_with_config(self, client, config): + api = login(kubeconfig='/path/to/file') + config.from_file.assert_called_once_with('/path/to/file') + config.from_service_account.assert_not_called() + config.from_file.return_value.set_current_context.assert_not_called() + client.assert_called_once_with(config.from_file.return_value) + assert api == client.return_value + + def test_login_with_config_and_context(self, client, config): + api = login(kubeconfig='/path/to/file', kubecontext='fake') + config.from_file.assert_called_once_with('/path/to/file') + config.from_service_account.assert_not_called() + config.from_file.return_value.set_current_context.assert_called_once_with('fake') + client.assert_called_once_with(config.from_file.return_value) + assert api == client.return_value + + def test_login_with_incluster(self, client, config): + api = login() + config.from_service_account.assert_called_once_with() + config.from_file.assert_not_called() + config.from_service_account.return_value.set_current_context.assert_not_called() + client.assert_called_once_with(config.from_service_account.return_value) + assert api == client.return_value + + def test_login_with_default_config(self, client, config): + config.from_service_account.side_effect = FileNotFoundError + api = login() + config.from_service_account.assert_called_once_with() + config.from_file.assert_called_once_with() + config.from_file.return_value.set_current_context.assert_not_called() + client.assert_called_once_with(config.from_file.return_value) + assert api == client.return_value diff --git a/tox.ini b/tox.ini index 1cfaf28..0936372 100644 --- a/tox.ini +++ b/tox.ini @@ -8,10 +8,11 @@ envlist = [testenv] deps = - coverage == 4.0.3 - flake8 == 2.5.4 - pytest == 2.9.0 - pytest-cov == 2.2.1 + coverage == 4.5.4 + flake8 == 3.7.8 + pytest == 5.2.1 + pytest-cov == 2.8.1 + responses == 0.10.6 usedevelop = True setenv = LANG=en_US.UTF-8