Repository: kubernetes-incubator/client-python (python)

Issue:
`stat: can't specify None for path argument` when loading config from GKE cluster
The client appears to be unable to parse authentication information from GKE clusters.

The exception is being raised here: https://github.com/kubernetes-incubator/client-python/blob/master/kubernetes/config/kube_config.py#L185, when `_load_cluster_info` expects there to be a `client-certificate` key in the user dictionary.

With the `GKE` provider, my config looks like this:

```
{'auth-provider': {'name': 'gcp', 'config': {'expiry': datetime.datetime(2016, 12, 27, 22, 18, 24, 911838), 'access-token': '<redacted>'}}}
```

I also had to fix this in pykube, as follows: https://github.com/kelproject/pykube/pull/67/files. Would you accept a fix along those lines here too?

Here is the full stack trace:

```
Traceback (most recent call last):
  File "dns_controller.py", line 17, in <module>
    main()
  File "dns_controller.py", line 6, in main
    config.load_kube_config()
  File "/Users/paul/.virtualenvs/dns-controller/lib/python3.5/site-packages/kubernetes/config/kube_config.py", line 297, in load_kube_config
    client_configuration=client_configuration).load_and_set()
  File "/Users/paul/.virtualenvs/dns-controller/lib/python3.5/site-packages/kubernetes/config/kube_config.py", line 203, in load_and_set
    self._load_cluster_info()
  File "/Users/paul/.virtualenvs/dns-controller/lib/python3.5/site-packages/kubernetes/config/kube_config.py", line 187, in _load_cluster_info
    file_base_path=self._config_base_path).as_file()
  File "/Users/paul/.virtualenvs/dns-controller/lib/python3.5/site-packages/kubernetes/config/kube_config.py", line 82, in as_file
    if not os.path.isfile(self._file):
  File "/Users/paul/.virtualenvs/dns-controller/bin/../lib/python3.5/genericpath.py", line 30, in isfile
    st = os.stat(path)
TypeError: stat: can't specify None for path argument
```

Pull request:
Bugfix: fix bearer token
fixes #77 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index afdbc2daa..0956ebb13 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# v1.0.0a4
+
+- Bugfix: Fixed broken config loader #77
+
 # v1.0.0a3
 
 - Add context switch to kube config loader #46 
diff --git a/kubernetes/config/kube_config.py b/kubernetes/config/kube_config.py
index 765196201..ea805b9f2 100644
--- a/kubernetes/config/kube_config.py
+++ b/kubernetes/config/kube_config.py
@@ -79,7 +79,7 @@ class FileOrData(object):
         if use_data_if_no_file:
             self._file = _create_temp_file_with_content(
                 base64.decodestring(self._data.encode()))
-        if not os.path.isfile(self._file):
+        if self._file and not os.path.isfile(self._file):
             raise ConfigException("File does not exists: %s" % self._file)
         return self._file
 
@@ -157,7 +157,7 @@ class KubeConfigLoader(object):
         # Ignore configs in auth-provider and rely on GoogleCredentials
         # caching and refresh mechanism.
         # TODO: support gcp command based token ("cmd-path" config).
-        self.token = self._get_google_credentials()
+        self.token = "Bearer %s" % self._get_google_credentials()
         return self.token
 
     def _load_user_token(self):
@@ -165,7 +165,7 @@ class KubeConfigLoader(object):
             self._user, 'tokenFile', 'token',
             file_base_path=self._config_base_path).as_data()
         if token:
-            self.token = token
+            self.token = "Bearer %s" % token
             return True
 
     def _load_user_pass_token(self):


Test patch:
diff --git a/kubernetes/config/kube_config_test.py b/kubernetes/config/kube_config_test.py
index db39185ca..26b42a219 100644
--- a/kubernetes/config/kube_config_test.py
+++ b/kubernetes/config/kube_config_test.py
@@ -26,6 +26,8 @@ from .kube_config import (ConfigNode, FileOrData, KubeConfigLoader,
                           load_kube_config, list_kube_config_contexts,
                           new_client_from_config)
 
+BEARER_TOKEN_FORMAT = "Bearer %s"
+
 NON_EXISTING_FILE = "zz_non_existing_file_472398324"
 
 
@@ -407,7 +409,8 @@ class TestKubeConfigLoader(BaseTestCase):
         self.assertEqual(expected, actual)
 
     def test_simple_token(self):
-        expected = FakeConfig(host=TEST_HOST, token=TEST_DATA_BASE64)
+        expected = FakeConfig(host=TEST_HOST,
+                              token=BEARER_TOKEN_FORMAT % TEST_DATA_BASE64)
         actual = FakeConfig()
         KubeConfigLoader(
             config_dict=self.TEST_KUBE_CONFIG,
@@ -420,10 +423,12 @@ class TestKubeConfigLoader(BaseTestCase):
             config_dict=self.TEST_KUBE_CONFIG,
             active_context="simple_token")
         self.assertTrue(loader._load_user_token())
-        self.assertEqual(TEST_DATA_BASE64, loader.token)
+        self.assertEqual(BEARER_TOKEN_FORMAT % TEST_DATA_BASE64, loader.token)
 
     def test_gcp(self):
-        expected = FakeConfig(host=TEST_HOST, token=TEST_ANOTHER_DATA_BASE64)
+        expected = FakeConfig(
+            host=TEST_HOST,
+            token=BEARER_TOKEN_FORMAT % TEST_ANOTHER_DATA_BASE64)
         actual = FakeConfig()
         KubeConfigLoader(
             config_dict=self.TEST_KUBE_CONFIG,
@@ -439,7 +444,8 @@ class TestKubeConfigLoader(BaseTestCase):
             active_context="gcp",
             get_google_credentials=lambda: TEST_ANOTHER_DATA_BASE64)
         self.assertTrue(loader._load_gcp_token())
-        self.assertEqual(TEST_ANOTHER_DATA_BASE64, loader.token)
+        self.assertEqual(BEARER_TOKEN_FORMAT % TEST_ANOTHER_DATA_BASE64,
+                         loader.token)
 
     def test_user_pass(self):
         expected = FakeConfig(host=TEST_HOST, token=TEST_BASIC_TOKEN)
@@ -458,13 +464,6 @@ class TestKubeConfigLoader(BaseTestCase):
         self.assertEqual(TEST_BASIC_TOKEN, loader.token)
 
     def test_ssl_no_cert_files(self):
-        expected = FakeConfig(
-            host=TEST_SSL_HOST,
-            token=TEST_DATA_BASE64,
-            cert_file=TEST_CLIENT_CERT,
-            key_file=TEST_CLIENT_KEY,
-            ssl_ca_cert=TEST_CERTIFICATE_AUTH
-        )
         actual = FakeConfig()
         loader = KubeConfigLoader(
             config_dict=self.TEST_KUBE_CONFIG,
@@ -475,7 +474,7 @@ class TestKubeConfigLoader(BaseTestCase):
     def test_ssl(self):
         expected = FakeConfig(
             host=TEST_SSL_HOST,
-            token=TEST_DATA_BASE64,
+            token=BEARER_TOKEN_FORMAT % TEST_DATA_BASE64,
             cert_file=self._create_temp_file(TEST_CLIENT_CERT),
             key_file=self._create_temp_file(TEST_CLIENT_KEY),
             ssl_ca_cert=self._create_temp_file(TEST_CERTIFICATE_AUTH)
@@ -513,7 +512,7 @@ class TestKubeConfigLoader(BaseTestCase):
     def test_ssl_with_relative_ssl_files(self):
         expected = FakeConfig(
             host=TEST_SSL_HOST,
-            token=TEST_DATA_BASE64,
+            token=BEARER_TOKEN_FORMAT % TEST_DATA_BASE64,
             cert_file=self._create_temp_file(TEST_CLIENT_CERT),
             key_file=self._create_temp_file(TEST_CLIENT_KEY),
             ssl_ca_cert=self._create_temp_file(TEST_CERTIFICATE_AUTH)
@@ -539,7 +538,8 @@ class TestKubeConfigLoader(BaseTestCase):
             shutil.rmtree(temp_dir)
 
     def test_load_kube_config(self):
-        expected = FakeConfig(host=TEST_HOST, token=TEST_DATA_BASE64)
+        expected = FakeConfig(host=TEST_HOST,
+                              token=BEARER_TOKEN_FORMAT % TEST_DATA_BASE64)
         config_file = self._create_temp_file(yaml.dump(self.TEST_KUBE_CONFIG))
         actual = FakeConfig()
         load_kube_config(config_file=config_file,context="simple_token",
@@ -564,7 +564,7 @@ class TestKubeConfigLoader(BaseTestCase):
         client = new_client_from_config(
             config_file=config_file, context="simple_token")
         self.assertEqual(TEST_HOST, client.config.host)
-        self.assertEqual(TEST_DATA_BASE64,
+        self.assertEqual(BEARER_TOKEN_FORMAT % TEST_DATA_BASE64,
                          client.config.api_key['authorization'])